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,189 @@
|
|
|
1
|
+
// src/cli/commands/web-login-command.ts
|
|
2
|
+
//
|
|
3
|
+
// `peaks web login --profile <name>` — the only path that persists a login.
|
|
4
|
+
// Split out of `web-lifecycle-commands.ts`; the verb name, its options, the
|
|
5
|
+
// gate-first order, the fold notices and every envelope shape are unchanged.
|
|
6
|
+
import { fail, getErrorMessage, ok } from 'peaks-loop-shared/result';
|
|
7
|
+
import { degradedEnvelope } from '../../services/web/web-fallback.js';
|
|
8
|
+
import { isWebDisabled } from '../../services/web/web-install-service.js';
|
|
9
|
+
import { cappedEcho, loginStorageStatePath, resolveProfileName, runHeadedLogin } from '../../services/web/web-login-profile.js';
|
|
10
|
+
import { addJsonOption, printResult } from '../cli-helpers.js';
|
|
11
|
+
/** The `degradedEnvelope` tier a disabled-web refusal reports (tech-doc §5.1). */
|
|
12
|
+
const WEB_DISABLED_TIER = 3;
|
|
13
|
+
/** What a caller can actually do after a refusal or an unclosed login. */
|
|
14
|
+
const LOGIN_NEXT_ACTIONS = [
|
|
15
|
+
'Re-run `peaks web login --profile <name>` when the user is ready to log in',
|
|
16
|
+
'Close the headed browser window when the login is finished — closing it is what saves the session'
|
|
17
|
+
];
|
|
18
|
+
/**
|
|
19
|
+
* The fold, said out loud on the one path that CANNOT fold (S4 repair, code F5 /
|
|
20
|
+
* security S5).
|
|
21
|
+
*
|
|
22
|
+
* The gate is statement #1 (tech-doc §5.1), so on this path the name was never
|
|
23
|
+
* validated and never folded — which is exactly why this refusal must not look
|
|
24
|
+
* like it disagrees with a live run about the profile. It reports what happened
|
|
25
|
+
* (nothing was folded, this is what was typed) rather than implying a canonical
|
|
26
|
+
* name was used, and it claims nothing about whether the name would be accepted.
|
|
27
|
+
* The echo is capped by the same helper the guard uses.
|
|
28
|
+
*/
|
|
29
|
+
function gateFoldNotice(rawProfile) {
|
|
30
|
+
if (rawProfile === undefined || rawProfile === rawProfile.toLowerCase()) {
|
|
31
|
+
return [];
|
|
32
|
+
}
|
|
33
|
+
return [
|
|
34
|
+
`--profile ${JSON.stringify(cappedEcho(rawProfile))} was NOT folded: PEAKS_WEB_DISABLED is ` +
|
|
35
|
+
'checked before the profile name, so this refusal echoes what was typed, not a canonical ' +
|
|
36
|
+
'profile. A run that gets past the gate lower-cases the name first.'
|
|
37
|
+
];
|
|
38
|
+
}
|
|
39
|
+
/** The disabled-web refusal, with the fold notice appended when there is one. */
|
|
40
|
+
function webDisabledLoginEnvelope(rawProfile) {
|
|
41
|
+
const gateEnvelope = degradedEnvelope('login', 'PEAKS_WEB_DISABLED=1', WEB_DISABLED_TIER, rawProfile === undefined ? {} : { profile: cappedEcho(rawProfile) });
|
|
42
|
+
return { ...gateEnvelope, warnings: [...gateEnvelope.warnings, ...gateFoldNotice(rawProfile)] };
|
|
43
|
+
}
|
|
44
|
+
function profileRequiredEnvelope() {
|
|
45
|
+
return fail('peaks.web.login', 'WEB_PROFILE_REQUIRED', '`peaks web login` requires --profile <name>: it is the only verb that persists a login, ' +
|
|
46
|
+
'and there is no default profile — without a name nothing is written', {}, LOGIN_NEXT_ACTIONS);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* `resolveProfileName`'s canonical name, or the refusal envelope to print.
|
|
50
|
+
* The helper's own message already begins with the code, and `fail()` puts the
|
|
51
|
+
* code in front of the message again — strip it, so human output does not read
|
|
52
|
+
* `WEB_PROFILE_NAME_INVALID: WEB_PROFILE_NAME_INVALID: …`.
|
|
53
|
+
*/
|
|
54
|
+
function resolveLoginProfile(rawProfile) {
|
|
55
|
+
try {
|
|
56
|
+
return { profile: resolveProfileName(rawProfile) };
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
const detail = getErrorMessage(error).replace(/^WEB_PROFILE_NAME_INVALID:\s*/, '');
|
|
60
|
+
return {
|
|
61
|
+
refusal: fail('peaks.web.login', 'WEB_PROFILE_NAME_INVALID', detail, {}, LOGIN_NEXT_ACTIONS)
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* The two sides are deliberately not the same value — the left is what the
|
|
67
|
+
* caller TYPED (echoed through `cappedEcho`, since it is still caller input),
|
|
68
|
+
* the right is the canonical name the run uses from here on.
|
|
69
|
+
*/
|
|
70
|
+
function loginFoldWarnings(rawProfile, profile) {
|
|
71
|
+
return rawProfile === profile
|
|
72
|
+
? []
|
|
73
|
+
: [`--profile ${JSON.stringify(cappedEcho(rawProfile))} resolved to the profile "${profile}"`];
|
|
74
|
+
}
|
|
75
|
+
/** The headed-browser instructions the user reads while the login is open. */
|
|
76
|
+
function announceHeadedLogin(io, profile) {
|
|
77
|
+
return () => {
|
|
78
|
+
io.stderr([
|
|
79
|
+
`peaks web login: a headed browser is open for profile "${profile}" — log in there yourself.`,
|
|
80
|
+
'Close the browser window when you are done: that is what saves the session, to ' +
|
|
81
|
+
`${loginStorageStatePath(profile)}.`,
|
|
82
|
+
'The session is captured while the window is open, so the saved state can be up to a ' +
|
|
83
|
+
'second older than what you see — finish logging in before you close it.'
|
|
84
|
+
].join('\n'));
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* S1's F1. This is the ONLY path on which the runner returns `ok: false` AND a
|
|
89
|
+
* warning (a login whose context never opened and whose headed browser then
|
|
90
|
+
* refused to close — a browser nothing can then stop, because `stop` is
|
|
91
|
+
* daemon-scoped). `fail()` hard-codes `warnings: []`, so the warning is spread
|
|
92
|
+
* back over it, the shape `degradedEnvelope` uses.
|
|
93
|
+
*/
|
|
94
|
+
function loginFailedEnvelope(command, outcome, foldWarnings) {
|
|
95
|
+
return {
|
|
96
|
+
...fail(command, outcome.code, outcome.message, {}, LOGIN_NEXT_ACTIONS),
|
|
97
|
+
warnings: [...foldWarnings, ...outcome.warnings]
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* The success envelope — counts, never the values: the file holds live session
|
|
102
|
+
* cookies and this envelope reaches a terminal (and a transcript).
|
|
103
|
+
*
|
|
104
|
+
* R5: a capture that was written but could not be read back is `ok` — the file
|
|
105
|
+
* did land, so it is not a failure — but it is not a clean success either. The
|
|
106
|
+
* code is what an ok-only consumer cannot miss.
|
|
107
|
+
*/
|
|
108
|
+
function loginResultEnvelope(command, outcome, foldWarnings) {
|
|
109
|
+
const envelope = ok(command, {
|
|
110
|
+
profile: outcome.profile,
|
|
111
|
+
storageStatePath: outcome.storageStatePath,
|
|
112
|
+
bytes: outcome.bytes,
|
|
113
|
+
cookies: outcome.cookies,
|
|
114
|
+
origins: outcome.origins
|
|
115
|
+
}, [...foldWarnings, ...outcome.warnings]);
|
|
116
|
+
return outcome.code === '' ? envelope : { ...envelope, code: outcome.code };
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* The catch-all failure envelope. A run that reached `resolveProfileName` knows
|
|
120
|
+
* the canonical name, so a failure before the browser was even up reports the
|
|
121
|
+
* fold like every other path (S4 repair, code F5 / security S5).
|
|
122
|
+
*/
|
|
123
|
+
function loginThrewEnvelope(command, error, foldWarnings) {
|
|
124
|
+
return {
|
|
125
|
+
...fail(command, 'WEB_LOGIN_FAILED', `peaks web login failed: ${getErrorMessage(error)}`, {}, LOGIN_NEXT_ACTIONS),
|
|
126
|
+
warnings: [...foldWarnings]
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* `peaks web login --profile <name>` — the only path that persists a login
|
|
131
|
+
* (design §2/§5, PRD R7).
|
|
132
|
+
*
|
|
133
|
+
* `--profile` is enforced HERE rather than with commander's `requiredOption`,
|
|
134
|
+
* because `requiredOption` refuses before this handler runs — and then the
|
|
135
|
+
* `PEAKS_WEB_DISABLED` gate would no longer be statement #1 (tech-doc §5.1,
|
|
136
|
+
* AC5). A profile-less login refuses without touching the profile root: no
|
|
137
|
+
* directory, no storage state, no browser.
|
|
138
|
+
*/
|
|
139
|
+
export async function runWebLogin(io, asJson, rawProfile) {
|
|
140
|
+
const command = 'peaks.web.login';
|
|
141
|
+
// Declared out here so the CATCH can report it too (S4 repair, security S5 /
|
|
142
|
+
// code F3): a launch failure happens AFTER the name was resolved, so a run
|
|
143
|
+
// that dies on `WEB_LAUNCH_FAILED` knows the canonical name just as well as
|
|
144
|
+
// one that succeeds, and must not be the one path where the fold is silent.
|
|
145
|
+
let foldWarnings = [];
|
|
146
|
+
try {
|
|
147
|
+
if (isWebDisabled(process.env)) {
|
|
148
|
+
printResult(io, webDisabledLoginEnvelope(rawProfile), asJson);
|
|
149
|
+
process.exitCode = 1;
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
if (rawProfile === undefined || rawProfile === '') {
|
|
153
|
+
printResult(io, profileRequiredEnvelope(), asJson);
|
|
154
|
+
process.exitCode = 1;
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
const resolved = resolveLoginProfile(rawProfile);
|
|
158
|
+
if ('refusal' in resolved) {
|
|
159
|
+
printResult(io, resolved.refusal, asJson);
|
|
160
|
+
process.exitCode = 1;
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
const profile = resolved.profile;
|
|
164
|
+
foldWarnings = loginFoldWarnings(rawProfile, profile);
|
|
165
|
+
const outcome = await runHeadedLogin({
|
|
166
|
+
profile,
|
|
167
|
+
announce: announceHeadedLogin(io, profile)
|
|
168
|
+
});
|
|
169
|
+
if (!outcome.ok) {
|
|
170
|
+
printResult(io, loginFailedEnvelope(command, outcome, foldWarnings), asJson);
|
|
171
|
+
process.exitCode = 1;
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
printResult(io, loginResultEnvelope(command, outcome, foldWarnings), asJson);
|
|
175
|
+
}
|
|
176
|
+
catch (error) {
|
|
177
|
+
printResult(io, loginThrewEnvelope(command, error, foldWarnings), asJson);
|
|
178
|
+
process.exitCode = 1;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
export function registerWebLoginCommand(web, io) {
|
|
182
|
+
addJsonOption(web
|
|
183
|
+
.command('login')
|
|
184
|
+
.description('Open a HEADED browser so the user can log in themselves, then persist that session to ' +
|
|
185
|
+
'~/.peaks/web-profiles/<name>/storageState.json. Run it only when the user asks for a ' +
|
|
186
|
+
'persistent login: it writes live session cookies to disk. --profile is required, and ' +
|
|
187
|
+
'without it nothing is persisted.')
|
|
188
|
+
.option('--profile <name>', 'the login profile to persist (required; [a-z0-9._-], 1-64 chars — upper case folds to lower)')).action((options) => runWebLogin(io, options.json === true, options.profile));
|
|
189
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { ResultEnvelope } from 'peaks-loop-shared/result';
|
|
2
|
+
import type { WebOp } from '../../services/web/web-protocol.js';
|
|
3
|
+
import { type ProgramIO } from '../cli-helpers.js';
|
|
4
|
+
interface WrappedPayload {
|
|
5
|
+
readonly data: Record<string, unknown>;
|
|
6
|
+
/** Raw human-mode stdout, or `null` for verbs whose output is not page content. */
|
|
7
|
+
readonly human: string | null;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Wrap the page-controlled part of each verb's payload (AC4 / §6.2) and pick
|
|
11
|
+
* the bytes that human mode prints verbatim. `shot` is unwrapped: its path and
|
|
12
|
+
* byte count are ours, not the page's.
|
|
13
|
+
*/
|
|
14
|
+
export declare function wrapPageData(op: WebOp, raw: Record<string, unknown>): WrappedPayload;
|
|
15
|
+
/**
|
|
16
|
+
* Print the envelope. Failures and `--json` go through `printResult`; a
|
|
17
|
+
* successful wrapped op in human mode prints its payload RAW, because the
|
|
18
|
+
* UNTRUSTED delimiters must stay on their own lines (AC4) and AC2 measures the
|
|
19
|
+
* byte count of exactly this stdout.
|
|
20
|
+
*/
|
|
21
|
+
export declare function emit<T>(io: ProgramIO, result: ResultEnvelope<T>, asJson: boolean, humanPayload: string | null): void;
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
// src/cli/commands/web-op-payload.ts
|
|
2
|
+
//
|
|
3
|
+
// How one `peaks web` op's daemon payload becomes stdout: the per-verb wrap of
|
|
4
|
+
// the page-controlled fields, the human-mode renderer for `metrics`, and the
|
|
5
|
+
// printer that keeps the UNTRUSTED delimiters on their own lines. Split out of
|
|
6
|
+
// `web-commands.ts`; every branch and every byte cap is unchanged.
|
|
7
|
+
import { capText, MAX_TEXT_BYTES } from '../../services/web/bounded-output.js';
|
|
8
|
+
import { wrapUntrusted, WRAPPED_OPS } from '../../services/web/untrusted-envelope.js';
|
|
9
|
+
import { printResult } from '../cli-helpers.js';
|
|
10
|
+
import { count, text } from './web-command-shared.js';
|
|
11
|
+
/**
|
|
12
|
+
* Wrap the page-controlled part of each verb's payload (AC4 / §6.2) and pick
|
|
13
|
+
* the bytes that human mode prints verbatim. `shot` is unwrapped: its path and
|
|
14
|
+
* byte count are ours, not the page's.
|
|
15
|
+
*/
|
|
16
|
+
export function wrapPageData(op, raw) {
|
|
17
|
+
if (!WRAPPED_OPS.has(op)) {
|
|
18
|
+
return { data: raw, human: null };
|
|
19
|
+
}
|
|
20
|
+
switch (op) {
|
|
21
|
+
case 'open': {
|
|
22
|
+
const title = wrapUntrusted(text(raw['title']));
|
|
23
|
+
return { data: { url: wrapUntrusted(text(raw['url'])), title }, human: title };
|
|
24
|
+
}
|
|
25
|
+
case 'text': {
|
|
26
|
+
const value = wrapUntrusted(text(raw['text']));
|
|
27
|
+
return {
|
|
28
|
+
data: {
|
|
29
|
+
text: value,
|
|
30
|
+
truncated: raw['truncated'] === true,
|
|
31
|
+
droppedBytes: count(raw['droppedBytes'])
|
|
32
|
+
},
|
|
33
|
+
human: value
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
case 'snap': {
|
|
37
|
+
const snapshot = wrapUntrusted(text(raw['snapshot']));
|
|
38
|
+
return {
|
|
39
|
+
data: {
|
|
40
|
+
snapshot,
|
|
41
|
+
droppedNodes: count(raw['droppedNodes']),
|
|
42
|
+
depthCapped: raw['depthCapped'] === true,
|
|
43
|
+
nodeCapped: raw['nodeCapped'] === true,
|
|
44
|
+
truncated: raw['truncated'] === true,
|
|
45
|
+
droppedBytes: count(raw['droppedBytes'])
|
|
46
|
+
},
|
|
47
|
+
human: snapshot
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
case 'click': {
|
|
51
|
+
const result = wrapUntrusted(text(raw['result']));
|
|
52
|
+
return { data: { result }, human: result };
|
|
53
|
+
}
|
|
54
|
+
case 'metrics': {
|
|
55
|
+
// The rendered lines come from the daemon's payload, so they are capped
|
|
56
|
+
// here as well as at the producer: this is the boundary that reaches
|
|
57
|
+
// stdout, and the ceiling must hold whatever the daemon sends.
|
|
58
|
+
const metrics = wrapUntrusted(capText(renderMetrics(raw), MAX_TEXT_BYTES).text);
|
|
59
|
+
return { data: { metrics }, human: metrics };
|
|
60
|
+
}
|
|
61
|
+
default:
|
|
62
|
+
return { data: raw, human: null };
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Print the envelope. Failures and `--json` go through `printResult`; a
|
|
67
|
+
* successful wrapped op in human mode prints its payload RAW, because the
|
|
68
|
+
* UNTRUSTED delimiters must stay on their own lines (AC4) and AC2 measures the
|
|
69
|
+
* byte count of exactly this stdout.
|
|
70
|
+
*/
|
|
71
|
+
export function emit(io, result, asJson, humanPayload) {
|
|
72
|
+
if (!result.ok || asJson || humanPayload === null) {
|
|
73
|
+
printResult(io, result, asJson);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
io.stdout(humanPayload);
|
|
77
|
+
for (const warning of result.warnings) {
|
|
78
|
+
io.stderr(`warning: ${warning}`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/** `available: false` is reported as such — never as fabricated zeros (C4). */
|
|
82
|
+
function renderMetrics(raw) {
|
|
83
|
+
if (raw['available'] !== true) {
|
|
84
|
+
return `available: false\nreason: ${text(raw['reason']) || 'unavailable'}`;
|
|
85
|
+
}
|
|
86
|
+
const values = (raw['values'] ?? {});
|
|
87
|
+
const lines = Object.entries(values).map(([key, value]) => `${key}: ${String(value)}`);
|
|
88
|
+
return lines.length > 0 ? lines.join('\n') : 'available: true';
|
|
89
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { fail } from 'peaks-loop-shared/result';
|
|
2
|
+
import type { WebOp } from '../../services/web/web-protocol.js';
|
|
3
|
+
/**
|
|
4
|
+
* What a caller can do after a refused `--profile` — the same sentence `login`
|
|
5
|
+
* gives, because it is the same mistake and the same verb fixes it.
|
|
6
|
+
*/
|
|
7
|
+
export declare const PROFILE_NEXT_ACTIONS: string[];
|
|
8
|
+
/**
|
|
9
|
+
* The resolver's own message begins with the code, and `fail()` puts the code in
|
|
10
|
+
* front of the message again — strip it, so human output does not read
|
|
11
|
+
* `WEB_PROFILE_NAME_INVALID: WEB_PROFILE_NAME_INVALID: …` (the `login` verb does
|
|
12
|
+
* the same).
|
|
13
|
+
*/
|
|
14
|
+
export declare function profileRefusal(error: unknown): string;
|
|
15
|
+
/** Every daemon warning, capped and wrapped. Empty entries are dropped. */
|
|
16
|
+
export declare function wrapDiagnostics(values: readonly string[]): string[];
|
|
17
|
+
/**
|
|
18
|
+
* Our own static sentence, then the daemon's own words as a wrapped, capped
|
|
19
|
+
* block. The daemon's `nextActions` are folded into that block rather than
|
|
20
|
+
* forwarded: `printResult` prints `nextActions` to STDOUT as `next: …`, the
|
|
21
|
+
* channel the notice calls instruction, and the daemon's text is not ours to
|
|
22
|
+
* promote there.
|
|
23
|
+
*/
|
|
24
|
+
export declare function failureMessage(op: WebOp, message: unknown, nextActions: readonly string[]): string;
|
|
25
|
+
/**
|
|
26
|
+
* A daemon-supplied `code` is printed on the envelope's first line, so only a
|
|
27
|
+
* protocol-shaped identifier is accepted; anything else falls back to ours.
|
|
28
|
+
*/
|
|
29
|
+
export declare function safeDaemonCode(value: unknown): string;
|
|
30
|
+
/** The unusable-daemon envelope: a named code, or the generic op failure. */
|
|
31
|
+
export declare function daemonFailureEnvelope(input: {
|
|
32
|
+
readonly op: WebOp;
|
|
33
|
+
readonly command: string;
|
|
34
|
+
readonly code: string;
|
|
35
|
+
readonly message: unknown;
|
|
36
|
+
readonly nextActions: readonly string[];
|
|
37
|
+
}): ReturnType<typeof fail>;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// src/cli/commands/web-op-refusals.ts
|
|
2
|
+
//
|
|
3
|
+
// How a `peaks web` op refuses: the diagnostic channel, the daemon failure
|
|
4
|
+
// envelope, and the refused-`--profile` pair of sentences. Split out of
|
|
5
|
+
// `web-commands.ts`; every wrap, every cap and every sentence is unchanged.
|
|
6
|
+
import { fail } from 'peaks-loop-shared/result';
|
|
7
|
+
import { capText, MAX_TEXT_BYTES } from '../../services/web/bounded-output.js';
|
|
8
|
+
import { wrapUntrusted } from '../../services/web/untrusted-envelope.js';
|
|
9
|
+
import { getErrorMessage } from '../cli-helpers.js';
|
|
10
|
+
import { text } from './web-command-shared.js';
|
|
11
|
+
/**
|
|
12
|
+
* What a caller can do after a refused `--profile` — the same sentence `login`
|
|
13
|
+
* gives, because it is the same mistake and the same verb fixes it.
|
|
14
|
+
*/
|
|
15
|
+
export const PROFILE_NEXT_ACTIONS = [
|
|
16
|
+
'Re-run with a name matching [a-z0-9._-], 1-64 chars',
|
|
17
|
+
'Or run `peaks web login --profile <name>` to create that profile'
|
|
18
|
+
];
|
|
19
|
+
/**
|
|
20
|
+
* The resolver's own message begins with the code, and `fail()` puts the code in
|
|
21
|
+
* front of the message again — strip it, so human output does not read
|
|
22
|
+
* `WEB_PROFILE_NAME_INVALID: WEB_PROFILE_NAME_INVALID: …` (the `login` verb does
|
|
23
|
+
* the same).
|
|
24
|
+
*/
|
|
25
|
+
export function profileRefusal(error) {
|
|
26
|
+
return getErrorMessage(error).replace(/^WEB_PROFILE_NAME_INVALID:\s*/, '');
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* A daemon- or page-derived diagnostic is DATA, never an instruction: it is
|
|
30
|
+
* byte-capped and wrapped before it can reach `message` or `warnings` (AC4 /
|
|
31
|
+
* R4 — the envelope must cover the diagnostic channel, not only `data`).
|
|
32
|
+
*
|
|
33
|
+
* This matters because Playwright's own error messages embed the matched
|
|
34
|
+
* elements' HTML, so a page with two elements matching a selector can put
|
|
35
|
+
* arbitrary text on a channel the CLI would otherwise print verbatim to stdout.
|
|
36
|
+
*/
|
|
37
|
+
function wrapDiagnostic(raw) {
|
|
38
|
+
const capped = capText(text(raw), MAX_TEXT_BYTES).text;
|
|
39
|
+
return capped === '' ? '' : wrapUntrusted(capped);
|
|
40
|
+
}
|
|
41
|
+
/** Every daemon warning, capped and wrapped. Empty entries are dropped. */
|
|
42
|
+
export function wrapDiagnostics(values) {
|
|
43
|
+
return values.map((value) => wrapDiagnostic(value)).filter((value) => value !== '');
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Our own static sentence, then the daemon's own words as a wrapped, capped
|
|
47
|
+
* block. The daemon's `nextActions` are folded into that block rather than
|
|
48
|
+
* forwarded: `printResult` prints `nextActions` to STDOUT as `next: …`, the
|
|
49
|
+
* channel the notice calls instruction, and the daemon's text is not ours to
|
|
50
|
+
* promote there.
|
|
51
|
+
*/
|
|
52
|
+
export function failureMessage(op, message, nextActions) {
|
|
53
|
+
const detail = [text(message), ...nextActions.map((action) => text(action))]
|
|
54
|
+
.filter((line) => line !== '')
|
|
55
|
+
.join('\n');
|
|
56
|
+
const wrapped = wrapDiagnostic(detail);
|
|
57
|
+
return wrapped === ''
|
|
58
|
+
? `peaks web ${op} failed in the daemon`
|
|
59
|
+
: `peaks web ${op} failed in the daemon\n${wrapped}`;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* A daemon-supplied `code` is printed on the envelope's first line, so only a
|
|
63
|
+
* protocol-shaped identifier is accepted; anything else falls back to ours.
|
|
64
|
+
*/
|
|
65
|
+
export function safeDaemonCode(value) {
|
|
66
|
+
return typeof value === 'string' && /^[A-Z][A-Z0-9_]{0,63}$/.test(value)
|
|
67
|
+
? value
|
|
68
|
+
: 'WEB_OP_FAILED';
|
|
69
|
+
}
|
|
70
|
+
/** The unusable-daemon envelope: a named code, or the generic op failure. */
|
|
71
|
+
export function daemonFailureEnvelope(input) {
|
|
72
|
+
return fail(input.command, input.code, failureMessage(input.op, input.message, input.nextActions), {}, []);
|
|
73
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { WebOp } from '../../services/web/web-protocol.js';
|
|
2
|
+
import { type ProgramIO } from '../cli-helpers.js';
|
|
3
|
+
/**
|
|
4
|
+
* Resolve the session, ensure a daemon, invoke one op, and emit exactly one
|
|
5
|
+
* envelope. `WRAPPED_OPS` is applied here, after the byte caps the daemon
|
|
6
|
+
* already imposed, so the UNTRUSTED markers are never themselves truncated.
|
|
7
|
+
*
|
|
8
|
+
* The `PEAKS_WEB_DISABLED` gate is the FIRST thing that happens (tech-doc §5.1
|
|
9
|
+
* step 1, AC5). Before the session lookup, so a project with no binding still
|
|
10
|
+
* gets `WEB_DISABLED` rather than `NO_SESSION`; before `ensureDaemon`, so
|
|
11
|
+
* nothing is spawned and no lock is taken; and therefore before anything that
|
|
12
|
+
* could touch the browser cache.
|
|
13
|
+
*/
|
|
14
|
+
export declare function runWebOp(io: ProgramIO, op: WebOp, args: Record<string, unknown>, asJson: boolean): Promise<void>;
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
// src/cli/commands/web-op-runner.ts
|
|
2
|
+
//
|
|
3
|
+
// `runWebOp` — resolve the session, ensure a daemon, invoke one op, and emit
|
|
4
|
+
// exactly one envelope. Split out of `web-commands.ts`, where this one function
|
|
5
|
+
// had reached 117 lines; the gates, their order and every envelope are
|
|
6
|
+
// unchanged.
|
|
7
|
+
import { fail, getErrorMessage, ok } from 'peaks-loop-shared/result';
|
|
8
|
+
import { ensureDaemon } from '../../services/web/daemon-supervisor.js';
|
|
9
|
+
import { degradedEnvelope } from '../../services/web/web-fallback.js';
|
|
10
|
+
import { isWebDisabled } from '../../services/web/web-install-service.js';
|
|
11
|
+
import { cappedEcho, resolveProfileName } from '../../services/web/web-login-profile.js';
|
|
12
|
+
import { WebDaemonClient } from '../../services/web/web-client.js';
|
|
13
|
+
import { printResult, redactSensitiveErrorMessage } from '../cli-helpers.js';
|
|
14
|
+
import { noSession, resolveSession } from './web-command-shared.js';
|
|
15
|
+
import { emit, wrapPageData } from './web-op-payload.js';
|
|
16
|
+
import { daemonFailureEnvelope, PROFILE_NEXT_ACTIONS, profileRefusal, safeDaemonCode, wrapDiagnostics } from './web-op-refusals.js';
|
|
17
|
+
/** A browser op is user-visible latency; 30 s is generous but bounded. */
|
|
18
|
+
const OP_TIMEOUT_MS = 30_000;
|
|
19
|
+
/**
|
|
20
|
+
* Resolve the session, ensure a daemon, invoke one op, and emit exactly one
|
|
21
|
+
* envelope. `WRAPPED_OPS` is applied here, after the byte caps the daemon
|
|
22
|
+
* already imposed, so the UNTRUSTED markers are never themselves truncated.
|
|
23
|
+
*
|
|
24
|
+
* The `PEAKS_WEB_DISABLED` gate is the FIRST thing that happens (tech-doc §5.1
|
|
25
|
+
* step 1, AC5). Before the session lookup, so a project with no binding still
|
|
26
|
+
* gets `WEB_DISABLED` rather than `NO_SESSION`; before `ensureDaemon`, so
|
|
27
|
+
* nothing is spawned and no lock is taken; and therefore before anything that
|
|
28
|
+
* could touch the browser cache.
|
|
29
|
+
*/
|
|
30
|
+
export async function runWebOp(io, op, args, asJson) {
|
|
31
|
+
const command = `peaks.web.${op}`;
|
|
32
|
+
// Declared outside the try so the CATCH reports the fold too (S4's F5/S5 rule
|
|
33
|
+
// for `login`, applied here): a run that dies after the name was resolved
|
|
34
|
+
// knows the canonical name just as well as a successful one.
|
|
35
|
+
let foldWarnings = [];
|
|
36
|
+
try {
|
|
37
|
+
if (isWebDisabled(process.env)) {
|
|
38
|
+
printResult(io, webDisabledEnvelope(op, args), asJson);
|
|
39
|
+
process.exitCode = 1;
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const profile = resolveWebProfile(command, args);
|
|
43
|
+
foldWarnings = profile.warnings;
|
|
44
|
+
if (profile.envelope !== null) {
|
|
45
|
+
printResult(io, profile.envelope, asJson);
|
|
46
|
+
process.exitCode = 1;
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
const session = resolveSession();
|
|
50
|
+
if (session === null) {
|
|
51
|
+
printResult(io, withFold(noSession(command), foldWarnings), asJson);
|
|
52
|
+
process.exitCode = 1;
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const response = await callWebDaemon(op, profile.args, session.projectRoot, session.sessionId);
|
|
56
|
+
if (!response.ok || response.data === null) {
|
|
57
|
+
const refusal = daemonRefusal({ op, command, response, opArgs: profile.args, foldWarnings });
|
|
58
|
+
printResult(io, refusal, asJson);
|
|
59
|
+
process.exitCode = 1;
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
const wrapped = wrapPageData(op, response.data);
|
|
63
|
+
emit(io, ok(command, wrapped.data, [...foldWarnings, ...wrapDiagnostics(response.warnings)]), asJson, wrapped.human);
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
printResult(io, webOpFailure(op, command, error, foldWarnings), asJson);
|
|
67
|
+
process.exitCode = 1;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/** The `WEB_OP_FAILED` envelope for a throw anywhere in the run, fold included. */
|
|
71
|
+
function webOpFailure(op, command, error, foldWarnings) {
|
|
72
|
+
return withFold(daemonFailureEnvelope({
|
|
73
|
+
op,
|
|
74
|
+
command,
|
|
75
|
+
code: 'WEB_OP_FAILED',
|
|
76
|
+
message: redactSensitiveErrorMessage(getErrorMessage(error)),
|
|
77
|
+
nextActions: []
|
|
78
|
+
}), foldWarnings);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* The `PEAKS_WEB_DISABLED` gate's envelope. The gate is statement #1, so a
|
|
82
|
+
* `--profile` has NOT been through the resolver yet and is still unbounded
|
|
83
|
+
* caller text; `degradedEnvelope` carries every string arg into the payload, so
|
|
84
|
+
* it is capped here — the same cap the `login` gate applies, for the same reason
|
|
85
|
+
* (S1's bounded output is a property of the envelope, not only of stdout).
|
|
86
|
+
*/
|
|
87
|
+
function webDisabledEnvelope(op, args) {
|
|
88
|
+
return degradedEnvelope(op, 'PEAKS_WEB_DISABLED=1', 3, cappedProfileArg(args));
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* The unusable-daemon envelope. The daemon no longer downloads (R3), so "the
|
|
92
|
+
* browser is not installed" arrives as a refusal: it is AC5's tier-3 branch,
|
|
93
|
+
* not an opaque op failure — the caller must be handed the same envelope (MCP
|
|
94
|
+
* tool, install command, screenshot consequence) that the gate produces.
|
|
95
|
+
*/
|
|
96
|
+
function daemonRefusal(input) {
|
|
97
|
+
const code = safeDaemonCode(input.response.code);
|
|
98
|
+
if (code === 'WEB_INSTALL_REQUIRED') {
|
|
99
|
+
const reason = `WEB_INSTALL_REQUIRED: ${input.response.message ?? ''}`;
|
|
100
|
+
return withFold(degradedEnvelope(input.op, reason, 3, input.opArgs), input.foldWarnings);
|
|
101
|
+
}
|
|
102
|
+
return withFold(daemonFailureEnvelope({
|
|
103
|
+
op: input.op,
|
|
104
|
+
command: input.command,
|
|
105
|
+
code,
|
|
106
|
+
message: input.response.message,
|
|
107
|
+
nextActions: input.response.nextActions
|
|
108
|
+
}), input.foldWarnings);
|
|
109
|
+
}
|
|
110
|
+
/** Prepend the fold notice to an envelope's warnings; never rewrite them away. */
|
|
111
|
+
function withFold(envelope, warnings) {
|
|
112
|
+
return warnings.length === 0
|
|
113
|
+
? envelope
|
|
114
|
+
: { ...envelope, warnings: [...warnings, ...envelope.warnings] };
|
|
115
|
+
}
|
|
116
|
+
/** The `PEAKS_WEB_DISABLED` gate's args: a `--profile` still raw, so still capped. */
|
|
117
|
+
function cappedProfileArg(args) {
|
|
118
|
+
return typeof args['profile'] === 'string'
|
|
119
|
+
? { ...args, profile: cappedEcho(args['profile']) }
|
|
120
|
+
: args;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* A caller-supplied `--profile` is validated HERE, before anything is sent, and
|
|
124
|
+
* the daemon runs the SAME resolver again on the payload it receives (a value
|
|
125
|
+
* off the wire is not trusted). `resolveProfileName` folds to lower case, so the
|
|
126
|
+
* canonical name is what travels, and the fold is reported rather than silent —
|
|
127
|
+
* the contract `login` honours.
|
|
128
|
+
*/
|
|
129
|
+
function resolveWebProfile(command, args) {
|
|
130
|
+
if (typeof args['profile'] !== 'string') {
|
|
131
|
+
return { args, warnings: [], envelope: null };
|
|
132
|
+
}
|
|
133
|
+
const typed = args['profile'];
|
|
134
|
+
let profile;
|
|
135
|
+
try {
|
|
136
|
+
profile = resolveProfileName(typed);
|
|
137
|
+
}
|
|
138
|
+
catch (error) {
|
|
139
|
+
return {
|
|
140
|
+
args,
|
|
141
|
+
warnings: [],
|
|
142
|
+
envelope: fail(command, 'WEB_PROFILE_NAME_INVALID', profileRefusal(error), {}, PROFILE_NEXT_ACTIONS)
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
const warnings = profile === typed
|
|
146
|
+
? []
|
|
147
|
+
: [`--profile ${JSON.stringify(cappedEcho(typed))} resolved to the profile "${profile}"`];
|
|
148
|
+
return { args: { ...args, profile }, warnings, envelope: null };
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Ensure the daemon and invoke one op. The daemon reads `projectRoot` back from
|
|
152
|
+
* `daemon.json` — the record it itself wrote — and that round-trip is the only
|
|
153
|
+
* path that survives the macOS `/var` <-> `/private/var` symlink: the writer's
|
|
154
|
+
* prefix may not match `projectRoot` resolved from `process.cwd()` (the kernel
|
|
155
|
+
* resolves symlinks on `chdir`), and the integration test asserts on that exact
|
|
156
|
+
* round-tripped value.
|
|
157
|
+
*/
|
|
158
|
+
async function callWebDaemon(op, args, projectRoot, sessionId) {
|
|
159
|
+
const info = await ensureDaemon(projectRoot, sessionId);
|
|
160
|
+
return new WebDaemonClient(info).call(op, {
|
|
161
|
+
...args,
|
|
162
|
+
dispatchId: process.env['PEAKS_DISPATCH_ID'] ?? 'current',
|
|
163
|
+
projectRoot: info.projectRoot,
|
|
164
|
+
sessionId
|
|
165
|
+
}, OP_TIMEOUT_MS);
|
|
166
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// src/cli/commands/web-status-command.ts
|
|
2
|
+
//
|
|
3
|
+
// `peaks web status` — this session's daemon instances (live / orphaned /
|
|
4
|
+
// stale), read from the filesystem and the loopback port, never from the daemon.
|
|
5
|
+
// Split out of `web-lifecycle-commands.ts`; the verb name, its options and the
|
|
6
|
+
// envelope shape are unchanged.
|
|
7
|
+
import { fail, getErrorMessage, ok } from 'peaks-loop-shared/result';
|
|
8
|
+
import { buildStatusReport } from '../../services/web/web-status-report.js';
|
|
9
|
+
import { addJsonOption, printResult } from '../cli-helpers.js';
|
|
10
|
+
import { noSession, resolveSession } from './web-command-shared.js';
|
|
11
|
+
export async function runWebStatus(io, asJson) {
|
|
12
|
+
const command = 'peaks.web.status';
|
|
13
|
+
try {
|
|
14
|
+
const session = resolveSession();
|
|
15
|
+
if (session === null) {
|
|
16
|
+
printResult(io, noSession(command), asJson);
|
|
17
|
+
process.exitCode = 1;
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
printResult(io, ok(command, await buildStatusReport(session.projectRoot, session.sessionId)), asJson);
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
printResult(io, fail(command, 'WEB_STATUS_FAILED', `peaks web status failed: ${getErrorMessage(error)}`, {}, []), asJson);
|
|
24
|
+
process.exitCode = 1;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export function registerWebStatusCommand(web, io) {
|
|
28
|
+
addJsonOption(web
|
|
29
|
+
.command('status')
|
|
30
|
+
.description("Report this session's web daemon instances (live / orphaned / stale). Works with no " +
|
|
31
|
+
'daemon running and never starts one.')).action((options) => runWebStatus(io, options.json === true));
|
|
32
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Command } from 'commander';
|
|
2
|
+
import { type ProgramIO } from '../cli-helpers.js';
|
|
3
|
+
/**
|
|
4
|
+
* Stop the daemon and clear its records. `stopped` counts the daemons whose
|
|
5
|
+
* process is confirmed GONE by return — not merely the ones we signalled — so a
|
|
6
|
+
* caller that checks the process table right after this returns is not racing
|
|
7
|
+
* the teardown (AC6).
|
|
8
|
+
*/
|
|
9
|
+
export declare function runWebStop(io: ProgramIO, asJson: boolean): Promise<void>;
|
|
10
|
+
export declare function registerWebStopCommand(web: Command, io: ProgramIO): void;
|