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
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ModelProviderConfig, PeaksConfig } from './config-types.js';
|
|
2
|
+
export declare function isSensitiveConfigPath(path: string): boolean;
|
|
3
|
+
export declare function isLegacyConfigKey(path: string): boolean;
|
|
4
|
+
export declare function isProviderConfigPath(path: string): boolean;
|
|
5
|
+
export declare function isSecretKey(key: string): boolean;
|
|
6
|
+
export declare function isProviderBaseUrlPath(path: string): boolean;
|
|
7
|
+
export declare function validateProviderBaseUrl(value: unknown): void;
|
|
8
|
+
export declare function getProxyUrlCandidate(key: string, value: unknown): unknown;
|
|
9
|
+
export declare function isProxyConfigPath(path: string): boolean;
|
|
10
|
+
export declare function validateModelProviderConfig(providers: ModelProviderConfig): void;
|
|
11
|
+
export declare function validateProviderConfig(partial: Partial<PeaksConfig>): void;
|
|
12
|
+
export declare function isValidProxyUrl(value: string): boolean;
|
|
13
|
+
export declare function validateProxyUrl(value: unknown): void;
|
|
14
|
+
export declare function validateProxyConfig(partial: Partial<PeaksConfig>): void;
|
|
15
|
+
export declare function containsSensitiveConfigValue(value: unknown): boolean;
|
|
16
|
+
export type RedactedConfigValue = string | number | boolean | null | RedactedConfigValue[] | {
|
|
17
|
+
[key: string]: RedactedConfigValue;
|
|
18
|
+
};
|
|
19
|
+
export declare function redactConfigSecrets(value: unknown, path?: string): RedactedConfigValue;
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config key/URL validators and the secret-redaction surface.
|
|
3
|
+
*
|
|
4
|
+
* Split out of `config-service.ts` (file-size cap campaign). The service
|
|
5
|
+
* re-exports every name declared here, so existing importers keep using
|
|
6
|
+
* `./config-service.js` unchanged.
|
|
7
|
+
*/
|
|
8
|
+
import { isRecord } from './config-primitives.js';
|
|
9
|
+
export function isSensitiveConfigPath(path) {
|
|
10
|
+
const normalized = path.toLowerCase().replace(/[^a-z0-9]/g, '');
|
|
11
|
+
return (normalized.includes('apikey') ||
|
|
12
|
+
normalized.includes('accesskey') ||
|
|
13
|
+
normalized.includes('privatekey') ||
|
|
14
|
+
normalized.includes('token') ||
|
|
15
|
+
normalized.includes('secret') ||
|
|
16
|
+
normalized.includes('password') ||
|
|
17
|
+
normalized.includes('bearer') ||
|
|
18
|
+
normalized.includes('credential') ||
|
|
19
|
+
normalized.includes('auth'));
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* 2.0.1 slim-config contract: `~/.peaks/config.json` only stores
|
|
23
|
+
* `version` + `ocr.llm.*` placeholders. The 1.x → 2.0 migration
|
|
24
|
+
* moved per-project fields (`language`, `model`, `economyMode`,
|
|
25
|
+
* `swarmMode`) to `<project>/.peaks/preferences.json` (per spec
|
|
26
|
+
* §10.4). `setConfig` rejects writes to those keys and points the
|
|
27
|
+
* user to the preferences path; tokens / providers / proxy still
|
|
28
|
+
* live in `~/.peaks/config.json` (the loader is tolerant of them
|
|
29
|
+
* but does not synthesise defaults for them anymore).
|
|
30
|
+
*/
|
|
31
|
+
const LEGACY_CONFIG_KEYS = new Set([
|
|
32
|
+
'language',
|
|
33
|
+
'model',
|
|
34
|
+
'economyMode',
|
|
35
|
+
'swarmMode'
|
|
36
|
+
]);
|
|
37
|
+
export function isLegacyConfigKey(path) {
|
|
38
|
+
const topLevel = path.split(/[.[].*/, 1)[0] ?? '';
|
|
39
|
+
return LEGACY_CONFIG_KEYS.has(topLevel);
|
|
40
|
+
}
|
|
41
|
+
export function isProviderConfigPath(path) {
|
|
42
|
+
return path === 'providers' || path.startsWith('providers.');
|
|
43
|
+
}
|
|
44
|
+
export function isSecretKey(key) {
|
|
45
|
+
return isSensitiveConfigPath(key);
|
|
46
|
+
}
|
|
47
|
+
function sanitizeBaseUrlForDisplay(value) {
|
|
48
|
+
try {
|
|
49
|
+
const url = new URL(value);
|
|
50
|
+
url.username = '';
|
|
51
|
+
url.password = '';
|
|
52
|
+
url.search = '';
|
|
53
|
+
url.hash = '';
|
|
54
|
+
return url.toString();
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return '[invalid-url-redacted]';
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
export function isProviderBaseUrlPath(path) {
|
|
61
|
+
return /^providers\.[^.]+\.baseUrl$/.test(path);
|
|
62
|
+
}
|
|
63
|
+
function isValidProviderBaseUrl(value) {
|
|
64
|
+
try {
|
|
65
|
+
const url = new URL(value);
|
|
66
|
+
return (url.protocol === 'https:' &&
|
|
67
|
+
url.username.length === 0 &&
|
|
68
|
+
url.password.length === 0 &&
|
|
69
|
+
url.search.length === 0 &&
|
|
70
|
+
url.hash.length === 0);
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
export function validateProviderBaseUrl(value) {
|
|
77
|
+
if (value !== undefined && (typeof value !== 'string' || !isValidProviderBaseUrl(value))) {
|
|
78
|
+
throw new Error('Provider base URL must be HTTPS without embedded credentials, query, or fragment');
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
export function getProxyUrlCandidate(key, value) {
|
|
82
|
+
if (key === 'proxy.httpProxy') {
|
|
83
|
+
return value;
|
|
84
|
+
}
|
|
85
|
+
if (key === 'proxy' && isRecord(value)) {
|
|
86
|
+
return value.httpProxy;
|
|
87
|
+
}
|
|
88
|
+
return undefined;
|
|
89
|
+
}
|
|
90
|
+
export function isProxyConfigPath(path) {
|
|
91
|
+
return path === 'proxy' || path.startsWith('proxy.');
|
|
92
|
+
}
|
|
93
|
+
export function validateModelProviderConfig(providers) {
|
|
94
|
+
for (const provider of Object.values(providers)) {
|
|
95
|
+
validateProviderBaseUrl(provider?.baseUrl);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
export function validateProviderConfig(partial) {
|
|
99
|
+
validateModelProviderConfig(partial.providers ?? {});
|
|
100
|
+
}
|
|
101
|
+
export function isValidProxyUrl(value) {
|
|
102
|
+
try {
|
|
103
|
+
const url = new URL(value);
|
|
104
|
+
return ((url.protocol === 'http:' || url.protocol === 'https:') &&
|
|
105
|
+
url.username.length === 0 &&
|
|
106
|
+
url.password.length === 0 &&
|
|
107
|
+
url.pathname === '/' &&
|
|
108
|
+
url.search.length === 0 &&
|
|
109
|
+
url.hash.length === 0);
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
export function validateProxyUrl(value) {
|
|
116
|
+
if (value !== undefined && (typeof value !== 'string' || !isValidProxyUrl(value))) {
|
|
117
|
+
throw new Error('Proxy URL must be an HTTP or HTTPS URL without embedded credentials');
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
export function validateProxyConfig(partial) {
|
|
121
|
+
validateProxyUrl(partial.proxy?.httpProxy);
|
|
122
|
+
}
|
|
123
|
+
export function containsSensitiveConfigValue(value) {
|
|
124
|
+
if (Array.isArray(value)) {
|
|
125
|
+
return value.some(containsSensitiveConfigValue);
|
|
126
|
+
}
|
|
127
|
+
if (value === null || typeof value !== 'object') {
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
return Object.entries(value).some(([key, entry]) => isSecretKey(key) || containsSensitiveConfigValue(entry));
|
|
131
|
+
}
|
|
132
|
+
export function redactConfigSecrets(value, path = '') {
|
|
133
|
+
if (Array.isArray(value)) {
|
|
134
|
+
return value.map((item, index) => redactConfigSecrets(item, `${path}[${index}]`));
|
|
135
|
+
}
|
|
136
|
+
if (value === null || typeof value !== 'object') {
|
|
137
|
+
if (isProviderBaseUrlPath(path) && typeof value === 'string') {
|
|
138
|
+
return sanitizeBaseUrlForDisplay(value);
|
|
139
|
+
}
|
|
140
|
+
return value;
|
|
141
|
+
}
|
|
142
|
+
return Object.fromEntries(Object.entries(value).map(([key, entry]) => {
|
|
143
|
+
const nextPath = path ? `${path}.${key}` : key;
|
|
144
|
+
if (isSecretKey(key)) {
|
|
145
|
+
return [key, '***'];
|
|
146
|
+
}
|
|
147
|
+
if (isProviderBaseUrlPath(nextPath) && typeof entry === 'string') {
|
|
148
|
+
return [key, sanitizeBaseUrlForDisplay(entry)];
|
|
149
|
+
}
|
|
150
|
+
return [key, redactConfigSecrets(entry, nextPath)];
|
|
151
|
+
}));
|
|
152
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ConfigLayer, WorkspaceConfig } from './config-types.js';
|
|
2
|
+
export declare function getWorkspaceConfig(workspaceId: string, _projectRoot?: string | null): WorkspaceConfig | null;
|
|
3
|
+
export declare function addWorkspace(workspace: WorkspaceConfig, layer?: ConfigLayer): void;
|
|
4
|
+
export declare function removeWorkspace(workspaceId: string, layer?: ConfigLayer): boolean;
|
|
5
|
+
export declare function setCurrentWorkspace(workspaceId: string, layer?: ConfigLayer): boolean;
|
|
6
|
+
export declare function getCurrentWorkspaceConfig(): WorkspaceConfig | null;
|
|
7
|
+
export declare function getWorkspaceConfigForPath(path?: string): WorkspaceConfig | null;
|
|
8
|
+
export declare function ensureWorkspaceConfigForPath(path?: string): WorkspaceConfig | null;
|
|
9
|
+
export declare function getWorkspaceConfigForCurrentPath(): WorkspaceConfig | null;
|
|
10
|
+
export declare function ensureWorkspaceConfigForCurrentPath(): WorkspaceConfig | null;
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workspace registry: the raw `workspaces` / `currentWorkspace` fields and the artifact marker.
|
|
3
|
+
*
|
|
4
|
+
* Split out of `config-service.ts` (file-size cap campaign). The service
|
|
5
|
+
* re-exports every name declared here, so existing importers keep using
|
|
6
|
+
* `./config-service.js` unchanged.
|
|
7
|
+
*/
|
|
8
|
+
import { existsSync } from 'node:fs';
|
|
9
|
+
import { dirname, isAbsolute, resolve } from 'node:path';
|
|
10
|
+
import { stablePath } from '../../shared/path-utils.js';
|
|
11
|
+
import { getUserConfigPath, isInsidePath, resolveProjectRootForConfig, validateArtifactWorkspaceMarkerPath, validateArtifactWorkspaceRoot, validateProjectBootstrapConfigPathForWrite, validateUserConfigPathForWrite, writeConfigFileSafely, writeProjectConfigFile, writeUserConfigFile } from './config-safety.js';
|
|
12
|
+
import { toWorkspaceConfigs } from './config-coercion.js';
|
|
13
|
+
import { ensureDir, getProjectWriteTarget, readJsonFile } from './config-file-io.js';
|
|
14
|
+
import { getConfig } from './config-get.js';
|
|
15
|
+
import { isRecord, isSafeConfigSegment } from './config-primitives.js';
|
|
16
|
+
function readRawWorkspaceData(layer) {
|
|
17
|
+
const config = getConfig({ layer });
|
|
18
|
+
return isRecord(config)
|
|
19
|
+
? {
|
|
20
|
+
currentWorkspace: typeof config.currentWorkspace === 'string' ? config.currentWorkspace : null,
|
|
21
|
+
workspaces: toWorkspaceConfigs(config.workspaces)
|
|
22
|
+
}
|
|
23
|
+
: { currentWorkspace: null, workspaces: [] };
|
|
24
|
+
}
|
|
25
|
+
function writeRawWorkspaceData(data, layer) {
|
|
26
|
+
const projectTarget = layer === 'project' ? getProjectWriteTarget() : null;
|
|
27
|
+
const targetPath = projectTarget?.configPath ?? getUserConfigPath();
|
|
28
|
+
ensureDir(dirname(targetPath));
|
|
29
|
+
const existing = projectTarget
|
|
30
|
+
? (readJsonFile(targetPath, () => validateProjectBootstrapConfigPathForWrite(projectTarget.projectRoot, targetPath)) ?? {})
|
|
31
|
+
: (readJsonFile(targetPath, () => validateUserConfigPathForWrite(targetPath)) ?? {});
|
|
32
|
+
const merged = { ...existing, ...data };
|
|
33
|
+
const content = JSON.stringify(merged, null, 2);
|
|
34
|
+
if (projectTarget) {
|
|
35
|
+
writeProjectConfigFile(projectTarget.projectRoot, targetPath, content);
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
writeUserConfigFile(targetPath, content);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function readAllWorkspaces() {
|
|
42
|
+
const userData = readRawWorkspaceData('user');
|
|
43
|
+
const projectData = readRawWorkspaceData('project');
|
|
44
|
+
const mergedWorkspaces = new Map();
|
|
45
|
+
for (const w of userData.workspaces)
|
|
46
|
+
mergedWorkspaces.set(w.workspaceId, w);
|
|
47
|
+
for (const w of projectData.workspaces)
|
|
48
|
+
mergedWorkspaces.set(w.workspaceId, w);
|
|
49
|
+
return {
|
|
50
|
+
currentWorkspace: projectData.currentWorkspace ?? userData.currentWorkspace,
|
|
51
|
+
workspaces: [...mergedWorkspaces.values()]
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
export function getWorkspaceConfig(workspaceId, _projectRoot) {
|
|
55
|
+
// Accepted for signature stability: the registry spans the user and project
|
|
56
|
+
// layers, so the id alone identifies the workspace.
|
|
57
|
+
void _projectRoot;
|
|
58
|
+
const { workspaces } = readAllWorkspaces();
|
|
59
|
+
return workspaces.find((w) => w.workspaceId === workspaceId) ?? null;
|
|
60
|
+
}
|
|
61
|
+
function readLayerConfig(layer) {
|
|
62
|
+
return readRawWorkspaceData(layer);
|
|
63
|
+
}
|
|
64
|
+
export function addWorkspace(workspace, layer = 'user') {
|
|
65
|
+
if (!isSafeConfigSegment(workspace.workspaceId)) {
|
|
66
|
+
throw new Error('Workspace id must only contain letters, numbers, dots, underscores, or hyphens and must not contain path traversal');
|
|
67
|
+
}
|
|
68
|
+
const config = readRawWorkspaceData(layer);
|
|
69
|
+
const workspaces = config.workspaces;
|
|
70
|
+
const existing = workspaces.findIndex((w) => w.workspaceId === workspace.workspaceId);
|
|
71
|
+
const updatedWorkspaces = existing >= 0
|
|
72
|
+
? workspaces.map((existingWorkspace) => existingWorkspace.workspaceId === workspace.workspaceId ? workspace : existingWorkspace)
|
|
73
|
+
: [...workspaces, workspace];
|
|
74
|
+
writeRawWorkspaceData({ workspaces: updatedWorkspaces }, layer);
|
|
75
|
+
}
|
|
76
|
+
export function removeWorkspace(workspaceId, layer = 'user') {
|
|
77
|
+
if (!isSafeConfigSegment(workspaceId))
|
|
78
|
+
return false;
|
|
79
|
+
const config = readRawWorkspaceData(layer);
|
|
80
|
+
const workspaces = config.workspaces;
|
|
81
|
+
const idx = workspaces.findIndex((w) => w.workspaceId === workspaceId);
|
|
82
|
+
if (idx < 0)
|
|
83
|
+
return false;
|
|
84
|
+
const updatedWorkspaces = workspaces.filter((w) => w.workspaceId !== workspaceId);
|
|
85
|
+
const currentWorkspace = config.currentWorkspace === workspaceId
|
|
86
|
+
? (updatedWorkspaces[0]?.workspaceId ?? null)
|
|
87
|
+
: (config.currentWorkspace ?? null);
|
|
88
|
+
writeRawWorkspaceData({ workspaces: updatedWorkspaces, currentWorkspace }, layer);
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
export function setCurrentWorkspace(workspaceId, layer = 'user') {
|
|
92
|
+
if (!isSafeConfigSegment(workspaceId))
|
|
93
|
+
return false;
|
|
94
|
+
const config = readRawWorkspaceData(layer);
|
|
95
|
+
const workspaces = config.workspaces;
|
|
96
|
+
const exists = workspaces.some((w) => w.workspaceId === workspaceId);
|
|
97
|
+
if (!exists)
|
|
98
|
+
return false;
|
|
99
|
+
writeRawWorkspaceData({ currentWorkspace: workspaceId }, layer);
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
export function getCurrentWorkspaceConfig() {
|
|
103
|
+
const { currentWorkspace, workspaces } = readAllWorkspaces();
|
|
104
|
+
if (!currentWorkspace)
|
|
105
|
+
return null;
|
|
106
|
+
return workspaces.find((w) => w.workspaceId === currentWorkspace) ?? null;
|
|
107
|
+
}
|
|
108
|
+
export function getWorkspaceConfigForPath(path = process.cwd()) {
|
|
109
|
+
const { workspaces } = readAllWorkspaces();
|
|
110
|
+
return findWorkspaceForPath(workspaces, path);
|
|
111
|
+
}
|
|
112
|
+
function findWorkspaceForPath(workspaces, path) {
|
|
113
|
+
const targetPath = stablePath(path);
|
|
114
|
+
const matches = workspaces.flatMap((workspace) => {
|
|
115
|
+
if (!isAbsolute(workspace.rootPath) || !existsSync(workspace.rootPath))
|
|
116
|
+
return [];
|
|
117
|
+
const rootPath = stablePath(workspace.rootPath);
|
|
118
|
+
return isInsidePath(targetPath, rootPath) ? [{ workspace, rootPath }] : [];
|
|
119
|
+
});
|
|
120
|
+
if (matches.length === 0)
|
|
121
|
+
return null;
|
|
122
|
+
return matches.reduce((best, match) => match.rootPath.length > best.rootPath.length ? match : best).workspace;
|
|
123
|
+
}
|
|
124
|
+
function getWorkspaceArtifactRoot(workspace) {
|
|
125
|
+
return workspace.artifactStorage?.localPath
|
|
126
|
+
? resolve(workspace.artifactStorage.localPath)
|
|
127
|
+
: resolve(workspace.rootPath, '.peaks', 'artifacts');
|
|
128
|
+
}
|
|
129
|
+
function ensureArtifactWorkspaceMarker(workspace) {
|
|
130
|
+
const artifactRoot = getWorkspaceArtifactRoot(workspace);
|
|
131
|
+
const peaksPath = resolve(artifactRoot, '.peaks');
|
|
132
|
+
const markerPath = resolve(peaksPath, 'config.json');
|
|
133
|
+
ensureDir(artifactRoot);
|
|
134
|
+
validateArtifactWorkspaceRoot(artifactRoot, workspace.rootPath);
|
|
135
|
+
ensureDir(peaksPath);
|
|
136
|
+
validateArtifactWorkspaceMarkerPath(artifactRoot, peaksPath, markerPath);
|
|
137
|
+
if (!existsSync(markerPath)) {
|
|
138
|
+
writeConfigFileSafely(markerPath, '{}\n', () => validateArtifactWorkspaceMarkerPath(artifactRoot, peaksPath, markerPath), 'Artifact workspace marker must stay inside the artifact workspace');
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
export function ensureWorkspaceConfigForPath(path = process.cwd()) {
|
|
142
|
+
const projectRoot = resolveProjectRootForConfig(path);
|
|
143
|
+
if (!isAbsolute(projectRoot) || !existsSync(projectRoot))
|
|
144
|
+
return null;
|
|
145
|
+
const config = readLayerConfig('user');
|
|
146
|
+
const existingWorkspace = findWorkspaceForPath(config.workspaces, path);
|
|
147
|
+
if (existingWorkspace) {
|
|
148
|
+
ensureArtifactWorkspaceMarker(existingWorkspace);
|
|
149
|
+
return existingWorkspace;
|
|
150
|
+
}
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
export function getWorkspaceConfigForCurrentPath() {
|
|
154
|
+
return getWorkspaceConfigForPath(process.cwd());
|
|
155
|
+
}
|
|
156
|
+
export function ensureWorkspaceConfigForCurrentPath() {
|
|
157
|
+
return ensureWorkspaceConfigForPath(process.cwd());
|
|
158
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Merge the peaks-managed Skill denylist into the existing settings object.
|
|
3
|
+
* Preserves every other `permissions.deny` entry the user (or another tool)
|
|
4
|
+
* has written so the install is additive, not destructive. The output is
|
|
5
|
+
* always deterministic: the same input always yields the same output,
|
|
6
|
+
* regardless of insertion order in the source array.
|
|
7
|
+
*
|
|
8
|
+
* Defensive behavior:
|
|
9
|
+
* - `settings.permissions` is missing or non-object → install creates a
|
|
10
|
+
* fresh `permissions: { deny: [...our entries] }` object.
|
|
11
|
+
* - `settings.permissions.deny` is missing or non-array → install replaces
|
|
12
|
+
* the field with a fresh array containing only our entries.
|
|
13
|
+
* - Duplicate entries (any source) are collapsed to one via `new Set`.
|
|
14
|
+
*
|
|
15
|
+
* The function is pure: it does not mutate the input. Atomic write happens
|
|
16
|
+
* at the call site (`applyHookInstall`).
|
|
17
|
+
*/
|
|
18
|
+
export declare function withSuperpowersSkillDenylist(settings: Record<string, unknown>): Record<string, unknown>;
|
|
19
|
+
/**
|
|
20
|
+
* Inverse of `withSuperpowersSkillDenylist`. Removes every peaks-managed
|
|
21
|
+
* `UseSkill(...)` entry from the deny list. If the resulting deny list is
|
|
22
|
+
* empty, the `deny` field itself is deleted; if the `permissions` object
|
|
23
|
+
* becomes empty, the `permissions` field itself is deleted. This is the
|
|
24
|
+
* uninstall path: every field we wrote must be removed exactly, and no
|
|
25
|
+
* other field may be touched.
|
|
26
|
+
*
|
|
27
|
+
* Pure (no mutation).
|
|
28
|
+
*/
|
|
29
|
+
export declare function withoutSuperpowersSkillDenylist(settings: Record<string, unknown>): Record<string, unknown>;
|
|
30
|
+
/**
|
|
31
|
+
* Read-only introspection. Returns the deny entries that `peaks hooks
|
|
32
|
+
* install` would write today. Useful for `peaks hooks status` and the
|
|
33
|
+
* dry-run envelope.
|
|
34
|
+
*/
|
|
35
|
+
export declare function listSuperpowersDenyEntries(): ReadonlyArray<string>;
|
|
36
|
+
/**
|
|
37
|
+
*
|
|
38
|
+
* In addition to the static SUPERPOWERS_DENIED_SKILLS list, peaks
|
|
39
|
+
* scans the existing settings file for "trigger phrases" that
|
|
40
|
+
* indicate the user has configured the superpowers chain (or
|
|
41
|
+
* any other auto-run worktree-creating tool) and appends a
|
|
42
|
+
* defensive deny to prevent the chain from running raw
|
|
43
|
+
* `git worktree add` (or `podman run`) directly.
|
|
44
|
+
*
|
|
45
|
+
* Triggers detected (substring match on the existing
|
|
46
|
+
* permissions.deny / permissions.allow list):
|
|
47
|
+
*
|
|
48
|
+
* - `superpowers:using-git-worktrees` — the chain's ground zero
|
|
49
|
+
* - `superpowers:brainstorming` etc. — the upstream skill
|
|
50
|
+
* - `Bash(git worktree add` — the user has explicitly
|
|
51
|
+
* allowed raw git worktree, which our L2 lease-aware gate
|
|
52
|
+
* would also intercept (defense in depth)
|
|
53
|
+
*
|
|
54
|
+
* Append-only — never replaces, never re-orders, never removes
|
|
55
|
+
* existing entries. Idempotent: re-running the install with
|
|
56
|
+
* the same input yields the same output.
|
|
57
|
+
*/
|
|
58
|
+
export declare const TRIGGER_PHRASES: ReadonlyArray<string>;
|
|
59
|
+
export declare function withTriggeredDenyList(settings: Record<string, unknown>): Record<string, unknown>;
|
|
60
|
+
/** Inverse of withTriggeredDenyList: strip every deny-trigger entry. */
|
|
61
|
+
export declare function withoutTriggeredDenyList(settings: Record<string, unknown>): Record<string, unknown>;
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The peaks-managed `permissions.deny` entries, and their inverses.
|
|
3
|
+
*
|
|
4
|
+
* Split out of `hooks-settings-service.ts` (file-size cap campaign). The
|
|
5
|
+
* service re-exports every name declared here, so existing importers keep
|
|
6
|
+
* using `./hooks-settings-service.js` unchanged.
|
|
7
|
+
*/
|
|
8
|
+
import { SUPERPOWERS_DENIED_SKILLS, SUPERPOWERS_DENY_SENTINELS, formatSuperpowersDenyEntry } from './hooks-codegate-superpowers.js';
|
|
9
|
+
/**
|
|
10
|
+
* Merge the peaks-managed Skill denylist into the existing settings object.
|
|
11
|
+
* Preserves every other `permissions.deny` entry the user (or another tool)
|
|
12
|
+
* has written so the install is additive, not destructive. The output is
|
|
13
|
+
* always deterministic: the same input always yields the same output,
|
|
14
|
+
* regardless of insertion order in the source array.
|
|
15
|
+
*
|
|
16
|
+
* Defensive behavior:
|
|
17
|
+
* - `settings.permissions` is missing or non-object → install creates a
|
|
18
|
+
* fresh `permissions: { deny: [...our entries] }` object.
|
|
19
|
+
* - `settings.permissions.deny` is missing or non-array → install replaces
|
|
20
|
+
* the field with a fresh array containing only our entries.
|
|
21
|
+
* - Duplicate entries (any source) are collapsed to one via `new Set`.
|
|
22
|
+
*
|
|
23
|
+
* The function is pure: it does not mutate the input. Atomic write happens
|
|
24
|
+
* at the call site (`applyHookInstall`).
|
|
25
|
+
*/
|
|
26
|
+
export function withSuperpowersSkillDenylist(settings) {
|
|
27
|
+
const ourEntries = SUPERPOWERS_DENIED_SKILLS.map(formatSuperpowersDenyEntry);
|
|
28
|
+
const permissions = settings.permissions &&
|
|
29
|
+
typeof settings.permissions === 'object' &&
|
|
30
|
+
!Array.isArray(settings.permissions)
|
|
31
|
+
? settings.permissions
|
|
32
|
+
: {};
|
|
33
|
+
const existingDeny = Array.isArray(permissions.deny)
|
|
34
|
+
? permissions.deny.filter((d) => typeof d === 'string')
|
|
35
|
+
: [];
|
|
36
|
+
const otherDeny = existingDeny.filter((d) => !SUPERPOWERS_DENY_SENTINELS.has(d));
|
|
37
|
+
const finalDeny = [...new Set([...otherDeny, ...ourEntries])];
|
|
38
|
+
return {
|
|
39
|
+
...settings,
|
|
40
|
+
permissions: { ...permissions, deny: finalDeny }
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Inverse of `withSuperpowersSkillDenylist`. Removes every peaks-managed
|
|
45
|
+
* `UseSkill(...)` entry from the deny list. If the resulting deny list is
|
|
46
|
+
* empty, the `deny` field itself is deleted; if the `permissions` object
|
|
47
|
+
* becomes empty, the `permissions` field itself is deleted. This is the
|
|
48
|
+
* uninstall path: every field we wrote must be removed exactly, and no
|
|
49
|
+
* other field may be touched.
|
|
50
|
+
*
|
|
51
|
+
* Pure (no mutation).
|
|
52
|
+
*/
|
|
53
|
+
export function withoutSuperpowersSkillDenylist(settings) {
|
|
54
|
+
const permissions = settings.permissions &&
|
|
55
|
+
typeof settings.permissions === 'object' &&
|
|
56
|
+
!Array.isArray(settings.permissions)
|
|
57
|
+
? settings.permissions
|
|
58
|
+
: {};
|
|
59
|
+
if (!Array.isArray(permissions.deny)) {
|
|
60
|
+
return settings;
|
|
61
|
+
}
|
|
62
|
+
const remainingDeny = permissions.deny
|
|
63
|
+
.filter((d) => typeof d === 'string')
|
|
64
|
+
.filter((d) => !SUPERPOWERS_DENY_SENTINELS.has(d));
|
|
65
|
+
const nextPermissions = { ...permissions };
|
|
66
|
+
if (remainingDeny.length > 0) {
|
|
67
|
+
nextPermissions.deny = remainingDeny;
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
delete nextPermissions.deny;
|
|
71
|
+
}
|
|
72
|
+
if (Object.keys(nextPermissions).length === 0) {
|
|
73
|
+
// The whole `permissions` object is empty (no deny, no allow, no other
|
|
74
|
+
// sub-fields). Drop it to avoid leaving an empty object on disk.
|
|
75
|
+
const rest = { ...settings };
|
|
76
|
+
delete rest['permissions'];
|
|
77
|
+
return rest;
|
|
78
|
+
}
|
|
79
|
+
return { ...settings, permissions: nextPermissions };
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Read-only introspection. Returns the deny entries that `peaks hooks
|
|
83
|
+
* install` would write today. Useful for `peaks hooks status` and the
|
|
84
|
+
* dry-run envelope.
|
|
85
|
+
*/
|
|
86
|
+
export function listSuperpowersDenyEntries() {
|
|
87
|
+
return SUPERPOWERS_DENIED_SKILLS.map(formatSuperpowersDenyEntry);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
*
|
|
91
|
+
* In addition to the static SUPERPOWERS_DENIED_SKILLS list, peaks
|
|
92
|
+
* scans the existing settings file for "trigger phrases" that
|
|
93
|
+
* indicate the user has configured the superpowers chain (or
|
|
94
|
+
* any other auto-run worktree-creating tool) and appends a
|
|
95
|
+
* defensive deny to prevent the chain from running raw
|
|
96
|
+
* `git worktree add` (or `podman run`) directly.
|
|
97
|
+
*
|
|
98
|
+
* Triggers detected (substring match on the existing
|
|
99
|
+
* permissions.deny / permissions.allow list):
|
|
100
|
+
*
|
|
101
|
+
* - `superpowers:using-git-worktrees` — the chain's ground zero
|
|
102
|
+
* - `superpowers:brainstorming` etc. — the upstream skill
|
|
103
|
+
* - `Bash(git worktree add` — the user has explicitly
|
|
104
|
+
* allowed raw git worktree, which our L2 lease-aware gate
|
|
105
|
+
* would also intercept (defense in depth)
|
|
106
|
+
*
|
|
107
|
+
* Append-only — never replaces, never re-orders, never removes
|
|
108
|
+
* existing entries. Idempotent: re-running the install with
|
|
109
|
+
* the same input yields the same output.
|
|
110
|
+
*/
|
|
111
|
+
export const TRIGGER_PHRASES = Object.freeze([
|
|
112
|
+
'superpowers:using-git-worktrees',
|
|
113
|
+
'superpowers:brainstorming',
|
|
114
|
+
'superpowers:writing-plans',
|
|
115
|
+
'superpowers:subagent-driven-development',
|
|
116
|
+
'Bash(git worktree add',
|
|
117
|
+
'Bash(podman run'
|
|
118
|
+
]);
|
|
119
|
+
/**
|
|
120
|
+
* Format a trigger-phrase into a stable `Edit` deny entry. We deny
|
|
121
|
+
* `Edit` (not `Bash`) on the *settings file* itself, so the
|
|
122
|
+
* user cannot edit the trigger away without an explicit
|
|
123
|
+
* `peaks hooks uninstall` first. The skill name (when
|
|
124
|
+
* applicable) is the value after the colon.
|
|
125
|
+
*/
|
|
126
|
+
function formatTriggerDenyEntry(phrase) {
|
|
127
|
+
return `Edit(deny-trigger:${phrase})`;
|
|
128
|
+
}
|
|
129
|
+
export function withTriggeredDenyList(settings) {
|
|
130
|
+
const existingDeny = Array.isArray(settings.permissions?.deny)
|
|
131
|
+
? settings.permissions.deny.filter((d) => typeof d === 'string')
|
|
132
|
+
: [];
|
|
133
|
+
// Detect triggers in the existing allow + deny lists.
|
|
134
|
+
const existingAllow = Array.isArray(settings.permissions?.allow)
|
|
135
|
+
? settings.permissions.allow.filter((d) => typeof d === 'string')
|
|
136
|
+
: [];
|
|
137
|
+
const haystack = [...existingDeny, ...existingAllow].join('|');
|
|
138
|
+
const triggered = TRIGGER_PHRASES.filter((p) => haystack.includes(p));
|
|
139
|
+
if (triggered.length === 0)
|
|
140
|
+
return settings;
|
|
141
|
+
const triggeredEntries = triggered.map(formatTriggerDenyEntry);
|
|
142
|
+
const permissions = settings.permissions &&
|
|
143
|
+
typeof settings.permissions === 'object' &&
|
|
144
|
+
!Array.isArray(settings.permissions)
|
|
145
|
+
? settings.permissions
|
|
146
|
+
: {};
|
|
147
|
+
const otherDeny = existingDeny.filter((d) => !triggeredEntries.includes(d));
|
|
148
|
+
return {
|
|
149
|
+
...settings,
|
|
150
|
+
permissions: { ...permissions, deny: [...new Set([...otherDeny, ...triggeredEntries])] }
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
/** Inverse of withTriggeredDenyList: strip every deny-trigger entry. */
|
|
154
|
+
export function withoutTriggeredDenyList(settings) {
|
|
155
|
+
const permissions = settings.permissions &&
|
|
156
|
+
typeof settings.permissions === 'object' &&
|
|
157
|
+
!Array.isArray(settings.permissions)
|
|
158
|
+
? settings.permissions
|
|
159
|
+
: {};
|
|
160
|
+
const existingDeny = Array.isArray(permissions.deny)
|
|
161
|
+
? permissions.deny.filter((d) => typeof d === 'string')
|
|
162
|
+
: [];
|
|
163
|
+
const kept = existingDeny.filter((d) => !d.startsWith('Edit(deny-trigger:'));
|
|
164
|
+
const next = { ...permissions, deny: kept };
|
|
165
|
+
if (kept.length === 0)
|
|
166
|
+
delete next.deny;
|
|
167
|
+
if (Object.keys(next).length === 0) {
|
|
168
|
+
const out = { ...settings };
|
|
169
|
+
delete out.permissions;
|
|
170
|
+
return out;
|
|
171
|
+
}
|
|
172
|
+
return { ...settings, permissions: next };
|
|
173
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { HookScope } from '../ide/shared/safe-path.js';
|
|
2
|
+
import type { HookRemoveResult, HookStatus, HookTarget } from './hooks-settings-types.js';
|
|
3
|
+
/** The uninstall envelope; a `localPath` is reported only when it is a distinct file. */
|
|
4
|
+
export declare function removedResult(scope: HookScope, settingsPath: string, localPath: string | undefined, removed: boolean): HookRemoveResult;
|
|
5
|
+
/**
|
|
6
|
+
* Strip every peaks-managed row from one target's file and write it back.
|
|
7
|
+
*
|
|
8
|
+
* The deny-list helpers run only on the SHARED settings file (the one that
|
|
9
|
+
* carries the committed `permissions.deny` block); the machine-local file
|
|
10
|
+
* carries hook entries plus, for Claude Code, the gate exemptions.
|
|
11
|
+
*/
|
|
12
|
+
export declare function applyRemovalToTarget(target: HookTarget, sentinels: ReadonlyArray<string>, isSharedFile: boolean): boolean;
|
|
13
|
+
/**
|
|
14
|
+
* The status envelope for an IDE that can never carry a peaks hook: the query
|
|
15
|
+
* ran, the disk was read, and the honest reply is "nothing, and nothing ever
|
|
16
|
+
* will be".
|
|
17
|
+
*/
|
|
18
|
+
export declare function unsupportedHookStatus(scope: HookScope, settingsPath: string, localPath: string | undefined): HookStatus;
|
|
19
|
+
/** The status envelope for a set of resolved targets. */
|
|
20
|
+
export declare function hookStatusFromTargets(scope: HookScope, settingsPath: string, targets: ReadonlyArray<HookTarget>): HookStatus;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The result envelopes the uninstall and status verbs return.
|
|
3
|
+
*
|
|
4
|
+
* Split out of `hooks-settings-service.ts` (file-size cap campaign). The
|
|
5
|
+
* service re-exports every name declared here, so existing importers keep
|
|
6
|
+
* using `./hooks-settings-service.js` unchanged.
|
|
7
|
+
*/
|
|
8
|
+
import { existsSync } from 'node:fs';
|
|
9
|
+
import { atomicWriteJson } from '../ide/shared/atomic-json.js';
|
|
10
|
+
import { withoutExternalGateExemptions } from './hooks-codegate-superpowers.js';
|
|
11
|
+
import { withoutSuperpowersSkillDenylist, withoutTriggeredDenyList } from './hooks-settings-deny-list.js';
|
|
12
|
+
import { isInstalledForEntries, readSettingsFile, stripPeaksEntries } from './hooks-settings-file-shape.js';
|
|
13
|
+
/** The uninstall envelope; a `localPath` is reported only when it is a distinct file. */
|
|
14
|
+
export function removedResult(scope, settingsPath, localPath, removed) {
|
|
15
|
+
return {
|
|
16
|
+
scope,
|
|
17
|
+
settingsPath,
|
|
18
|
+
removed,
|
|
19
|
+
...(localPath !== undefined && localPath !== settingsPath
|
|
20
|
+
? { localSettingsPath: localPath }
|
|
21
|
+
: {})
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Strip every peaks-managed row from one target's file and write it back.
|
|
26
|
+
*
|
|
27
|
+
* The deny-list helpers run only on the SHARED settings file (the one that
|
|
28
|
+
* carries the committed `permissions.deny` block); the machine-local file
|
|
29
|
+
* carries hook entries plus, for Claude Code, the gate exemptions.
|
|
30
|
+
*/
|
|
31
|
+
export function applyRemovalToTarget(target, sentinels, isSharedFile) {
|
|
32
|
+
const { settings, removed } = stripPeaksEntries(target, sentinels);
|
|
33
|
+
let finalSettings = settings;
|
|
34
|
+
if (target.envExemptions === true) {
|
|
35
|
+
finalSettings = withoutExternalGateExemptions(finalSettings);
|
|
36
|
+
}
|
|
37
|
+
if (isSharedFile) {
|
|
38
|
+
finalSettings = withoutTriggeredDenyList(withoutSuperpowersSkillDenylist(finalSettings));
|
|
39
|
+
}
|
|
40
|
+
atomicWriteJson(target.settingsPath, finalSettings);
|
|
41
|
+
return removed;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* The status envelope for an IDE that can never carry a peaks hook: the query
|
|
45
|
+
* ran, the disk was read, and the honest reply is "nothing, and nothing ever
|
|
46
|
+
* will be".
|
|
47
|
+
*/
|
|
48
|
+
export function unsupportedHookStatus(scope, settingsPath, localPath) {
|
|
49
|
+
return {
|
|
50
|
+
scope,
|
|
51
|
+
settingsPath,
|
|
52
|
+
exists: existsSync(settingsPath),
|
|
53
|
+
...(localPath !== undefined && localPath !== settingsPath
|
|
54
|
+
? { localSettingsPath: localPath, localExists: existsSync(localPath) }
|
|
55
|
+
: {}),
|
|
56
|
+
installed: false,
|
|
57
|
+
supportsHooks: false
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
/** The status envelope for a set of resolved targets. */
|
|
61
|
+
export function hookStatusFromTargets(scope, settingsPath, targets) {
|
|
62
|
+
const localTarget = targets.find((t) => t.settingsPath !== settingsPath);
|
|
63
|
+
return {
|
|
64
|
+
scope,
|
|
65
|
+
settingsPath,
|
|
66
|
+
exists: existsSync(settingsPath),
|
|
67
|
+
...(localTarget !== undefined
|
|
68
|
+
? {
|
|
69
|
+
localSettingsPath: localTarget.settingsPath,
|
|
70
|
+
localExists: existsSync(localTarget.settingsPath)
|
|
71
|
+
}
|
|
72
|
+
: {}),
|
|
73
|
+
installed: targets.some((t) => {
|
|
74
|
+
const settings = readSettingsFile(t.settingsPath);
|
|
75
|
+
return Object.keys(settings).length > 0 && isInstalledForEntries(settings, t.entries);
|
|
76
|
+
}),
|
|
77
|
+
supportsHooks: true
|
|
78
|
+
};
|
|
79
|
+
}
|