@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,346 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// EZ Motion reference study: measure a video the user likes so a new video can
|
|
3
|
+
// take its rules (pace, stillness, how scenes change), never its scenes.
|
|
4
|
+
//
|
|
5
|
+
// Usage: node reference-study.mjs <reference-video> [--out <folder>]
|
|
6
|
+
// Default out: ./reference-study. Writes report.json, report.md, two contact
|
|
7
|
+
// sheets (one frame per shot, and an even timeline) and the frames behind them.
|
|
8
|
+
// Prints a one-line JSON summary.
|
|
9
|
+
//
|
|
10
|
+
// Every frame is decoded once on motion-check's small grey flow grid, so a
|
|
11
|
+
// reference and a EZ render are measured the same way.
|
|
12
|
+
import { execFile } from "node:child_process";
|
|
13
|
+
import { mkdir, rm, stat, writeFile } from "node:fs/promises";
|
|
14
|
+
import { basename, dirname, join, resolve } from "node:path";
|
|
15
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
16
|
+
import { promisify } from "node:util";
|
|
17
|
+
import { mediaBinaries } from "./media-binaries.mjs";
|
|
18
|
+
import { measureFlow } from "./motion-check.mjs";
|
|
19
|
+
|
|
20
|
+
const run = promisify(execFile);
|
|
21
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
22
|
+
|
|
23
|
+
/** A grid pixel changed visibly when its grey level moves by more than this... */
|
|
24
|
+
export const VISIBLE_LEVEL = 8;
|
|
25
|
+
/** ...and a frame step is still when at most this share of the grid changed visibly.
|
|
26
|
+
* Counting pixels, not averaging them, keeps a small moving thing (a cursor, a talking
|
|
27
|
+
* head in a corner) from reading as still. */
|
|
28
|
+
export const STILL_SHARE = 0.0002;
|
|
29
|
+
/** A still stretch at least this long is a rest. */
|
|
30
|
+
export const REST_SECONDS = 0.5;
|
|
31
|
+
/** Cuts this close together (seconds) belong to one burst... */
|
|
32
|
+
export const BURST_GAP = 0.6;
|
|
33
|
+
/** ...of at least this many cuts. */
|
|
34
|
+
export const BURST_CUTS = 3;
|
|
35
|
+
const MAX_SHOT_FRAMES = 24;
|
|
36
|
+
const TIMELINE_FRAMES = 16;
|
|
37
|
+
|
|
38
|
+
const round = (value, places = 3) => Math.round(value * 10 ** places) / 10 ** places;
|
|
39
|
+
|
|
40
|
+
function quantile(sorted, q) {
|
|
41
|
+
if (!sorted.length) return 0;
|
|
42
|
+
const at = (sorted.length - 1) * q;
|
|
43
|
+
const low = Math.floor(at);
|
|
44
|
+
const high = Math.ceil(at);
|
|
45
|
+
return sorted[low] + (sorted[high] - sorted[low]) * (at - low);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* The study's figures from a flow measurement and two figures per frame step
|
|
50
|
+
* (index i is frame i-1 → i; index 0 is unused): `energy`, the mean grey change
|
|
51
|
+
* (0..1), and `changed`, the share of the grid that changed visibly.
|
|
52
|
+
* @param {{ duration: number; fps: number; cuts: number[]; fast: { start: number; end: number; peak: number }[] }} flow
|
|
53
|
+
* @param {{ energy: ArrayLike<number>; changed: ArrayLike<number> }} steps
|
|
54
|
+
*/
|
|
55
|
+
export function studyFlow(flow, { energy, changed }) {
|
|
56
|
+
const { duration, fps } = flow;
|
|
57
|
+
if (!(duration > 0) || !(fps > 0)) throw new Error("Study needs a duration and frame rate");
|
|
58
|
+
const cuts = [...flow.cuts].filter((t) => t > 0 && t < duration).sort((a, b) => a - b);
|
|
59
|
+
if (energy.length !== changed.length) throw new Error("Study needs both figures for every step");
|
|
60
|
+
const steps = Math.max(0, energy.length - 1);
|
|
61
|
+
|
|
62
|
+
// Stillness, and the rests: still stretches long enough to read as a pause.
|
|
63
|
+
let still = 0;
|
|
64
|
+
const rests = [];
|
|
65
|
+
let runStart = -1;
|
|
66
|
+
const closeRun = (end) => {
|
|
67
|
+
if (runStart >= 0 && (end - runStart) / fps >= REST_SECONDS)
|
|
68
|
+
rests.push({ start: round((runStart - 1) / fps, 2), end: round((end - 1) / fps, 2) });
|
|
69
|
+
runStart = -1;
|
|
70
|
+
};
|
|
71
|
+
const moving = [];
|
|
72
|
+
for (let i = 1; i <= steps; i++) {
|
|
73
|
+
if (changed[i] <= STILL_SHARE) {
|
|
74
|
+
still++;
|
|
75
|
+
if (runStart < 0) runStart = i;
|
|
76
|
+
} else {
|
|
77
|
+
closeRun(i);
|
|
78
|
+
moving.push(energy[i]);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
closeRun(steps + 1);
|
|
82
|
+
|
|
83
|
+
// Shots between hard cuts, and how even their lengths are.
|
|
84
|
+
const bounds = [0, ...cuts, duration];
|
|
85
|
+
const shots = [];
|
|
86
|
+
for (let i = 1; i < bounds.length; i++) shots.push(round(bounds[i] - bounds[i - 1], 2));
|
|
87
|
+
const sortedShots = [...shots].sort((a, b) => a - b);
|
|
88
|
+
const mean = shots.reduce((sum, s) => sum + s, 0) / shots.length;
|
|
89
|
+
const sd = Math.sqrt(shots.reduce((sum, s) => sum + (s - mean) ** 2, 0) / shots.length);
|
|
90
|
+
|
|
91
|
+
// Bursts: runs of cuts close together.
|
|
92
|
+
const bursts = [];
|
|
93
|
+
let group = [];
|
|
94
|
+
const closeGroup = () => {
|
|
95
|
+
if (group.length >= BURST_CUTS)
|
|
96
|
+
bursts.push({ start: group[0], end: group.at(-1), cuts: group.length });
|
|
97
|
+
group = [];
|
|
98
|
+
};
|
|
99
|
+
for (const cut of cuts) {
|
|
100
|
+
if (group.length && cut - group.at(-1) > BURST_GAP) closeGroup();
|
|
101
|
+
group.push(cut);
|
|
102
|
+
}
|
|
103
|
+
closeGroup();
|
|
104
|
+
|
|
105
|
+
const fastSeconds = flow.fast.reduce((sum, run) => sum + (run.end - run.start), 0);
|
|
106
|
+
moving.sort((a, b) => a - b);
|
|
107
|
+
return {
|
|
108
|
+
duration: round(duration, 2),
|
|
109
|
+
fps: round(fps, 2),
|
|
110
|
+
stillShare: steps ? round(still / steps) : 0,
|
|
111
|
+
rests,
|
|
112
|
+
longestRest: rests.reduce((best, r) => Math.max(best, round(r.end - r.start, 2)), 0),
|
|
113
|
+
cuts: cuts.map((t) => round(t, 2)),
|
|
114
|
+
cutsPerMinute: round((cuts.length / duration) * 60, 1),
|
|
115
|
+
bursts: bursts.map((b) => ({ start: round(b.start, 2), end: round(b.end, 2), cuts: b.cuts })),
|
|
116
|
+
shots: {
|
|
117
|
+
count: shots.length,
|
|
118
|
+
lengths: shots,
|
|
119
|
+
mean: round(mean, 2),
|
|
120
|
+
median: round(quantile(sortedShots, 0.5), 2),
|
|
121
|
+
shortest: sortedShots[0],
|
|
122
|
+
longest: sortedShots.at(-1),
|
|
123
|
+
// Standard deviation over mean: near 0 is metronomic, above ~0.5 is varied.
|
|
124
|
+
spread: mean > 0 ? round(sd / mean, 2) : 0,
|
|
125
|
+
},
|
|
126
|
+
motion: {
|
|
127
|
+
// Share of the length with something moving faster than 2% of the frame per frame.
|
|
128
|
+
fastShare: round(Math.min(1, fastSeconds / duration)),
|
|
129
|
+
fastMoves: flow.fast.length,
|
|
130
|
+
// Fastest move, as a share of the frame's long side per frame.
|
|
131
|
+
peak: flow.fast.reduce((best, run) => Math.max(best, run.peak), 0),
|
|
132
|
+
// Typical and busy picture change while moving (mean grey change per frame, %).
|
|
133
|
+
typical: round(quantile(moving, 0.5) * 100, 2),
|
|
134
|
+
busy: round(quantile(moving, 0.9) * 100, 2),
|
|
135
|
+
},
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const seconds = (t) => `${t.toFixed(2)} s`;
|
|
140
|
+
|
|
141
|
+
/** A short, factual reading of the figures, for report.md. */
|
|
142
|
+
export function studyMarkdown(study, name) {
|
|
143
|
+
const lines = [
|
|
144
|
+
`# Reference study: ${name}`,
|
|
145
|
+
"",
|
|
146
|
+
"Rules to take, never scenes. Figures are measured on every frame.",
|
|
147
|
+
"",
|
|
148
|
+
"| Figure | Value |",
|
|
149
|
+
"|---|---|",
|
|
150
|
+
`| Length | ${seconds(study.duration)} at ${study.fps} fps |`,
|
|
151
|
+
`| Still | ${Math.round(study.stillShare * 100)}% of frames; ${study.rests.length} rest${study.rests.length === 1 ? "" : "s"} of ${REST_SECONDS} s or more, longest ${seconds(study.longestRest)} |`,
|
|
152
|
+
`| Hard cuts | ${study.cuts.length} (${study.cutsPerMinute} a minute) |`,
|
|
153
|
+
`| Bursts | ${study.bursts.length ? study.bursts.map((b) => `${b.cuts} cuts ${seconds(b.start)}–${seconds(b.end)}`).join("; ") : "none"} |`,
|
|
154
|
+
`| Shots | ${study.shots.count}; median ${seconds(study.shots.median)}, ${seconds(study.shots.shortest)}–${seconds(study.shots.longest)}, spread ${study.shots.spread} |`,
|
|
155
|
+
`| Fast motion | ${Math.round(study.motion.fastShare * 100)}% of the length in ${study.motion.fastMoves} move${study.motion.fastMoves === 1 ? "" : "s"}; peak ${Math.round(study.motion.peak * 100)}% of the frame a frame |`,
|
|
156
|
+
`| Picture change while moving | typical ${study.motion.typical}%, busy ${study.motion.busy}% a frame |`,
|
|
157
|
+
"",
|
|
158
|
+
"How to read it:",
|
|
159
|
+
"",
|
|
160
|
+
"- Spread near 0 means even shot lengths; above about 0.5 means a varied rhythm.",
|
|
161
|
+
"- Few cuts with motion most of the time means the video carries its scenes",
|
|
162
|
+
" instead of cutting; take the carry, not the cuts.",
|
|
163
|
+
"- Bursts are where the video speeds up on purpose; note where they fall in",
|
|
164
|
+
" the length, not what they show.",
|
|
165
|
+
"",
|
|
166
|
+
];
|
|
167
|
+
if (study.rests.length)
|
|
168
|
+
lines.push(
|
|
169
|
+
"Rests:",
|
|
170
|
+
"",
|
|
171
|
+
...study.rests.map((r) => `- ${seconds(r.start)}–${seconds(r.end)}`),
|
|
172
|
+
"",
|
|
173
|
+
);
|
|
174
|
+
if (study.cuts.length) lines.push("Cuts:", "", study.cuts.map((t) => seconds(t)).join(", "), "");
|
|
175
|
+
lines.push(
|
|
176
|
+
"Sheets: `sheet-shots.jpg` (one frame from the middle of each shot) and",
|
|
177
|
+
"`sheet-timeline.jpg` (evenly spaced). The frames behind them are in `frames/`.",
|
|
178
|
+
"",
|
|
179
|
+
);
|
|
180
|
+
return lines.join("\n");
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/** Up to `count` evenly spread items of a list. */
|
|
184
|
+
function spread(list, count) {
|
|
185
|
+
if (list.length <= count) return list;
|
|
186
|
+
return Array.from(
|
|
187
|
+
{ length: count },
|
|
188
|
+
(_, i) => list[Math.round((i * (list.length - 1)) / (count - 1))],
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
async function grabFrames(ffmpeg, file, times, folder, signal) {
|
|
193
|
+
await rm(folder, { recursive: true, force: true });
|
|
194
|
+
await mkdir(folder, { recursive: true });
|
|
195
|
+
for (const t of times) {
|
|
196
|
+
await run(
|
|
197
|
+
ffmpeg,
|
|
198
|
+
[
|
|
199
|
+
"-hide_banner",
|
|
200
|
+
"-nostdin",
|
|
201
|
+
"-loglevel",
|
|
202
|
+
"error",
|
|
203
|
+
"-protocol_whitelist",
|
|
204
|
+
"file,pipe",
|
|
205
|
+
"-ss",
|
|
206
|
+
t.toFixed(3),
|
|
207
|
+
"-i",
|
|
208
|
+
file,
|
|
209
|
+
"-frames:v",
|
|
210
|
+
"1",
|
|
211
|
+
"-vf",
|
|
212
|
+
"scale=640:-2",
|
|
213
|
+
"-q:v",
|
|
214
|
+
"3",
|
|
215
|
+
join(folder, `${t.toFixed(2)}s.jpg`),
|
|
216
|
+
],
|
|
217
|
+
{ timeout: 60_000, windowsHide: true, signal },
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
async function sheet(frames, out, signal) {
|
|
223
|
+
await run(process.execPath, [join(here, "contact-sheet.mjs"), frames, out, "--cols", "4"], {
|
|
224
|
+
timeout: 120_000,
|
|
225
|
+
windowsHide: true,
|
|
226
|
+
signal,
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function parseArgs(argv) {
|
|
231
|
+
const [video, ...rest] = argv;
|
|
232
|
+
if (!video || video.startsWith("--"))
|
|
233
|
+
throw new Error("usage: reference-study.mjs <reference-video> [--out <folder>]");
|
|
234
|
+
const options = { video: resolve(video), out: resolve("reference-study") };
|
|
235
|
+
for (let index = 0; index < rest.length; index += 2) {
|
|
236
|
+
const flag = rest[index];
|
|
237
|
+
const value = rest[index + 1];
|
|
238
|
+
if (value === undefined || value.startsWith("--")) throw new Error(`${flag} needs a value`);
|
|
239
|
+
if (flag === "--out") options.out = resolve(value);
|
|
240
|
+
else throw new Error(`Unsupported option ${flag}`);
|
|
241
|
+
}
|
|
242
|
+
return options;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
async function main() {
|
|
246
|
+
const started = performance.now();
|
|
247
|
+
const options = parseArgs(process.argv.slice(2));
|
|
248
|
+
if (!(await stat(options.video).catch(() => null))?.isFile())
|
|
249
|
+
throw new Error("Expected a local video file (download a linked video first)");
|
|
250
|
+
const controller = new AbortController();
|
|
251
|
+
const abort = () => controller.abort();
|
|
252
|
+
process.once("SIGTERM", abort);
|
|
253
|
+
process.once("SIGINT", abort);
|
|
254
|
+
try {
|
|
255
|
+
// Per frame step, measured in the same decode as cuts and fast moves.
|
|
256
|
+
const energy = [0];
|
|
257
|
+
const changed = [0];
|
|
258
|
+
let previous = null;
|
|
259
|
+
const flow = await measureFlow(options.video, controller.signal, (frame) => {
|
|
260
|
+
if (previous) {
|
|
261
|
+
let total = 0;
|
|
262
|
+
let visible = 0;
|
|
263
|
+
for (let i = 0; i < frame.length; i++) {
|
|
264
|
+
const difference = Math.abs(frame[i] - previous[i]);
|
|
265
|
+
total += difference;
|
|
266
|
+
if (difference > VISIBLE_LEVEL) visible++;
|
|
267
|
+
}
|
|
268
|
+
energy.push(total / frame.length / 255);
|
|
269
|
+
changed.push(visible / frame.length);
|
|
270
|
+
}
|
|
271
|
+
previous = Uint8Array.from(frame);
|
|
272
|
+
});
|
|
273
|
+
const study = studyFlow(flow, { energy, changed });
|
|
274
|
+
const name = basename(options.video);
|
|
275
|
+
await mkdir(options.out, { recursive: true });
|
|
276
|
+
|
|
277
|
+
const { ffmpeg } = await mediaBinaries();
|
|
278
|
+
// Frames sit a little inside each shot and the length, away from cuts and fades.
|
|
279
|
+
const end = Math.max(0, study.duration - 0.05);
|
|
280
|
+
const bounds = [0, ...study.cuts, study.duration];
|
|
281
|
+
const shotTimes = spread(
|
|
282
|
+
bounds.slice(1).map((b, i) => Math.min(end, (bounds[i] + b) / 2)),
|
|
283
|
+
MAX_SHOT_FRAMES,
|
|
284
|
+
);
|
|
285
|
+
const timeline = Array.from({ length: TIMELINE_FRAMES }, (_, i) =>
|
|
286
|
+
Math.min(end, ((i + 0.5) * study.duration) / TIMELINE_FRAMES),
|
|
287
|
+
);
|
|
288
|
+
await grabFrames(
|
|
289
|
+
ffmpeg,
|
|
290
|
+
options.video,
|
|
291
|
+
shotTimes,
|
|
292
|
+
join(options.out, "frames", "shots"),
|
|
293
|
+
controller.signal,
|
|
294
|
+
);
|
|
295
|
+
await grabFrames(
|
|
296
|
+
ffmpeg,
|
|
297
|
+
options.video,
|
|
298
|
+
timeline,
|
|
299
|
+
join(options.out, "frames", "timeline"),
|
|
300
|
+
controller.signal,
|
|
301
|
+
);
|
|
302
|
+
await sheet(
|
|
303
|
+
join(options.out, "frames", "shots"),
|
|
304
|
+
join(options.out, "sheet-shots.jpg"),
|
|
305
|
+
controller.signal,
|
|
306
|
+
);
|
|
307
|
+
await sheet(
|
|
308
|
+
join(options.out, "frames", "timeline"),
|
|
309
|
+
join(options.out, "sheet-timeline.jpg"),
|
|
310
|
+
controller.signal,
|
|
311
|
+
);
|
|
312
|
+
|
|
313
|
+
await writeFile(
|
|
314
|
+
join(options.out, "report.json"),
|
|
315
|
+
`${JSON.stringify({ version: 1, video: name, ...study }, null, 2)}\n`,
|
|
316
|
+
);
|
|
317
|
+
await writeFile(join(options.out, "report.md"), studyMarkdown(study, name));
|
|
318
|
+
process.stdout.write(
|
|
319
|
+
`${JSON.stringify({
|
|
320
|
+
ok: true,
|
|
321
|
+
out: options.out,
|
|
322
|
+
duration: study.duration,
|
|
323
|
+
stillShare: study.stillShare,
|
|
324
|
+
cuts: study.cuts.length,
|
|
325
|
+
bursts: study.bursts.length,
|
|
326
|
+
shotSpread: study.shots.spread,
|
|
327
|
+
fastShare: study.motion.fastShare,
|
|
328
|
+
elapsedMs: Math.round(performance.now() - started),
|
|
329
|
+
})}\n`,
|
|
330
|
+
);
|
|
331
|
+
} finally {
|
|
332
|
+
process.removeListener("SIGTERM", abort);
|
|
333
|
+
process.removeListener("SIGINT", abort);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
if (process.argv[1] && import.meta.url === pathToFileURL(resolve(process.argv[1])).href) {
|
|
338
|
+
try {
|
|
339
|
+
await main();
|
|
340
|
+
} catch (error) {
|
|
341
|
+
process.stderr.write(
|
|
342
|
+
`Reference study failed: ${error instanceof Error ? error.message : "invalid input"}\n`,
|
|
343
|
+
);
|
|
344
|
+
process.exitCode = 1;
|
|
345
|
+
}
|
|
346
|
+
}
|