@su-record/vibe 2.16.4 → 3.1.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/CLAUDE.md +8 -8
- package/README.en.md +46 -29
- package/README.md +41 -24
- package/agents/acceptance-tester.md +56 -0
- package/agents/architect.md +25 -67
- package/agents/build-error-resolver.md +28 -97
- package/agents/code-reviewer.md +89 -0
- package/agents/diagrammer.md +34 -169
- package/agents/documenter.md +43 -0
- package/agents/e2e-tester.md +46 -281
- package/agents/event/event-ops.md +54 -77
- package/agents/event/event-planner.md +63 -0
- package/agents/figma/figma-engineer.md +76 -0
- package/agents/implementer.md +26 -41
- package/agents/security-reviewer.md +56 -0
- package/agents/tester.md +37 -33
- package/agents/ui/design-reviewer.md +62 -0
- package/agents/ui/design-system-gen.md +63 -0
- package/dist/cli/commands/remove.d.ts.map +1 -1
- package/dist/cli/commands/remove.js +8 -10
- package/dist/cli/commands/remove.js.map +1 -1
- package/dist/cli/index.d.ts +0 -4
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +0 -4
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/llm/model-refresh.js +1 -1
- package/dist/cli/llm/model-refresh.js.map +1 -1
- package/dist/cli/postinstall/claude-agents.d.ts.map +1 -1
- package/dist/cli/postinstall/claude-agents.js +16 -77
- package/dist/cli/postinstall/claude-agents.js.map +1 -1
- package/dist/cli/postinstall/constants.d.ts.map +1 -1
- package/dist/cli/postinstall/constants.js +80 -296
- package/dist/cli/postinstall/constants.js.map +1 -1
- package/dist/cli/postinstall/cursor-agents.d.ts +5 -0
- package/dist/cli/postinstall/cursor-agents.d.ts.map +1 -1
- package/dist/cli/postinstall/cursor-agents.js +26 -68
- package/dist/cli/postinstall/cursor-agents.js.map +1 -1
- package/dist/cli/postinstall/cursor-skills.d.ts.map +1 -1
- package/dist/cli/postinstall/cursor-skills.js +26 -30
- package/dist/cli/postinstall/cursor-skills.js.map +1 -1
- package/dist/cli/postinstall/main.d.ts.map +1 -1
- package/dist/cli/postinstall/main.js +0 -2
- package/dist/cli/postinstall/main.js.map +1 -1
- package/dist/cli/setup/Provisioner.d.ts.map +1 -1
- package/dist/cli/setup/Provisioner.js +19 -21
- package/dist/cli/setup/Provisioner.js.map +1 -1
- package/dist/cli/utils.d.ts +4 -1
- package/dist/cli/utils.d.ts.map +1 -1
- package/dist/cli/utils.js +4 -1
- package/dist/cli/utils.js.map +1 -1
- package/dist/infra/lib/FrameworkDetector.js +4 -4
- package/dist/infra/lib/FrameworkDetector.js.map +1 -1
- package/dist/infra/lib/OrchestrateWorkflow.js +2 -2
- package/dist/infra/lib/OrchestrateWorkflow.js.map +1 -1
- package/dist/infra/lib/browser/launch.js +1 -1
- package/dist/infra/lib/browser/launch.js.map +1 -1
- package/dist/infra/lib/browser/types.d.ts +1 -1
- package/dist/infra/lib/browser/types.js +1 -1
- package/dist/infra/lib/constants.d.ts +1 -1
- package/dist/infra/lib/constants.d.ts.map +1 -1
- package/dist/infra/lib/constants.js +4 -5
- package/dist/infra/lib/constants.js.map +1 -1
- package/dist/infra/lib/evolution/__tests__/integration.test.js +7 -7
- package/dist/infra/lib/evolution/__tests__/integration.test.js.map +1 -1
- package/dist/infra/lib/memory/index.d.ts +0 -2
- package/dist/infra/lib/memory/index.d.ts.map +1 -1
- package/dist/infra/lib/memory/index.js +0 -2
- package/dist/infra/lib/memory/index.js.map +1 -1
- package/dist/infra/lib/telemetry/SkillTelemetry.test.js +1 -1
- package/dist/infra/lib/telemetry/SkillTelemetry.test.js.map +1 -1
- package/dist/tools/index.d.ts +0 -4
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +0 -4
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/memory/autoSaveContext.d.ts +0 -1
- package/dist/tools/memory/autoSaveContext.d.ts.map +1 -1
- package/dist/tools/memory/autoSaveContext.js +13 -27
- package/dist/tools/memory/autoSaveContext.js.map +1 -1
- package/hooks/scripts/__tests__/.vibe/command-log.txt +3 -78
- package/hooks/scripts/__tests__/.vibe/memories/memories.db +0 -0
- package/hooks/scripts/__tests__/.vibe/memories/memories.db-shm +0 -0
- package/hooks/scripts/__tests__/.vibe/memories/memories.db-wal +0 -0
- package/hooks/scripts/__tests__/clone-behaviors.test.js +64 -0
- package/hooks/scripts/__tests__/clone-merge-responsive.test.js +106 -0
- package/hooks/scripts/__tests__/code-check-detectors.test.js +2 -2
- package/hooks/scripts/__tests__/run-ledger.test.js +1 -1
- package/hooks/scripts/__tests__/scope-from-spec.test.js +12 -12
- package/hooks/scripts/__tests__/step-counter.test.js +1 -1
- package/hooks/scripts/clone-extract.js +242 -28
- package/hooks/scripts/clone-merge-responsive.js +184 -0
- package/hooks/scripts/clone-spec.js +33 -8
- package/hooks/scripts/clone-validate.js +15 -9
- package/hooks/scripts/code-check.js +16 -203
- package/hooks/scripts/context-save.js +0 -11
- package/hooks/scripts/lib/scope-from-spec.js +9 -6
- package/hooks/scripts/post-edit-dispatcher.js +1 -1
- package/hooks/scripts/prompt-dispatcher.js +7 -18
- package/hooks/scripts/session-start.js +25 -35
- package/package.json +6 -5
- package/skills/agents-md/SKILL.md +62 -15
- package/skills/arch-guard/SKILL.md +1 -1
- package/skills/brand-assets/SKILL.md +2 -2
- package/skills/capability-loop/SKILL.md +1 -1
- package/skills/chub-usage/SKILL.md +1 -1
- package/skills/clone/SKILL.md +132 -55
- package/skills/commerce-patterns/SKILL.md +2 -2
- package/skills/commit-push-pr/SKILL.md +0 -1
- package/skills/context7-usage/SKILL.md +1 -1
- package/skills/design-refine/SKILL.md +140 -0
- package/skills/{design-polish → design-refine}/templates/polish-report.md +1 -1
- package/skills/{design-normalize → design-refine}/templates/token-audit.md +3 -3
- package/skills/design-review/SKILL.md +143 -0
- package/skills/{design-audit → design-review}/agents/a11y-auditor.md +1 -1
- package/skills/{design-audit → design-review}/agents/performance-auditor.md +1 -1
- package/skills/{design-audit → design-review}/agents/responsive-auditor.md +1 -1
- package/skills/{design-audit → design-review}/agents/slop-detector.md +1 -1
- package/skills/{design-audit → design-review}/frameworks/core-web-vitals.md +1 -1
- package/skills/{design-audit → design-review}/frameworks/wcag-checklist.md +1 -1
- package/skills/{design-audit → design-review}/orchestrator.md +3 -3
- package/skills/{design-critique → design-review}/templates/critique-report.md +3 -3
- package/skills/{design-audit → design-review}/templates/report.md +3 -3
- package/skills/design-teach/SKILL.md +11 -11
- package/skills/docs/SKILL.md +14 -16
- package/skills/e2e-commerce/SKILL.md +1 -1
- package/skills/event-comms/SKILL.md +1 -1
- package/skills/event-ops/SKILL.md +2 -2
- package/skills/event-planning/SKILL.md +1 -1
- package/skills/exec-plan/SKILL.md +2 -2
- package/skills/figma/SKILL.md +240 -148
- package/skills/figma/rubrics/css-mapping.md +125 -0
- package/skills/git-worktree/SKILL.md +1 -1
- package/skills/handoff/SKILL.md +1 -1
- package/skills/parallel-research/SKILL.md +14 -28
- package/skills/priority-todos/SKILL.md +1 -1
- package/skills/regress/SKILL.md +11 -0
- package/skills/restraint/SKILL.md +72 -0
- package/skills/seo-checklist/SKILL.md +2 -2
- package/skills/spec/SKILL.md +65 -836
- package/skills/test/SKILL.md +3 -3
- package/skills/tool-fallback/SKILL.md +2 -2
- package/skills/vercel-react-best-practices/SKILL.md +1 -1
- package/skills/vibe/SKILL.md +20 -35
- package/skills/vibe.analyze/SKILL.md +7 -9
- package/skills/vibe.clone/SKILL.md +39 -19
- package/skills/vibe.docs/SKILL.md +1 -1
- package/skills/vibe.event/SKILL.md +27 -27
- package/skills/vibe.figma/SKILL.md +14 -18
- package/skills/vibe.harness/SKILL.md +5 -5
- package/skills/vibe.reason/SKILL.md +0 -2
- package/skills/vibe.review/SKILL.md +45 -49
- package/skills/vibe.run/SKILL.md +2 -5
- package/skills/vibe.run/references/parallel-agents.md +33 -98
- package/skills/vibe.spec/SKILL.md +38 -535
- package/skills/vibe.utils/SKILL.md +3 -3
- package/skills/vibe.verify/SKILL.md +70 -542
- package/skills/video-production/SKILL.md +1 -1
- package/vibe/rules/orchestrator-contract.md +5 -4
- package/vibe/rules/quality/performance.md +1 -1
- package/vibe/templates/claudemd-template.md +1 -1
- package/vibe/templates/spec-template.md +35 -185
- package/agents/architect-low.md +0 -41
- package/agents/architect-medium.md +0 -59
- package/agents/compounder.md +0 -265
- package/agents/docs/api-documenter.md +0 -99
- package/agents/docs/changelog-writer.md +0 -93
- package/agents/event/event-comms.md +0 -78
- package/agents/event/event-content.md +0 -68
- package/agents/event/event-image.md +0 -95
- package/agents/event/event-scheduler.md +0 -69
- package/agents/event/event-speaker.md +0 -86
- package/agents/explorer-low.md +0 -42
- package/agents/explorer-medium.md +0 -59
- package/agents/explorer.md +0 -48
- package/agents/figma/figma-analyst.md +0 -56
- package/agents/figma/figma-architect.md +0 -116
- package/agents/figma/figma-auditor.md +0 -86
- package/agents/figma/figma-builder.md +0 -104
- package/agents/implementer-low.md +0 -43
- package/agents/implementer-medium.md +0 -52
- package/agents/junior-mentor.md +0 -141
- package/agents/planning/requirements-analyst.md +0 -84
- package/agents/planning/ux-advisor.md +0 -83
- package/agents/qa/acceptance-tester.md +0 -86
- package/agents/qa/edge-case-finder.md +0 -93
- package/agents/qa/qa-coordinator.md +0 -131
- package/agents/refactor-cleaner.md +0 -143
- package/agents/research/best-practices.md +0 -199
- package/agents/research/codebase-patterns.md +0 -157
- package/agents/research/framework-docs.md +0 -188
- package/agents/research/security-advisory.md +0 -213
- package/agents/review/architecture-reviewer.md +0 -107
- package/agents/review/complexity-reviewer.md +0 -116
- package/agents/review/data-integrity-reviewer.md +0 -88
- package/agents/review/git-history-reviewer.md +0 -103
- package/agents/review/performance-reviewer.md +0 -86
- package/agents/review/python-reviewer.md +0 -150
- package/agents/review/rails-reviewer.md +0 -139
- package/agents/review/react-reviewer.md +0 -144
- package/agents/review/security-reviewer.md +0 -80
- package/agents/review/simplicity-reviewer.md +0 -140
- package/agents/review/test-coverage-reviewer.md +0 -116
- package/agents/review/typescript-reviewer.md +0 -127
- package/agents/searcher.md +0 -54
- package/agents/simplifier.md +0 -124
- package/agents/teams/debug-team.md +0 -74
- package/agents/teams/dev-team.md +0 -92
- package/agents/teams/docs-team.md +0 -84
- package/agents/teams/figma-team.md +0 -89
- package/agents/teams/fullstack-team.md +0 -87
- package/agents/teams/lite-team.md +0 -73
- package/agents/teams/migration-team.md +0 -82
- package/agents/teams/refactor-team.md +0 -98
- package/agents/teams/research-team.md +0 -90
- package/agents/teams/review-debate-team.md +0 -129
- package/agents/teams/security-team.md +0 -85
- package/agents/ui/ui-a11y-auditor.md +0 -93
- package/agents/ui/ui-antipattern-detector.md +0 -102
- package/agents/ui/ui-dataviz-advisor.md +0 -69
- package/agents/ui/ui-design-system-gen.md +0 -57
- package/agents/ui/ui-industry-analyzer.md +0 -49
- package/agents/ui/ui-layout-architect.md +0 -65
- package/agents/ui/ui-stack-implementer.md +0 -68
- package/agents/ui/ux-compliance-reviewer.md +0 -81
- package/agents/ui-previewer.md +0 -262
- package/dist/cli/llm/gemini-commands.d.ts +0 -25
- package/dist/cli/llm/gemini-commands.d.ts.map +0 -1
- package/dist/cli/llm/gemini-commands.js +0 -143
- package/dist/cli/llm/gemini-commands.js.map +0 -1
- package/dist/cli/postinstall/codex-agents.d.ts +0 -24
- package/dist/cli/postinstall/codex-agents.d.ts.map +0 -1
- package/dist/cli/postinstall/codex-agents.js +0 -114
- package/dist/cli/postinstall/codex-agents.js.map +0 -1
- package/dist/cli/postinstall/codex-instruction.d.ts +0 -10
- package/dist/cli/postinstall/codex-instruction.d.ts.map +0 -1
- package/dist/cli/postinstall/codex-instruction.js +0 -56
- package/dist/cli/postinstall/codex-instruction.js.map +0 -1
- package/dist/cli/postinstall/gemini-agents.d.ts +0 -12
- package/dist/cli/postinstall/gemini-agents.d.ts.map +0 -1
- package/dist/cli/postinstall/gemini-agents.js +0 -80
- package/dist/cli/postinstall/gemini-agents.js.map +0 -1
- package/dist/cli/postinstall/gemini-instruction.d.ts +0 -10
- package/dist/cli/postinstall/gemini-instruction.d.ts.map +0 -1
- package/dist/cli/postinstall/gemini-instruction.js +0 -59
- package/dist/cli/postinstall/gemini-instruction.js.map +0 -1
- package/dist/infra/lib/ContextCompressor.d.ts +0 -104
- package/dist/infra/lib/ContextCompressor.d.ts.map +0 -1
- package/dist/infra/lib/ContextCompressor.js +0 -297
- package/dist/infra/lib/ContextCompressor.js.map +0 -1
- package/dist/infra/lib/ContextCompressor.test.d.ts +0 -2
- package/dist/infra/lib/ContextCompressor.test.d.ts.map +0 -1
- package/dist/infra/lib/ContextCompressor.test.js +0 -25
- package/dist/infra/lib/ContextCompressor.test.js.map +0 -1
- package/dist/infra/lib/ProgressTracker.d.ts +0 -73
- package/dist/infra/lib/ProgressTracker.d.ts.map +0 -1
- package/dist/infra/lib/ProgressTracker.js +0 -267
- package/dist/infra/lib/ProgressTracker.js.map +0 -1
- package/dist/infra/lib/TokenBudgetTracker.d.ts +0 -68
- package/dist/infra/lib/TokenBudgetTracker.d.ts.map +0 -1
- package/dist/infra/lib/TokenBudgetTracker.js +0 -191
- package/dist/infra/lib/TokenBudgetTracker.js.map +0 -1
- package/dist/infra/lib/autonomy/AuditStore.d.ts +0 -63
- package/dist/infra/lib/autonomy/AuditStore.d.ts.map +0 -1
- package/dist/infra/lib/autonomy/AuditStore.js +0 -185
- package/dist/infra/lib/autonomy/AuditStore.js.map +0 -1
- package/dist/infra/lib/autonomy/AutonomyConfig.d.ts +0 -84
- package/dist/infra/lib/autonomy/AutonomyConfig.d.ts.map +0 -1
- package/dist/infra/lib/autonomy/AutonomyConfig.js +0 -49
- package/dist/infra/lib/autonomy/AutonomyConfig.js.map +0 -1
- package/dist/infra/lib/autonomy/AutonomyOrchestrator.d.ts +0 -78
- package/dist/infra/lib/autonomy/AutonomyOrchestrator.d.ts.map +0 -1
- package/dist/infra/lib/autonomy/AutonomyOrchestrator.js +0 -246
- package/dist/infra/lib/autonomy/AutonomyOrchestrator.js.map +0 -1
- package/dist/infra/lib/autonomy/BackgroundMonitor.d.ts +0 -36
- package/dist/infra/lib/autonomy/BackgroundMonitor.d.ts.map +0 -1
- package/dist/infra/lib/autonomy/BackgroundMonitor.js +0 -138
- package/dist/infra/lib/autonomy/BackgroundMonitor.js.map +0 -1
- package/dist/infra/lib/autonomy/CollaborationProtocol.d.ts +0 -56
- package/dist/infra/lib/autonomy/CollaborationProtocol.d.ts.map +0 -1
- package/dist/infra/lib/autonomy/CollaborationProtocol.js +0 -122
- package/dist/infra/lib/autonomy/CollaborationProtocol.js.map +0 -1
- package/dist/infra/lib/autonomy/ConfirmationManager.d.ts +0 -42
- package/dist/infra/lib/autonomy/ConfirmationManager.d.ts.map +0 -1
- package/dist/infra/lib/autonomy/ConfirmationManager.js +0 -200
- package/dist/infra/lib/autonomy/ConfirmationManager.js.map +0 -1
- package/dist/infra/lib/autonomy/ConfirmationStore.d.ts +0 -55
- package/dist/infra/lib/autonomy/ConfirmationStore.d.ts.map +0 -1
- package/dist/infra/lib/autonomy/ConfirmationStore.js +0 -130
- package/dist/infra/lib/autonomy/ConfirmationStore.js.map +0 -1
- package/dist/infra/lib/autonomy/EventBus.d.ts +0 -20
- package/dist/infra/lib/autonomy/EventBus.d.ts.map +0 -1
- package/dist/infra/lib/autonomy/EventBus.js +0 -119
- package/dist/infra/lib/autonomy/EventBus.js.map +0 -1
- package/dist/infra/lib/autonomy/EventOutbox.d.ts +0 -32
- package/dist/infra/lib/autonomy/EventOutbox.d.ts.map +0 -1
- package/dist/infra/lib/autonomy/EventOutbox.js +0 -152
- package/dist/infra/lib/autonomy/EventOutbox.js.map +0 -1
- package/dist/infra/lib/autonomy/NotificationDispatcher.d.ts +0 -24
- package/dist/infra/lib/autonomy/NotificationDispatcher.d.ts.map +0 -1
- package/dist/infra/lib/autonomy/NotificationDispatcher.js +0 -112
- package/dist/infra/lib/autonomy/NotificationDispatcher.js.map +0 -1
- package/dist/infra/lib/autonomy/PolicyEngine.d.ts +0 -76
- package/dist/infra/lib/autonomy/PolicyEngine.d.ts.map +0 -1
- package/dist/infra/lib/autonomy/PolicyEngine.js +0 -208
- package/dist/infra/lib/autonomy/PolicyEngine.js.map +0 -1
- package/dist/infra/lib/autonomy/ProactiveAnalyzer.d.ts +0 -61
- package/dist/infra/lib/autonomy/ProactiveAnalyzer.d.ts.map +0 -1
- package/dist/infra/lib/autonomy/ProactiveAnalyzer.js +0 -236
- package/dist/infra/lib/autonomy/ProactiveAnalyzer.js.map +0 -1
- package/dist/infra/lib/autonomy/RiskClassifier.d.ts +0 -35
- package/dist/infra/lib/autonomy/RiskClassifier.d.ts.map +0 -1
- package/dist/infra/lib/autonomy/RiskClassifier.js +0 -147
- package/dist/infra/lib/autonomy/RiskClassifier.js.map +0 -1
- package/dist/infra/lib/autonomy/SecuritySentinel.d.ts +0 -51
- package/dist/infra/lib/autonomy/SecuritySentinel.d.ts.map +0 -1
- package/dist/infra/lib/autonomy/SecuritySentinel.js +0 -162
- package/dist/infra/lib/autonomy/SecuritySentinel.js.map +0 -1
- package/dist/infra/lib/autonomy/SuggestionStore.d.ts +0 -54
- package/dist/infra/lib/autonomy/SuggestionStore.d.ts.map +0 -1
- package/dist/infra/lib/autonomy/SuggestionStore.js +0 -144
- package/dist/infra/lib/autonomy/SuggestionStore.js.map +0 -1
- package/dist/infra/lib/autonomy/TaskDecomposer.d.ts +0 -38
- package/dist/infra/lib/autonomy/TaskDecomposer.d.ts.map +0 -1
- package/dist/infra/lib/autonomy/TaskDecomposer.js +0 -175
- package/dist/infra/lib/autonomy/TaskDecomposer.js.map +0 -1
- package/dist/infra/lib/autonomy/__tests__/audit-store.test.d.ts +0 -2
- package/dist/infra/lib/autonomy/__tests__/audit-store.test.d.ts.map +0 -1
- package/dist/infra/lib/autonomy/__tests__/audit-store.test.js +0 -198
- package/dist/infra/lib/autonomy/__tests__/audit-store.test.js.map +0 -1
- package/dist/infra/lib/autonomy/__tests__/event-bus.test.d.ts +0 -2
- package/dist/infra/lib/autonomy/__tests__/event-bus.test.d.ts.map +0 -1
- package/dist/infra/lib/autonomy/__tests__/event-bus.test.js +0 -225
- package/dist/infra/lib/autonomy/__tests__/event-bus.test.js.map +0 -1
- package/dist/infra/lib/autonomy/__tests__/event-core.test.d.ts +0 -2
- package/dist/infra/lib/autonomy/__tests__/event-core.test.d.ts.map +0 -1
- package/dist/infra/lib/autonomy/__tests__/event-core.test.js +0 -194
- package/dist/infra/lib/autonomy/__tests__/event-core.test.js.map +0 -1
- package/dist/infra/lib/autonomy/__tests__/governance.test.d.ts +0 -2
- package/dist/infra/lib/autonomy/__tests__/governance.test.d.ts.map +0 -1
- package/dist/infra/lib/autonomy/__tests__/governance.test.js +0 -540
- package/dist/infra/lib/autonomy/__tests__/governance.test.js.map +0 -1
- package/dist/infra/lib/autonomy/__tests__/integration.test.d.ts +0 -2
- package/dist/infra/lib/autonomy/__tests__/integration.test.d.ts.map +0 -1
- package/dist/infra/lib/autonomy/__tests__/integration.test.js +0 -480
- package/dist/infra/lib/autonomy/__tests__/integration.test.js.map +0 -1
- package/dist/infra/lib/autonomy/__tests__/proactive.test.d.ts +0 -2
- package/dist/infra/lib/autonomy/__tests__/proactive.test.d.ts.map +0 -1
- package/dist/infra/lib/autonomy/__tests__/proactive.test.js +0 -410
- package/dist/infra/lib/autonomy/__tests__/proactive.test.js.map +0 -1
- package/dist/infra/lib/autonomy/__tests__/sentinel.test.d.ts +0 -2
- package/dist/infra/lib/autonomy/__tests__/sentinel.test.d.ts.map +0 -1
- package/dist/infra/lib/autonomy/__tests__/sentinel.test.js +0 -486
- package/dist/infra/lib/autonomy/__tests__/sentinel.test.js.map +0 -1
- package/dist/infra/lib/autonomy/index.d.ts +0 -18
- package/dist/infra/lib/autonomy/index.d.ts.map +0 -1
- package/dist/infra/lib/autonomy/index.js +0 -22
- package/dist/infra/lib/autonomy/index.js.map +0 -1
- package/dist/infra/lib/autonomy/schemas.d.ts +0 -317
- package/dist/infra/lib/autonomy/schemas.d.ts.map +0 -1
- package/dist/infra/lib/autonomy/schemas.js +0 -90
- package/dist/infra/lib/autonomy/schemas.js.map +0 -1
- package/dist/infra/lib/claude/index.d.ts +0 -5
- package/dist/infra/lib/claude/index.d.ts.map +0 -1
- package/dist/infra/lib/claude/index.js +0 -5
- package/dist/infra/lib/claude/index.js.map +0 -1
- package/dist/infra/lib/claude/storage.d.ts +0 -12
- package/dist/infra/lib/claude/storage.d.ts.map +0 -1
- package/dist/infra/lib/claude/storage.js +0 -54
- package/dist/infra/lib/claude/storage.js.map +0 -1
- package/dist/infra/lib/gemini/auth.d.ts +0 -18
- package/dist/infra/lib/gemini/auth.d.ts.map +0 -1
- package/dist/infra/lib/gemini/auth.js +0 -32
- package/dist/infra/lib/gemini/auth.js.map +0 -1
- package/dist/infra/lib/gemini/capabilities.d.ts +0 -28
- package/dist/infra/lib/gemini/capabilities.d.ts.map +0 -1
- package/dist/infra/lib/gemini/capabilities.js +0 -178
- package/dist/infra/lib/gemini/capabilities.js.map +0 -1
- package/dist/infra/lib/gemini/chat.d.ts +0 -35
- package/dist/infra/lib/gemini/chat.d.ts.map +0 -1
- package/dist/infra/lib/gemini/chat.js +0 -161
- package/dist/infra/lib/gemini/chat.js.map +0 -1
- package/dist/infra/lib/gemini/completion.d.ts +0 -12
- package/dist/infra/lib/gemini/completion.d.ts.map +0 -1
- package/dist/infra/lib/gemini/completion.js +0 -13
- package/dist/infra/lib/gemini/completion.js.map +0 -1
- package/dist/infra/lib/gemini/constants.d.ts +0 -8
- package/dist/infra/lib/gemini/constants.d.ts.map +0 -1
- package/dist/infra/lib/gemini/constants.js +0 -11
- package/dist/infra/lib/gemini/constants.js.map +0 -1
- package/dist/infra/lib/gemini/index.d.ts +0 -13
- package/dist/infra/lib/gemini/index.d.ts.map +0 -1
- package/dist/infra/lib/gemini/index.js +0 -12
- package/dist/infra/lib/gemini/index.js.map +0 -1
- package/dist/infra/lib/gemini/models.d.ts +0 -11
- package/dist/infra/lib/gemini/models.d.ts.map +0 -1
- package/dist/infra/lib/gemini/models.js +0 -38
- package/dist/infra/lib/gemini/models.js.map +0 -1
- package/dist/infra/lib/gemini/orchestration.d.ts +0 -33
- package/dist/infra/lib/gemini/orchestration.d.ts.map +0 -1
- package/dist/infra/lib/gemini/orchestration.js +0 -62
- package/dist/infra/lib/gemini/orchestration.js.map +0 -1
- package/dist/infra/lib/gemini/types.d.ts +0 -115
- package/dist/infra/lib/gemini/types.d.ts.map +0 -1
- package/dist/infra/lib/gemini/types.js +0 -5
- package/dist/infra/lib/gemini/types.js.map +0 -1
- package/dist/infra/orchestrator/AgentAnnouncer.d.ts +0 -64
- package/dist/infra/orchestrator/AgentAnnouncer.d.ts.map +0 -1
- package/dist/infra/orchestrator/AgentAnnouncer.js +0 -127
- package/dist/infra/orchestrator/AgentAnnouncer.js.map +0 -1
- package/dist/infra/orchestrator/AgentAnnouncer.test.d.ts +0 -5
- package/dist/infra/orchestrator/AgentAnnouncer.test.d.ts.map +0 -1
- package/dist/infra/orchestrator/AgentAnnouncer.test.js +0 -119
- package/dist/infra/orchestrator/AgentAnnouncer.test.js.map +0 -1
- package/dist/infra/orchestrator/AgentExecutor.d.ts +0 -22
- package/dist/infra/orchestrator/AgentExecutor.d.ts.map +0 -1
- package/dist/infra/orchestrator/AgentExecutor.js +0 -272
- package/dist/infra/orchestrator/AgentExecutor.js.map +0 -1
- package/dist/infra/orchestrator/AgentManager.d.ts +0 -72
- package/dist/infra/orchestrator/AgentManager.d.ts.map +0 -1
- package/dist/infra/orchestrator/AgentManager.js +0 -183
- package/dist/infra/orchestrator/AgentManager.js.map +0 -1
- package/dist/infra/orchestrator/AgentManifestCache.d.ts +0 -54
- package/dist/infra/orchestrator/AgentManifestCache.d.ts.map +0 -1
- package/dist/infra/orchestrator/AgentManifestCache.js +0 -191
- package/dist/infra/orchestrator/AgentManifestCache.js.map +0 -1
- package/dist/infra/orchestrator/AgentRegistry.d.ts +0 -76
- package/dist/infra/orchestrator/AgentRegistry.d.ts.map +0 -1
- package/dist/infra/orchestrator/AgentRegistry.js +0 -217
- package/dist/infra/orchestrator/AgentRegistry.js.map +0 -1
- package/dist/infra/orchestrator/AgentRegistry.test.d.ts +0 -5
- package/dist/infra/orchestrator/AgentRegistry.test.d.ts.map +0 -1
- package/dist/infra/orchestrator/AgentRegistry.test.js +0 -122
- package/dist/infra/orchestrator/AgentRegistry.test.js.map +0 -1
- package/dist/infra/orchestrator/BackgroundManager.d.ts +0 -128
- package/dist/infra/orchestrator/BackgroundManager.d.ts.map +0 -1
- package/dist/infra/orchestrator/BackgroundManager.js +0 -620
- package/dist/infra/orchestrator/BackgroundManager.js.map +0 -1
- package/dist/infra/orchestrator/BackgroundManager.test.d.ts +0 -6
- package/dist/infra/orchestrator/BackgroundManager.test.d.ts.map +0 -1
- package/dist/infra/orchestrator/BackgroundManager.test.js +0 -162
- package/dist/infra/orchestrator/BackgroundManager.test.js.map +0 -1
- package/dist/infra/orchestrator/CheckpointManager.d.ts +0 -54
- package/dist/infra/orchestrator/CheckpointManager.d.ts.map +0 -1
- package/dist/infra/orchestrator/CheckpointManager.js +0 -121
- package/dist/infra/orchestrator/CheckpointManager.js.map +0 -1
- package/dist/infra/orchestrator/CodexAgentRuntime.d.ts +0 -12
- package/dist/infra/orchestrator/CodexAgentRuntime.d.ts.map +0 -1
- package/dist/infra/orchestrator/CodexAgentRuntime.js +0 -94
- package/dist/infra/orchestrator/CodexAgentRuntime.js.map +0 -1
- package/dist/infra/orchestrator/CodexAgentRuntime.test.d.ts +0 -2
- package/dist/infra/orchestrator/CodexAgentRuntime.test.d.ts.map +0 -1
- package/dist/infra/orchestrator/CodexAgentRuntime.test.js +0 -37
- package/dist/infra/orchestrator/CodexAgentRuntime.test.js.map +0 -1
- package/dist/infra/orchestrator/LLMCluster.d.ts +0 -82
- package/dist/infra/orchestrator/LLMCluster.d.ts.map +0 -1
- package/dist/infra/orchestrator/LLMCluster.js +0 -146
- package/dist/infra/orchestrator/LLMCluster.js.map +0 -1
- package/dist/infra/orchestrator/MultiLlmResearch.d.ts +0 -31
- package/dist/infra/orchestrator/MultiLlmResearch.d.ts.map +0 -1
- package/dist/infra/orchestrator/MultiLlmResearch.js +0 -160
- package/dist/infra/orchestrator/MultiLlmResearch.js.map +0 -1
- package/dist/infra/orchestrator/PhasePipeline.d.ts +0 -122
- package/dist/infra/orchestrator/PhasePipeline.d.ts.map +0 -1
- package/dist/infra/orchestrator/PhasePipeline.js +0 -385
- package/dist/infra/orchestrator/PhasePipeline.js.map +0 -1
- package/dist/infra/orchestrator/PhaseResultStore.d.ts +0 -39
- package/dist/infra/orchestrator/PhaseResultStore.d.ts.map +0 -1
- package/dist/infra/orchestrator/PhaseResultStore.js +0 -151
- package/dist/infra/orchestrator/PhaseResultStore.js.map +0 -1
- package/dist/infra/orchestrator/SessionStore.d.ts +0 -40
- package/dist/infra/orchestrator/SessionStore.d.ts.map +0 -1
- package/dist/infra/orchestrator/SessionStore.js +0 -116
- package/dist/infra/orchestrator/SessionStore.js.map +0 -1
- package/dist/infra/orchestrator/SmartRouter.d.ts +0 -90
- package/dist/infra/orchestrator/SmartRouter.d.ts.map +0 -1
- package/dist/infra/orchestrator/SmartRouter.js +0 -277
- package/dist/infra/orchestrator/SmartRouter.js.map +0 -1
- package/dist/infra/orchestrator/SmartRouter.test.d.ts +0 -5
- package/dist/infra/orchestrator/SmartRouter.test.d.ts.map +0 -1
- package/dist/infra/orchestrator/SmartRouter.test.js +0 -484
- package/dist/infra/orchestrator/SmartRouter.test.js.map +0 -1
- package/dist/infra/orchestrator/SwarmOrchestrator.d.ts +0 -143
- package/dist/infra/orchestrator/SwarmOrchestrator.d.ts.map +0 -1
- package/dist/infra/orchestrator/SwarmOrchestrator.js +0 -378
- package/dist/infra/orchestrator/SwarmOrchestrator.js.map +0 -1
- package/dist/infra/orchestrator/SwarmOrchestrator.test.d.ts +0 -5
- package/dist/infra/orchestrator/SwarmOrchestrator.test.d.ts.map +0 -1
- package/dist/infra/orchestrator/SwarmOrchestrator.test.js +0 -95
- package/dist/infra/orchestrator/SwarmOrchestrator.test.js.map +0 -1
- package/dist/infra/orchestrator/agentDiscovery.d.ts +0 -26
- package/dist/infra/orchestrator/agentDiscovery.d.ts.map +0 -1
- package/dist/infra/orchestrator/agentDiscovery.js +0 -175
- package/dist/infra/orchestrator/agentDiscovery.js.map +0 -1
- package/dist/infra/orchestrator/backgroundAgent.d.ts +0 -9
- package/dist/infra/orchestrator/backgroundAgent.d.ts.map +0 -1
- package/dist/infra/orchestrator/backgroundAgent.js +0 -10
- package/dist/infra/orchestrator/backgroundAgent.js.map +0 -1
- package/dist/infra/orchestrator/index.d.ts +0 -207
- package/dist/infra/orchestrator/index.d.ts.map +0 -1
- package/dist/infra/orchestrator/index.js +0 -362
- package/dist/infra/orchestrator/index.js.map +0 -1
- package/dist/infra/orchestrator/orchestrator.d.ts +0 -60
- package/dist/infra/orchestrator/orchestrator.d.ts.map +0 -1
- package/dist/infra/orchestrator/orchestrator.js +0 -214
- package/dist/infra/orchestrator/orchestrator.js.map +0 -1
- package/dist/infra/orchestrator/parallelResearch.d.ts +0 -27
- package/dist/infra/orchestrator/parallelResearch.d.ts.map +0 -1
- package/dist/infra/orchestrator/parallelResearch.js +0 -285
- package/dist/infra/orchestrator/parallelResearch.js.map +0 -1
- package/dist/infra/orchestrator/types.d.ts +0 -205
- package/dist/infra/orchestrator/types.d.ts.map +0 -1
- package/dist/infra/orchestrator/types.js +0 -87
- package/dist/infra/orchestrator/types.js.map +0 -1
- package/dist/infra/orchestrator/types.test.d.ts +0 -2
- package/dist/infra/orchestrator/types.test.d.ts.map +0 -1
- package/dist/infra/orchestrator/types.test.js +0 -57
- package/dist/infra/orchestrator/types.test.js.map +0 -1
- package/dist/tools/semantic/analyzeDependencyGraph.d.ts +0 -12
- package/dist/tools/semantic/analyzeDependencyGraph.d.ts.map +0 -1
- package/dist/tools/semantic/analyzeDependencyGraph.js +0 -359
- package/dist/tools/semantic/analyzeDependencyGraph.js.map +0 -1
- package/dist/tools/semantic/astGrep.d.ts +0 -25
- package/dist/tools/semantic/astGrep.d.ts.map +0 -1
- package/dist/tools/semantic/astGrep.js +0 -324
- package/dist/tools/semantic/astGrep.js.map +0 -1
- package/dist/tools/semantic/astGrep.test.d.ts +0 -2
- package/dist/tools/semantic/astGrep.test.d.ts.map +0 -1
- package/dist/tools/semantic/astGrep.test.js +0 -74
- package/dist/tools/semantic/astGrep.test.js.map +0 -1
- package/dist/tools/semantic/findReferences.d.ts +0 -9
- package/dist/tools/semantic/findReferences.d.ts.map +0 -1
- package/dist/tools/semantic/findReferences.js +0 -200
- package/dist/tools/semantic/findReferences.js.map +0 -1
- package/dist/tools/semantic/findSymbol.d.ts +0 -8
- package/dist/tools/semantic/findSymbol.d.ts.map +0 -1
- package/dist/tools/semantic/findSymbol.js +0 -204
- package/dist/tools/semantic/findSymbol.js.map +0 -1
- package/dist/tools/semantic/index.d.ts +0 -9
- package/dist/tools/semantic/index.d.ts.map +0 -1
- package/dist/tools/semantic/index.js +0 -11
- package/dist/tools/semantic/index.js.map +0 -1
- package/dist/tools/semantic/lsp.d.ts +0 -68
- package/dist/tools/semantic/lsp.d.ts.map +0 -1
- package/dist/tools/semantic/lsp.js +0 -561
- package/dist/tools/semantic/lsp.js.map +0 -1
- package/dist/tools/spec/e2eTestGenerator.d.ts +0 -61
- package/dist/tools/spec/e2eTestGenerator.d.ts.map +0 -1
- package/dist/tools/spec/e2eTestGenerator.js +0 -255
- package/dist/tools/spec/e2eTestGenerator.js.map +0 -1
- package/dist/tools/spec/specVersioning.d.ts +0 -76
- package/dist/tools/spec/specVersioning.d.ts.map +0 -1
- package/dist/tools/spec/specVersioning.js +0 -236
- package/dist/tools/spec/specVersioning.js.map +0 -1
- package/hooks/scripts/__tests__/keyword-detector.test.js +0 -242
- package/hooks/scripts/keyword-detector.js +0 -226
- package/skills/characterization-test/SKILL.md +0 -209
- package/skills/characterization-test/agents/behavior-capturer.md +0 -50
- package/skills/characterization-test/agents/coverage-checker.md +0 -54
- package/skills/characterization-test/agents/reporter.md +0 -50
- package/skills/characterization-test/agents/test-writer.md +0 -49
- package/skills/characterization-test/rubrics/coverage-criteria.md +0 -53
- package/skills/characterization-test/templates/test-template.ts +0 -101
- package/skills/claude-md-guide/SKILL.md +0 -353
- package/skills/claude-md-guide/rubrics/anti-patterns.md +0 -88
- package/skills/design-audit/SKILL.md +0 -154
- package/skills/design-critique/SKILL.md +0 -140
- package/skills/design-distill/SKILL.md +0 -131
- package/skills/design-normalize/SKILL.md +0 -135
- package/skills/design-polish/SKILL.md +0 -132
- package/skills/figma-convert/SKILL.md +0 -236
- package/skills/figma-extract/SKILL.md +0 -242
- package/skills/interview/SKILL.md +0 -358
- package/skills/interview/checklists/api.md +0 -101
- package/skills/interview/checklists/feature.md +0 -88
- package/skills/interview/checklists/library.md +0 -95
- package/skills/interview/checklists/mobile.md +0 -89
- package/skills/interview/checklists/webapp.md +0 -97
- package/skills/interview/checklists/website.md +0 -99
- package/skills/plan/SKILL.md +0 -254
- package/skills/rob-pike/SKILL.md +0 -66
- package/skills/spec/references/askuser-examples.md +0 -57
- package/skills/spec/references/example-session.md +0 -87
- package/skills/spec/references/templates.md +0 -194
- package/skills/spec-review/SKILL.md +0 -725
- package/skills/systematic-debugging/SKILL.md +0 -142
- package/skills/techdebt/SKILL.md +0 -126
- package/skills/techdebt/agents/analyzer.md +0 -50
- package/skills/techdebt/agents/fixer.md +0 -41
- package/skills/techdebt/agents/reviewer.md +0 -47
- package/skills/techdebt/agents/scanner.md +0 -44
- package/skills/techdebt/orchestrator.md +0 -72
- package/skills/techdebt/rubrics/severity.md +0 -51
- package/skills/techdebt/scripts/scan.js +0 -90
- package/skills/techdebt/templates/report.md +0 -86
- package/skills/typescript-advanced-types/SKILL.md +0 -68
- package/skills/typescript-advanced-types/rubrics/type-patterns.md +0 -109
- package/skills/yagni-ladder/SKILL.md +0 -90
- /package/skills/{claude-md-guide → agents-md}/templates/claude-md.md +0 -0
- /package/skills/{design-polish → design-refine}/rubrics/polish-checklist.md +0 -0
- /package/skills/{design-normalize → design-refine}/rubrics/token-naming.md +0 -0
- /package/skills/{design-distill → design-refine}/templates/design-system.md +0 -0
- /package/skills/{design-audit → design-review}/agents/scorer.md +0 -0
- /package/skills/{design-audit → design-review}/rubrics/ai-slop-patterns.md +0 -0
- /package/skills/{design-audit → design-review}/rubrics/scoring.md +0 -0
- /package/skills/{design-critique → design-review}/rubrics/ux-heuristics.md +0 -0
- /package/skills/{figma-convert → figma}/rubrics/conversion-rules.md +0 -0
- /package/skills/{figma-extract → figma}/rubrics/image-rules.md +0 -0
- /package/skills/{figma-convert → figma}/templates/component.md +0 -0
|
@@ -650,34 +650,139 @@ const TAB_CONTENT_FP = `(function (g) {
|
|
|
650
650
|
return (root.innerText || '').replace(/\\s+/g, ' ').trim().slice(0, 4000);
|
|
651
651
|
})`;
|
|
652
652
|
|
|
653
|
-
|
|
653
|
+
// Hover diff props — 색/그림자/변형 등 호버에서 실제로 바뀌는 것들
|
|
654
|
+
const HOVER_PROPS = [
|
|
655
|
+
'color', 'background-color', 'border-color', 'box-shadow',
|
|
656
|
+
'transform', 'opacity', 'text-decoration-line', 'filter', 'outline-width',
|
|
657
|
+
];
|
|
654
658
|
|
|
655
|
-
|
|
656
|
-
|
|
659
|
+
// In-view 등장 애니메이션 diff props
|
|
660
|
+
const INVIEW_PROPS = ['opacity', 'transform', 'visibility', 'filter', 'clip-path'];
|
|
657
661
|
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
const
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
662
|
+
// In-page: tag hover candidates. 같은 시그니처(tag+첫 클래스)는 1개만 샘플 — nav 링크 30개 → 1개.
|
|
663
|
+
const TAG_HOVER_CANDIDATES = `(function () {
|
|
664
|
+
const els = Array.from(document.querySelectorAll('a, button, [role="button"], [class*="btn" i], [class*="card" i]'));
|
|
665
|
+
const seen = new Set(); const out = []; let i = 0;
|
|
666
|
+
for (const el of els) {
|
|
667
|
+
if (i >= 30) break;
|
|
668
|
+
const r = el.getBoundingClientRect();
|
|
669
|
+
if (r.width < 8 || r.height < 8) continue;
|
|
670
|
+
const cls = (el.getAttribute('class') || '').trim().split(/\\s+/).filter(Boolean)[0] || '';
|
|
671
|
+
const sig = el.tagName + '.' + cls;
|
|
672
|
+
if (seen.has(sig)) continue;
|
|
673
|
+
seen.add(sig);
|
|
674
|
+
el.setAttribute('data-clone-hover', 'h' + i);
|
|
675
|
+
out.push({ probe: 'h' + i, tag: el.tagName.toLowerCase(), cls, transition: getComputedStyle(el).transition });
|
|
676
|
+
i++;
|
|
677
|
+
}
|
|
678
|
+
return out;
|
|
679
|
+
})`;
|
|
680
|
+
|
|
681
|
+
// In-page: snapshot computed props of all elements tagged with an attribute.
|
|
682
|
+
const SNAP_ATTR = `(function (attr, props) {
|
|
683
|
+
const out = {};
|
|
684
|
+
document.querySelectorAll('[' + attr + ']').forEach((el) => {
|
|
685
|
+
const cs = getComputedStyle(el); const o = {};
|
|
686
|
+
for (const p of props) { const v = cs.getPropertyValue(p); if (v) o[p] = v.trim(); }
|
|
687
|
+
out[el.getAttribute(attr)] = o;
|
|
688
|
+
});
|
|
689
|
+
return out;
|
|
690
|
+
})`;
|
|
691
|
+
|
|
692
|
+
// In-page: tag below-the-fold elements that look "waiting to animate" (opacity 0 / transform offset).
|
|
693
|
+
const TAG_INVIEW = `(function () {
|
|
694
|
+
const innerH = window.innerHeight;
|
|
695
|
+
const all = Array.from(document.querySelectorAll('body *')).slice(0, 3000);
|
|
696
|
+
const out = []; let i = 0;
|
|
697
|
+
for (const el of all) {
|
|
698
|
+
if (i >= 20) break;
|
|
699
|
+
const r = el.getBoundingClientRect();
|
|
700
|
+
if (r.width < 40 || r.height < 40) continue;
|
|
701
|
+
if (r.top < innerH) continue;
|
|
702
|
+
const cs = getComputedStyle(el);
|
|
703
|
+
const hidden = parseFloat(cs.opacity) < 0.05;
|
|
704
|
+
const shifted = cs.transform && cs.transform !== 'none';
|
|
705
|
+
if (!hidden && !shifted) continue;
|
|
706
|
+
if (el.parentElement && el.parentElement.closest('[data-clone-inview]')) continue;
|
|
707
|
+
el.setAttribute('data-clone-inview', 'v' + i);
|
|
708
|
+
const cls = (el.getAttribute('class') || '').trim().split(/\\s+/).filter(Boolean)[0] || '';
|
|
709
|
+
out.push({ probe: 'v' + i, tag: el.tagName.toLowerCase(), cls, top: Math.round(r.top + window.scrollY) });
|
|
710
|
+
i++;
|
|
711
|
+
}
|
|
712
|
+
return out;
|
|
713
|
+
})`;
|
|
714
|
+
|
|
715
|
+
// In-page: observe class/style mutations for N ms with no input → time-driven candidates (carousels, cycling).
|
|
716
|
+
const OBSERVE_MUTATIONS = `(function (ms) {
|
|
717
|
+
return new Promise((resolve) => {
|
|
718
|
+
const counts = new Map();
|
|
719
|
+
const obs = new MutationObserver((muts) => {
|
|
720
|
+
for (const m of muts) {
|
|
721
|
+
const el = m.target;
|
|
722
|
+
if (!el || !el.tagName || el === document.body || el === document.documentElement) continue;
|
|
723
|
+
const tag = el.tagName.toLowerCase();
|
|
724
|
+
const cls = ((el.getAttribute && el.getAttribute('class')) || '').trim().split(/\\s+/).filter(Boolean)[0] || '';
|
|
725
|
+
const key = tag + (cls ? '.' + cls : '');
|
|
726
|
+
const e = counts.get(key) || { tag, cls, mutations: 0, kinds: new Set() };
|
|
727
|
+
e.mutations++; e.kinds.add(m.type === 'attributes' ? m.attributeName : m.type);
|
|
728
|
+
counts.set(key, e);
|
|
676
729
|
}
|
|
730
|
+
});
|
|
731
|
+
obs.observe(document.body, { subtree: true, attributes: true, attributeFilter: ['class', 'style'], childList: true });
|
|
732
|
+
setTimeout(() => {
|
|
733
|
+
obs.disconnect();
|
|
734
|
+
resolve(Array.from(counts.entries())
|
|
735
|
+
.map(([label, e]) => ({ label, tag: e.tag, cls: e.cls, mutations: e.mutations, kinds: Array.from(e.kinds) }))
|
|
736
|
+
.sort((a, b) => b.mutations - a.mutations)
|
|
737
|
+
.slice(0, 10));
|
|
738
|
+
}, ms);
|
|
739
|
+
});
|
|
740
|
+
})`;
|
|
741
|
+
|
|
742
|
+
// In-page: smooth-scroll library detection (Lenis, Locomotive). 네이티브와 체감이 확연히 달라 놓치면 바로 티가 난다.
|
|
743
|
+
const DETECT_SCROLL_LIB = `(function () {
|
|
744
|
+
const checks = [
|
|
745
|
+
['lenis', 'html.lenis, .lenis, [data-lenis]'],
|
|
746
|
+
['locomotive-scroll', '.locomotive-scroll, [data-scroll-container]'],
|
|
747
|
+
];
|
|
748
|
+
for (const [name, sel] of checks) {
|
|
749
|
+
if (document.querySelector(sel)) return { name, evidence: sel };
|
|
750
|
+
}
|
|
751
|
+
if (window.Lenis) return { name: 'lenis', evidence: 'window.Lenis' };
|
|
752
|
+
if (window.LocomotiveScroll || window.locomotive) return { name: 'locomotive-scroll', evidence: 'window.LocomotiveScroll' };
|
|
753
|
+
return null;
|
|
754
|
+
})`;
|
|
755
|
+
|
|
756
|
+
const wait = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
757
|
+
|
|
758
|
+
// ── Scroll-triggered state (header/nav shrink, background, shadow on scroll) ──
|
|
759
|
+
async function sweepScrollState(page) {
|
|
760
|
+
const out = [];
|
|
761
|
+
const candidates = await page.evaluate(`(${TAG_SCROLL_CANDIDATES})()`);
|
|
762
|
+
if (!candidates.length) return out;
|
|
763
|
+
const before = await page.evaluate(`(${SNAP_PROBES})(${JSON.stringify(BEHAVIOR_PROPS)})`);
|
|
764
|
+
const innerH = await page.evaluate('window.innerHeight');
|
|
765
|
+
const triggerY = Math.min(700, Math.max(200, Math.round(innerH * 0.9)));
|
|
766
|
+
await page.evaluate(`window.scrollTo(0, ${triggerY})`);
|
|
767
|
+
await wait(500);
|
|
768
|
+
const after = await page.evaluate(`(${SNAP_PROBES})(${JSON.stringify(BEHAVIOR_PROPS)})`);
|
|
769
|
+
await page.evaluate('window.scrollTo(0, 0)');
|
|
770
|
+
await wait(300);
|
|
771
|
+
for (const c of candidates) {
|
|
772
|
+
const changed = diffStyles(before[c.probe], after[c.probe]);
|
|
773
|
+
if (Object.keys(changed).length) {
|
|
774
|
+
out.push({
|
|
775
|
+
label: c.cls ? `${c.tag}.${c.cls}` : c.tag,
|
|
776
|
+
tag: c.tag, cls: c.cls, triggerScrollY: triggerY, changed,
|
|
777
|
+
});
|
|
677
778
|
}
|
|
678
779
|
}
|
|
780
|
+
return out;
|
|
781
|
+
}
|
|
679
782
|
|
|
680
|
-
|
|
783
|
+
// ── Click-driven tab groups (content swap detection) ──
|
|
784
|
+
async function sweepTabGroups(page) {
|
|
785
|
+
const out = [];
|
|
681
786
|
const groups = await page.evaluate(`(${TAG_TAB_GROUPS})()`);
|
|
682
787
|
for (const grp of groups) {
|
|
683
788
|
try {
|
|
@@ -693,7 +798,7 @@ async function runInteractionSweep(page) {
|
|
|
693
798
|
`(function (g) { const t = document.querySelector('[data-clone-tab="' + g + '_0"]'); if (t) t.click(); })(${grp.group})`
|
|
694
799
|
);
|
|
695
800
|
await wait(200);
|
|
696
|
-
|
|
801
|
+
out.push({
|
|
697
802
|
kind: 'tab-group',
|
|
698
803
|
count: grp.count,
|
|
699
804
|
tabLabels: grp.labels,
|
|
@@ -701,14 +806,105 @@ async function runInteractionSweep(page) {
|
|
|
701
806
|
});
|
|
702
807
|
} catch { /* one bad group must not abort the whole sweep */ }
|
|
703
808
|
}
|
|
809
|
+
return out;
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
// ── Hover states set by JS (static :hover rules already land in states.json) ──
|
|
813
|
+
async function sweepHover(page) {
|
|
814
|
+
const out = [];
|
|
815
|
+
const candidates = await page.evaluate(`(${TAG_HOVER_CANDIDATES})()`);
|
|
816
|
+
for (const c of candidates) {
|
|
817
|
+
try {
|
|
818
|
+
const sel = `[data-clone-hover="${c.probe}"]`;
|
|
819
|
+
await page.evaluate(`document.querySelector('${sel}')?.scrollIntoView({ block: 'center' })`);
|
|
820
|
+
await wait(150);
|
|
821
|
+
const snap = `(${SNAP_ATTR})('data-clone-hover', ${JSON.stringify(HOVER_PROPS)})`;
|
|
822
|
+
const before = (await page.evaluate(snap))[c.probe];
|
|
823
|
+
await page.hover(sel);
|
|
824
|
+
await wait(350);
|
|
825
|
+
const after = (await page.evaluate(snap))[c.probe];
|
|
826
|
+
await page.mouse.move(0, 0);
|
|
827
|
+
await wait(150);
|
|
828
|
+
const changed = diffStyles(before, after);
|
|
829
|
+
if (Object.keys(changed).length) {
|
|
830
|
+
out.push({
|
|
831
|
+
label: c.cls ? `${c.tag}.${c.cls}` : c.tag,
|
|
832
|
+
tag: c.tag, cls: c.cls, transition: c.transition, changed,
|
|
833
|
+
});
|
|
834
|
+
}
|
|
835
|
+
} catch { /* fail-open: 요소 하나가 스윕 전체를 죽이면 안 된다 */ }
|
|
836
|
+
}
|
|
837
|
+
await page.evaluate('window.scrollTo(0, 0)');
|
|
838
|
+
await wait(200);
|
|
839
|
+
return out;
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
// ── In-view entrance animations (fade-up, slide-in) ──
|
|
843
|
+
// 1회성 등장 애니메이션은 lazy-load 스크롤에서 이미 발화했으므로 페이지를 새로 로드해 관찰한다.
|
|
844
|
+
async function sweepInView(page) {
|
|
845
|
+
const out = [];
|
|
846
|
+
await page.goto(page.url(), { waitUntil: 'networkidle2', timeout: 90000 });
|
|
847
|
+
await wait(800);
|
|
848
|
+
const candidates = await page.evaluate(`(${TAG_INVIEW})()`);
|
|
849
|
+
if (!candidates.length) return out;
|
|
850
|
+
const snap = `(${SNAP_ATTR})('data-clone-inview', ${JSON.stringify(INVIEW_PROPS)})`;
|
|
851
|
+
const before = await page.evaluate(snap);
|
|
852
|
+
for (const c of candidates) {
|
|
853
|
+
try {
|
|
854
|
+
await page.evaluate(`document.querySelector('[data-clone-inview="${c.probe}"]')?.scrollIntoView({ block: 'center' })`);
|
|
855
|
+
await wait(600);
|
|
856
|
+
} catch { /* fail-open */ }
|
|
857
|
+
}
|
|
858
|
+
const after = await page.evaluate(snap);
|
|
859
|
+
await page.evaluate('window.scrollTo(0, 0)');
|
|
860
|
+
await wait(300);
|
|
861
|
+
for (const c of candidates) {
|
|
862
|
+
const changed = diffStyles(before[c.probe], after[c.probe]);
|
|
863
|
+
if (Object.keys(changed).length) {
|
|
864
|
+
out.push({
|
|
865
|
+
label: c.cls ? `${c.tag}.${c.cls}` : c.tag,
|
|
866
|
+
tag: c.tag, cls: c.cls, triggerY: c.top, changed,
|
|
867
|
+
});
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
await page.evaluate('document.querySelectorAll("[data-clone-inview]").forEach((e) => e.removeAttribute("data-clone-inview"))');
|
|
871
|
+
return out;
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
async function runInteractionSweep(page) {
|
|
875
|
+
const behaviors = { scroll: [], interactive: [], hover: [], inview: [], timeDriven: [], scrollLib: null };
|
|
876
|
+
|
|
877
|
+
behaviors.scroll = await sweepScrollState(page);
|
|
878
|
+
behaviors.interactive = await sweepTabGroups(page);
|
|
879
|
+
behaviors.hover = await sweepHover(page);
|
|
880
|
+
// 무입력 3초 관찰 — 캐러셀/자동 사이클 후보
|
|
881
|
+
try { behaviors.timeDriven = await page.evaluate(`(${OBSERVE_MUTATIONS})(3000)`); } catch { /* fail-open */ }
|
|
882
|
+
try { behaviors.scrollLib = await page.evaluate(`(${DETECT_SCROLL_LIB})()`); } catch { /* fail-open */ }
|
|
704
883
|
|
|
705
884
|
// Clean up probe attributes BEFORE static extraction so they don't pollute output.
|
|
706
885
|
await page.evaluate(
|
|
707
|
-
'document.querySelectorAll("[data-clone-probe],[data-clone-tab]").forEach((e) => { e.removeAttribute("data-clone-probe"); e.removeAttribute("data-clone-tab"); })'
|
|
886
|
+
'document.querySelectorAll("[data-clone-probe],[data-clone-tab],[data-clone-hover]").forEach((e) => { e.removeAttribute("data-clone-probe"); e.removeAttribute("data-clone-tab"); e.removeAttribute("data-clone-hover"); })'
|
|
708
887
|
);
|
|
888
|
+
|
|
889
|
+
// 마지막: in-view 스윕은 리로드를 동반하므로 다른 스윕 뒤에 실행한다.
|
|
890
|
+
behaviors.inview = await sweepInView(page);
|
|
891
|
+
// 리로드로 lazy-load 상태가 초기화됐으니 정적 추출 전에 복원한다.
|
|
892
|
+
await scrollToBottom(page);
|
|
709
893
|
return behaviors;
|
|
710
894
|
}
|
|
711
895
|
|
|
896
|
+
// In-page: favicon / OG image / webmanifest URLs (Foundation 단계 — public/seo/ 배선용)
|
|
897
|
+
const SEO_EXTRACT = `(function () {
|
|
898
|
+
const abs = (u) => { try { return new URL(u, location.href).href; } catch { return null; } };
|
|
899
|
+
const icons = Array.from(document.querySelectorAll(
|
|
900
|
+
'link[rel*="icon" i], link[rel="apple-touch-icon"], link[rel="manifest"]'
|
|
901
|
+
)).map((l) => abs(l.getAttribute('href'))).filter(Boolean);
|
|
902
|
+
const og = Array.from(document.querySelectorAll(
|
|
903
|
+
'meta[property="og:image"], meta[name="twitter:image"]'
|
|
904
|
+
)).map((m) => abs(m.getAttribute('content'))).filter(Boolean);
|
|
905
|
+
return Array.from(new Set(icons.concat(og)));
|
|
906
|
+
})`;
|
|
907
|
+
|
|
712
908
|
// HTML sanitization: strip scripts/analytics before saving
|
|
713
909
|
function sanitizeHtml(html) {
|
|
714
910
|
return html
|
|
@@ -739,8 +935,10 @@ async function capture({ url, opts }) {
|
|
|
739
935
|
const assetsDir = path.join(opts.out, 'assets');
|
|
740
936
|
const imagesDir = path.join(assetsDir, 'images');
|
|
741
937
|
const fontsDir = path.join(assetsDir, 'fonts');
|
|
938
|
+
const seoDir = path.join(assetsDir, 'seo');
|
|
742
939
|
fs.mkdirSync(imagesDir, { recursive: true });
|
|
743
940
|
fs.mkdirSync(fontsDir, { recursive: true });
|
|
941
|
+
fs.mkdirSync(seoDir, { recursive: true });
|
|
744
942
|
|
|
745
943
|
console.log(`[clone-extract] ${opts.bp || ''} ${viewport.width}x${viewport.height}@${viewport.deviceScaleFactor} ${url}`);
|
|
746
944
|
|
|
@@ -775,7 +973,12 @@ async function capture({ url, opts }) {
|
|
|
775
973
|
if (opts.interact) {
|
|
776
974
|
try {
|
|
777
975
|
behaviors = await runInteractionSweep(page);
|
|
778
|
-
console.log(
|
|
976
|
+
console.log(
|
|
977
|
+
`[clone-extract] interaction sweep: ${behaviors.scroll.length} scroll-state, ` +
|
|
978
|
+
`${behaviors.interactive.length} tab-group(s), ${behaviors.hover.length} hover, ` +
|
|
979
|
+
`${behaviors.inview.length} in-view, ${behaviors.timeDriven.length} time-driven` +
|
|
980
|
+
`${behaviors.scrollLib ? `, scroll-lib: ${behaviors.scrollLib.name}` : ''}`
|
|
981
|
+
);
|
|
779
982
|
} catch (e) {
|
|
780
983
|
console.log(`[clone-extract] interaction sweep skipped: ${e.message}`);
|
|
781
984
|
}
|
|
@@ -805,9 +1008,14 @@ async function capture({ url, opts }) {
|
|
|
805
1008
|
if (sorted[1]) fontDownloadSet.add(sorted[1].url);
|
|
806
1009
|
}
|
|
807
1010
|
|
|
808
|
-
|
|
1011
|
+
// Favicon / OG / webmanifest — Foundation 단계에서 public/seo/ 로 배선한다
|
|
1012
|
+
let seoUrls = [];
|
|
1013
|
+
try { seoUrls = await page.evaluate(`(${SEO_EXTRACT})()`); } catch { /* fail-open */ }
|
|
1014
|
+
|
|
1015
|
+
console.log(`[clone-extract] downloading ${extracted.assets.images.length} images, ${fontDownloadSet.size} fonts (filtered from ${extracted.assets.fonts.length}), ${seoUrls.length} seo assets`);
|
|
809
1016
|
const imageMap = await downloadAssets(extracted.assets.images, imagesDir, 8);
|
|
810
1017
|
const fontMap = await downloadAssets(Array.from(fontDownloadSet), fontsDir, 4);
|
|
1018
|
+
const seoMap = await downloadAssets(seoUrls, seoDir, 4);
|
|
811
1019
|
|
|
812
1020
|
const assetMap = {};
|
|
813
1021
|
for (const [u, info] of Object.entries(imageMap)) {
|
|
@@ -820,6 +1028,11 @@ async function capture({ url, opts }) {
|
|
|
820
1028
|
? { local: `assets/fonts/${info.local}`, status: 'ok', bytes: info.bytes, kind: 'font' }
|
|
821
1029
|
: { ...info, kind: 'font' };
|
|
822
1030
|
}
|
|
1031
|
+
for (const [u, info] of Object.entries(seoMap)) {
|
|
1032
|
+
assetMap[u] = info.status === 'ok'
|
|
1033
|
+
? { local: `assets/seo/${info.local}`, status: 'ok', bytes: info.bytes, kind: 'seo' }
|
|
1034
|
+
: { ...info, kind: 'seo' };
|
|
1035
|
+
}
|
|
823
1036
|
|
|
824
1037
|
// Rewrite HTML — replace remote URLs with local paths
|
|
825
1038
|
let html = sanitizeHtml(extracted.html);
|
|
@@ -896,8 +1109,9 @@ async function capture({ url, opts }) {
|
|
|
896
1109
|
);
|
|
897
1110
|
fs.writeFileSync(path.join(opts.out, 'asset-map.json'), JSON.stringify(assetMap, null, 2));
|
|
898
1111
|
if (behaviors) {
|
|
899
|
-
// Rewrite any remote asset URLs captured in
|
|
900
|
-
|
|
1112
|
+
// Rewrite any remote asset URLs captured in behavior diffs (scroll/hover/inview).
|
|
1113
|
+
const diffed = [...behaviors.scroll, ...(behaviors.hover || []), ...(behaviors.inview || [])];
|
|
1114
|
+
for (const s of diffed) {
|
|
901
1115
|
for (const ch of Object.values(s.changed)) {
|
|
902
1116
|
if (typeof ch.from === 'string') ch.from = rewriteCssValue(ch.from);
|
|
903
1117
|
if (typeof ch.to === 'string') ch.to = rewriteCssValue(ch.to);
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* clone-merge-responsive.js — MO/PC per-BP SCSS → mobile-first responsive merge
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* node clone-merge-responsive.js --mo=<styles-dir> --pc=<styles-dir> --out=<dir> [--breakpoint=1024]
|
|
8
|
+
*
|
|
9
|
+
* Why this exists (clone Phase 3C):
|
|
10
|
+
* Phase 3A/3B produce two fixed-viewport SCSS trees (styles/{feature}/mo, /pc).
|
|
11
|
+
* This merges them mobile-first: MO declarations become the base, and only the
|
|
12
|
+
* declarations where PC differs go into a single @media (min-width: <bp>) block.
|
|
13
|
+
* Deterministic text merge — no value invention. Post-merge correctness is judged
|
|
14
|
+
* by Phase 5 (pixel + computed-CSS verification at BOTH viewports).
|
|
15
|
+
*
|
|
16
|
+
* Fail-open:
|
|
17
|
+
* - PC-only selectors → whole rule inside the media block
|
|
18
|
+
* - MO-only selectors → base as-is (reported)
|
|
19
|
+
* - unparseable/missing files → reported and skipped, never a hard abort
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import fs from 'fs';
|
|
23
|
+
import path from 'path';
|
|
24
|
+
import { parseScss, normalize } from './clone-validate.js';
|
|
25
|
+
|
|
26
|
+
// ─── CLI ────────────────────────────────────────────────────────────
|
|
27
|
+
function parseArgs(argv) {
|
|
28
|
+
const opts = { breakpoint: 1024 };
|
|
29
|
+
for (const a of argv.slice(2)) {
|
|
30
|
+
if (a.startsWith('--mo=')) opts.mo = a.slice(5);
|
|
31
|
+
else if (a.startsWith('--pc=')) opts.pc = a.slice(5);
|
|
32
|
+
else if (a.startsWith('--out=')) opts.out = a.slice(6);
|
|
33
|
+
else if (a.startsWith('--breakpoint=')) opts.breakpoint = Number(a.slice(13)) || 1024;
|
|
34
|
+
}
|
|
35
|
+
return opts;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// ─── Merge core (pure — exported for tests) ─────────────────────────
|
|
39
|
+
// moRules/pcRules: Map<selector, {prop: value}> (parseScss output)
|
|
40
|
+
// → { base: Map, media: Map, stats }
|
|
41
|
+
function mergeRules(moRules, pcRules) {
|
|
42
|
+
const base = new Map();
|
|
43
|
+
const media = new Map();
|
|
44
|
+
const stats = { selectors: 0, moOnly: 0, pcOnly: 0, overrides: 0, shared: 0 };
|
|
45
|
+
|
|
46
|
+
const selectors = new Set([...moRules.keys(), ...pcRules.keys()]);
|
|
47
|
+
for (const sel of selectors) {
|
|
48
|
+
stats.selectors++;
|
|
49
|
+
const mo = moRules.get(sel);
|
|
50
|
+
const pc = pcRules.get(sel);
|
|
51
|
+
if (mo && Object.keys(mo).length) base.set(sel, mo);
|
|
52
|
+
|
|
53
|
+
if (!pc || !Object.keys(pc).length) { if (mo) stats.moOnly++; continue; }
|
|
54
|
+
if (!mo || !Object.keys(mo).length) {
|
|
55
|
+
// PC 전용 셀렉터 — 데스크탑에서만 존재하는 노드
|
|
56
|
+
media.set(sel, pc);
|
|
57
|
+
stats.pcOnly++;
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const diff = {};
|
|
62
|
+
for (const [prop, val] of Object.entries(pc)) {
|
|
63
|
+
if (mo[prop] === undefined || normalize(mo[prop]) !== normalize(val)) diff[prop] = val;
|
|
64
|
+
}
|
|
65
|
+
if (Object.keys(diff).length) { media.set(sel, diff); stats.overrides++; }
|
|
66
|
+
else stats.shared++;
|
|
67
|
+
}
|
|
68
|
+
return { base, media, stats };
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function emitRules(rules, indent) {
|
|
72
|
+
const out = [];
|
|
73
|
+
for (const [sel, decls] of rules) {
|
|
74
|
+
const body = Object.entries(decls).map(([p, v]) => `${indent} ${p}: ${v};`).join('\n');
|
|
75
|
+
if (!body) continue;
|
|
76
|
+
out.push(`${indent}${sel} {\n${body}\n${indent}}`);
|
|
77
|
+
}
|
|
78
|
+
return out.join('\n\n');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Merged partial: MO base rules + one @media (min-width) block with PC diffs.
|
|
82
|
+
function emitMerged(moRules, pcRules, breakpoint, header) {
|
|
83
|
+
const { base, media, stats } = mergeRules(moRules, pcRules);
|
|
84
|
+
const parts = [header, '', emitRules(base, '')];
|
|
85
|
+
if (media.size) {
|
|
86
|
+
parts.push('');
|
|
87
|
+
parts.push(`@media (min-width: ${breakpoint}px) {`);
|
|
88
|
+
parts.push(emitRules(media, ' '));
|
|
89
|
+
parts.push('}');
|
|
90
|
+
}
|
|
91
|
+
return { scss: parts.filter((p) => p !== null).join('\n') + '\n', stats };
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// ─── File-level orchestration ───────────────────────────────────────
|
|
95
|
+
function readScssRules(file) {
|
|
96
|
+
if (!fs.existsSync(file)) return null;
|
|
97
|
+
try { return parseScss(fs.readFileSync(file, 'utf8')); }
|
|
98
|
+
catch (e) {
|
|
99
|
+
console.error(`[clone-merge] parse skipped (${e.message}): ${file}`);
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function listSections(dir) {
|
|
105
|
+
const d = path.join(dir, 'sections');
|
|
106
|
+
if (!fs.existsSync(d)) return [];
|
|
107
|
+
return fs.readdirSync(d).filter((f) => f.startsWith('_') && f.endsWith('.scss'));
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function mergeTokens(moDir, pcDir, outDir, breakpoint) {
|
|
111
|
+
const mo = readScssRules(path.join(moDir, '_tokens.scss')) || new Map();
|
|
112
|
+
const pc = readScssRules(path.join(pcDir, '_tokens.scss')) || new Map();
|
|
113
|
+
const { scss } = emitMerged(mo, pc, breakpoint, '// Auto-merged by clone-merge-responsive.js (mobile-first)');
|
|
114
|
+
fs.writeFileSync(path.join(outDir, '_tokens.scss'), scss);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function copyIfExists(src, dst) {
|
|
118
|
+
if (fs.existsSync(src)) fs.copyFileSync(src, dst);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function mergeClassPlans(moDir, pcDir, outDir) {
|
|
122
|
+
const read = (d) => {
|
|
123
|
+
const f = path.join(d, 'class-plan.json');
|
|
124
|
+
return fs.existsSync(f) ? JSON.parse(fs.readFileSync(f, 'utf8')) : {};
|
|
125
|
+
};
|
|
126
|
+
// MO 우선 — 동일 노드 id가 다른 클래스면 MO가 base이므로 MO를 채택
|
|
127
|
+
const merged = { ...read(pcDir), ...read(moDir) };
|
|
128
|
+
fs.writeFileSync(path.join(outDir, 'class-plan.json'), JSON.stringify(merged, null, 2));
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function main() {
|
|
132
|
+
const opts = parseArgs(process.argv);
|
|
133
|
+
if (!opts.mo || !opts.pc || !opts.out) {
|
|
134
|
+
console.error('Usage: node clone-merge-responsive.js --mo=<styles-dir> --pc=<styles-dir> --out=<dir> [--breakpoint=1024]');
|
|
135
|
+
process.exit(2);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
fs.mkdirSync(path.join(opts.out, 'sections'), { recursive: true });
|
|
139
|
+
|
|
140
|
+
const files = [...new Set([...listSections(opts.mo), ...listSections(opts.pc)])].sort();
|
|
141
|
+
const totals = { selectors: 0, moOnly: 0, pcOnly: 0, overrides: 0, shared: 0 };
|
|
142
|
+
const merged = [];
|
|
143
|
+
|
|
144
|
+
for (const f of files) {
|
|
145
|
+
const mo = readScssRules(path.join(opts.mo, 'sections', f)) || new Map();
|
|
146
|
+
const pc = readScssRules(path.join(opts.pc, 'sections', f)) || new Map();
|
|
147
|
+
if (!mo.size && !pc.size) { console.error(`[clone-merge] empty on both BPs, skipped: ${f}`); continue; }
|
|
148
|
+
const { scss, stats } = emitMerged(mo, pc, opts.breakpoint, `// Section: ${f} — merged mobile-first`);
|
|
149
|
+
fs.writeFileSync(path.join(opts.out, 'sections', f), scss);
|
|
150
|
+
for (const k of Object.keys(totals)) totals[k] += stats[k];
|
|
151
|
+
merged.push(f);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
mergeTokens(opts.mo, opts.pc, opts.out, opts.breakpoint);
|
|
155
|
+
copyIfExists(path.join(opts.mo, '_base.scss'), path.join(opts.out, '_base.scss'));
|
|
156
|
+
copyIfExists(path.join(opts.mo, '_shared.scss'), path.join(opts.out, '_shared.scss'));
|
|
157
|
+
mergeClassPlans(opts.mo, opts.pc, opts.out);
|
|
158
|
+
|
|
159
|
+
const index = [
|
|
160
|
+
'// Auto-merged by clone-merge-responsive.js — mobile-first responsive',
|
|
161
|
+
'',
|
|
162
|
+
`@use './tokens';`,
|
|
163
|
+
`@use './base';`,
|
|
164
|
+
`@use './shared';`,
|
|
165
|
+
...merged.map((f) => `@use './sections/${f.replace(/^_|\.scss$/g, '')}';`),
|
|
166
|
+
].join('\n') + '\n';
|
|
167
|
+
fs.writeFileSync(path.join(opts.out, 'index.scss'), index);
|
|
168
|
+
|
|
169
|
+
console.log(`[clone-merge] done → ${opts.out}`);
|
|
170
|
+
console.log(` sections: ${merged.length}, selectors: ${totals.selectors} (shared ${totals.shared}, overrides ${totals.overrides}, mo-only ${totals.moOnly}, pc-only ${totals.pcOnly})`);
|
|
171
|
+
console.log(` breakpoint: @media (min-width: ${opts.breakpoint}px)`);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const isMain = process.argv[1] && process.argv[1].replace(/\\/g, '/').endsWith('clone-merge-responsive.js');
|
|
175
|
+
if (isMain) {
|
|
176
|
+
try { main(); }
|
|
177
|
+
catch (e) {
|
|
178
|
+
console.error(`[clone-merge] FAIL: ${e.message}`);
|
|
179
|
+
if (process.env.DEBUG) console.error(e.stack);
|
|
180
|
+
process.exit(1);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export { mergeRules, emitMerged };
|
|
@@ -28,6 +28,7 @@ function parseArgs(argv) {
|
|
|
28
28
|
else if (a.startsWith('--section=')) opts.section = a.slice(10);
|
|
29
29
|
else if (a.startsWith('--feature=')) opts.feature = a.slice(10);
|
|
30
30
|
else if (a.startsWith('--behaviors=')) opts.behaviors = a.slice(12);
|
|
31
|
+
else if (a === '--real-content') opts.realContent = true;
|
|
31
32
|
}
|
|
32
33
|
return { sectionsPath, opts };
|
|
33
34
|
}
|
|
@@ -101,20 +102,28 @@ function sectionHasNode(section, tag, cls) {
|
|
|
101
102
|
return (section.children || []).some(hit);
|
|
102
103
|
}
|
|
103
104
|
|
|
105
|
+
function diffLines(changed) {
|
|
106
|
+
return Object.entries(changed)
|
|
107
|
+
.map(([k, v]) => ` - ${k}: \`${v.from}\` → \`${v.to}\``).join('\n');
|
|
108
|
+
}
|
|
109
|
+
|
|
104
110
|
function behaviorsBlock(section, behaviors) {
|
|
105
111
|
if (!behaviors) return null;
|
|
106
|
-
const
|
|
112
|
+
const inSection = (list) => (list || []).filter((b) => sectionHasNode(section, b.tag, b.cls));
|
|
113
|
+
const scroll = inSection(behaviors.scroll);
|
|
114
|
+
const hover = inSection(behaviors.hover);
|
|
115
|
+
const inview = inSection(behaviors.inview);
|
|
116
|
+
const timed = inSection(behaviors.timeDriven);
|
|
107
117
|
// Tab groups aren't tag-keyed; attach to any section that contains a [role=tab]-ish node.
|
|
108
118
|
const tabs = (behaviors.interactive || []).filter(() =>
|
|
109
119
|
sectionHasNode(section, 'button') || sectionHasNode(section, 'li') || sectionHasNode(section, 'a'),
|
|
110
120
|
);
|
|
111
|
-
|
|
121
|
+
const lib = behaviors.scrollLib;
|
|
122
|
+
if (!scroll.length && !tabs.length && !hover.length && !inview.length && !timed.length && !lib) return null;
|
|
112
123
|
|
|
113
124
|
const lines = [];
|
|
114
125
|
for (const b of scroll) {
|
|
115
|
-
|
|
116
|
-
.map(([k, v]) => ` - ${k}: \`${v.from}\` → \`${v.to}\``).join('\n');
|
|
117
|
-
lines.push(`- **Scroll-triggered** on \`${b.label}\` (past ~${b.triggerScrollY}px scroll):\n${diffs}`);
|
|
126
|
+
lines.push(`- **Scroll-triggered** on \`${b.label}\` (past ~${b.triggerScrollY}px scroll):\n${diffLines(b.changed)}`);
|
|
118
127
|
}
|
|
119
128
|
for (const t of tabs) {
|
|
120
129
|
const labels = (t.tabLabels || []).map((l) => `"${l}"`).join(', ') || '(unlabeled)';
|
|
@@ -123,6 +132,19 @@ function behaviorsBlock(section, behaviors) {
|
|
|
123
132
|
: 'no content swap detected (styling-only tabs)';
|
|
124
133
|
lines.push(`- **Tab group** ×${t.count} [${labels}]: ${swap}`);
|
|
125
134
|
}
|
|
135
|
+
for (const b of hover) {
|
|
136
|
+
const tr = b.transition && b.transition !== 'all 0s ease 0s' ? ` (transition: \`${b.transition}\`)` : '';
|
|
137
|
+
lines.push(`- **Hover** on \`${b.label}\`${tr}:\n${diffLines(b.changed)}`);
|
|
138
|
+
}
|
|
139
|
+
for (const b of inview) {
|
|
140
|
+
lines.push(`- **In-view entrance** on \`${b.label}\` (enters at ~${b.triggerY}px):\n${diffLines(b.changed)}`);
|
|
141
|
+
}
|
|
142
|
+
for (const b of timed) {
|
|
143
|
+
lines.push(`- **Time-driven** \`${b.label}\` — ${b.mutations} mutations/3s [${(b.kinds || []).join(', ')}] → carousel/auto-cycle candidate`);
|
|
144
|
+
}
|
|
145
|
+
if (lib) {
|
|
146
|
+
lines.push(`- **Smooth-scroll library (page-level):** ${lib.name} (evidence: \`${lib.evidence}\`) → wire in globals, not per-section`);
|
|
147
|
+
}
|
|
126
148
|
return lines.join('\n');
|
|
127
149
|
}
|
|
128
150
|
|
|
@@ -171,7 +193,9 @@ ${cssBlock(section.css)}
|
|
|
171
193
|
## Assets (local paths only — never hotlink)
|
|
172
194
|
${assetsBlock(section.images)}
|
|
173
195
|
|
|
174
|
-
## Text content
|
|
196
|
+
## Text content ${meta.realContent
|
|
197
|
+
? '(verbatim — user confirmed rights to reuse this copy)'
|
|
198
|
+
: '(replace copyrighted copy with placeholders)'}
|
|
175
199
|
${textBlock}
|
|
176
200
|
|
|
177
201
|
## Component candidates
|
|
@@ -179,7 +203,7 @@ ${componentsBlock(section.components)}
|
|
|
179
203
|
|
|
180
204
|
## Build checklist
|
|
181
205
|
- [ ] HTML semantics + final tags chosen
|
|
182
|
-
- [ ] SCSS
|
|
206
|
+
- [ ] SCSS started from the clone-to-scss.js draft — value edits only with evidence cited from computed.json/states.json/behaviors.json (no eyeballing); clone-validate.js is the judge
|
|
183
207
|
- [ ] Every state above implemented
|
|
184
208
|
- [ ] Interaction model confirmed on live site & wired
|
|
185
209
|
- [ ] All assets local (public/images/${meta.feature}/) — no hotlinks
|
|
@@ -196,6 +220,7 @@ function main() {
|
|
|
196
220
|
url: data.meta && data.meta.url,
|
|
197
221
|
viewport: data.meta && data.meta.viewport,
|
|
198
222
|
bp: opts.section ? (data.meta && data.meta.bp) : (data.meta && data.meta.bp) || '?',
|
|
223
|
+
realContent: !!opts.realContent,
|
|
199
224
|
};
|
|
200
225
|
// behaviors.json (active interaction sweep) lives next to the source computed.json.
|
|
201
226
|
const behaviorsPath = opts.behaviors || path.join(path.dirname(sectionsPath), 'behaviors.json');
|
|
@@ -223,7 +248,7 @@ function main() {
|
|
|
223
248
|
const isMain = process.argv[1] && process.argv[1].replace(/\\/g, '/').endsWith('clone-spec.js');
|
|
224
249
|
if (isMain) {
|
|
225
250
|
if (!sectionsPath || !opts.out) {
|
|
226
|
-
console.error('Usage: node clone-spec.js <sections.json> --out=<dir> [--section=Name] [--feature=name] [--behaviors=path]');
|
|
251
|
+
console.error('Usage: node clone-spec.js <sections.json> --out=<dir> [--section=Name] [--feature=name] [--behaviors=path] [--real-content]');
|
|
227
252
|
process.exit(1);
|
|
228
253
|
}
|
|
229
254
|
try { main(); }
|
|
@@ -34,10 +34,6 @@ function parseArgs(argv) {
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
const { stylesDir, sectionsPath, opts } = parseArgs(process.argv);
|
|
37
|
-
if (!stylesDir || !sectionsPath) {
|
|
38
|
-
console.error('Usage: node clone-validate.js <styles-dir> <sections.json> [--section=<name>]');
|
|
39
|
-
process.exit(2);
|
|
40
|
-
}
|
|
41
37
|
|
|
42
38
|
// ─── Minimal SCSS parser ────────────────────────────────────────────
|
|
43
39
|
// Strips comments, expands `&::pseudo` (one level), flattens nested rules.
|
|
@@ -272,9 +268,19 @@ function main() {
|
|
|
272
268
|
process.exit(0);
|
|
273
269
|
}
|
|
274
270
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
if (
|
|
279
|
-
|
|
271
|
+
// isMain 가드 — clone-merge-responsive.js가 parseScss를 import할 때 main()이 돌면 안 된다
|
|
272
|
+
const isMain = process.argv[1] && process.argv[1].replace(/\\/g, '/').endsWith('clone-validate.js');
|
|
273
|
+
if (isMain) {
|
|
274
|
+
if (!stylesDir || !sectionsPath) {
|
|
275
|
+
console.error('Usage: node clone-validate.js <styles-dir> <sections.json> [--section=<name>]');
|
|
276
|
+
process.exit(2);
|
|
277
|
+
}
|
|
278
|
+
try { main(); }
|
|
279
|
+
catch (e) {
|
|
280
|
+
console.error(`[clone-validate] FAIL: ${e.message}`);
|
|
281
|
+
if (process.env.DEBUG) console.error(e.stack);
|
|
282
|
+
process.exit(2);
|
|
283
|
+
}
|
|
280
284
|
}
|
|
285
|
+
|
|
286
|
+
export { parseScss, normalize, compareValue };
|