@prestyj/cli 5.28.0 → 5.29.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/assets/motion/THIRD-PARTY.md +14 -19
- package/assets/motion/bin/contact-sheet.mjs +9 -3
- package/assets/motion/bin/cues.mjs +337 -0
- package/assets/motion/bin/flash-check.mjs +314 -0
- package/assets/motion/bin/fonts.mjs +17 -13
- package/assets/motion/bin/library.mjs +61 -18
- package/assets/motion/bin/motion-blur.mjs +943 -0
- package/assets/motion/bin/motion-check.mjs +366 -9
- package/assets/motion/bin/music-fit.mjs +436 -0
- package/assets/motion/bin/pdf-extract.mjs +22 -10
- package/assets/motion/bin/reference-study.mjs +346 -0
- package/assets/motion/bin/score-synth.mjs +1052 -93
- package/assets/motion/fonts/finger-paint/OFL.txt +93 -0
- package/assets/motion/fonts/finger-paint/finger-paint-normal.woff2 +0 -0
- package/assets/motion/fonts/fonts.json +56 -0
- package/assets/motion/fonts/short-stack/OFL.txt +94 -0
- package/assets/motion/fonts/short-stack/short-stack-normal.woff2 +0 -0
- package/assets/motion/fonts/sora/OFL.txt +93 -0
- package/assets/motion/fonts/sora/sora-normal.woff2 +0 -0
- package/assets/motion/fonts/specimen.jpg +0 -0
- package/assets/motion/fonts/unbounded/OFL.txt +93 -0
- package/assets/motion/fonts/unbounded/unbounded-normal.woff2 +0 -0
- package/assets/motion/library/README.md +52 -14
- package/assets/motion/library/kit/moves.js +1981 -0
- package/assets/motion/library/library.json +232 -0
- package/assets/motion/library/pieces/camera-rig/meta.json +13 -0
- package/assets/motion/library/pieces/camera-rig/piece.html +153 -0
- package/assets/motion/library/pieces/camera-rig/preview.jpg +0 -0
- package/assets/motion/library/pieces/chain-knock/meta.json +13 -0
- package/assets/motion/library/pieces/chain-knock/piece.html +195 -0
- package/assets/motion/library/pieces/chain-knock/preview.jpg +0 -0
- package/assets/motion/library/pieces/gather-to-logo/meta.json +13 -0
- package/assets/motion/library/pieces/gather-to-logo/piece.html +159 -0
- package/assets/motion/library/pieces/gather-to-logo/preview.jpg +0 -0
- package/assets/motion/library/pieces/morph-carry/meta.json +13 -0
- package/assets/motion/library/pieces/morph-carry/piece.html +173 -0
- package/assets/motion/library/pieces/morph-carry/preview.jpg +0 -0
- package/assets/motion/library/pieces/one-shape-journey/meta.json +13 -0
- package/assets/motion/library/pieces/one-shape-journey/piece.html +195 -0
- package/assets/motion/library/pieces/one-shape-journey/preview.jpg +0 -0
- package/assets/motion/library/pieces/open-from-subject/meta.json +13 -0
- package/assets/motion/library/pieces/open-from-subject/piece.html +168 -0
- package/assets/motion/library/pieces/open-from-subject/preview.jpg +0 -0
- package/assets/motion/library/pieces/request-to-result/meta.json +13 -0
- package/assets/motion/library/pieces/request-to-result/piece.html +212 -0
- package/assets/motion/library/pieces/request-to-result/preview.jpg +0 -0
- package/assets/motion/library/pieces/scale-dive/meta.json +13 -0
- package/assets/motion/library/pieces/scale-dive/piece.html +321 -0
- package/assets/motion/library/pieces/scale-dive/preview.jpg +0 -0
- package/assets/motion/library/pieces/screen-replica-steps/meta.json +13 -0
- package/assets/motion/library/pieces/screen-replica-steps/piece.html +366 -0
- package/assets/motion/library/pieces/screen-replica-steps/preview.jpg +0 -0
- package/assets/motion/library/pieces/zoom-into-card/meta.json +13 -0
- package/assets/motion/library/pieces/zoom-into-card/piece.html +179 -0
- package/assets/motion/library/pieces/zoom-into-card/preview.jpg +0 -0
- package/assets/motion/library/sheets/diagram.jpg +0 -0
- package/assets/motion/library/sheets/frame.jpg +0 -0
- package/assets/motion/library/sheets/transition.jpg +0 -0
- package/assets/motion/library/sheets/ui.jpg +0 -0
- package/assets/motion/plugin.json +1 -1
- package/assets/motion/references/build-sheet.md +206 -0
- package/assets/motion/references/runtime/determinism-rules.md +3 -3
- package/assets/motion/references/runtime/gsap-easing-and-stagger.md +28 -28
- package/assets/motion/references/runtime/gsap.md +3 -3
- package/assets/motion/references/runtime/inputs-and-assets.md +21 -16
- package/assets/motion/references/runtime/lint-validate-inspect.md +3 -3
- package/assets/motion/references/runtime/minimal-composition.md +6 -0
- package/assets/motion/references/runtime/preview-render.md +3 -3
- package/assets/motion/skills/app-walkthrough/SKILL.md +66 -0
- package/assets/motion/skills/before-after/SKILL.md +53 -0
- package/assets/motion/skills/brand-kit/SKILL.md +17 -16
- package/assets/motion/skills/dev-tool-video/SKILL.md +57 -0
- package/assets/motion/skills/launch-video/SKILL.md +62 -0
- package/assets/motion/skills/match-reference/SKILL.md +58 -0
- package/assets/motion/skills/motion/SKILL.md +167 -98
- package/assets/motion/skills/source-ingest/SKILL.md +23 -15
- package/assets/motion/skills/website-video/SKILL.md +59 -0
- package/assets/skills/bulletproof/SKILL.md +36 -11
- package/assets/skills/bulletproof/references/agent-surface.md +19 -9
- package/assets/skills/bulletproof/references/audit-protocol.md +20 -5
- package/assets/skills/bulletproof/references/platform-playbooks.md +5 -4
- package/assets/skills/bulletproof/references/provenance.md +26 -1
- package/assets/skills/bulletproof/references/secure-defaults.md +6 -5
- package/assets/skills/bulletproof/references/supply-chain.md +21 -17
- package/assets/skills/bulletproof/references/threat-landscape.md +28 -26
- package/assets/skills/bulletproof/references/verification.md +2 -0
- package/assets/skills/clarify/SKILL.md +25 -16
- package/assets/skills/code-review/SKILL.md +71 -13
- package/assets/skills/code-review/references/agent-diffs.md +27 -0
- package/assets/skills/code-review/references/tests.md +19 -0
- package/assets/skills/compliance-guard/SKILL.md +20 -5
- package/assets/skills/compliance-guard/references/artifacts.md +1 -1
- package/assets/skills/compliance-guard/references/eu-uk.md +16 -16
- package/assets/skills/compliance-guard/references/lawsuit-vectors.md +5 -5
- package/assets/skills/compliance-guard/references/provenance.md +41 -2
- package/assets/skills/compliance-guard/references/sector-gates.md +3 -3
- package/assets/skills/compliance-guard/references/security-baseline.md +2 -2
- package/assets/skills/compliance-guard/references/trigger-map.md +5 -5
- package/assets/skills/compliance-guard/references/us.md +27 -21
- package/assets/skills/durable/SKILL.md +87 -79
- package/assets/skills/durable/references/agent-db-safety.md +69 -0
- package/assets/skills/durable/references/backups-and-runtime.md +19 -12
- package/assets/skills/durable/references/migrations-and-schema.md +13 -6
- package/assets/skills/evidence-led-ui/SKILL.md +69 -127
- package/assets/skills/evidence-led-ui/references/anti-defaults.md +107 -208
- package/assets/skills/evidence-led-ui/references/direction.md +124 -0
- package/assets/skills/evidence-led-ui/references/production-contract.md +8 -0
- package/assets/skills/evidence-led-ui/references/provenance.md +24 -1
- package/assets/skills/lean/SKILL.md +90 -71
- package/assets/skills/lean/references/memory-and-processes.md +3 -2
- package/assets/skills/lean/references/playbooks.md +37 -12
- package/assets/skills/refactoring/SKILL.md +24 -3
- package/assets/skills/refactoring/references/agent-pitfalls.md +4 -1
- package/assets/skills/refactoring/references/legacy.md +21 -0
- package/assets/skills/root-cause/SKILL.md +20 -10
- package/assets/skills/shared-language/SKILL.md +16 -14
- package/assets/skills/tdd/SKILL.md +27 -15
- package/dist/app-sidecar.js +203 -47
- package/dist/app-sidecar.js.map +1 -1
- package/dist/cli.js +20 -28
- package/dist/cli.js.map +1 -1
- package/dist/core/acceptance-checks.d.ts +48 -0
- package/dist/core/acceptance-checks.js +144 -0
- package/dist/core/acceptance-checks.js.map +1 -0
- package/dist/core/agent-session.d.ts +119 -75
- package/dist/core/agent-session.js +561 -395
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/agents.d.ts +6 -5
- package/dist/core/agents.js +12 -3
- package/dist/core/agents.js.map +1 -1
- package/dist/core/ask-user.d.ts +90 -8
- package/dist/core/ask-user.js +124 -13
- package/dist/core/ask-user.js.map +1 -1
- package/dist/core/auth-providers.js +1 -1
- package/dist/core/auth-providers.js.map +1 -1
- package/dist/core/autopilot-verdict.d.ts +5 -1
- package/dist/core/autopilot-verdict.js +30 -13
- package/dist/core/autopilot-verdict.js.map +1 -1
- package/dist/core/bundled-agents.js +1 -3
- package/dist/core/bundled-agents.js.map +1 -1
- package/dist/core/cache-diagnostics.d.ts +68 -0
- package/dist/core/cache-diagnostics.js +196 -0
- package/dist/core/cache-diagnostics.js.map +1 -0
- package/dist/core/cache-expiry.d.ts +87 -0
- package/dist/core/cache-expiry.js +111 -0
- package/dist/core/cache-expiry.js.map +1 -0
- package/dist/core/compaction/compactor.js +78 -48
- package/dist/core/compaction/compactor.js.map +1 -1
- package/dist/core/compaction/plan-step-policy.d.ts +46 -0
- package/dist/core/compaction/plan-step-policy.js +57 -0
- package/dist/core/compaction/plan-step-policy.js.map +1 -0
- package/dist/core/destructive-git-guard.d.ts +90 -0
- package/dist/core/destructive-git-guard.js +871 -0
- package/dist/core/destructive-git-guard.js.map +1 -0
- package/dist/core/event-bus.d.ts +3 -0
- package/dist/core/event-bus.js +5 -0
- package/dist/core/event-bus.js.map +1 -1
- package/dist/core/fast-apply-benchmark.d.ts +1 -1
- package/dist/core/fast-apply-benchmark.js +2 -2
- package/dist/core/fast-apply-benchmark.js.map +1 -1
- package/dist/core/injection-detect.d.ts +38 -0
- package/dist/core/injection-detect.js +232 -0
- package/dist/core/injection-detect.js.map +1 -0
- package/dist/core/keep-awake.d.ts +88 -0
- package/dist/core/keep-awake.js +251 -0
- package/dist/core/keep-awake.js.map +1 -0
- package/dist/core/mcp/client.d.ts +72 -0
- package/dist/core/mcp/client.js +264 -41
- package/dist/core/mcp/client.js.map +1 -1
- package/dist/core/mcp/content.js +6 -2
- package/dist/core/mcp/content.js.map +1 -1
- package/dist/core/mcp/store.d.ts +6 -1
- package/dist/core/mcp/store.js +12 -1
- package/dist/core/mcp/store.js.map +1 -1
- package/dist/core/mcp/types.d.ts +18 -0
- package/dist/core/model-unavailable.d.ts +14 -0
- package/dist/core/model-unavailable.js +23 -0
- package/dist/core/model-unavailable.js.map +1 -0
- package/dist/core/node-debugger.d.ts +148 -0
- package/dist/core/node-debugger.js +642 -0
- package/dist/core/node-debugger.js.map +1 -0
- package/dist/core/nolan-context.d.ts +7 -5
- package/dist/core/nolan-context.js +106 -16
- package/dist/core/nolan-context.js.map +1 -1
- package/dist/core/nolan-prompt.js +24 -21
- package/dist/core/nolan-prompt.js.map +1 -1
- package/dist/core/package-threats.d.ts +18 -0
- package/dist/core/package-threats.js +168 -0
- package/dist/core/package-threats.js.map +1 -0
- package/dist/core/persistent-shell.d.ts +58 -6
- package/dist/core/persistent-shell.js +331 -49
- package/dist/core/persistent-shell.js.map +1 -1
- package/dist/core/process-manager.d.ts +14 -0
- package/dist/core/process-manager.js +61 -0
- package/dist/core/process-manager.js.map +1 -1
- package/dist/core/progress/git-xp.js +8 -14
- package/dist/core/progress/git-xp.js.map +1 -1
- package/dist/core/project-discovery.js +77 -26
- package/dist/core/project-discovery.js.map +1 -1
- package/dist/core/semantic-search-benchmark.d.ts +1 -1
- package/dist/core/semantic-search-benchmark.js +2 -2
- package/dist/core/semantic-search-benchmark.js.map +1 -1
- package/dist/core/session-history.d.ts +12 -0
- package/dist/core/session-history.js +27 -0
- package/dist/core/session-history.js.map +1 -1
- package/dist/core/session-manager.d.ts +13 -1
- package/dist/core/session-manager.js +38 -18
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/session-summary-index.d.ts +37 -0
- package/dist/core/session-summary-index.js +172 -0
- package/dist/core/session-summary-index.js.map +1 -0
- package/dist/core/settings-manager.d.ts +2 -0
- package/dist/core/settings-manager.js +10 -0
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/shell-threats-popular-packages.d.ts +11 -0
- package/dist/core/shell-threats-popular-packages.js +675 -0
- package/dist/core/shell-threats-popular-packages.js.map +1 -0
- package/dist/core/shell-threats.d.ts +8 -0
- package/dist/core/shell-threats.js +186 -0
- package/dist/core/shell-threats.js.map +1 -0
- package/dist/core/skills.js +16 -4
- package/dist/core/skills.js.map +1 -1
- package/dist/core/stream-rules.d.ts +30 -0
- package/dist/core/stream-rules.js +151 -0
- package/dist/core/stream-rules.js.map +1 -0
- package/dist/core/subagent-manager.d.ts +23 -6
- package/dist/core/subagent-manager.js +25 -9
- package/dist/core/subagent-manager.js.map +1 -1
- package/dist/core/subagent-policy.js +1 -1
- package/dist/core/subagent-policy.js.map +1 -1
- package/dist/core/subagent-receipt.d.ts +54 -0
- package/dist/core/subagent-receipt.js +276 -0
- package/dist/core/subagent-receipt.js.map +1 -0
- package/dist/core/subagent-turn-record.d.ts +2 -0
- package/dist/core/subagent-turn-record.js.map +1 -1
- package/dist/core/test-impact.d.ts +73 -0
- package/dist/core/test-impact.js +467 -0
- package/dist/core/test-impact.js.map +1 -0
- package/dist/core/thinking-level.d.ts +1 -1
- package/dist/core/thinking-level.js +1 -1
- package/dist/core/thinking-level.js.map +1 -1
- package/dist/core/verification-gate.d.ts +2 -0
- package/dist/core/verification-gate.js +4 -0
- package/dist/core/verification-gate.js.map +1 -1
- package/dist/core/verification-snapshot.js +3 -5
- package/dist/core/verification-snapshot.js.map +1 -1
- package/dist/core/workspace-guard.d.ts +18 -7
- package/dist/core/workspace-guard.js +227 -60
- package/dist/core/workspace-guard.js.map +1 -1
- package/dist/core/worktree-setup.d.ts +23 -0
- package/dist/core/worktree-setup.js +128 -9
- package/dist/core/worktree-setup.js.map +1 -1
- package/dist/core/worktree.d.ts +20 -2
- package/dist/core/worktree.js +74 -31
- package/dist/core/worktree.js.map +1 -1
- package/dist/interactive.js +2 -1
- package/dist/interactive.js.map +1 -1
- package/dist/modes/json-mode.js +11 -2
- package/dist/modes/json-mode.js.map +1 -1
- package/dist/modes/subagent-worker-mode.d.ts +36 -1
- package/dist/modes/subagent-worker-mode.js +100 -42
- package/dist/modes/subagent-worker-mode.js.map +1 -1
- package/dist/motion-agent/motion-agent.d.ts +7 -3
- package/dist/motion-agent/motion-agent.js +6 -8
- package/dist/motion-agent/motion-agent.js.map +1 -1
- package/dist/motion-agent/motion-prompt.d.ts +1 -1
- package/dist/motion-agent/motion-prompt.js +16 -25
- package/dist/motion-agent/motion-prompt.js.map +1 -1
- package/dist/motion-agent/motion-review-session.js +1 -1
- package/dist/motion-agent/motion-review-session.js.map +1 -1
- package/dist/motion-agent/motion-review.d.ts +10 -3
- package/dist/motion-agent/motion-review.js +15 -7
- package/dist/motion-agent/motion-review.js.map +1 -1
- package/dist/motion-agent/motion-studio-context.js +1 -1
- package/dist/motion-agent/motion-studio-context.js.map +1 -1
- package/dist/system-prompt.d.ts +2 -1
- package/dist/system-prompt.js +15 -4
- package/dist/system-prompt.js.map +1 -1
- package/dist/test-support/keep-alive.d.ts +14 -0
- package/dist/test-support/keep-alive.js +17 -0
- package/dist/test-support/keep-alive.js.map +1 -0
- package/dist/tools/ask-user.js +3 -3
- package/dist/tools/ask-user.js.map +1 -1
- package/dist/tools/bash-read-evidence.d.ts +10 -0
- package/dist/tools/bash-read-evidence.js +133 -0
- package/dist/tools/bash-read-evidence.js.map +1 -0
- package/dist/tools/bash.d.ts +10 -1
- package/dist/tools/bash.js +179 -7
- package/dist/tools/bash.js.map +1 -1
- package/dist/tools/debug.d.ts +54 -0
- package/dist/tools/debug.js +233 -0
- package/dist/tools/debug.js.map +1 -0
- package/dist/tools/edit.js +13 -5
- package/dist/tools/edit.js.map +1 -1
- package/dist/tools/goals.d.ts +1 -1
- package/dist/tools/index.d.ts +25 -2
- package/dist/tools/index.js +48 -7
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/prompt-hints.js +2 -0
- package/dist/tools/prompt-hints.js.map +1 -1
- package/dist/tools/read-tracker.d.ts +35 -2
- package/dist/tools/read-tracker.js +108 -11
- package/dist/tools/read-tracker.js.map +1 -1
- package/dist/tools/read.js +39 -7
- package/dist/tools/read.js.map +1 -1
- package/dist/tools/skill.js +5 -0
- package/dist/tools/skill.js.map +1 -1
- package/dist/tools/subagent-control.js +44 -8
- package/dist/tools/subagent-control.js.map +1 -1
- package/dist/tools/subagent-shared.d.ts +48 -8
- package/dist/tools/subagent-shared.js +75 -14
- package/dist/tools/subagent-shared.js.map +1 -1
- package/dist/tools/subagent.d.ts +8 -2
- package/dist/tools/subagent.js +28 -10
- package/dist/tools/subagent.js.map +1 -1
- package/dist/tools/task-output.js +3 -2
- package/dist/tools/task-output.js.map +1 -1
- package/dist/tools/task-send.d.ts +1 -1
- package/dist/tools/task-send.js +15 -1
- package/dist/tools/task-send.js.map +1 -1
- package/dist/tools/tool-tiers.d.ts +2 -2
- package/dist/tools/tool-tiers.js +3 -2
- package/dist/tools/tool-tiers.js.map +1 -1
- package/dist/tools/truncate.d.ts +21 -0
- package/dist/tools/truncate.js +187 -0
- package/dist/tools/truncate.js.map +1 -1
- package/dist/tools/ui-adopt.js +2 -0
- package/dist/tools/ui-adopt.js.map +1 -1
- package/dist/tools/write.js +4 -3
- package/dist/tools/write.js.map +1 -1
- package/dist/ui/App.d.ts +0 -4
- package/dist/ui/App.js +5 -28
- package/dist/ui/App.js.map +1 -1
- package/dist/ui/components/ActivityIndicator.js +1 -0
- package/dist/ui/components/ActivityIndicator.js.map +1 -1
- package/dist/ui/components/Footer.js +1 -1
- package/dist/ui/components/Footer.js.map +1 -1
- package/dist/ui/hooks/useAgentLoop.d.ts +1 -8
- package/dist/ui/hooks/useAgentLoop.js +1 -119
- package/dist/ui/hooks/useAgentLoop.js.map +1 -1
- package/dist/ui/render.d.ts +2 -4
- package/dist/ui/render.js +3 -2
- package/dist/ui/render.js.map +1 -1
- package/dist/utils/git.d.ts +77 -0
- package/dist/utils/git.js +285 -21
- package/dist/utils/git.js.map +1 -1
- package/dist/utils/github-ci.js +2 -1
- package/dist/utils/github-ci.js.map +1 -1
- package/dist/utils/github.js +11 -9
- package/dist/utils/github.js.map +1 -1
- package/dist/utils/image.d.ts +14 -0
- package/dist/utils/image.js +16 -0
- package/dist/utils/image.js.map +1 -1
- package/dist/utils/process.d.ts +20 -0
- package/dist/utils/process.js +98 -0
- package/dist/utils/process.js.map +1 -1
- package/dist/utils/text.d.ts +12 -0
- package/dist/utils/text.js +11 -0
- package/dist/utils/text.js.map +1 -1
- package/package.json +6 -6
- package/assets/motion/skills/mixkit-split-text-617/SKILL.md +0 -115
- package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-480.json +0 -1
- package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-494.json +0 -1
- package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-5.json +0 -1
- package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-508.json +0 -1
- package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-6525.json +0 -1
- package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-6539.json +0 -1
- package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-6647.json +0 -1
- package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-6663.json +0 -1
- package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-6677.json +0 -1
- package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-6691.json +0 -1
- package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-6706.json +0 -1
- package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-6722.json +0 -1
- package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-6736.json +0 -1
- package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-6750.json +0 -1
- package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-6764.json +0 -1
- package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-6780.json +0 -1
- package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-6794.json +0 -1
- package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-6810.json +0 -1
- package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-6823.json +0 -1
- package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-6872.json +0 -1
- package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-6936.json +0 -1
- package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-76.json +0 -1
- package/assets/motion/skills/mixkit-split-text-617/data/manifest.json +0 -495
- package/assets/motion/skills/mixkit-split-text-617/references/RECONSTRUCTION.md +0 -201
- package/assets/motion/skills/mixkit-split-text-617/references/VERIFICATION.md +0 -107
- package/assets/motion/skills/mixkit-split-text-617/tools/inspect_motion.py +0 -130
- package/assets/motion/skills/video-qa/SKILL.md +0 -66
- package/dist/core/ideal-review-subagent.d.ts +0 -42
- package/dist/core/ideal-review-subagent.js +0 -95
- package/dist/core/ideal-review-subagent.js.map +0 -1
- package/dist/core/ideal-review.d.ts +0 -82
- package/dist/core/ideal-review.js +0 -242
- package/dist/core/ideal-review.js.map +0 -1
- package/dist/motion-agent/motion-check-tool.d.ts +0 -21
- package/dist/motion-agent/motion-check-tool.js +0 -206
- package/dist/motion-agent/motion-check-tool.js.map +0 -1
|
@@ -0,0 +1,642 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
4
|
+
import { resolveShell } from "./shell.js";
|
|
5
|
+
import { prepareSandboxLaunch, SANDBOX_ENV_PATCH } from "./sandbox.js";
|
|
6
|
+
import { getSafeToolEnv } from "../tools/safe-env.js";
|
|
7
|
+
import { localOperations } from "../tools/operations.js";
|
|
8
|
+
import { killProcessTree } from "../utils/process.js";
|
|
9
|
+
import { log } from "./logger.js";
|
|
10
|
+
const MAX_OUTPUT_BYTES = 1024 * 1024;
|
|
11
|
+
const MAX_VALUE_CHARS = 200;
|
|
12
|
+
const MAX_PROPERTIES_PER_SCOPE = 40;
|
|
13
|
+
const COMMAND_TIMEOUT_MS = 10_000;
|
|
14
|
+
/** Scope types worth showing; `global` is thousands of builtins. */
|
|
15
|
+
const SHOWN_SCOPES = new Set(["local", "closure", "block", "catch", "module", "script", "with"]);
|
|
16
|
+
/** Inspector chatter Node writes to stderr; not the program's output. */
|
|
17
|
+
const INSPECTOR_NOISE_RE = /^(Debugger listening on .*|For help, see: .*|Debugger attached\.|Waiting for the debugger to disconnect\.\.\.)\r?\n?/gm;
|
|
18
|
+
function escapeRegex(value) {
|
|
19
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
20
|
+
}
|
|
21
|
+
/** Quote one argument for the shell `resolveShell` picked. */
|
|
22
|
+
function quoteArg(value, cmdFallback) {
|
|
23
|
+
if (cmdFallback)
|
|
24
|
+
return /^[\w@%+=:,./\\-]+$/.test(value) ? value : `"${value.replace(/"/g, '""')}"`;
|
|
25
|
+
return /^[\w@%+=:,./-]+$/.test(value) ? value : `'${value.replace(/'/g, `'\\''`)}'`;
|
|
26
|
+
}
|
|
27
|
+
/** Symlink-resolved path; the input unchanged when it does not exist (yet). */
|
|
28
|
+
function realPath(p) {
|
|
29
|
+
try {
|
|
30
|
+
return fs.realpathSync.native(p);
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return p;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Every spelling Node may load `p` under. Node's module loader resolves
|
|
38
|
+
* symlinks with the JS `fs.realpathSync`, which keeps Windows 8.3 short names
|
|
39
|
+
* (`C:\Users\RUNNER~1`) that the native resolver expands — so the as-given,
|
|
40
|
+
* JS-resolved and native-resolved forms can all differ.
|
|
41
|
+
*/
|
|
42
|
+
function pathForms(p) {
|
|
43
|
+
const forms = new Set([p, realPath(p)]);
|
|
44
|
+
try {
|
|
45
|
+
forms.add(fs.realpathSync(p));
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
// does not exist (yet); the as-given form stands
|
|
49
|
+
}
|
|
50
|
+
return [...forms].sort();
|
|
51
|
+
}
|
|
52
|
+
/** Comparable form of a path: fully resolved, case-folded where the filesystem is. */
|
|
53
|
+
function comparablePath(p) {
|
|
54
|
+
const real = realPath(p);
|
|
55
|
+
return process.platform === "win32" ? real.toLowerCase() : real;
|
|
56
|
+
}
|
|
57
|
+
/** Windows paths are case-insensitive; CDP's urlRegex takes no flags, so spell it out. */
|
|
58
|
+
function caseInsensitive(pattern) {
|
|
59
|
+
return pattern.replace(/[a-z]/gi, (c) => `[${c.toLowerCase()}${c.toUpperCase()}]`);
|
|
60
|
+
}
|
|
61
|
+
function truncate(text, max = MAX_VALUE_CHARS) {
|
|
62
|
+
return text.length > max ? `${text.slice(0, max - 1)}…` : text;
|
|
63
|
+
}
|
|
64
|
+
/** One-line rendering of a value the inspector returned. */
|
|
65
|
+
export function formatRemoteObject(object) {
|
|
66
|
+
if (object.type === "undefined")
|
|
67
|
+
return "undefined";
|
|
68
|
+
if (object.unserializableValue !== undefined)
|
|
69
|
+
return object.unserializableValue;
|
|
70
|
+
if (object.type === "string")
|
|
71
|
+
return truncate(JSON.stringify(String(object.value ?? "")));
|
|
72
|
+
if (object.subtype === "null")
|
|
73
|
+
return "null";
|
|
74
|
+
if (object.type === "number" || object.type === "boolean")
|
|
75
|
+
return String(object.value);
|
|
76
|
+
if (object.type === "bigint")
|
|
77
|
+
return object.description ?? String(object.value);
|
|
78
|
+
if (object.type === "function")
|
|
79
|
+
return truncate(`ƒ ${object.description?.split("\n")[0] ?? ""}`);
|
|
80
|
+
if (object.preview)
|
|
81
|
+
return truncate(formatPreview(object.preview));
|
|
82
|
+
return truncate(object.description ?? object.type);
|
|
83
|
+
}
|
|
84
|
+
function formatPreview(preview) {
|
|
85
|
+
const more = preview.overflow ? ", …" : "";
|
|
86
|
+
if (preview.entries) {
|
|
87
|
+
const entries = preview.entries.map((entry) => entry.key
|
|
88
|
+
? `${formatPreview(entry.key)} => ${formatPreview(entry.value)}`
|
|
89
|
+
: formatPreview(entry.value));
|
|
90
|
+
return `${preview.description ?? preview.type} {${entries.join(", ")}${more}}`;
|
|
91
|
+
}
|
|
92
|
+
if (preview.type !== "object")
|
|
93
|
+
return preview.description ?? preview.type;
|
|
94
|
+
const parts = preview.properties.map((p) => {
|
|
95
|
+
const value = p.type === "string" ? JSON.stringify(p.value ?? "") : (p.value ?? p.type);
|
|
96
|
+
return preview.subtype === "array" ? value : `${p.name}: ${value}`;
|
|
97
|
+
});
|
|
98
|
+
if (preview.subtype === "array")
|
|
99
|
+
return `${preview.description ?? "Array"} [${parts.join(", ")}${more}]`;
|
|
100
|
+
const prefix = preview.description && preview.description !== "Object" ? `${preview.description} ` : "";
|
|
101
|
+
return `${prefix}{${parts.join(", ")}${more}}`;
|
|
102
|
+
}
|
|
103
|
+
/** File path for an inspector script URL, or undefined for node: internals and evals. */
|
|
104
|
+
export function urlToPath(url) {
|
|
105
|
+
if (url.startsWith("file://")) {
|
|
106
|
+
try {
|
|
107
|
+
return fileURLToPath(url);
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
return undefined;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return path.isAbsolute(url) ? url : undefined;
|
|
114
|
+
}
|
|
115
|
+
export class NodeDebugSession {
|
|
116
|
+
launchCwd;
|
|
117
|
+
cwd;
|
|
118
|
+
child;
|
|
119
|
+
socket;
|
|
120
|
+
pending = new Map();
|
|
121
|
+
scripts = new Map();
|
|
122
|
+
breakpoints = new Map();
|
|
123
|
+
stopWaiters = new Set();
|
|
124
|
+
/** In-flight exact-URL breakpoint bindings (see `bindToScript`). */
|
|
125
|
+
binding = new Set();
|
|
126
|
+
nextMessageId = 1;
|
|
127
|
+
nextBreakpoint = 1;
|
|
128
|
+
paused;
|
|
129
|
+
exitCode;
|
|
130
|
+
output = "";
|
|
131
|
+
outputDropped = false;
|
|
132
|
+
outputRead = 0;
|
|
133
|
+
constructor(
|
|
134
|
+
/** The cwd as the program was launched in it. */
|
|
135
|
+
launchCwd,
|
|
136
|
+
/** `launchCwd` fully resolved, for displaying paths relative to it. */
|
|
137
|
+
cwd, child, socket) {
|
|
138
|
+
this.launchCwd = launchCwd;
|
|
139
|
+
this.cwd = cwd;
|
|
140
|
+
this.child = child;
|
|
141
|
+
this.socket = socket;
|
|
142
|
+
}
|
|
143
|
+
/** Start `node --inspect-brk <program>`, attach, set breakpoints, run to the first stop. */
|
|
144
|
+
static async launch(options) {
|
|
145
|
+
const ops = options.ops ?? localOperations;
|
|
146
|
+
const program = path.resolve(options.cwd, options.program);
|
|
147
|
+
// Probe for the shell form first: quoting depends on which shell runs it.
|
|
148
|
+
const probe = resolveShell("node");
|
|
149
|
+
const command = [
|
|
150
|
+
"node",
|
|
151
|
+
"--inspect-brk=127.0.0.1:0",
|
|
152
|
+
...(options.nodeArgs ?? []),
|
|
153
|
+
program,
|
|
154
|
+
...(options.args ?? []),
|
|
155
|
+
]
|
|
156
|
+
.map((arg, index) => (index === 0 ? arg : quoteArg(arg, probe.isCmdFallback)))
|
|
157
|
+
.join(" ");
|
|
158
|
+
const launch = await prepareSandboxLaunch(resolveShell(command), options.cwd, options.sandboxPolicy ?? { mode: "off", allowedDomains: [] });
|
|
159
|
+
const child = ops.spawn(launch.file, launch.args, {
|
|
160
|
+
cwd: options.cwd,
|
|
161
|
+
detached: true,
|
|
162
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
163
|
+
env: launch.sandboxed ? { ...getSafeToolEnv(), ...SANDBOX_ENV_PATCH } : getSafeToolEnv(),
|
|
164
|
+
});
|
|
165
|
+
child.on("error", () => { }); // 'close' below owns failure handling
|
|
166
|
+
let early = "";
|
|
167
|
+
// Filled once connected; the stream and exit handlers below are wired
|
|
168
|
+
// first so no output or exit is missed while the inspector comes up.
|
|
169
|
+
const attached = {};
|
|
170
|
+
const wsUrl = await new Promise((resolve, reject) => {
|
|
171
|
+
const timer = setTimeout(() => {
|
|
172
|
+
reject(new Error(`the inspector did not start within ${options.startTimeoutMs ?? 10_000}ms`));
|
|
173
|
+
}, options.startTimeoutMs ?? 10_000);
|
|
174
|
+
const onData = (chunk) => {
|
|
175
|
+
const text = chunk.toString("utf-8");
|
|
176
|
+
if (attached.session) {
|
|
177
|
+
attached.session.appendOutput(text);
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
early += text;
|
|
181
|
+
const match = /Debugger listening on (ws:\/\/\S+)/.exec(early);
|
|
182
|
+
if (match?.[1]) {
|
|
183
|
+
clearTimeout(timer);
|
|
184
|
+
resolve(match[1]);
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
child.stdout?.on("data", onData);
|
|
188
|
+
child.stderr?.on("data", onData);
|
|
189
|
+
child.once("close", (code) => {
|
|
190
|
+
clearTimeout(timer);
|
|
191
|
+
if (attached.session)
|
|
192
|
+
attached.session.markExited(code);
|
|
193
|
+
else
|
|
194
|
+
reject(new Error(`node exited (code ${code}) before the inspector started:\n${early.trim()}`));
|
|
195
|
+
});
|
|
196
|
+
}).catch((error) => {
|
|
197
|
+
if (child.pid && child.exitCode === null)
|
|
198
|
+
killProcessTree(child.pid);
|
|
199
|
+
throw error;
|
|
200
|
+
});
|
|
201
|
+
const socket = new WebSocket(wsUrl);
|
|
202
|
+
const session = new NodeDebugSession(options.cwd, realPath(options.cwd), child, socket);
|
|
203
|
+
attached.session = session;
|
|
204
|
+
session.appendOutput(early);
|
|
205
|
+
try {
|
|
206
|
+
await session.connect();
|
|
207
|
+
await session.initialize(options);
|
|
208
|
+
}
|
|
209
|
+
catch (error) {
|
|
210
|
+
session.stop();
|
|
211
|
+
throw error;
|
|
212
|
+
}
|
|
213
|
+
return session;
|
|
214
|
+
}
|
|
215
|
+
connect() {
|
|
216
|
+
return new Promise((resolve, reject) => {
|
|
217
|
+
this.socket.addEventListener("open", () => resolve(), { once: true });
|
|
218
|
+
this.socket.addEventListener("error", () => reject(new Error("could not connect to the Node inspector")), { once: true });
|
|
219
|
+
this.socket.addEventListener("message", (event) => this.onMessage(String(event.data)));
|
|
220
|
+
this.socket.addEventListener("close", () => {
|
|
221
|
+
for (const pending of this.pending.values()) {
|
|
222
|
+
pending.reject(new Error("the debug connection closed"));
|
|
223
|
+
}
|
|
224
|
+
this.pending.clear();
|
|
225
|
+
this.wakeStopWaiters();
|
|
226
|
+
});
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
async initialize(options) {
|
|
230
|
+
await this.send("Runtime.enable");
|
|
231
|
+
await this.send("Debugger.enable");
|
|
232
|
+
// Stepping skips Node internals and dependencies; breakpoints set in them still hit.
|
|
233
|
+
await this.send("Debugger.setBlackboxPatterns", { patterns: ["^node:", "/node_modules/"] });
|
|
234
|
+
await this.send("Debugger.setPauseOnExceptions", {
|
|
235
|
+
state: options.pauseOnExceptions ?? "uncaught",
|
|
236
|
+
});
|
|
237
|
+
for (const bp of options.breakpoints ?? []) {
|
|
238
|
+
await this.setBreakpoint(bp.file, bp.line, bp.condition);
|
|
239
|
+
}
|
|
240
|
+
// --inspect-brk holds the program before its first line until this call;
|
|
241
|
+
// it then pauses there ("Break on start"), after breakpoints are armed.
|
|
242
|
+
await this.send("Runtime.runIfWaitingForDebugger");
|
|
243
|
+
}
|
|
244
|
+
onMessage(raw) {
|
|
245
|
+
let message;
|
|
246
|
+
try {
|
|
247
|
+
message = JSON.parse(raw);
|
|
248
|
+
}
|
|
249
|
+
catch {
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
if (message.id !== undefined) {
|
|
253
|
+
const pending = this.pending.get(message.id);
|
|
254
|
+
this.pending.delete(message.id);
|
|
255
|
+
if (message.error)
|
|
256
|
+
pending?.reject(new Error(message.error.message));
|
|
257
|
+
else
|
|
258
|
+
pending?.resolve(message.result);
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
const params = message.params ?? {};
|
|
262
|
+
switch (message.method) {
|
|
263
|
+
case "Debugger.scriptParsed": {
|
|
264
|
+
const url = String(params.url ?? "");
|
|
265
|
+
this.scripts.set(String(params.scriptId), url);
|
|
266
|
+
for (const bp of this.breakpoints.values())
|
|
267
|
+
this.bindToScript(bp, url);
|
|
268
|
+
break;
|
|
269
|
+
}
|
|
270
|
+
case "Debugger.paused":
|
|
271
|
+
this.paused = {
|
|
272
|
+
reason: String(params.reason ?? "other"),
|
|
273
|
+
...(params.data ? { data: params.data } : {}),
|
|
274
|
+
hitBreakpoints: params.hitBreakpoints ?? [],
|
|
275
|
+
callFrames: params.callFrames ?? [],
|
|
276
|
+
};
|
|
277
|
+
this.wakeStopWaiters();
|
|
278
|
+
break;
|
|
279
|
+
case "Debugger.resumed":
|
|
280
|
+
this.paused = undefined;
|
|
281
|
+
break;
|
|
282
|
+
case "Debugger.breakpointResolved": {
|
|
283
|
+
const cdpId = String(params.breakpointId);
|
|
284
|
+
const location = params.location;
|
|
285
|
+
for (const bp of this.breakpoints.values()) {
|
|
286
|
+
if (bp.cdpIds.includes(cdpId) &&
|
|
287
|
+
location &&
|
|
288
|
+
!bp.boundLines.includes(location.lineNumber + 1)) {
|
|
289
|
+
bp.boundLines.push(location.lineNumber + 1);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
break;
|
|
293
|
+
}
|
|
294
|
+
case "Runtime.executionContextDestroyed":
|
|
295
|
+
// The program finished; Node now waits for us to disconnect before exiting.
|
|
296
|
+
if (this.socket.readyState === WebSocket.OPEN)
|
|
297
|
+
this.socket.close();
|
|
298
|
+
break;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
send(method, params = {}) {
|
|
302
|
+
if (this.socket.readyState !== WebSocket.OPEN) {
|
|
303
|
+
return Promise.reject(new Error("the program is no longer running"));
|
|
304
|
+
}
|
|
305
|
+
const id = this.nextMessageId++;
|
|
306
|
+
return new Promise((resolve, reject) => {
|
|
307
|
+
const timer = setTimeout(() => {
|
|
308
|
+
this.pending.delete(id);
|
|
309
|
+
reject(new Error(`${method} got no reply within ${COMMAND_TIMEOUT_MS}ms`));
|
|
310
|
+
}, COMMAND_TIMEOUT_MS);
|
|
311
|
+
this.pending.set(id, {
|
|
312
|
+
resolve: (value) => {
|
|
313
|
+
clearTimeout(timer);
|
|
314
|
+
resolve(value);
|
|
315
|
+
},
|
|
316
|
+
reject: (error) => {
|
|
317
|
+
clearTimeout(timer);
|
|
318
|
+
reject(error);
|
|
319
|
+
},
|
|
320
|
+
});
|
|
321
|
+
this.socket.send(JSON.stringify({ id, method, params }));
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
appendOutput(text) {
|
|
325
|
+
const clean = text.replace(INSPECTOR_NOISE_RE, "");
|
|
326
|
+
if (!clean)
|
|
327
|
+
return;
|
|
328
|
+
this.output += clean;
|
|
329
|
+
if (this.output.length > MAX_OUTPUT_BYTES) {
|
|
330
|
+
const drop = this.output.length - MAX_OUTPUT_BYTES;
|
|
331
|
+
this.output = this.output.slice(drop);
|
|
332
|
+
this.outputRead = Math.max(0, this.outputRead - drop);
|
|
333
|
+
this.outputDropped = true;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
markExited(code) {
|
|
337
|
+
this.exitCode = code;
|
|
338
|
+
this.paused = undefined;
|
|
339
|
+
if (this.socket.readyState === WebSocket.OPEN)
|
|
340
|
+
this.socket.close();
|
|
341
|
+
this.wakeStopWaiters();
|
|
342
|
+
}
|
|
343
|
+
wakeStopWaiters() {
|
|
344
|
+
for (const wake of this.stopWaiters)
|
|
345
|
+
wake();
|
|
346
|
+
this.stopWaiters.clear();
|
|
347
|
+
}
|
|
348
|
+
get isPaused() {
|
|
349
|
+
return this.paused !== undefined;
|
|
350
|
+
}
|
|
351
|
+
get hasExited() {
|
|
352
|
+
return this.exitCode !== undefined;
|
|
353
|
+
}
|
|
354
|
+
state() {
|
|
355
|
+
if (this.exitCode !== undefined)
|
|
356
|
+
return { kind: "exited", code: this.exitCode };
|
|
357
|
+
return this.paused ? { kind: "paused" } : { kind: "running" };
|
|
358
|
+
}
|
|
359
|
+
/** Wait until the program pauses or exits, up to `timeoutMs`. */
|
|
360
|
+
async waitForStop(timeoutMs, signal) {
|
|
361
|
+
const deadline = Date.now() + timeoutMs;
|
|
362
|
+
// Loop because the connection closes a moment before the process reports
|
|
363
|
+
// its exit: that wake alone must not read as "still running".
|
|
364
|
+
while (!this.paused && this.exitCode === undefined && !signal?.aborted) {
|
|
365
|
+
const remaining = deadline - Date.now();
|
|
366
|
+
if (remaining <= 0)
|
|
367
|
+
break;
|
|
368
|
+
await new Promise((resolve) => {
|
|
369
|
+
const done = () => {
|
|
370
|
+
clearTimeout(timer);
|
|
371
|
+
signal?.removeEventListener("abort", done);
|
|
372
|
+
this.stopWaiters.delete(done);
|
|
373
|
+
resolve();
|
|
374
|
+
};
|
|
375
|
+
// After the socket closes nothing but the child's exit can wake us.
|
|
376
|
+
const timer = setTimeout(done, this.socket.readyState === WebSocket.OPEN ? remaining : Math.min(remaining, 50));
|
|
377
|
+
signal?.addEventListener("abort", done, { once: true });
|
|
378
|
+
this.stopWaiters.add(done);
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
return this.state();
|
|
382
|
+
}
|
|
383
|
+
/** Resume (or step) and wait for the next stop. */
|
|
384
|
+
async resume(how, timeoutMs, signal) {
|
|
385
|
+
if (!this.paused)
|
|
386
|
+
throw new Error("the program is not paused");
|
|
387
|
+
const method = {
|
|
388
|
+
continue: "Debugger.resume",
|
|
389
|
+
step_over: "Debugger.stepOver",
|
|
390
|
+
step_into: "Debugger.stepInto",
|
|
391
|
+
step_out: "Debugger.stepOut",
|
|
392
|
+
}[how];
|
|
393
|
+
// Breakpoints being bound to just-loaded scripts must land before it runs on.
|
|
394
|
+
await Promise.all(this.binding);
|
|
395
|
+
this.paused = undefined;
|
|
396
|
+
await this.send(method);
|
|
397
|
+
return this.waitForStop(timeoutMs, signal);
|
|
398
|
+
}
|
|
399
|
+
async pause(timeoutMs, signal) {
|
|
400
|
+
if (!this.paused)
|
|
401
|
+
await this.send("Debugger.pause");
|
|
402
|
+
return this.waitForStop(timeoutMs, signal);
|
|
403
|
+
}
|
|
404
|
+
async setBreakpoint(file, line, condition) {
|
|
405
|
+
// Node reports scripts by real path; a symlinked project dir (macOS /var
|
|
406
|
+
// → /private/var) would otherwise never match and never bind.
|
|
407
|
+
// Resolve against the cwd the program was launched in, not its real path,
|
|
408
|
+
// so the as-given spelling (Windows 8.3 short names) stays among the forms.
|
|
409
|
+
const forms = pathForms(path.resolve(this.launchCwd, file));
|
|
410
|
+
// Scripts load as file:// URLs (ESM, modern CJS) or bare paths (older CJS).
|
|
411
|
+
const alternatives = forms
|
|
412
|
+
.flatMap((abs) => [pathToFileURL(abs).href, abs])
|
|
413
|
+
.map((form) => escapeRegex(form));
|
|
414
|
+
const body = alternatives.join("|");
|
|
415
|
+
const urlRegex = `^(?:${process.platform === "win32" ? caseInsensitive(body) : body})$`;
|
|
416
|
+
const result = (await this.send("Debugger.setBreakpointByUrl", {
|
|
417
|
+
lineNumber: line - 1,
|
|
418
|
+
urlRegex,
|
|
419
|
+
...(condition ? { condition } : {}),
|
|
420
|
+
}));
|
|
421
|
+
const bp = {
|
|
422
|
+
id: `bp${this.nextBreakpoint++}`,
|
|
423
|
+
cdpIds: [result.breakpointId],
|
|
424
|
+
urlRegex,
|
|
425
|
+
target: comparablePath(forms[0] ?? file),
|
|
426
|
+
file,
|
|
427
|
+
line,
|
|
428
|
+
...(condition ? { condition } : {}),
|
|
429
|
+
boundLines: [...new Set(result.locations.map((l) => l.lineNumber + 1))],
|
|
430
|
+
};
|
|
431
|
+
this.breakpoints.set(bp.id, bp);
|
|
432
|
+
for (const url of new Set(this.scripts.values()))
|
|
433
|
+
this.bindToScript(bp, url);
|
|
434
|
+
await Promise.all(this.binding);
|
|
435
|
+
return bp;
|
|
436
|
+
}
|
|
437
|
+
/**
|
|
438
|
+
* Also bind `bp` by the exact URL of a loaded script that is the target file
|
|
439
|
+
* but that the URL pattern missed — Node can name a script in a spelling no
|
|
440
|
+
* path form predicts (Windows short names, drive-letter case, URL encoding).
|
|
441
|
+
* The file itself, resolved on disk, decides whether it is the same script.
|
|
442
|
+
*/
|
|
443
|
+
bindToScript(bp, url) {
|
|
444
|
+
const file = urlToPath(url);
|
|
445
|
+
if (!file || new RegExp(bp.urlRegex).test(url))
|
|
446
|
+
return;
|
|
447
|
+
if (comparablePath(file) !== bp.target)
|
|
448
|
+
return;
|
|
449
|
+
const task = (async () => {
|
|
450
|
+
try {
|
|
451
|
+
const result = (await this.send("Debugger.setBreakpointByUrl", {
|
|
452
|
+
lineNumber: bp.line - 1,
|
|
453
|
+
url,
|
|
454
|
+
...(bp.condition ? { condition: bp.condition } : {}),
|
|
455
|
+
}));
|
|
456
|
+
// Removed while this was in flight: drop the binding it just made.
|
|
457
|
+
if (!this.breakpoints.has(bp.id)) {
|
|
458
|
+
await this.send("Debugger.removeBreakpoint", { breakpointId: result.breakpointId });
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
461
|
+
bp.cdpIds.push(result.breakpointId);
|
|
462
|
+
for (const location of result.locations) {
|
|
463
|
+
if (!bp.boundLines.includes(location.lineNumber + 1)) {
|
|
464
|
+
bp.boundLines.push(location.lineNumber + 1);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
catch (error) {
|
|
469
|
+
// Already bound at that URL, or the session closed; the pattern stands.
|
|
470
|
+
log("WARN", "debug", "could not bind breakpoint to script", {
|
|
471
|
+
breakpoint: bp.id,
|
|
472
|
+
url,
|
|
473
|
+
error: error instanceof Error ? error.message : String(error),
|
|
474
|
+
});
|
|
475
|
+
}
|
|
476
|
+
})();
|
|
477
|
+
this.binding.add(task);
|
|
478
|
+
void task.finally(() => this.binding.delete(task));
|
|
479
|
+
}
|
|
480
|
+
async removeBreakpoint(id) {
|
|
481
|
+
const bp = this.breakpoints.get(id);
|
|
482
|
+
if (!bp)
|
|
483
|
+
return false;
|
|
484
|
+
this.breakpoints.delete(id);
|
|
485
|
+
for (const breakpointId of bp.cdpIds) {
|
|
486
|
+
await this.send("Debugger.removeBreakpoint", { breakpointId });
|
|
487
|
+
}
|
|
488
|
+
return true;
|
|
489
|
+
}
|
|
490
|
+
listBreakpoints() {
|
|
491
|
+
return [...this.breakpoints.values()];
|
|
492
|
+
}
|
|
493
|
+
frame(index) {
|
|
494
|
+
if (!this.paused)
|
|
495
|
+
throw new Error("the program is not paused");
|
|
496
|
+
const frame = this.paused.callFrames[index];
|
|
497
|
+
if (!frame) {
|
|
498
|
+
throw new Error(`no frame ${index}; the stack has ${this.paused.callFrames.length} frames`);
|
|
499
|
+
}
|
|
500
|
+
return frame;
|
|
501
|
+
}
|
|
502
|
+
frameLocation(frame) {
|
|
503
|
+
const url = frame.url || this.scripts.get(frame.location.scriptId) || "";
|
|
504
|
+
const file = urlToPath(url);
|
|
505
|
+
// Both sides through the same resolver: Node may report a script under a
|
|
506
|
+
// spelling (symlink, Windows short name) that differs from the real cwd.
|
|
507
|
+
const shown = file ? path.relative(this.cwd, realPath(file)) || file : url || "<anonymous>";
|
|
508
|
+
return `${shown}:${frame.location.lineNumber + 1}:${(frame.location.columnNumber ?? 0) + 1}`;
|
|
509
|
+
}
|
|
510
|
+
/** `#0 parseUser (src/user.ts:12:5)` lines, innermost first. */
|
|
511
|
+
stack(limit = 20) {
|
|
512
|
+
if (!this.paused)
|
|
513
|
+
throw new Error("the program is not paused");
|
|
514
|
+
const frames = this.paused.callFrames.slice(0, limit).map((frame, index) => {
|
|
515
|
+
return `#${index} ${frame.functionName || "<anonymous>"} (${this.frameLocation(frame)})`;
|
|
516
|
+
});
|
|
517
|
+
const more = this.paused.callFrames.length - frames.length;
|
|
518
|
+
return frames.join("\n") + (more > 0 ? `\n… ${more} more frames` : "");
|
|
519
|
+
}
|
|
520
|
+
/** Source lines around a frame's position, the current line marked. */
|
|
521
|
+
sourceSnippet(index = 0, context = 3) {
|
|
522
|
+
const frame = this.frame(index);
|
|
523
|
+
const file = urlToPath(frame.url || this.scripts.get(frame.location.scriptId) || "");
|
|
524
|
+
if (!file)
|
|
525
|
+
return "";
|
|
526
|
+
let lines;
|
|
527
|
+
try {
|
|
528
|
+
lines = fs.readFileSync(file, "utf-8").split(/\r?\n/);
|
|
529
|
+
}
|
|
530
|
+
catch {
|
|
531
|
+
return "";
|
|
532
|
+
}
|
|
533
|
+
const current = frame.location.lineNumber;
|
|
534
|
+
const start = Math.max(0, current - context);
|
|
535
|
+
const end = Math.min(lines.length, current + context + 1);
|
|
536
|
+
const width = String(end).length;
|
|
537
|
+
return lines
|
|
538
|
+
.slice(start, end)
|
|
539
|
+
.map((text, offset) => {
|
|
540
|
+
const lineNo = start + offset;
|
|
541
|
+
const marker = lineNo === current ? ">" : " ";
|
|
542
|
+
return `${marker} ${String(lineNo + 1).padStart(width)} | ${truncate(text, 160)}`;
|
|
543
|
+
})
|
|
544
|
+
.join("\n");
|
|
545
|
+
}
|
|
546
|
+
/** Visible variables of a frame, scope by scope, innermost first. */
|
|
547
|
+
async variables(index = 0) {
|
|
548
|
+
const frame = this.frame(index);
|
|
549
|
+
const sections = [];
|
|
550
|
+
for (const scope of frame.scopeChain) {
|
|
551
|
+
if (!SHOWN_SCOPES.has(scope.type) || !scope.object.objectId)
|
|
552
|
+
continue;
|
|
553
|
+
const result = (await this.send("Runtime.getProperties", {
|
|
554
|
+
objectId: scope.object.objectId,
|
|
555
|
+
ownProperties: true,
|
|
556
|
+
generatePreview: true,
|
|
557
|
+
}));
|
|
558
|
+
const props = result.result.filter((p) => p.value);
|
|
559
|
+
if (props.length === 0)
|
|
560
|
+
continue;
|
|
561
|
+
const shown = props.slice(0, MAX_PROPERTIES_PER_SCOPE).map((p) => {
|
|
562
|
+
return ` ${p.name} = ${p.value ? formatRemoteObject(p.value) : "?"}`;
|
|
563
|
+
});
|
|
564
|
+
if (props.length > shown.length)
|
|
565
|
+
shown.push(` … ${props.length - shown.length} more`);
|
|
566
|
+
const label = scope.name ? `${scope.type} (${scope.name})` : scope.type;
|
|
567
|
+
sections.push(`${label}:\n${shown.join("\n")}`);
|
|
568
|
+
}
|
|
569
|
+
if (frame.this.type !== "undefined") {
|
|
570
|
+
sections.push(`this = ${formatRemoteObject(frame.this)}`);
|
|
571
|
+
}
|
|
572
|
+
return sections.join("\n") || "(no local variables)";
|
|
573
|
+
}
|
|
574
|
+
/** Evaluate in a paused frame, or in the global context while running. */
|
|
575
|
+
async evaluate(expression, index = 0) {
|
|
576
|
+
const params = { expression, generatePreview: true, silent: true };
|
|
577
|
+
const result = (this.paused
|
|
578
|
+
? await this.send("Debugger.evaluateOnCallFrame", {
|
|
579
|
+
...params,
|
|
580
|
+
callFrameId: this.frame(index).callFrameId,
|
|
581
|
+
})
|
|
582
|
+
: await this.send("Runtime.evaluate", params));
|
|
583
|
+
if (result.exceptionDetails) {
|
|
584
|
+
const thrown = result.exceptionDetails.exception;
|
|
585
|
+
return `Threw: ${thrown ? (thrown.description ?? formatRemoteObject(thrown)) : result.exceptionDetails.text}`;
|
|
586
|
+
}
|
|
587
|
+
return formatRemoteObject(result.result);
|
|
588
|
+
}
|
|
589
|
+
/** Why and where the program is paused. */
|
|
590
|
+
pauseSummary() {
|
|
591
|
+
if (!this.paused)
|
|
592
|
+
return "";
|
|
593
|
+
const top = this.paused.callFrames[0];
|
|
594
|
+
const where = top ? `${top.functionName || "<anonymous>"} (${this.frameLocation(top)})` : "?";
|
|
595
|
+
const hit = [
|
|
596
|
+
...new Set(this.paused.hitBreakpoints
|
|
597
|
+
.map((cdpId) => [...this.breakpoints.values()].find((bp) => bp.cdpIds.includes(cdpId))?.id)
|
|
598
|
+
.filter((id) => id !== undefined)),
|
|
599
|
+
];
|
|
600
|
+
let reason;
|
|
601
|
+
switch (this.paused.reason) {
|
|
602
|
+
case "Break on start":
|
|
603
|
+
reason = "on the first line";
|
|
604
|
+
break;
|
|
605
|
+
case "exception":
|
|
606
|
+
case "promiseRejection": {
|
|
607
|
+
const thrown = this.paused.data;
|
|
608
|
+
const what = thrown
|
|
609
|
+
? (thrown.description?.split("\n")[0] ?? formatRemoteObject(thrown))
|
|
610
|
+
: "";
|
|
611
|
+
reason = `on an exception${what ? `: ${truncate(what, 300)}` : ""}`;
|
|
612
|
+
break;
|
|
613
|
+
}
|
|
614
|
+
default:
|
|
615
|
+
reason = hit.length > 0 ? `at breakpoint ${hit.join(", ")}` : `(${this.paused.reason})`;
|
|
616
|
+
}
|
|
617
|
+
return `Paused ${reason} in ${where}`;
|
|
618
|
+
}
|
|
619
|
+
/** Program output since the last call. */
|
|
620
|
+
readNewOutput() {
|
|
621
|
+
const fresh = this.output.slice(this.outputRead);
|
|
622
|
+
this.outputRead = this.output.length;
|
|
623
|
+
const dropped = this.outputDropped ? "[earlier output dropped; last 1 MiB kept]\n" : "";
|
|
624
|
+
this.outputDropped = false;
|
|
625
|
+
return fresh ? dropped + fresh : "";
|
|
626
|
+
}
|
|
627
|
+
/** Kill the program and close the connection. Safe to call twice. */
|
|
628
|
+
stop() {
|
|
629
|
+
try {
|
|
630
|
+
if (this.socket.readyState === WebSocket.OPEN)
|
|
631
|
+
this.socket.close();
|
|
632
|
+
}
|
|
633
|
+
catch {
|
|
634
|
+
// Already closing.
|
|
635
|
+
}
|
|
636
|
+
if (this.child.pid && this.child.exitCode === null && this.child.signalCode === null) {
|
|
637
|
+
killProcessTree(this.child.pid);
|
|
638
|
+
}
|
|
639
|
+
log("INFO", "debugger", "Debug session stopped", { pid: String(this.child.pid ?? "") });
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
//# sourceMappingURL=node-debugger.js.map
|