peaks-loop 4.1.3 → 4.1.4
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/.claude-plugin/marketplace.json +2 -2
- package/CHANGELOG.md +56 -0
- package/README-en.md +1 -1
- package/README.md +1 -1
- package/dist/cli/commands/asset-command-shared.d.ts +12 -0
- package/dist/cli/commands/asset-command-shared.js +45 -0
- package/dist/cli/commands/asset-commands.d.ts +6 -1
- package/dist/cli/commands/asset-commands.js +11 -372
- package/dist/cli/commands/asset-crystallize-command.d.ts +3 -0
- package/dist/cli/commands/asset-crystallize-command.js +60 -0
- package/dist/cli/commands/asset-crystallize-payload.d.ts +47 -0
- package/dist/cli/commands/asset-crystallize-payload.js +85 -0
- package/dist/cli/commands/asset-crystallize-runner.d.ts +3 -0
- package/dist/cli/commands/asset-crystallize-runner.js +133 -0
- package/dist/cli/commands/asset-dispose-command.d.ts +3 -0
- package/dist/cli/commands/asset-dispose-command.js +99 -0
- package/dist/cli/commands/asset-status-command.d.ts +3 -0
- package/dist/cli/commands/asset-status-command.js +100 -0
- package/dist/cli/commands/baseline-audit-command.d.ts +3 -0
- package/dist/cli/commands/baseline-audit-command.js +64 -0
- package/dist/cli/commands/baseline-command-shared.d.ts +23 -0
- package/dist/cli/commands/baseline-command-shared.js +39 -0
- package/dist/cli/commands/baseline-commands.js +33 -313
- package/dist/cli/commands/baseline-freeze-commands.d.ts +4 -0
- package/dist/cli/commands/baseline-freeze-commands.js +81 -0
- package/dist/cli/commands/baseline-guard-command.d.ts +3 -0
- package/dist/cli/commands/baseline-guard-command.js +52 -0
- package/dist/cli/commands/baseline-read-commands.d.ts +5 -0
- package/dist/cli/commands/baseline-read-commands.js +72 -0
- package/dist/cli/commands/baseline-rollback-commands.d.ts +4 -0
- package/dist/cli/commands/baseline-rollback-commands.js +88 -0
- package/dist/cli/commands/classify-downgrade-command.d.ts +9 -0
- package/dist/cli/commands/classify-downgrade-command.js +21 -0
- package/dist/cli/commands/classify-run-command.d.ts +9 -0
- package/dist/cli/commands/classify-run-command.js +73 -0
- package/dist/cli/commands/classify-signals.d.ts +5 -0
- package/dist/cli/commands/classify-signals.js +104 -0
- package/dist/cli/commands/code-emit-handoff-command.js +40 -3
- package/dist/cli/commands/code-gate-step-08-command.js +25 -9
- package/dist/cli/commands/codegraph-command-options.d.ts +22 -0
- package/dist/cli/commands/codegraph-command-options.js +22 -0
- package/dist/cli/commands/codegraph-commands.d.ts +2 -2
- package/dist/cli/commands/codegraph-commands.js +14 -397
- package/dist/cli/commands/codegraph-config-restore-command.d.ts +3 -0
- package/dist/cli/commands/codegraph-config-restore-command.js +200 -0
- package/dist/cli/commands/codegraph-proxy-commands.d.ts +10 -0
- package/dist/cli/commands/codegraph-proxy-commands.js +159 -0
- package/dist/cli/commands/codegraph-repair-commands.d.ts +3 -0
- package/dist/cli/commands/codegraph-repair-commands.js +94 -0
- package/dist/cli/commands/codegraph-status-command.d.ts +1 -1
- package/dist/cli/commands/codegraph-status-command.js +27 -214
- package/dist/cli/commands/codegraph-status-integrity.d.ts +44 -0
- package/dist/cli/commands/codegraph-status-integrity.js +121 -0
- package/dist/cli/commands/codegraph-status-json.d.ts +5 -0
- package/dist/cli/commands/codegraph-status-json.js +127 -0
- package/dist/cli/commands/container-command-shared.d.ts +60 -0
- package/dist/cli/commands/container-command-shared.js +52 -0
- package/dist/cli/commands/container-commands.d.ts +1 -1
- package/dist/cli/commands/container-commands.js +4 -216
- package/dist/cli/commands/container-release-command.d.ts +3 -0
- package/dist/cli/commands/container-release-command.js +105 -0
- package/dist/cli/commands/container-spawn-command.d.ts +3 -0
- package/dist/cli/commands/container-spawn-command.js +148 -0
- package/dist/cli/commands/context-check-command.d.ts +3 -0
- package/dist/cli/commands/context-check-command.js +81 -0
- package/dist/cli/commands/context-commands.d.ts +2 -7
- package/dist/cli/commands/context-commands.js +6 -276
- package/dist/cli/commands/context-layer-command.d.ts +3 -0
- package/dist/cli/commands/context-layer-command.js +34 -0
- package/dist/cli/commands/context-layer-fetchers.d.ts +15 -0
- package/dist/cli/commands/context-layer-fetchers.js +162 -0
- package/dist/cli/commands/context-status-command.d.ts +17 -0
- package/dist/cli/commands/context-status-command.js +41 -0
- package/dist/cli/commands/contract-write-command.d.ts +3 -0
- package/dist/cli/commands/contract-write-command.js +144 -0
- package/dist/cli/commands/core/doctor-bindings.d.ts +17 -0
- package/dist/cli/commands/core/doctor-bindings.js +30 -0
- package/dist/cli/commands/core/doctor-command.d.ts +4 -18
- package/dist/cli/commands/core/doctor-command.js +2 -323
- package/dist/cli/commands/core/doctor-logs.d.ts +8 -0
- package/dist/cli/commands/core/doctor-logs.js +32 -0
- package/dist/cli/commands/core/doctor-probes.d.ts +3 -0
- package/dist/cli/commands/core/doctor-probes.js +55 -0
- package/dist/cli/commands/core/doctor-run-command.d.ts +12 -0
- package/dist/cli/commands/core/doctor-run-command.js +172 -0
- package/dist/cli/commands/core/doctor-summary.d.ts +7 -0
- package/dist/cli/commands/core/doctor-summary.js +39 -0
- package/dist/cli/commands/core/memory-command-shared.d.ts +25 -0
- package/dist/cli/commands/core/memory-command-shared.js +20 -0
- package/dist/cli/commands/core/memory-command.d.ts +1 -1
- package/dist/cli/commands/core/memory-command.js +6 -227
- package/dist/cli/commands/core/memory-delegated-verbs.d.ts +4 -0
- package/dist/cli/commands/core/memory-delegated-verbs.js +178 -0
- package/dist/cli/commands/core/memory-extract-command.d.ts +3 -0
- package/dist/cli/commands/core/memory-extract-command.js +90 -0
- package/dist/cli/commands/core/memory-sync-command.d.ts +3 -0
- package/dist/cli/commands/core/memory-sync-command.js +38 -0
- package/dist/cli/commands/core/session-command.d.ts +1 -1
- package/dist/cli/commands/core/session-command.js +12 -206
- package/dist/cli/commands/core/session-info-command.d.ts +3 -0
- package/dist/cli/commands/core/session-info-command.js +142 -0
- package/dist/cli/commands/core/session-verb-commands.d.ts +5 -0
- package/dist/cli/commands/core/session-verb-commands.js +58 -0
- package/dist/cli/commands/core/standards-command.d.ts +1 -24
- package/dist/cli/commands/core/standards-command.js +33 -201
- package/dist/cli/commands/core/standards-init-command.d.ts +3 -0
- package/dist/cli/commands/core/standards-init-command.js +87 -0
- package/dist/cli/commands/core/standards-lint.d.ts +24 -0
- package/dist/cli/commands/core/standards-lint.js +57 -0
- package/dist/cli/commands/core/standards-migrate-command.d.ts +3 -0
- package/dist/cli/commands/core/standards-migrate-command.js +57 -0
- package/dist/cli/commands/cron-scheduler-commands.d.ts +5 -1
- package/dist/cli/commands/cron-scheduler-commands.js +36 -206
- package/dist/cli/commands/cron-scheduler-run-once-command.d.ts +7 -0
- package/dist/cli/commands/cron-scheduler-run-once-command.js +35 -0
- package/dist/cli/commands/cron-scheduler-shared.d.ts +6 -0
- package/dist/cli/commands/cron-scheduler-shared.js +48 -0
- package/dist/cli/commands/cron-scheduler-start-command.d.ts +7 -0
- package/dist/cli/commands/cron-scheduler-start-command.js +65 -0
- package/dist/cli/commands/cron-scheduler-status-command.d.ts +7 -0
- package/dist/cli/commands/cron-scheduler-status-command.js +46 -0
- package/dist/cli/commands/cron-scheduler-stop-command.d.ts +7 -0
- package/dist/cli/commands/cron-scheduler-stop-command.js +61 -0
- package/dist/cli/commands/dispatch-dag-envelope.d.ts +41 -0
- package/dist/cli/commands/dispatch-dag-envelope.js +49 -0
- package/dist/cli/commands/dispatch-dag-failure.d.ts +18 -0
- package/dist/cli/commands/dispatch-dag-failure.js +16 -0
- package/dist/cli/commands/dispatch-dag-preflight.d.ts +51 -0
- package/dist/cli/commands/dispatch-dag-preflight.js +105 -0
- package/dist/cli/commands/dispatch-dag-runners.d.ts +48 -0
- package/dist/cli/commands/dispatch-dag-runners.js +73 -0
- package/dist/cli/commands/dispatch-from-dag.d.ts +27 -0
- package/dist/cli/commands/dispatch-from-dag.js +87 -257
- package/dist/cli/commands/final-review-command-envelopes.d.ts +44 -0
- package/dist/cli/commands/final-review-command-envelopes.js +100 -0
- package/dist/cli/commands/final-review-command-shared.d.ts +52 -0
- package/dist/cli/commands/final-review-command-shared.js +35 -0
- package/dist/cli/commands/final-review-commands.d.ts +7 -27
- package/dist/cli/commands/final-review-commands.js +13 -240
- package/dist/cli/commands/final-review-prepare-command.d.ts +3 -0
- package/dist/cli/commands/final-review-prepare-command.js +200 -0
- package/dist/cli/commands/governance-classify-contract-commands.d.ts +23 -9
- package/dist/cli/commands/governance-classify-contract-commands.js +26 -269
- package/dist/cli/commands/hooks-command-shared.d.ts +42 -0
- package/dist/cli/commands/hooks-command-shared.js +32 -0
- package/dist/cli/commands/hooks-commands.d.ts +20 -0
- package/dist/cli/commands/hooks-commands.js +75 -309
- package/dist/cli/commands/hooks-install-envelopes.d.ts +6 -0
- package/dist/cli/commands/hooks-install-envelopes.js +144 -0
- package/dist/cli/commands/hooks-status-command.d.ts +3 -0
- package/dist/cli/commands/hooks-status-command.js +93 -0
- package/dist/cli/commands/hooks-uninstall-command.d.ts +3 -0
- package/dist/cli/commands/hooks-uninstall-command.js +43 -0
- package/dist/cli/commands/loop-command-shared.d.ts +31 -0
- package/dist/cli/commands/loop-command-shared.js +15 -0
- package/dist/cli/commands/loop-commands.d.ts +12 -17
- package/dist/cli/commands/loop-commands.js +56 -238
- package/dist/cli/commands/loop-export-command.d.ts +3 -0
- package/dist/cli/commands/loop-export-command.js +73 -0
- package/dist/cli/commands/loop-goal-compose-command.d.ts +3 -0
- package/dist/cli/commands/loop-goal-compose-command.js +36 -0
- package/dist/cli/commands/loop-import-command.d.ts +3 -0
- package/dist/cli/commands/loop-import-command.js +86 -0
- package/dist/cli/commands/loop-placeholder-commands.d.ts +3 -0
- package/dist/cli/commands/loop-placeholder-commands.js +52 -0
- package/dist/cli/commands/memory-command-shared.d.ts +59 -0
- package/dist/cli/commands/memory-command-shared.js +39 -0
- package/dist/cli/commands/memory-commands.d.ts +6 -79
- package/dist/cli/commands/memory-commands.js +19 -309
- package/dist/cli/commands/memory-ingest-command.d.ts +3 -0
- package/dist/cli/commands/memory-ingest-command.js +50 -0
- package/dist/cli/commands/memory-list-command.d.ts +16 -0
- package/dist/cli/commands/memory-list-command.js +129 -0
- package/dist/cli/commands/memory-reindex-command.d.ts +9 -0
- package/dist/cli/commands/memory-reindex-command.js +78 -0
- package/dist/cli/commands/memory-rotate-command.d.ts +3 -0
- package/dist/cli/commands/memory-rotate-command.js +55 -0
- package/dist/cli/commands/memory-search-command.d.ts +7 -0
- package/dist/cli/commands/memory-search-command.js +46 -0
- package/dist/cli/commands/openspec-archive-command.d.ts +3 -0
- package/dist/cli/commands/openspec-archive-command.js +55 -0
- package/dist/cli/commands/openspec-command-shared.d.ts +62 -0
- package/dist/cli/commands/openspec-command-shared.js +135 -0
- package/dist/cli/commands/openspec-commands.d.ts +1 -1
- package/dist/cli/commands/openspec-commands.js +33 -306
- package/dist/cli/commands/openspec-from-doctor-command.d.ts +3 -0
- package/dist/cli/commands/openspec-from-doctor-command.js +66 -0
- package/dist/cli/commands/openspec-init-command.d.ts +3 -0
- package/dist/cli/commands/openspec-init-command.js +49 -0
- package/dist/cli/commands/openspec-list-command.d.ts +3 -0
- package/dist/cli/commands/openspec-list-command.js +27 -0
- package/dist/cli/commands/openspec-render-command.d.ts +3 -0
- package/dist/cli/commands/openspec-render-command.js +33 -0
- package/dist/cli/commands/openspec-show-command.d.ts +3 -0
- package/dist/cli/commands/openspec-show-command.js +33 -0
- package/dist/cli/commands/openspec-to-rd-command.d.ts +3 -0
- package/dist/cli/commands/openspec-to-rd-command.js +33 -0
- package/dist/cli/commands/openspec-validate-command.d.ts +3 -0
- package/dist/cli/commands/openspec-validate-command.js +45 -0
- package/dist/cli/commands/playwright-browser-command.d.ts +8 -0
- package/dist/cli/commands/playwright-browser-command.js +61 -0
- package/dist/cli/commands/playwright-commands.d.ts +10 -62
- package/dist/cli/commands/playwright-commands.js +77 -400
- package/dist/cli/commands/playwright-envelope.d.ts +8 -0
- package/dist/cli/commands/playwright-envelope.js +29 -0
- package/dist/cli/commands/playwright-ls-stop-commands.d.ts +4 -0
- package/dist/cli/commands/playwright-ls-stop-commands.js +74 -0
- package/dist/cli/commands/playwright-session-store.d.ts +65 -0
- package/dist/cli/commands/playwright-session-store.js +189 -0
- package/dist/cli/commands/project-commands.d.ts +19 -0
- package/dist/cli/commands/project-commands.js +98 -259
- package/dist/cli/commands/project-context-command.d.ts +3 -0
- package/dist/cli/commands/project-context-command.js +44 -0
- package/dist/cli/commands/project-dashboard-command.d.ts +3 -0
- package/dist/cli/commands/project-dashboard-command.js +74 -0
- package/dist/cli/commands/project-knowledge-command.d.ts +3 -0
- package/dist/cli/commands/project-knowledge-command.js +48 -0
- package/dist/cli/commands/project-memories-show-command.d.ts +3 -0
- package/dist/cli/commands/project-memories-show-command.js +87 -0
- package/dist/cli/commands/project-memory-index-command.d.ts +3 -0
- package/dist/cli/commands/project-memory-index-command.js +31 -0
- package/dist/cli/commands/qa-archive-screenshots-command.d.ts +3 -0
- package/dist/cli/commands/qa-archive-screenshots-command.js +53 -0
- package/dist/cli/commands/qa-commands.d.ts +14 -87
- package/dist/cli/commands/qa-commands.js +17 -315
- package/dist/cli/commands/qa-context-prestep.d.ts +1 -0
- package/dist/cli/commands/qa-context-prestep.js +34 -0
- package/dist/cli/commands/qa-run-command.d.ts +3 -0
- package/dist/cli/commands/qa-run-command.js +105 -0
- package/dist/cli/commands/qa-run-options.d.ts +23 -0
- package/dist/cli/commands/qa-run-options.js +31 -0
- package/dist/cli/commands/qa-run-slice.d.ts +41 -0
- package/dist/cli/commands/qa-run-slice.js +145 -0
- package/dist/cli/commands/release-canary-command.d.ts +28 -0
- package/dist/cli/commands/release-canary-command.js +129 -0
- package/dist/cli/commands/release-command-shared.d.ts +13 -0
- package/dist/cli/commands/release-command-shared.js +18 -0
- package/dist/cli/commands/release-commands.d.ts +10 -18
- package/dist/cli/commands/release-commands.js +25 -298
- package/dist/cli/commands/release-done-command.d.ts +3 -0
- package/dist/cli/commands/release-done-command.js +64 -0
- package/dist/cli/commands/release-hotfix-command.d.ts +3 -0
- package/dist/cli/commands/release-hotfix-command.js +50 -0
- package/dist/cli/commands/release-plan-command.d.ts +3 -0
- package/dist/cli/commands/release-plan-command.js +33 -0
- package/dist/cli/commands/release-precheck-command.d.ts +3 -0
- package/dist/cli/commands/release-precheck-command.js +28 -0
- package/dist/cli/commands/release-promote-command.d.ts +3 -0
- package/dist/cli/commands/release-promote-command.js +34 -0
- package/dist/cli/commands/release-rollback-command.d.ts +3 -0
- package/dist/cli/commands/release-rollback-command.js +33 -0
- package/dist/cli/commands/release-watch-command.d.ts +3 -0
- package/dist/cli/commands/release-watch-command.js +44 -0
- package/dist/cli/commands/sediment-argv-flags.d.ts +54 -0
- package/dist/cli/commands/sediment-argv-flags.js +116 -0
- package/dist/cli/commands/sediment-command-shared.d.ts +15 -0
- package/dist/cli/commands/sediment-command-shared.js +5 -0
- package/dist/cli/commands/sediment-commands.d.ts +35 -59
- package/dist/cli/commands/sediment-commands.js +36 -590
- package/dist/cli/commands/sediment-pool-commands.d.ts +9 -0
- package/dist/cli/commands/sediment-pool-commands.js +185 -0
- package/dist/cli/commands/sediment-query-commands.d.ts +4 -0
- package/dist/cli/commands/sediment-query-commands.js +94 -0
- package/dist/cli/commands/sediment-release-commands.d.ts +8 -0
- package/dist/cli/commands/sediment-release-commands.js +232 -0
- package/dist/cli/commands/sop-advance-command.d.ts +3 -0
- package/dist/cli/commands/sop-advance-command.js +160 -0
- package/dist/cli/commands/sop-check-command.d.ts +3 -0
- package/dist/cli/commands/sop-check-command.js +44 -0
- package/dist/cli/commands/sop-command-shared.d.ts +23 -0
- package/dist/cli/commands/sop-command-shared.js +18 -0
- package/dist/cli/commands/sop-commands.d.ts +15 -1
- package/dist/cli/commands/sop-commands.js +26 -240
- package/dist/cli/commands/sop-init-command.d.ts +3 -0
- package/dist/cli/commands/sop-init-command.js +51 -0
- package/dist/cli/commands/sop-lint-command.d.ts +3 -0
- package/dist/cli/commands/sop-lint-command.js +64 -0
- package/dist/cli/commands/sop-register-command.d.ts +3 -0
- package/dist/cli/commands/sop-register-command.js +48 -0
- package/dist/cli/commands/sop-registry-command.d.ts +3 -0
- package/dist/cli/commands/sop-registry-command.js +30 -0
- package/dist/cli/commands/statusline-command-shared.d.ts +73 -0
- package/dist/cli/commands/statusline-command-shared.js +90 -0
- package/dist/cli/commands/statusline-commands.d.ts +1 -19
- package/dist/cli/commands/statusline-commands.js +48 -287
- package/dist/cli/commands/statusline-compact-command.d.ts +4 -0
- package/dist/cli/commands/statusline-compact-command.js +54 -0
- package/dist/cli/commands/statusline-install-command.d.ts +3 -0
- package/dist/cli/commands/statusline-install-command.js +48 -0
- package/dist/cli/commands/statusline-render-command.d.ts +9 -0
- package/dist/cli/commands/statusline-render-command.js +55 -0
- package/dist/cli/commands/statusline-status-command.d.ts +3 -0
- package/dist/cli/commands/statusline-status-command.js +23 -0
- package/dist/cli/commands/statusline-uninstall-command.d.ts +3 -0
- package/dist/cli/commands/statusline-uninstall-command.js +23 -0
- package/dist/cli/commands/test-command-run-helpers.d.ts +27 -0
- package/dist/cli/commands/test-command-run-helpers.js +73 -0
- package/dist/cli/commands/test-command-runner-resolution.d.ts +57 -0
- package/dist/cli/commands/test-command-runner-resolution.js +183 -0
- package/dist/cli/commands/test-commands.d.ts +8 -56
- package/dist/cli/commands/test-commands.js +26 -249
- package/dist/cli/commands/vm-command-shared.d.ts +23 -0
- package/dist/cli/commands/vm-command-shared.js +23 -0
- package/dist/cli/commands/vm-commands.d.ts +1 -28
- package/dist/cli/commands/vm-commands.js +36 -270
- package/dist/cli/commands/vm-hypervisor-runtime.d.ts +15 -0
- package/dist/cli/commands/vm-hypervisor-runtime.js +64 -0
- package/dist/cli/commands/vm-release-command.d.ts +5 -0
- package/dist/cli/commands/vm-release-command.js +101 -0
- package/dist/cli/commands/vm-spawn-command.d.ts +5 -0
- package/dist/cli/commands/vm-spawn-command.js +177 -0
- package/dist/cli/commands/web-command-shared.d.ts +12 -0
- package/dist/cli/commands/web-command-shared.js +30 -0
- package/dist/cli/commands/web-commands.d.ts +7 -14
- package/dist/cli/commands/web-commands.js +6 -314
- package/dist/cli/commands/web-install-command.d.ts +10 -0
- package/dist/cli/commands/web-install-command.js +116 -0
- package/dist/cli/commands/web-lifecycle-commands.d.ts +9 -30
- package/dist/cli/commands/web-lifecycle-commands.js +14 -322
- package/dist/cli/commands/web-login-command.d.ts +14 -0
- package/dist/cli/commands/web-login-command.js +189 -0
- package/dist/cli/commands/web-op-payload.d.ts +22 -0
- package/dist/cli/commands/web-op-payload.js +89 -0
- package/dist/cli/commands/web-op-refusals.d.ts +37 -0
- package/dist/cli/commands/web-op-refusals.js +73 -0
- package/dist/cli/commands/web-op-runner.d.ts +14 -0
- package/dist/cli/commands/web-op-runner.js +166 -0
- package/dist/cli/commands/web-status-command.d.ts +4 -0
- package/dist/cli/commands/web-status-command.js +32 -0
- package/dist/cli/commands/web-stop-command.d.ts +10 -0
- package/dist/cli/commands/web-stop-command.js +59 -0
- package/dist/cli/commands/web-verb-specs.d.ts +18 -0
- package/dist/cli/commands/web-verb-specs.js +66 -0
- package/dist/cli/commands/workflow-command-shared.d.ts +102 -0
- package/dist/cli/commands/workflow-command-shared.js +74 -0
- package/dist/cli/commands/workflow-graph-commands.d.ts +3 -0
- package/dist/cli/commands/workflow-graph-commands.js +73 -0
- package/dist/cli/commands/workflow-init-command.d.ts +3 -0
- package/dist/cli/commands/workflow-init-command.js +68 -0
- package/dist/cli/commands/workflow-lifecycle-commands.d.ts +9 -59
- package/dist/cli/commands/workflow-lifecycle-commands.js +14 -348
- package/dist/cli/commands/workflow-node-commands.d.ts +3 -0
- package/dist/cli/commands/workflow-node-commands.js +154 -0
- package/dist/cli/commands/workflow-terminalize-command.d.ts +3 -0
- package/dist/cli/commands/workflow-terminalize-command.js +56 -0
- package/dist/services/code/auto-compact-artifacts.d.ts +54 -0
- package/dist/services/code/auto-compact-artifacts.js +135 -0
- package/dist/services/code/auto-compact-attempt.d.ts +46 -0
- package/dist/services/code/auto-compact-attempt.js +88 -0
- package/dist/services/code/auto-compact-decision.d.ts +74 -0
- package/dist/services/code/auto-compact-decision.js +149 -0
- package/dist/services/code/auto-compact-dispatch-gate.d.ts +36 -0
- package/dist/services/code/auto-compact-dispatch-gate.js +86 -0
- package/dist/services/code/auto-compact-envelopes.d.ts +33 -0
- package/dist/services/code/auto-compact-envelopes.js +134 -0
- package/dist/services/code/auto-compact-history.d.ts +46 -0
- package/dist/services/code/auto-compact-history.js +17 -0
- package/dist/services/code/auto-compact-orchestrator.d.ts +11 -240
- package/dist/services/code/auto-compact-orchestrator.js +165 -686
- package/dist/services/code/auto-compact-run-types.d.ts +123 -0
- package/dist/services/code/auto-compact-run-types.js +1 -0
- package/dist/services/code/emit-handoff.d.ts +35 -1
- package/dist/services/code/emit-handoff.js +128 -7
- package/dist/services/code/step-08-gate.d.ts +28 -19
- package/dist/services/code/step-08-gate.js +92 -35
- package/dist/services/config/config-coercion.d.ts +7 -0
- package/dist/services/config/config-coercion.js +156 -0
- package/dist/services/config/config-file-io.d.ts +11 -0
- package/dist/services/config/config-file-io.js +61 -0
- package/dist/services/config/config-get.d.ts +2 -0
- package/dist/services/config/config-get.js +36 -0
- package/dist/services/config/config-global-loader.d.ts +15 -0
- package/dist/services/config/config-global-loader.js +111 -0
- package/dist/services/config/config-nested-path.d.ts +3 -0
- package/dist/services/config/config-nested-path.js +53 -0
- package/dist/services/config/config-primitives.d.ts +16 -0
- package/dist/services/config/config-primitives.js +24 -0
- package/dist/services/config/config-service.d.ts +9 -33
- package/dist/services/config/config-service.js +16 -665
- package/dist/services/config/config-validation.d.ts +19 -0
- package/dist/services/config/config-validation.js +152 -0
- package/dist/services/config/config-workspace.d.ts +10 -0
- package/dist/services/config/config-workspace.js +158 -0
- package/dist/services/skills/hooks-settings-deny-list.d.ts +61 -0
- package/dist/services/skills/hooks-settings-deny-list.js +173 -0
- package/dist/services/skills/hooks-settings-envelopes.d.ts +20 -0
- package/dist/services/skills/hooks-settings-envelopes.js +79 -0
- package/dist/services/skills/hooks-settings-file-shape.d.ts +43 -0
- package/dist/services/skills/hooks-settings-file-shape.js +207 -0
- package/dist/services/skills/hooks-settings-paths.d.ts +34 -0
- package/dist/services/skills/hooks-settings-paths.js +75 -0
- package/dist/services/skills/hooks-settings-read-installed.d.ts +39 -0
- package/dist/services/skills/hooks-settings-read-installed.js +60 -0
- package/dist/services/skills/hooks-settings-service.d.ts +12 -212
- package/dist/services/skills/hooks-settings-service.js +71 -657
- package/dist/services/skills/hooks-settings-types.d.ts +139 -0
- package/dist/services/skills/hooks-settings-types.js +1 -0
- package/dist/services/workspace/claude-settings-template-merge.d.ts +89 -0
- package/dist/services/workspace/claude-settings-template-merge.js +243 -0
- package/dist/services/workspace/claude-settings-template.d.ts +29 -87
- package/dist/services/workspace/claude-settings-template.js +81 -236
- package/package.json +5 -5
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
2
|
* Companion CLI to Part 14 (peaks cron init/list/run). The
|
|
4
3
|
* scheduler is a long-running background daemon that wakes up
|
|
5
4
|
* once per minute, reads `.peaks/cron/schedule.json`, and runs
|
|
@@ -25,198 +24,48 @@
|
|
|
25
24
|
* the scheduler to write its own pid. Or just run from
|
|
26
25
|
* `nohup peaks-cron-scheduler start &` if you don't need
|
|
27
26
|
* restart-on-crash.
|
|
27
|
+
*
|
|
28
|
+
* This file owns `registerCronSchedulerCommand`, `runSchedulerLoop` and the
|
|
29
|
+
* standalone entry shim the `bin/peaks-cron-scheduler.js` script loads; the
|
|
30
|
+
* four verb bodies live beside it, over the pid-file vocabulary in
|
|
31
|
+
* `cron-scheduler-shared.ts`.
|
|
28
32
|
*/
|
|
29
|
-
import {
|
|
30
|
-
import { existsSync, readFileSync, writeFileSync, unlinkSync } from 'node:fs';
|
|
31
|
-
import { dirname, join, resolve } from 'node:path';
|
|
32
|
-
import { fileURLToPath } from 'node:url';
|
|
33
|
-
import { fail, getErrorMessage, ok } from 'peaks-loop-shared/result';
|
|
34
|
-
import { addJsonOption, printResult } from '../cli-helpers.js';
|
|
33
|
+
import { getErrorMessage } from 'peaks-loop-shared/result';
|
|
35
34
|
import { findProjectRoot } from '../../services/config/config-safety.js';
|
|
36
|
-
import {
|
|
35
|
+
import { listDueTasks, runTask } from './cron-commands.js';
|
|
37
36
|
import { persistLastRunAt } from './cron-scheduler-persist.js';
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}
|
|
43
|
-
function readSchedulerPid(projectRoot) {
|
|
44
|
-
const p = schedulerPidPath(projectRoot);
|
|
45
|
-
if (!existsSync(p))
|
|
46
|
-
return null;
|
|
47
|
-
const raw = readFileSync(p, 'utf8').trim();
|
|
48
|
-
const pid = Number.parseInt(raw, 10);
|
|
49
|
-
if (!Number.isFinite(pid) || pid <= 0)
|
|
50
|
-
return null;
|
|
51
|
-
return pid;
|
|
52
|
-
}
|
|
53
|
-
function isPidAlive(pid) {
|
|
54
|
-
try {
|
|
55
|
-
// `process.kill(pid, 0)` does not actually kill; it just
|
|
56
|
-
// checks if the process exists. ESRCH means no such pid;
|
|
57
|
-
// EPERM means it exists but we don't have permission to
|
|
58
|
-
// signal it (still alive).
|
|
59
|
-
process.kill(pid, 0);
|
|
60
|
-
return true;
|
|
61
|
-
}
|
|
62
|
-
catch (err) {
|
|
63
|
-
const code = err.code;
|
|
64
|
-
return code === 'EPERM';
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
function findSchedulerEntryPoint() {
|
|
68
|
-
// The peaks-cron-scheduler.js entry shim lives in bin/ (not
|
|
69
|
-
// dist/, so the pnpm build does not overwrite it). It forwards
|
|
70
|
-
// to dist/cli/commands/cron-scheduler-commands.js with
|
|
71
|
-
// PEAKS_CRON_SCHEDULER_DAEMON=1 set; the CLI detects the env
|
|
72
|
-
// and runs runSchedulerLoop directly.
|
|
73
|
-
const here = dirname(fileURLToPath(import.meta.url));
|
|
74
|
-
// dist/cli/commands/cron-scheduler-commands.js → bin/peaks-cron-scheduler.js
|
|
75
|
-
return resolve(here, '..', '..', '..', 'bin', 'peaks-cron-scheduler.js');
|
|
76
|
-
}
|
|
37
|
+
import { SCHEDULER_TICK_MS } from './cron-scheduler-shared.js';
|
|
38
|
+
import { registerCronSchedulerStartCommand } from './cron-scheduler-start-command.js';
|
|
39
|
+
import { registerCronSchedulerStopCommand } from './cron-scheduler-stop-command.js';
|
|
40
|
+
import { registerCronSchedulerStatusCommand } from './cron-scheduler-status-command.js';
|
|
41
|
+
import { registerCronSchedulerRunOnceCommand } from './cron-scheduler-run-once-command.js';
|
|
77
42
|
export function registerCronSchedulerCommand(program, io) {
|
|
78
43
|
const cmd = program
|
|
79
44
|
.command('cron-scheduler')
|
|
80
45
|
.description('Long-running background scheduler for peaks cron tasks (Part 15).');
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
// scheduler in its own process group (POSIX) / detaches
|
|
100
|
-
// from the console (Windows). PEAKS_CRON_SCHEDULER_DAEMON
|
|
101
|
-
// env is the canonical "I'm the long-running child" signal.
|
|
102
|
-
const entry = findSchedulerEntryPoint();
|
|
103
|
-
const child = spawn(process.execPath, [entry, '--project', projectRoot], {
|
|
104
|
-
cwd: projectRoot,
|
|
105
|
-
stdio: 'ignore',
|
|
106
|
-
detached: true,
|
|
107
|
-
windowsHide: true,
|
|
108
|
-
env: { ...process.env, PEAKS_CRON_SCHEDULER: '1', PEAKS_CRON_SCHEDULER_DAEMON: '1' }
|
|
109
|
-
});
|
|
110
|
-
child.unref();
|
|
111
|
-
if (typeof child.pid !== 'number') {
|
|
112
|
-
throw new Error('spawn returned no pid');
|
|
113
|
-
}
|
|
114
|
-
writeFileSync(pidFile, String(child.pid), 'utf8');
|
|
115
|
-
printResult(io, ok('cron-scheduler.start', { projectRoot, started: true, pid: child.pid, pidFile }, [], [
|
|
116
|
-
`Scheduler started at pid ${child.pid}; logs go to .peaks/cron/scheduler.log.`,
|
|
117
|
-
'Use `peaks cron-scheduler status` to confirm it is alive; `stop` to terminate.'
|
|
118
|
-
]), options.json);
|
|
119
|
-
}
|
|
120
|
-
catch (err) {
|
|
121
|
-
printResult(io, fail('cron-scheduler.start', 'SCHEDULER_START_FAILED', getErrorMessage(err), { projectRoot: options.project }, [
|
|
122
|
-
'Verify the peaks-cron-scheduler.js entry point is on disk.',
|
|
123
|
-
'Check that the .peaks/cron/ directory is writable.'
|
|
124
|
-
]), options.json);
|
|
125
|
-
process.exitCode = 1;
|
|
126
|
-
}
|
|
127
|
-
});
|
|
128
|
-
addJsonOption(cmd
|
|
129
|
-
.command('stop')
|
|
130
|
-
.description('Send SIGTERM to the scheduler pid (best-effort; removes the pid file either way).')
|
|
131
|
-
.option('--project <path>', 'project root (default: findProjectRoot(cwd))')).action((options) => {
|
|
132
|
-
try {
|
|
133
|
-
const projectRoot = options.project ?? findProjectRoot(process.cwd()) ?? process.cwd();
|
|
134
|
-
const pid = readSchedulerPid(projectRoot);
|
|
135
|
-
if (pid === null) {
|
|
136
|
-
printResult(io, ok('cron-scheduler.stop', { projectRoot, stopped: false, reason: 'no-pid-file' }, [], ['No scheduler pid file found; nothing to stop.']), options.json);
|
|
137
|
-
return;
|
|
138
|
-
}
|
|
139
|
-
let signalSent = false;
|
|
140
|
-
if (isPidAlive(pid)) {
|
|
141
|
-
try {
|
|
142
|
-
process.kill(pid, 'SIGTERM');
|
|
143
|
-
signalSent = true;
|
|
144
|
-
}
|
|
145
|
-
catch {
|
|
146
|
-
signalSent = false;
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
const pidFile = schedulerPidPath(projectRoot);
|
|
150
|
-
try {
|
|
151
|
-
unlinkSync(pidFile);
|
|
152
|
-
}
|
|
153
|
-
catch {
|
|
154
|
-
/* best-effort */
|
|
155
|
-
}
|
|
156
|
-
printResult(io, ok('cron-scheduler.stop', { projectRoot, stopped: signalSent, pid, pidFile }, [], [
|
|
157
|
-
signalSent
|
|
158
|
-
? `Sent SIGTERM to pid ${pid}; pid file removed.`
|
|
159
|
-
: `pid ${pid} was not alive; pid file removed.`
|
|
160
|
-
]), options.json);
|
|
161
|
-
}
|
|
162
|
-
catch (err) {
|
|
163
|
-
printResult(io, fail('cron-scheduler.stop', 'SCHEDULER_STOP_FAILED', getErrorMessage(err), { projectRoot: options.project }, ['Verify the pid file is readable / the process is yours.']), options.json);
|
|
164
|
-
process.exitCode = 1;
|
|
165
|
-
}
|
|
166
|
-
});
|
|
167
|
-
addJsonOption(cmd
|
|
168
|
-
.command('status')
|
|
169
|
-
.description('Report whether the scheduler is alive + when it last ran a task.')
|
|
170
|
-
.option('--project <path>', 'project root (default: findProjectRoot(cwd))')).action((options) => {
|
|
171
|
-
try {
|
|
172
|
-
const projectRoot = options.project ?? findProjectRoot(process.cwd()) ?? process.cwd();
|
|
173
|
-
const pid = readSchedulerPid(projectRoot);
|
|
174
|
-
const alive = pid !== null && isPidAlive(pid);
|
|
175
|
-
let schedule;
|
|
176
|
-
try {
|
|
177
|
-
schedule = readSchedule(projectRoot);
|
|
178
|
-
}
|
|
179
|
-
catch (err) {
|
|
180
|
-
schedule = { version: 1, entries: [] };
|
|
181
|
-
}
|
|
182
|
-
const due = alive ? listDueTasks(projectRoot) : [];
|
|
183
|
-
printResult(io, ok('cron-scheduler.status', {
|
|
184
|
-
projectRoot,
|
|
185
|
-
pid,
|
|
186
|
-
alive,
|
|
187
|
-
scheduleEntries: schedule.entries.length,
|
|
188
|
-
dueTaskCount: due.length
|
|
189
|
-
}, [], [
|
|
190
|
-
alive
|
|
191
|
-
? `Scheduler alive at pid ${pid}; ${due.length} task(s) due now.`
|
|
192
|
-
: 'Scheduler is NOT running. Use `peaks cron-scheduler start` to spawn.'
|
|
193
|
-
]), options.json);
|
|
194
|
-
}
|
|
195
|
-
catch (err) {
|
|
196
|
-
printResult(io, fail('cron-scheduler.status', 'SCHEDULER_STATUS_FAILED', getErrorMessage(err), { projectRoot: options.project }, ['Verify the .peaks/cron/ directory exists.']), options.json);
|
|
197
|
-
process.exitCode = 1;
|
|
198
|
-
}
|
|
199
|
-
});
|
|
200
|
-
addJsonOption(cmd
|
|
201
|
-
.command('run-once')
|
|
202
|
-
.description('Synchronous foreground one-shot: run every currently-due task and exit. Useful for manual cron substitute.')
|
|
203
|
-
.option('--project <path>', 'project root (default: findProjectRoot(cwd))')).action((options) => {
|
|
204
|
-
try {
|
|
205
|
-
const projectRoot = options.project ?? findProjectRoot(process.cwd()) ?? process.cwd();
|
|
206
|
-
const due = listDueTasks(projectRoot);
|
|
207
|
-
const records = due.map((t) => runTask(projectRoot, t));
|
|
208
|
-
// §2.24 applied to the one-shot path too: without it `run-once` under an
|
|
209
|
-
// external crontab re-ran the same task on every invocation.
|
|
210
|
-
persistLastRunAt(projectRoot, records);
|
|
211
|
-
printResult(io, ok('cron-scheduler.run-once', { projectRoot, ran: records.length, records }, [], [
|
|
212
|
-
`${records.length} due task(s) ran; ${records.filter((r) => r.exitCode === 0).length} succeeded.`
|
|
213
|
-
]), options.json);
|
|
214
|
-
if (records.some((r) => r.exitCode !== 0))
|
|
215
|
-
process.exitCode = 1;
|
|
46
|
+
registerCronSchedulerStartCommand(cmd, io);
|
|
47
|
+
registerCronSchedulerStopCommand(cmd, io);
|
|
48
|
+
registerCronSchedulerStatusCommand(cmd, io);
|
|
49
|
+
registerCronSchedulerRunOnceCommand(cmd, io);
|
|
50
|
+
}
|
|
51
|
+
/** The loop's interval handle, cleared when the shutdown signal arrives. */
|
|
52
|
+
function waitForShutdown(signal, handle) {
|
|
53
|
+
// Wait for the abort signal (POSIX) or the platform equivalent. We don't use
|
|
54
|
+
// Node's process.on('SIGTERM') for portability — the parent process kills us
|
|
55
|
+
// via `process.kill(pid, 'SIGTERM')` and the event loop exits naturally if
|
|
56
|
+
// the interval is the only thing keeping the loop alive.
|
|
57
|
+
return new Promise((resolveShutdown) => {
|
|
58
|
+
const onAbort = () => {
|
|
59
|
+
clearInterval(handle);
|
|
60
|
+
resolveShutdown();
|
|
61
|
+
};
|
|
62
|
+
if (signal) {
|
|
63
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
216
64
|
}
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
process.
|
|
65
|
+
else {
|
|
66
|
+
// POSIX: SIGTERM. Windows: kill the process directly.
|
|
67
|
+
process.on('SIGTERM', onAbort);
|
|
68
|
+
process.on('SIGINT', onAbort);
|
|
220
69
|
}
|
|
221
70
|
});
|
|
222
71
|
}
|
|
@@ -246,7 +95,7 @@ export async function runSchedulerLoop(args) {
|
|
|
246
95
|
// due. Without it `lastRunAt` stays null, `listDueTasks` keeps the entry
|
|
247
96
|
// due, and a 24 h task re-fires on every 60,000 ms tick (measured: 6 fires
|
|
248
97
|
// across 6 ticks, 1 after the write). Killed runs are deliberately NOT
|
|
249
|
-
// stamped — here, in `run-once
|
|
98
|
+
// stamped — here, in `run-once`, and since repair cycle 1 in `peaks
|
|
250
99
|
// cron run` too; the rule and its per-platform costs are in
|
|
251
100
|
// `cron-scheduler-persist.ts`.
|
|
252
101
|
persistLastRunAt(args.projectRoot, records);
|
|
@@ -259,26 +108,7 @@ export async function runSchedulerLoop(args) {
|
|
|
259
108
|
// for the first run after a start).
|
|
260
109
|
tick();
|
|
261
110
|
const handle = setInterval(tick, tickMs);
|
|
262
|
-
|
|
263
|
-
// equivalent. We don't use Node's process.on('SIGTERM')
|
|
264
|
-
// for portability — the parent process kills us via
|
|
265
|
-
// `process.kill(pid, 'SIGTERM')` and the event loop
|
|
266
|
-
// exits naturally if the interval is the only thing
|
|
267
|
-
// keeping the loop alive. We clearInterval on exit.
|
|
268
|
-
await new Promise((resolve) => {
|
|
269
|
-
const onAbort = () => {
|
|
270
|
-
clearInterval(handle);
|
|
271
|
-
resolve();
|
|
272
|
-
};
|
|
273
|
-
if (args.signal) {
|
|
274
|
-
args.signal.addEventListener('abort', onAbort, { once: true });
|
|
275
|
-
}
|
|
276
|
-
else {
|
|
277
|
-
// POSIX: SIGTERM. Windows: kill the process directly.
|
|
278
|
-
process.on('SIGTERM', onAbort);
|
|
279
|
-
process.on('SIGINT', onAbort);
|
|
280
|
-
}
|
|
281
|
-
});
|
|
111
|
+
await waitForShutdown(args.signal, handle);
|
|
282
112
|
process.exit(0);
|
|
283
113
|
}
|
|
284
114
|
// Standalone entry shim. When this file is run directly via
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Command } from 'commander';
|
|
2
|
+
import { type ProgramIO } from '../cli-helpers.js';
|
|
3
|
+
export declare function runCronSchedulerRunOnce(io: ProgramIO, options: {
|
|
4
|
+
project?: string;
|
|
5
|
+
json?: boolean;
|
|
6
|
+
}): void;
|
|
7
|
+
export declare function registerCronSchedulerRunOnceCommand(cmd: Command, io: ProgramIO): void;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// src/cli/commands/cron-scheduler-run-once-command.ts
|
|
2
|
+
//
|
|
3
|
+
// `peaks cron-scheduler run-once` — the synchronous foreground one-shot.
|
|
4
|
+
// Split out of `cron-scheduler-commands.ts`; the persistence step, the
|
|
5
|
+
// success envelope and the exit-code rule are unchanged.
|
|
6
|
+
import { addJsonOption, getErrorMessage, printResult } from '../cli-helpers.js';
|
|
7
|
+
import { fail, ok } from 'peaks-loop-shared/result';
|
|
8
|
+
import { findProjectRoot } from '../../services/config/config-safety.js';
|
|
9
|
+
import { listDueTasks, runTask } from './cron-commands.js';
|
|
10
|
+
import { persistLastRunAt } from './cron-scheduler-persist.js';
|
|
11
|
+
export function runCronSchedulerRunOnce(io, options) {
|
|
12
|
+
try {
|
|
13
|
+
const projectRoot = options.project ?? findProjectRoot(process.cwd()) ?? process.cwd();
|
|
14
|
+
const due = listDueTasks(projectRoot);
|
|
15
|
+
const records = due.map((t) => runTask(projectRoot, t));
|
|
16
|
+
// §2.24 applied to the one-shot path too: without it `run-once` under an
|
|
17
|
+
// external crontab re-ran the same task on every invocation.
|
|
18
|
+
persistLastRunAt(projectRoot, records);
|
|
19
|
+
printResult(io, ok('cron-scheduler.run-once', { projectRoot, ran: records.length, records }, [], [
|
|
20
|
+
`${records.length} due task(s) ran; ${records.filter((r) => r.exitCode === 0).length} succeeded.`
|
|
21
|
+
]), options.json ?? false);
|
|
22
|
+
if (records.some((r) => r.exitCode !== 0))
|
|
23
|
+
process.exitCode = 1;
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
printResult(io, fail('cron-scheduler.run-once', 'SCHEDULER_RUN_ONCE_FAILED', getErrorMessage(err), { projectRoot: options.project }, ["If schedule.json is missing, run 'peaks cron init' first."]), options.json ?? false);
|
|
27
|
+
process.exitCode = 1;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export function registerCronSchedulerRunOnceCommand(cmd, io) {
|
|
31
|
+
addJsonOption(cmd
|
|
32
|
+
.command('run-once')
|
|
33
|
+
.description('Synchronous foreground one-shot: run every currently-due task and exit. Useful for manual cron substitute.')
|
|
34
|
+
.option('--project <path>', 'project root (default: findProjectRoot(cwd))')).action((options) => runCronSchedulerRunOnce(io, options));
|
|
35
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare const SCHEDULER_TICK_MS = 60000;
|
|
2
|
+
export declare const PID_FILENAME = "scheduler.pid";
|
|
3
|
+
export declare function schedulerPidPath(projectRoot: string): string;
|
|
4
|
+
export declare function readSchedulerPid(projectRoot: string): number | null;
|
|
5
|
+
export declare function isPidAlive(pid: number): boolean;
|
|
6
|
+
export declare function findSchedulerEntryPoint(): string;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// src/cli/commands/cron-scheduler-shared.ts
|
|
2
|
+
//
|
|
3
|
+
// What every `peaks cron-scheduler *` verb shares: the tick period, the pid
|
|
4
|
+
// file, and the two questions asked of it (is there a pid, is it alive) plus
|
|
5
|
+
// where the detached child's entry shim lives. Split out of
|
|
6
|
+
// `cron-scheduler-commands.ts`; every path, probe and constant is unchanged.
|
|
7
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
8
|
+
import { dirname, join, resolve } from 'node:path';
|
|
9
|
+
import { fileURLToPath } from 'node:url';
|
|
10
|
+
export const SCHEDULER_TICK_MS = 60_000; // 1 minute
|
|
11
|
+
export const PID_FILENAME = 'scheduler.pid';
|
|
12
|
+
export function schedulerPidPath(projectRoot) {
|
|
13
|
+
return join(projectRoot, '.peaks', 'cron', PID_FILENAME);
|
|
14
|
+
}
|
|
15
|
+
export function readSchedulerPid(projectRoot) {
|
|
16
|
+
const p = schedulerPidPath(projectRoot);
|
|
17
|
+
if (!existsSync(p))
|
|
18
|
+
return null;
|
|
19
|
+
const raw = readFileSync(p, 'utf8').trim();
|
|
20
|
+
const pid = Number.parseInt(raw, 10);
|
|
21
|
+
if (!Number.isFinite(pid) || pid <= 0)
|
|
22
|
+
return null;
|
|
23
|
+
return pid;
|
|
24
|
+
}
|
|
25
|
+
export function isPidAlive(pid) {
|
|
26
|
+
try {
|
|
27
|
+
// `process.kill(pid, 0)` does not actually kill; it just
|
|
28
|
+
// checks if the process exists. ESRCH means no such pid;
|
|
29
|
+
// EPERM means it exists but we don't have permission to
|
|
30
|
+
// signal it (still alive).
|
|
31
|
+
process.kill(pid, 0);
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
catch (err) {
|
|
35
|
+
const code = err.code;
|
|
36
|
+
return code === 'EPERM';
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
export function findSchedulerEntryPoint() {
|
|
40
|
+
// The peaks-cron-scheduler.js entry shim lives in bin/ (not
|
|
41
|
+
// dist/, so the pnpm build does not overwrite it). It forwards
|
|
42
|
+
// to dist/cli/commands/cron-scheduler-commands.js with
|
|
43
|
+
// PEAKS_CRON_SCHEDULER_DAEMON=1 set; the CLI detects the env
|
|
44
|
+
// and runs runSchedulerLoop directly.
|
|
45
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
46
|
+
// dist/cli/commands/cron-scheduler-commands.js → bin/peaks-cron-scheduler.js
|
|
47
|
+
return resolve(here, '..', '..', '..', 'bin', 'peaks-cron-scheduler.js');
|
|
48
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Command } from 'commander';
|
|
2
|
+
import { type ProgramIO } from '../cli-helpers.js';
|
|
3
|
+
export declare function runCronSchedulerStart(io: ProgramIO, options: {
|
|
4
|
+
project?: string;
|
|
5
|
+
json?: boolean;
|
|
6
|
+
}): void;
|
|
7
|
+
export declare function registerCronSchedulerStartCommand(cmd: Command, io: ProgramIO): void;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// src/cli/commands/cron-scheduler-start-command.ts
|
|
2
|
+
//
|
|
3
|
+
// `peaks cron-scheduler start` — spawn the scheduler as a detached background
|
|
4
|
+
// process. Split out of `cron-scheduler-commands.ts`; the idempotency rule,
|
|
5
|
+
// the spawn options, the pid file and both envelopes are unchanged.
|
|
6
|
+
import { spawn } from 'node:child_process';
|
|
7
|
+
import { writeFileSync } from 'node:fs';
|
|
8
|
+
import { addJsonOption, getErrorMessage, printResult } from '../cli-helpers.js';
|
|
9
|
+
import { fail, ok } from 'peaks-loop-shared/result';
|
|
10
|
+
import { findProjectRoot } from '../../services/config/config-safety.js';
|
|
11
|
+
import { findSchedulerEntryPoint, isPidAlive, readSchedulerPid, schedulerPidPath } from './cron-scheduler-shared.js';
|
|
12
|
+
/**
|
|
13
|
+
* Spawn detached via `peaks-cron-scheduler.js` — the child runs
|
|
14
|
+
* `runSchedulerLoop` (60s setInterval + due-task runner). The detached flag +
|
|
15
|
+
* stdio:ignore puts the scheduler in its own process group (POSIX) / detaches
|
|
16
|
+
* from the console (Windows). PEAKS_CRON_SCHEDULER_DAEMON env is the canonical
|
|
17
|
+
* "I'm the long-running child" signal.
|
|
18
|
+
*/
|
|
19
|
+
function spawnDetachedScheduler(io, options, projectRoot, pidFile) {
|
|
20
|
+
const entry = findSchedulerEntryPoint();
|
|
21
|
+
const child = spawn(process.execPath, [entry, '--project', projectRoot], {
|
|
22
|
+
cwd: projectRoot,
|
|
23
|
+
stdio: 'ignore',
|
|
24
|
+
detached: true,
|
|
25
|
+
windowsHide: true,
|
|
26
|
+
env: { ...process.env, PEAKS_CRON_SCHEDULER: '1', PEAKS_CRON_SCHEDULER_DAEMON: '1' }
|
|
27
|
+
});
|
|
28
|
+
child.unref();
|
|
29
|
+
if (typeof child.pid !== 'number') {
|
|
30
|
+
throw new Error('spawn returned no pid');
|
|
31
|
+
}
|
|
32
|
+
writeFileSync(pidFile, String(child.pid), 'utf8');
|
|
33
|
+
printResult(io, ok('cron-scheduler.start', { projectRoot, started: true, pid: child.pid, pidFile }, [], [
|
|
34
|
+
`Scheduler started at pid ${child.pid}; logs go to .peaks/cron/scheduler.log.`,
|
|
35
|
+
'Use `peaks cron-scheduler status` to confirm it is alive; `stop` to terminate.'
|
|
36
|
+
]), options.json ?? false);
|
|
37
|
+
}
|
|
38
|
+
export function runCronSchedulerStart(io, options) {
|
|
39
|
+
try {
|
|
40
|
+
const projectRoot = options.project ?? findProjectRoot(process.cwd()) ?? process.cwd();
|
|
41
|
+
const pidFile = schedulerPidPath(projectRoot);
|
|
42
|
+
const existing = readSchedulerPid(projectRoot);
|
|
43
|
+
if (existing !== null && isPidAlive(existing)) {
|
|
44
|
+
printResult(io, ok('cron-scheduler.start', { projectRoot, started: false, alreadyRunning: true, existingPid: existing }, [], [
|
|
45
|
+
`Scheduler already running at pid ${existing}; not starting a second one.`,
|
|
46
|
+
'Use `peaks cron-scheduler stop` first if you need to restart.'
|
|
47
|
+
]), options.json ?? false);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
spawnDetachedScheduler(io, options, projectRoot, pidFile);
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
printResult(io, fail('cron-scheduler.start', 'SCHEDULER_START_FAILED', getErrorMessage(err), { projectRoot: options.project }, [
|
|
54
|
+
'Verify the peaks-cron-scheduler.js entry point is on disk.',
|
|
55
|
+
'Check that the .peaks/cron/ directory is writable.'
|
|
56
|
+
]), options.json ?? false);
|
|
57
|
+
process.exitCode = 1;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
export function registerCronSchedulerStartCommand(cmd, io) {
|
|
61
|
+
addJsonOption(cmd
|
|
62
|
+
.command('start')
|
|
63
|
+
.description('Spawn the scheduler as a detached background process. Idempotent: refuses to start when an alive pid already exists.')
|
|
64
|
+
.option('--project <path>', 'project root (default: findProjectRoot(cwd))')).action((options) => runCronSchedulerStart(io, options));
|
|
65
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Command } from 'commander';
|
|
2
|
+
import { type ProgramIO } from '../cli-helpers.js';
|
|
3
|
+
export declare function runCronSchedulerStatus(io: ProgramIO, options: {
|
|
4
|
+
project?: string;
|
|
5
|
+
json?: boolean;
|
|
6
|
+
}): void;
|
|
7
|
+
export declare function registerCronSchedulerStatusCommand(cmd: Command, io: ProgramIO): void;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// src/cli/commands/cron-scheduler-status-command.ts
|
|
2
|
+
//
|
|
3
|
+
// `peaks cron-scheduler status` — report whether the scheduler is alive and
|
|
4
|
+
// how many tasks are due. Split out of `cron-scheduler-commands.ts`; the
|
|
5
|
+
// degraded-tier schedule read and both envelopes are unchanged.
|
|
6
|
+
import { addJsonOption, getErrorMessage, printResult } from '../cli-helpers.js';
|
|
7
|
+
import { fail, ok } from 'peaks-loop-shared/result';
|
|
8
|
+
import { findProjectRoot } from '../../services/config/config-safety.js';
|
|
9
|
+
import { listDueTasks, readSchedule } from './cron-commands.js';
|
|
10
|
+
import { isPidAlive, readSchedulerPid } from './cron-scheduler-shared.js';
|
|
11
|
+
export function runCronSchedulerStatus(io, options) {
|
|
12
|
+
try {
|
|
13
|
+
const projectRoot = options.project ?? findProjectRoot(process.cwd()) ?? process.cwd();
|
|
14
|
+
const pid = readSchedulerPid(projectRoot);
|
|
15
|
+
const alive = pid !== null && isPidAlive(pid);
|
|
16
|
+
let schedule;
|
|
17
|
+
try {
|
|
18
|
+
schedule = readSchedule(projectRoot);
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
schedule = { version: 1, entries: [] };
|
|
22
|
+
}
|
|
23
|
+
const due = alive ? listDueTasks(projectRoot) : [];
|
|
24
|
+
printResult(io, ok('cron-scheduler.status', {
|
|
25
|
+
projectRoot,
|
|
26
|
+
pid,
|
|
27
|
+
alive,
|
|
28
|
+
scheduleEntries: schedule.entries.length,
|
|
29
|
+
dueTaskCount: due.length
|
|
30
|
+
}, [], [
|
|
31
|
+
alive
|
|
32
|
+
? `Scheduler alive at pid ${pid}; ${due.length} task(s) due now.`
|
|
33
|
+
: 'Scheduler is NOT running. Use `peaks cron-scheduler start` to spawn.'
|
|
34
|
+
]), options.json ?? false);
|
|
35
|
+
}
|
|
36
|
+
catch (err) {
|
|
37
|
+
printResult(io, fail('cron-scheduler.status', 'SCHEDULER_STATUS_FAILED', getErrorMessage(err), { projectRoot: options.project }, ['Verify the .peaks/cron/ directory exists.']), options.json ?? false);
|
|
38
|
+
process.exitCode = 1;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
export function registerCronSchedulerStatusCommand(cmd, io) {
|
|
42
|
+
addJsonOption(cmd
|
|
43
|
+
.command('status')
|
|
44
|
+
.description('Report whether the scheduler is alive + when it last ran a task.')
|
|
45
|
+
.option('--project <path>', 'project root (default: findProjectRoot(cwd))')).action((options) => runCronSchedulerStatus(io, options));
|
|
46
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Command } from 'commander';
|
|
2
|
+
import { type ProgramIO } from '../cli-helpers.js';
|
|
3
|
+
export declare function runCronSchedulerStop(io: ProgramIO, options: {
|
|
4
|
+
project?: string;
|
|
5
|
+
json?: boolean;
|
|
6
|
+
}): void;
|
|
7
|
+
export declare function registerCronSchedulerStopCommand(cmd: Command, io: ProgramIO): void;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// src/cli/commands/cron-scheduler-stop-command.ts
|
|
2
|
+
//
|
|
3
|
+
// `peaks cron-scheduler stop` — SIGTERM the scheduler pid (best-effort) and
|
|
4
|
+
// remove the pid file either way. Split out of `cron-scheduler-commands.ts`;
|
|
5
|
+
// the signal, the unlink and both envelopes are unchanged.
|
|
6
|
+
import { unlinkSync } from 'node:fs';
|
|
7
|
+
import { addJsonOption, getErrorMessage, printResult } from '../cli-helpers.js';
|
|
8
|
+
import { fail, ok } from 'peaks-loop-shared/result';
|
|
9
|
+
import { findProjectRoot } from '../../services/config/config-safety.js';
|
|
10
|
+
import { isPidAlive, readSchedulerPid, schedulerPidPath } from './cron-scheduler-shared.js';
|
|
11
|
+
/** The no-pid-file outcome: nothing to signal, nothing to unlink. */
|
|
12
|
+
function emitNoPidFile(io, options, projectRoot) {
|
|
13
|
+
printResult(io, ok('cron-scheduler.stop', { projectRoot, stopped: false, reason: 'no-pid-file' }, [], ['No scheduler pid file found; nothing to stop.']), options.json ?? false);
|
|
14
|
+
}
|
|
15
|
+
/** SIGTERM the pid (best-effort) and remove the pid file either way. */
|
|
16
|
+
function terminateScheduler(projectRoot, pid) {
|
|
17
|
+
let signalSent = false;
|
|
18
|
+
if (isPidAlive(pid)) {
|
|
19
|
+
try {
|
|
20
|
+
process.kill(pid, 'SIGTERM');
|
|
21
|
+
signalSent = true;
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
signalSent = false;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
const pidFile = schedulerPidPath(projectRoot);
|
|
28
|
+
try {
|
|
29
|
+
unlinkSync(pidFile);
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
/* best-effort */
|
|
33
|
+
}
|
|
34
|
+
return { signalSent, pidFile };
|
|
35
|
+
}
|
|
36
|
+
export function runCronSchedulerStop(io, options) {
|
|
37
|
+
try {
|
|
38
|
+
const projectRoot = options.project ?? findProjectRoot(process.cwd()) ?? process.cwd();
|
|
39
|
+
const pid = readSchedulerPid(projectRoot);
|
|
40
|
+
if (pid === null) {
|
|
41
|
+
emitNoPidFile(io, options, projectRoot);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const { signalSent, pidFile } = terminateScheduler(projectRoot, pid);
|
|
45
|
+
printResult(io, ok('cron-scheduler.stop', { projectRoot, stopped: signalSent, pid, pidFile }, [], [
|
|
46
|
+
signalSent
|
|
47
|
+
? `Sent SIGTERM to pid ${pid}; pid file removed.`
|
|
48
|
+
: `pid ${pid} was not alive; pid file removed.`
|
|
49
|
+
]), options.json ?? false);
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
printResult(io, fail('cron-scheduler.stop', 'SCHEDULER_STOP_FAILED', getErrorMessage(err), { projectRoot: options.project }, ['Verify the pid file is readable / the process is yours.']), options.json ?? false);
|
|
53
|
+
process.exitCode = 1;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
export function registerCronSchedulerStopCommand(cmd, io) {
|
|
57
|
+
addJsonOption(cmd
|
|
58
|
+
.command('stop')
|
|
59
|
+
.description('Send SIGTERM to the scheduler pid (best-effort; removes the pid file either way).')
|
|
60
|
+
.option('--project <path>', 'project root (default: findProjectRoot(cwd))')).action((options) => runCronSchedulerStop(io, options));
|
|
61
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { SubAgentToolCall } from '../../services/dispatch/sub-agent-dispatcher.js';
|
|
2
|
+
import type { SliceDag } from '../../services/dispatch/slice-dag.js';
|
|
3
|
+
import type { SliceComplexity } from '../../services/dispatch/slice-dag-types.js';
|
|
4
|
+
/** Everything the `--from-dag` success envelope reports, already resolved. */
|
|
5
|
+
export type DagEnvelopeInput = {
|
|
6
|
+
readonly role: string;
|
|
7
|
+
readonly ide: string;
|
|
8
|
+
readonly fromDag: string;
|
|
9
|
+
readonly batchId: string;
|
|
10
|
+
readonly levelsTotal: number;
|
|
11
|
+
readonly emittedSliceIds: readonly string[];
|
|
12
|
+
readonly emittedToolCalls: readonly SubAgentToolCall[];
|
|
13
|
+
readonly firstLevelWaves: unknown;
|
|
14
|
+
readonly existingContractCount: number;
|
|
15
|
+
readonly dag: SliceDag;
|
|
16
|
+
readonly isSliceComplexity: (value: string) => value is SliceComplexity;
|
|
17
|
+
};
|
|
18
|
+
/** The `ok('sub-agent.dispatch', …)` envelope for a completed `--from-dag` run. */
|
|
19
|
+
export declare function buildDagSuccessEnvelope(input: DagEnvelopeInput): import("peaks-loop-shared/result").ResultEnvelope<{
|
|
20
|
+
envelopeVersion: string;
|
|
21
|
+
role: string;
|
|
22
|
+
ide: string;
|
|
23
|
+
fromDag: string;
|
|
24
|
+
batchId: string;
|
|
25
|
+
dispatchCount: number;
|
|
26
|
+
levelsTotal: number;
|
|
27
|
+
firstLevel: readonly string[];
|
|
28
|
+
firstLevelWaves: unknown;
|
|
29
|
+
toolCalls: readonly SubAgentToolCall[];
|
|
30
|
+
existingContractCount: number;
|
|
31
|
+
expectedCompletionSeconds: number;
|
|
32
|
+
artifactsPublicPaths: never[];
|
|
33
|
+
orchestratorVisibleHint: string;
|
|
34
|
+
sliceMeta: {
|
|
35
|
+
id: string;
|
|
36
|
+
foundation: boolean;
|
|
37
|
+
upstreamSync: boolean;
|
|
38
|
+
complexity: SliceComplexity | null;
|
|
39
|
+
}[];
|
|
40
|
+
nextActions: string[];
|
|
41
|
+
}>;
|