@su-record/vibe 3.0.0 → 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/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/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/package.json +5 -2
- package/skills/clone/SKILL.md +132 -55
- package/skills/vibe.clone/SKILL.md +39 -19
- 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
|
@@ -1,78 +1,3 @@
|
|
|
1
|
-
[2026-
|
|
2
|
-
[2026-
|
|
3
|
-
[2026-
|
|
4
|
-
[2026-06-10T07:48:46.450Z] rm -rf /
|
|
5
|
-
[2026-06-10T07:48:46.533Z] ls -la
|
|
6
|
-
[2026-06-10T07:48:46.615Z] rm -rf src/infra/lib/autonomy/
|
|
7
|
-
[2026-06-10T23:31:11.461Z] rm -rf /
|
|
8
|
-
[2026-06-10T23:31:11.532Z] ls -la
|
|
9
|
-
[2026-06-10T23:31:11.610Z] rm -rf src/infra/lib/autonomy/
|
|
10
|
-
[2026-06-11T00:54:20.384Z] rm -rf /
|
|
11
|
-
[2026-06-11T00:54:20.472Z] ls -la
|
|
12
|
-
[2026-06-11T00:54:20.544Z] rm -rf src/infra/lib/autonomy/
|
|
13
|
-
[2026-06-11T00:55:23.164Z] rm -rf /
|
|
14
|
-
[2026-06-11T00:55:23.258Z] ls -la
|
|
15
|
-
[2026-06-11T00:55:23.351Z] rm -rf src/infra/lib/autonomy/
|
|
16
|
-
[2026-06-11T01:04:45.163Z] rm -rf /
|
|
17
|
-
[2026-06-11T01:04:45.246Z] ls -la
|
|
18
|
-
[2026-06-11T01:04:45.326Z] rm -rf src/infra/lib/autonomy/
|
|
19
|
-
[2026-06-11T01:05:19.173Z] rm -rf /
|
|
20
|
-
[2026-06-11T01:05:19.280Z] ls -la
|
|
21
|
-
[2026-06-11T01:05:19.346Z] rm -rf src/infra/lib/autonomy/
|
|
22
|
-
[2026-06-11T01:20:55.438Z] rm -rf /
|
|
23
|
-
[2026-06-11T01:20:55.530Z] ls -la
|
|
24
|
-
[2026-06-11T01:20:55.622Z] rm -rf src/infra/lib/autonomy/
|
|
25
|
-
[2026-06-11T01:21:25.176Z] rm -rf /
|
|
26
|
-
[2026-06-11T01:21:25.271Z] ls -la
|
|
27
|
-
[2026-06-11T01:21:25.380Z] rm -rf src/infra/lib/evolution/
|
|
28
|
-
[2026-06-11T01:21:40.631Z] rm -rf /
|
|
29
|
-
[2026-06-11T01:21:40.715Z] ls -la
|
|
30
|
-
[2026-06-11T01:21:40.789Z] rm -rf src/infra/lib/evolution/
|
|
31
|
-
[2026-06-11T01:21:58.442Z] rm -rf /
|
|
32
|
-
[2026-06-11T01:21:58.547Z] ls -la
|
|
33
|
-
[2026-06-11T01:21:58.640Z] rm -rf src/infra/lib/evolution/
|
|
34
|
-
[2026-06-11T01:22:15.393Z] rm -rf /
|
|
35
|
-
[2026-06-11T01:22:15.536Z] ls -la
|
|
36
|
-
[2026-06-11T01:22:15.628Z] rm -rf src/infra/lib/evolution/
|
|
37
|
-
[2026-06-11T01:30:46.209Z] rm -rf /
|
|
38
|
-
[2026-06-11T01:30:46.279Z] ls -la
|
|
39
|
-
[2026-06-11T01:30:46.366Z] rm -rf src/infra/lib/evolution/
|
|
40
|
-
[2026-06-11T05:39:24.632Z] rm -rf /
|
|
41
|
-
[2026-06-11T05:39:24.707Z] ls -la
|
|
42
|
-
[2026-06-11T05:39:24.788Z] rm -rf src/infra/lib/evolution/
|
|
43
|
-
[2026-06-11T05:42:56.571Z] rm -rf /
|
|
44
|
-
[2026-06-11T05:42:56.647Z] ls -la
|
|
45
|
-
[2026-06-11T05:42:56.719Z] rm -rf src/infra/lib/evolution/
|
|
46
|
-
[2026-06-11T05:43:10.797Z] rm -rf /
|
|
47
|
-
[2026-06-11T05:43:10.863Z] ls -la
|
|
48
|
-
[2026-06-11T05:43:10.937Z] rm -rf src/infra/lib/evolution/
|
|
49
|
-
[2026-06-11T05:43:26.675Z] rm -rf /
|
|
50
|
-
[2026-06-11T05:43:26.735Z] ls -la
|
|
51
|
-
[2026-06-11T05:43:26.812Z] rm -rf src/infra/lib/evolution/
|
|
52
|
-
[2026-06-11T06:34:26.211Z] rm -rf /
|
|
53
|
-
[2026-06-11T06:34:26.309Z] ls -la
|
|
54
|
-
[2026-06-11T06:34:26.395Z] rm -rf src/infra/lib/evolution/
|
|
55
|
-
[2026-06-11T06:34:42.990Z] rm -rf /
|
|
56
|
-
[2026-06-11T06:34:43.071Z] ls -la
|
|
57
|
-
[2026-06-11T06:34:43.148Z] rm -rf src/infra/lib/evolution/
|
|
58
|
-
[2026-06-11T06:36:18.231Z] rm -rf /
|
|
59
|
-
[2026-06-11T06:36:18.309Z] ls -la
|
|
60
|
-
[2026-06-11T06:36:18.387Z] rm -rf src/infra/lib/evolution/
|
|
61
|
-
[2026-06-11T07:31:46.181Z] rm -rf /
|
|
62
|
-
[2026-06-11T07:31:46.265Z] ls -la
|
|
63
|
-
[2026-06-11T07:31:46.343Z] rm -rf src/infra/lib/evolution/
|
|
64
|
-
[2026-06-11T07:47:25.041Z] rm -rf /
|
|
65
|
-
[2026-06-11T07:47:25.127Z] ls -la
|
|
66
|
-
[2026-06-11T07:47:25.229Z] rm -rf src/infra/lib/evolution/
|
|
67
|
-
[2026-06-11T07:52:00.840Z] rm -rf /
|
|
68
|
-
[2026-06-11T07:52:00.919Z] ls -la
|
|
69
|
-
[2026-06-11T07:52:00.992Z] rm -rf src/infra/lib/evolution/
|
|
70
|
-
[2026-06-11T07:52:09.088Z] rm -rf /
|
|
71
|
-
[2026-06-11T07:52:09.162Z] ls -la
|
|
72
|
-
[2026-06-11T07:52:09.229Z] rm -rf src/infra/lib/evolution/
|
|
73
|
-
[2026-06-11T07:52:48.347Z] rm -rf /
|
|
74
|
-
[2026-06-11T07:52:48.431Z] ls -la
|
|
75
|
-
[2026-06-11T07:52:48.509Z] rm -rf src/infra/lib/evolution/
|
|
76
|
-
[2026-06-11T07:53:35.344Z] rm -rf /
|
|
77
|
-
[2026-06-11T07:53:35.434Z] ls -la
|
|
78
|
-
[2026-06-11T07:53:35.516Z] rm -rf src/infra/lib/evolution/
|
|
1
|
+
[2026-07-02T09:11:20.705Z] rm -rf /
|
|
2
|
+
[2026-07-02T09:11:20.800Z] ls -la
|
|
3
|
+
[2026-07-02T09:11:20.907Z] rm -rf src/infra/lib/evolution/
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -53,4 +53,68 @@ describe('behavior → section attachment', () => {
|
|
|
53
53
|
const footer = { name: 'Footer', children: [{ tag: 'p', classes: '', children: [] }] };
|
|
54
54
|
expect(behaviorsBlock(footer, behaviors)).toBeNull();
|
|
55
55
|
});
|
|
56
|
+
|
|
57
|
+
it('renders hover / in-view / time-driven / scroll-lib behavior kinds', () => {
|
|
58
|
+
const behaviors = {
|
|
59
|
+
scroll: [],
|
|
60
|
+
interactive: [],
|
|
61
|
+
hover: [{ label: 'a.cta', tag: 'a', cls: 'cta', transition: 'all 0.3s ease 0s', changed: { 'background-color': { from: 'rgb(0, 0, 0)', to: 'rgb(255, 0, 0)' } } }],
|
|
62
|
+
inview: [{ label: 'div.fade', tag: 'div', cls: 'fade', triggerY: 1400, changed: { opacity: { from: '0', to: '1' } } }],
|
|
63
|
+
timeDriven: [{ label: 'div.slide', tag: 'div', cls: 'slide', mutations: 12, kinds: ['class'] }],
|
|
64
|
+
scrollLib: { name: 'lenis', evidence: 'html.lenis' },
|
|
65
|
+
};
|
|
66
|
+
const hero = {
|
|
67
|
+
name: 'Hero',
|
|
68
|
+
children: [{ tag: 'div', classes: 'fade slide', children: [{ tag: 'a', classes: 'cta', children: [] }] }],
|
|
69
|
+
};
|
|
70
|
+
const block = behaviorsBlock(hero, behaviors);
|
|
71
|
+
expect(block).toContain('**Hover** on `a.cta`');
|
|
72
|
+
expect(block).toContain('transition: `all 0.3s ease 0s`');
|
|
73
|
+
expect(block).toContain('**In-view entrance** on `div.fade` (enters at ~1400px)');
|
|
74
|
+
expect(block).toContain('opacity: `0` → `1`');
|
|
75
|
+
expect(block).toContain('**Time-driven** `div.slide` — 12 mutations/3s');
|
|
76
|
+
expect(block).toContain('lenis');
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('renders a page-level scroll-lib note even when no section-scoped behavior matches', () => {
|
|
80
|
+
const onlyLib = { scroll: [], interactive: [], scrollLib: { name: 'lenis', evidence: 'window.Lenis' } };
|
|
81
|
+
const footer = { name: 'Footer', children: [{ tag: 'p', classes: '', children: [] }] };
|
|
82
|
+
expect(behaviorsBlock(footer, onlyLib)).toContain('lenis');
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('suppresses the default transition value on hover entries', () => {
|
|
86
|
+
const behaviors = {
|
|
87
|
+
hover: [{ label: 'button.x', tag: 'button', cls: 'x', transition: 'all 0s ease 0s', changed: { color: { from: 'rgb(0, 0, 0)', to: 'rgb(9, 9, 9)' } } }],
|
|
88
|
+
};
|
|
89
|
+
const sec = { name: 'S', children: [{ tag: 'button', classes: 'x', children: [] }] };
|
|
90
|
+
expect(behaviorsBlock(sec, behaviors)).not.toContain('transition:');
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
describe('clone-spec CLI --real-content', () => {
|
|
95
|
+
const runCli = async (extraArgs) => {
|
|
96
|
+
const [fs, os, path, url, cp] = await Promise.all([
|
|
97
|
+
import('fs'), import('os'), import('path'), import('url'), import('child_process'),
|
|
98
|
+
]);
|
|
99
|
+
const tmp = fs.default.mkdtempSync(path.default.join(os.default.tmpdir(), 'clone-spec-'));
|
|
100
|
+
const sections = path.default.join(tmp, 'sections.json');
|
|
101
|
+
fs.default.writeFileSync(sections, JSON.stringify({
|
|
102
|
+
meta: { feature: 'f', bp: 'mo', url: 'https://x.test' },
|
|
103
|
+
sections: [{ name: 'Hero', nodeRef: '0', tag: 'section', css: {}, children: [] }],
|
|
104
|
+
}));
|
|
105
|
+
const script = url.default.fileURLToPath(new URL('../clone-spec.js', import.meta.url));
|
|
106
|
+
cp.default.execFileSync('node', [script, sections, `--out=${tmp}/specs`, ...extraArgs]);
|
|
107
|
+
return fs.default.readFileSync(path.default.join(tmp, 'specs', 'Hero.spec.md'), 'utf8');
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
it('defaults to placeholder replacement wording', async () => {
|
|
111
|
+
const spec = await runCli([]);
|
|
112
|
+
expect(spec).toContain('(replace copyrighted copy with placeholders)');
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('switches to verbatim wording with --real-content', async () => {
|
|
116
|
+
const spec = await runCli(['--real-content']);
|
|
117
|
+
expect(spec).toContain('(verbatim — user confirmed rights to reuse this copy)');
|
|
118
|
+
expect(spec).not.toContain('(replace copyrighted copy with placeholders)');
|
|
119
|
+
});
|
|
56
120
|
});
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* clone-merge-responsive — MO/PC SCSS → mobile-first 병합
|
|
3
|
+
* - mergeRules/emitMerged: 순수 병합 코어
|
|
4
|
+
* - CLI: fixture 디렉토리 → sections/tokens/index/class-plan 병합 산출
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { describe, it, expect } from 'vitest';
|
|
8
|
+
import fs from 'fs';
|
|
9
|
+
import os from 'os';
|
|
10
|
+
import path from 'path';
|
|
11
|
+
import { fileURLToPath } from 'url';
|
|
12
|
+
import { execFileSync } from 'child_process';
|
|
13
|
+
import { mergeRules, emitMerged } from '../clone-merge-responsive.js';
|
|
14
|
+
import { parseScss } from '../clone-validate.js';
|
|
15
|
+
|
|
16
|
+
const SCRIPT = fileURLToPath(new URL('../clone-merge-responsive.js', import.meta.url));
|
|
17
|
+
|
|
18
|
+
const MO = `.f__hero { display: flex; flex-direction: column; padding-top: 24px; }
|
|
19
|
+
.f__hero__title { font-size: 28px; color: rgb(0, 0, 0); }`;
|
|
20
|
+
|
|
21
|
+
const PC = `.f__hero { display: flex; flex-direction: row; padding-top: 64px; }
|
|
22
|
+
.f__hero__title { font-size: 48px; color: rgb(0, 0, 0); }
|
|
23
|
+
.f__hero__side { width: 320px; }`;
|
|
24
|
+
|
|
25
|
+
describe('mergeRules', () => {
|
|
26
|
+
const { base, media, stats } = mergeRules(parseScss(MO), parseScss(PC));
|
|
27
|
+
|
|
28
|
+
it('keeps MO declarations as the mobile-first base', () => {
|
|
29
|
+
expect(base.get('.f__hero')).toEqual({
|
|
30
|
+
display: 'flex', 'flex-direction': 'column', 'padding-top': '24px',
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('puts only differing PC declarations into the media bucket', () => {
|
|
35
|
+
expect(media.get('.f__hero')).toEqual({ 'flex-direction': 'row', 'padding-top': '64px' });
|
|
36
|
+
// color는 양쪽 동일 → media에서 제외
|
|
37
|
+
expect(media.get('.f__hero__title')).toEqual({ 'font-size': '48px' });
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('moves PC-only selectors wholly into the media bucket', () => {
|
|
41
|
+
expect(base.has('.f__hero__side')).toBe(false);
|
|
42
|
+
expect(media.get('.f__hero__side')).toEqual({ width: '320px' });
|
|
43
|
+
expect(stats.pcOnly).toBe(1);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
describe('emitMerged', () => {
|
|
48
|
+
it('emits base + a single min-width block without duplicating shared declarations', () => {
|
|
49
|
+
const { scss } = emitMerged(parseScss(MO), parseScss(PC), 1024, '// merged');
|
|
50
|
+
expect(scss).toContain('@media (min-width: 1024px)');
|
|
51
|
+
expect(scss.match(/@media/g)).toHaveLength(1);
|
|
52
|
+
// 양 BP 동일 선언은 base에 1번만 등장
|
|
53
|
+
expect(scss.match(/display: flex;/g)).toHaveLength(1);
|
|
54
|
+
expect(scss.match(/color: rgb\(0, 0, 0\);/g)).toHaveLength(1);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('omits the media block when PC has no differences', () => {
|
|
58
|
+
const { scss } = emitMerged(parseScss(MO), parseScss(MO), 1024, '// same');
|
|
59
|
+
expect(scss).not.toContain('@media');
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
describe('CLI file-level merge', () => {
|
|
64
|
+
const write = (dir, rel, content) => {
|
|
65
|
+
const f = path.join(dir, rel);
|
|
66
|
+
fs.mkdirSync(path.dirname(f), { recursive: true });
|
|
67
|
+
fs.writeFileSync(f, content);
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
it('merges section dirs and writes index/tokens/class-plan', () => {
|
|
71
|
+
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'clone-merge-'));
|
|
72
|
+
const mo = path.join(tmp, 'mo');
|
|
73
|
+
const pc = path.join(tmp, 'pc');
|
|
74
|
+
const out = path.join(tmp, 'merged');
|
|
75
|
+
write(mo, 'sections/_hero.scss', MO);
|
|
76
|
+
write(pc, 'sections/_hero.scss', PC);
|
|
77
|
+
write(pc, 'sections/_footer.scss', '.f__footer { height: 200px; }'); // PC 전용 섹션
|
|
78
|
+
write(mo, '_tokens.scss', ':root { --c-1: #000; --sp-1: 16px; }');
|
|
79
|
+
write(pc, '_tokens.scss', ':root { --c-1: #000; --sp-1: 32px; }');
|
|
80
|
+
write(mo, 'class-plan.json', JSON.stringify({ 0: 'f__hero' }));
|
|
81
|
+
write(pc, 'class-plan.json', JSON.stringify({ 0: 'f__hero', 0.9: 'f__footer' }));
|
|
82
|
+
|
|
83
|
+
execFileSync('node', [SCRIPT, `--mo=${mo}`, `--pc=${pc}`, `--out=${out}`, '--breakpoint=1024']);
|
|
84
|
+
|
|
85
|
+
const hero = fs.readFileSync(path.join(out, 'sections/_hero.scss'), 'utf8');
|
|
86
|
+
expect(hero).toContain('flex-direction: column');
|
|
87
|
+
expect(hero).toContain('@media (min-width: 1024px)');
|
|
88
|
+
|
|
89
|
+
// PC 전용 섹션 파일은 통째로 media 블록 안
|
|
90
|
+
const footer = fs.readFileSync(path.join(out, 'sections/_footer.scss'), 'utf8');
|
|
91
|
+
expect(footer).toContain('@media (min-width: 1024px)');
|
|
92
|
+
expect(footer).toContain('height: 200px');
|
|
93
|
+
|
|
94
|
+
const tokens = fs.readFileSync(path.join(out, '_tokens.scss'), 'utf8');
|
|
95
|
+
expect(tokens).toContain('--sp-1: 16px'); // base = MO
|
|
96
|
+
expect(tokens).toContain('--sp-1: 32px'); // PC diff → media
|
|
97
|
+
|
|
98
|
+
const index = fs.readFileSync(path.join(out, 'index.scss'), 'utf8');
|
|
99
|
+
expect(index).toContain(`@use './sections/hero'`);
|
|
100
|
+
expect(index).toContain(`@use './sections/footer'`);
|
|
101
|
+
|
|
102
|
+
const plan = JSON.parse(fs.readFileSync(path.join(out, 'class-plan.json'), 'utf8'));
|
|
103
|
+
expect(plan['0']).toBe('f__hero');
|
|
104
|
+
expect(plan['0.9']).toBe('f__footer');
|
|
105
|
+
});
|
|
106
|
+
});
|
|
@@ -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);
|