@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.
Files changed (341) hide show
  1. package/hooks/scripts/__tests__/.vibe/command-log.txt +3 -78
  2. package/hooks/scripts/__tests__/.vibe/memories/memories.db +0 -0
  3. package/hooks/scripts/__tests__/.vibe/memories/memories.db-shm +0 -0
  4. package/hooks/scripts/__tests__/.vibe/memories/memories.db-wal +0 -0
  5. package/hooks/scripts/__tests__/clone-behaviors.test.js +64 -0
  6. package/hooks/scripts/__tests__/clone-merge-responsive.test.js +106 -0
  7. package/hooks/scripts/clone-extract.js +242 -28
  8. package/hooks/scripts/clone-merge-responsive.js +184 -0
  9. package/hooks/scripts/clone-spec.js +33 -8
  10. package/hooks/scripts/clone-validate.js +15 -9
  11. package/package.json +5 -2
  12. package/skills/clone/SKILL.md +132 -55
  13. package/skills/vibe.clone/SKILL.md +39 -19
  14. package/dist/cli/llm/gemini-commands.d.ts +0 -25
  15. package/dist/cli/llm/gemini-commands.d.ts.map +0 -1
  16. package/dist/cli/llm/gemini-commands.js +0 -143
  17. package/dist/cli/llm/gemini-commands.js.map +0 -1
  18. package/dist/cli/postinstall/codex-agents.d.ts +0 -24
  19. package/dist/cli/postinstall/codex-agents.d.ts.map +0 -1
  20. package/dist/cli/postinstall/codex-agents.js +0 -114
  21. package/dist/cli/postinstall/codex-agents.js.map +0 -1
  22. package/dist/cli/postinstall/codex-instruction.d.ts +0 -10
  23. package/dist/cli/postinstall/codex-instruction.d.ts.map +0 -1
  24. package/dist/cli/postinstall/codex-instruction.js +0 -56
  25. package/dist/cli/postinstall/codex-instruction.js.map +0 -1
  26. package/dist/cli/postinstall/gemini-agents.d.ts +0 -12
  27. package/dist/cli/postinstall/gemini-agents.d.ts.map +0 -1
  28. package/dist/cli/postinstall/gemini-agents.js +0 -80
  29. package/dist/cli/postinstall/gemini-agents.js.map +0 -1
  30. package/dist/cli/postinstall/gemini-instruction.d.ts +0 -10
  31. package/dist/cli/postinstall/gemini-instruction.d.ts.map +0 -1
  32. package/dist/cli/postinstall/gemini-instruction.js +0 -59
  33. package/dist/cli/postinstall/gemini-instruction.js.map +0 -1
  34. package/dist/infra/lib/ContextCompressor.d.ts +0 -104
  35. package/dist/infra/lib/ContextCompressor.d.ts.map +0 -1
  36. package/dist/infra/lib/ContextCompressor.js +0 -297
  37. package/dist/infra/lib/ContextCompressor.js.map +0 -1
  38. package/dist/infra/lib/ContextCompressor.test.d.ts +0 -2
  39. package/dist/infra/lib/ContextCompressor.test.d.ts.map +0 -1
  40. package/dist/infra/lib/ContextCompressor.test.js +0 -25
  41. package/dist/infra/lib/ContextCompressor.test.js.map +0 -1
  42. package/dist/infra/lib/ProgressTracker.d.ts +0 -73
  43. package/dist/infra/lib/ProgressTracker.d.ts.map +0 -1
  44. package/dist/infra/lib/ProgressTracker.js +0 -267
  45. package/dist/infra/lib/ProgressTracker.js.map +0 -1
  46. package/dist/infra/lib/TokenBudgetTracker.d.ts +0 -68
  47. package/dist/infra/lib/TokenBudgetTracker.d.ts.map +0 -1
  48. package/dist/infra/lib/TokenBudgetTracker.js +0 -191
  49. package/dist/infra/lib/TokenBudgetTracker.js.map +0 -1
  50. package/dist/infra/lib/autonomy/AuditStore.d.ts +0 -63
  51. package/dist/infra/lib/autonomy/AuditStore.d.ts.map +0 -1
  52. package/dist/infra/lib/autonomy/AuditStore.js +0 -185
  53. package/dist/infra/lib/autonomy/AuditStore.js.map +0 -1
  54. package/dist/infra/lib/autonomy/AutonomyConfig.d.ts +0 -84
  55. package/dist/infra/lib/autonomy/AutonomyConfig.d.ts.map +0 -1
  56. package/dist/infra/lib/autonomy/AutonomyConfig.js +0 -49
  57. package/dist/infra/lib/autonomy/AutonomyConfig.js.map +0 -1
  58. package/dist/infra/lib/autonomy/AutonomyOrchestrator.d.ts +0 -78
  59. package/dist/infra/lib/autonomy/AutonomyOrchestrator.d.ts.map +0 -1
  60. package/dist/infra/lib/autonomy/AutonomyOrchestrator.js +0 -246
  61. package/dist/infra/lib/autonomy/AutonomyOrchestrator.js.map +0 -1
  62. package/dist/infra/lib/autonomy/BackgroundMonitor.d.ts +0 -36
  63. package/dist/infra/lib/autonomy/BackgroundMonitor.d.ts.map +0 -1
  64. package/dist/infra/lib/autonomy/BackgroundMonitor.js +0 -138
  65. package/dist/infra/lib/autonomy/BackgroundMonitor.js.map +0 -1
  66. package/dist/infra/lib/autonomy/CollaborationProtocol.d.ts +0 -56
  67. package/dist/infra/lib/autonomy/CollaborationProtocol.d.ts.map +0 -1
  68. package/dist/infra/lib/autonomy/CollaborationProtocol.js +0 -122
  69. package/dist/infra/lib/autonomy/CollaborationProtocol.js.map +0 -1
  70. package/dist/infra/lib/autonomy/ConfirmationManager.d.ts +0 -42
  71. package/dist/infra/lib/autonomy/ConfirmationManager.d.ts.map +0 -1
  72. package/dist/infra/lib/autonomy/ConfirmationManager.js +0 -200
  73. package/dist/infra/lib/autonomy/ConfirmationManager.js.map +0 -1
  74. package/dist/infra/lib/autonomy/ConfirmationStore.d.ts +0 -55
  75. package/dist/infra/lib/autonomy/ConfirmationStore.d.ts.map +0 -1
  76. package/dist/infra/lib/autonomy/ConfirmationStore.js +0 -130
  77. package/dist/infra/lib/autonomy/ConfirmationStore.js.map +0 -1
  78. package/dist/infra/lib/autonomy/EventBus.d.ts +0 -20
  79. package/dist/infra/lib/autonomy/EventBus.d.ts.map +0 -1
  80. package/dist/infra/lib/autonomy/EventBus.js +0 -119
  81. package/dist/infra/lib/autonomy/EventBus.js.map +0 -1
  82. package/dist/infra/lib/autonomy/EventOutbox.d.ts +0 -32
  83. package/dist/infra/lib/autonomy/EventOutbox.d.ts.map +0 -1
  84. package/dist/infra/lib/autonomy/EventOutbox.js +0 -152
  85. package/dist/infra/lib/autonomy/EventOutbox.js.map +0 -1
  86. package/dist/infra/lib/autonomy/NotificationDispatcher.d.ts +0 -24
  87. package/dist/infra/lib/autonomy/NotificationDispatcher.d.ts.map +0 -1
  88. package/dist/infra/lib/autonomy/NotificationDispatcher.js +0 -112
  89. package/dist/infra/lib/autonomy/NotificationDispatcher.js.map +0 -1
  90. package/dist/infra/lib/autonomy/PolicyEngine.d.ts +0 -76
  91. package/dist/infra/lib/autonomy/PolicyEngine.d.ts.map +0 -1
  92. package/dist/infra/lib/autonomy/PolicyEngine.js +0 -208
  93. package/dist/infra/lib/autonomy/PolicyEngine.js.map +0 -1
  94. package/dist/infra/lib/autonomy/ProactiveAnalyzer.d.ts +0 -61
  95. package/dist/infra/lib/autonomy/ProactiveAnalyzer.d.ts.map +0 -1
  96. package/dist/infra/lib/autonomy/ProactiveAnalyzer.js +0 -236
  97. package/dist/infra/lib/autonomy/ProactiveAnalyzer.js.map +0 -1
  98. package/dist/infra/lib/autonomy/RiskClassifier.d.ts +0 -35
  99. package/dist/infra/lib/autonomy/RiskClassifier.d.ts.map +0 -1
  100. package/dist/infra/lib/autonomy/RiskClassifier.js +0 -147
  101. package/dist/infra/lib/autonomy/RiskClassifier.js.map +0 -1
  102. package/dist/infra/lib/autonomy/SecuritySentinel.d.ts +0 -51
  103. package/dist/infra/lib/autonomy/SecuritySentinel.d.ts.map +0 -1
  104. package/dist/infra/lib/autonomy/SecuritySentinel.js +0 -162
  105. package/dist/infra/lib/autonomy/SecuritySentinel.js.map +0 -1
  106. package/dist/infra/lib/autonomy/SuggestionStore.d.ts +0 -54
  107. package/dist/infra/lib/autonomy/SuggestionStore.d.ts.map +0 -1
  108. package/dist/infra/lib/autonomy/SuggestionStore.js +0 -144
  109. package/dist/infra/lib/autonomy/SuggestionStore.js.map +0 -1
  110. package/dist/infra/lib/autonomy/TaskDecomposer.d.ts +0 -38
  111. package/dist/infra/lib/autonomy/TaskDecomposer.d.ts.map +0 -1
  112. package/dist/infra/lib/autonomy/TaskDecomposer.js +0 -175
  113. package/dist/infra/lib/autonomy/TaskDecomposer.js.map +0 -1
  114. package/dist/infra/lib/autonomy/__tests__/audit-store.test.d.ts +0 -2
  115. package/dist/infra/lib/autonomy/__tests__/audit-store.test.d.ts.map +0 -1
  116. package/dist/infra/lib/autonomy/__tests__/audit-store.test.js +0 -198
  117. package/dist/infra/lib/autonomy/__tests__/audit-store.test.js.map +0 -1
  118. package/dist/infra/lib/autonomy/__tests__/event-bus.test.d.ts +0 -2
  119. package/dist/infra/lib/autonomy/__tests__/event-bus.test.d.ts.map +0 -1
  120. package/dist/infra/lib/autonomy/__tests__/event-bus.test.js +0 -225
  121. package/dist/infra/lib/autonomy/__tests__/event-bus.test.js.map +0 -1
  122. package/dist/infra/lib/autonomy/__tests__/event-core.test.d.ts +0 -2
  123. package/dist/infra/lib/autonomy/__tests__/event-core.test.d.ts.map +0 -1
  124. package/dist/infra/lib/autonomy/__tests__/event-core.test.js +0 -194
  125. package/dist/infra/lib/autonomy/__tests__/event-core.test.js.map +0 -1
  126. package/dist/infra/lib/autonomy/__tests__/governance.test.d.ts +0 -2
  127. package/dist/infra/lib/autonomy/__tests__/governance.test.d.ts.map +0 -1
  128. package/dist/infra/lib/autonomy/__tests__/governance.test.js +0 -540
  129. package/dist/infra/lib/autonomy/__tests__/governance.test.js.map +0 -1
  130. package/dist/infra/lib/autonomy/__tests__/integration.test.d.ts +0 -2
  131. package/dist/infra/lib/autonomy/__tests__/integration.test.d.ts.map +0 -1
  132. package/dist/infra/lib/autonomy/__tests__/integration.test.js +0 -480
  133. package/dist/infra/lib/autonomy/__tests__/integration.test.js.map +0 -1
  134. package/dist/infra/lib/autonomy/__tests__/proactive.test.d.ts +0 -2
  135. package/dist/infra/lib/autonomy/__tests__/proactive.test.d.ts.map +0 -1
  136. package/dist/infra/lib/autonomy/__tests__/proactive.test.js +0 -410
  137. package/dist/infra/lib/autonomy/__tests__/proactive.test.js.map +0 -1
  138. package/dist/infra/lib/autonomy/__tests__/sentinel.test.d.ts +0 -2
  139. package/dist/infra/lib/autonomy/__tests__/sentinel.test.d.ts.map +0 -1
  140. package/dist/infra/lib/autonomy/__tests__/sentinel.test.js +0 -486
  141. package/dist/infra/lib/autonomy/__tests__/sentinel.test.js.map +0 -1
  142. package/dist/infra/lib/autonomy/index.d.ts +0 -18
  143. package/dist/infra/lib/autonomy/index.d.ts.map +0 -1
  144. package/dist/infra/lib/autonomy/index.js +0 -22
  145. package/dist/infra/lib/autonomy/index.js.map +0 -1
  146. package/dist/infra/lib/autonomy/schemas.d.ts +0 -317
  147. package/dist/infra/lib/autonomy/schemas.d.ts.map +0 -1
  148. package/dist/infra/lib/autonomy/schemas.js +0 -90
  149. package/dist/infra/lib/autonomy/schemas.js.map +0 -1
  150. package/dist/infra/lib/claude/index.d.ts +0 -5
  151. package/dist/infra/lib/claude/index.d.ts.map +0 -1
  152. package/dist/infra/lib/claude/index.js +0 -5
  153. package/dist/infra/lib/claude/index.js.map +0 -1
  154. package/dist/infra/lib/claude/storage.d.ts +0 -12
  155. package/dist/infra/lib/claude/storage.d.ts.map +0 -1
  156. package/dist/infra/lib/claude/storage.js +0 -54
  157. package/dist/infra/lib/claude/storage.js.map +0 -1
  158. package/dist/infra/lib/gemini/auth.d.ts +0 -18
  159. package/dist/infra/lib/gemini/auth.d.ts.map +0 -1
  160. package/dist/infra/lib/gemini/auth.js +0 -32
  161. package/dist/infra/lib/gemini/auth.js.map +0 -1
  162. package/dist/infra/lib/gemini/capabilities.d.ts +0 -28
  163. package/dist/infra/lib/gemini/capabilities.d.ts.map +0 -1
  164. package/dist/infra/lib/gemini/capabilities.js +0 -178
  165. package/dist/infra/lib/gemini/capabilities.js.map +0 -1
  166. package/dist/infra/lib/gemini/chat.d.ts +0 -35
  167. package/dist/infra/lib/gemini/chat.d.ts.map +0 -1
  168. package/dist/infra/lib/gemini/chat.js +0 -161
  169. package/dist/infra/lib/gemini/chat.js.map +0 -1
  170. package/dist/infra/lib/gemini/completion.d.ts +0 -12
  171. package/dist/infra/lib/gemini/completion.d.ts.map +0 -1
  172. package/dist/infra/lib/gemini/completion.js +0 -13
  173. package/dist/infra/lib/gemini/completion.js.map +0 -1
  174. package/dist/infra/lib/gemini/constants.d.ts +0 -8
  175. package/dist/infra/lib/gemini/constants.d.ts.map +0 -1
  176. package/dist/infra/lib/gemini/constants.js +0 -11
  177. package/dist/infra/lib/gemini/constants.js.map +0 -1
  178. package/dist/infra/lib/gemini/index.d.ts +0 -13
  179. package/dist/infra/lib/gemini/index.d.ts.map +0 -1
  180. package/dist/infra/lib/gemini/index.js +0 -12
  181. package/dist/infra/lib/gemini/index.js.map +0 -1
  182. package/dist/infra/lib/gemini/models.d.ts +0 -11
  183. package/dist/infra/lib/gemini/models.d.ts.map +0 -1
  184. package/dist/infra/lib/gemini/models.js +0 -38
  185. package/dist/infra/lib/gemini/models.js.map +0 -1
  186. package/dist/infra/lib/gemini/orchestration.d.ts +0 -33
  187. package/dist/infra/lib/gemini/orchestration.d.ts.map +0 -1
  188. package/dist/infra/lib/gemini/orchestration.js +0 -62
  189. package/dist/infra/lib/gemini/orchestration.js.map +0 -1
  190. package/dist/infra/lib/gemini/types.d.ts +0 -115
  191. package/dist/infra/lib/gemini/types.d.ts.map +0 -1
  192. package/dist/infra/lib/gemini/types.js +0 -5
  193. package/dist/infra/lib/gemini/types.js.map +0 -1
  194. package/dist/infra/orchestrator/AgentAnnouncer.d.ts +0 -64
  195. package/dist/infra/orchestrator/AgentAnnouncer.d.ts.map +0 -1
  196. package/dist/infra/orchestrator/AgentAnnouncer.js +0 -127
  197. package/dist/infra/orchestrator/AgentAnnouncer.js.map +0 -1
  198. package/dist/infra/orchestrator/AgentAnnouncer.test.d.ts +0 -5
  199. package/dist/infra/orchestrator/AgentAnnouncer.test.d.ts.map +0 -1
  200. package/dist/infra/orchestrator/AgentAnnouncer.test.js +0 -119
  201. package/dist/infra/orchestrator/AgentAnnouncer.test.js.map +0 -1
  202. package/dist/infra/orchestrator/AgentExecutor.d.ts +0 -22
  203. package/dist/infra/orchestrator/AgentExecutor.d.ts.map +0 -1
  204. package/dist/infra/orchestrator/AgentExecutor.js +0 -272
  205. package/dist/infra/orchestrator/AgentExecutor.js.map +0 -1
  206. package/dist/infra/orchestrator/AgentManager.d.ts +0 -72
  207. package/dist/infra/orchestrator/AgentManager.d.ts.map +0 -1
  208. package/dist/infra/orchestrator/AgentManager.js +0 -183
  209. package/dist/infra/orchestrator/AgentManager.js.map +0 -1
  210. package/dist/infra/orchestrator/AgentManifestCache.d.ts +0 -54
  211. package/dist/infra/orchestrator/AgentManifestCache.d.ts.map +0 -1
  212. package/dist/infra/orchestrator/AgentManifestCache.js +0 -191
  213. package/dist/infra/orchestrator/AgentManifestCache.js.map +0 -1
  214. package/dist/infra/orchestrator/AgentRegistry.d.ts +0 -76
  215. package/dist/infra/orchestrator/AgentRegistry.d.ts.map +0 -1
  216. package/dist/infra/orchestrator/AgentRegistry.js +0 -217
  217. package/dist/infra/orchestrator/AgentRegistry.js.map +0 -1
  218. package/dist/infra/orchestrator/AgentRegistry.test.d.ts +0 -5
  219. package/dist/infra/orchestrator/AgentRegistry.test.d.ts.map +0 -1
  220. package/dist/infra/orchestrator/AgentRegistry.test.js +0 -122
  221. package/dist/infra/orchestrator/AgentRegistry.test.js.map +0 -1
  222. package/dist/infra/orchestrator/BackgroundManager.d.ts +0 -128
  223. package/dist/infra/orchestrator/BackgroundManager.d.ts.map +0 -1
  224. package/dist/infra/orchestrator/BackgroundManager.js +0 -620
  225. package/dist/infra/orchestrator/BackgroundManager.js.map +0 -1
  226. package/dist/infra/orchestrator/BackgroundManager.test.d.ts +0 -6
  227. package/dist/infra/orchestrator/BackgroundManager.test.d.ts.map +0 -1
  228. package/dist/infra/orchestrator/BackgroundManager.test.js +0 -162
  229. package/dist/infra/orchestrator/BackgroundManager.test.js.map +0 -1
  230. package/dist/infra/orchestrator/CheckpointManager.d.ts +0 -54
  231. package/dist/infra/orchestrator/CheckpointManager.d.ts.map +0 -1
  232. package/dist/infra/orchestrator/CheckpointManager.js +0 -121
  233. package/dist/infra/orchestrator/CheckpointManager.js.map +0 -1
  234. package/dist/infra/orchestrator/CodexAgentRuntime.d.ts +0 -12
  235. package/dist/infra/orchestrator/CodexAgentRuntime.d.ts.map +0 -1
  236. package/dist/infra/orchestrator/CodexAgentRuntime.js +0 -94
  237. package/dist/infra/orchestrator/CodexAgentRuntime.js.map +0 -1
  238. package/dist/infra/orchestrator/CodexAgentRuntime.test.d.ts +0 -2
  239. package/dist/infra/orchestrator/CodexAgentRuntime.test.d.ts.map +0 -1
  240. package/dist/infra/orchestrator/CodexAgentRuntime.test.js +0 -37
  241. package/dist/infra/orchestrator/CodexAgentRuntime.test.js.map +0 -1
  242. package/dist/infra/orchestrator/LLMCluster.d.ts +0 -82
  243. package/dist/infra/orchestrator/LLMCluster.d.ts.map +0 -1
  244. package/dist/infra/orchestrator/LLMCluster.js +0 -146
  245. package/dist/infra/orchestrator/LLMCluster.js.map +0 -1
  246. package/dist/infra/orchestrator/MultiLlmResearch.d.ts +0 -31
  247. package/dist/infra/orchestrator/MultiLlmResearch.d.ts.map +0 -1
  248. package/dist/infra/orchestrator/MultiLlmResearch.js +0 -160
  249. package/dist/infra/orchestrator/MultiLlmResearch.js.map +0 -1
  250. package/dist/infra/orchestrator/PhasePipeline.d.ts +0 -122
  251. package/dist/infra/orchestrator/PhasePipeline.d.ts.map +0 -1
  252. package/dist/infra/orchestrator/PhasePipeline.js +0 -385
  253. package/dist/infra/orchestrator/PhasePipeline.js.map +0 -1
  254. package/dist/infra/orchestrator/PhaseResultStore.d.ts +0 -39
  255. package/dist/infra/orchestrator/PhaseResultStore.d.ts.map +0 -1
  256. package/dist/infra/orchestrator/PhaseResultStore.js +0 -151
  257. package/dist/infra/orchestrator/PhaseResultStore.js.map +0 -1
  258. package/dist/infra/orchestrator/SessionStore.d.ts +0 -40
  259. package/dist/infra/orchestrator/SessionStore.d.ts.map +0 -1
  260. package/dist/infra/orchestrator/SessionStore.js +0 -116
  261. package/dist/infra/orchestrator/SessionStore.js.map +0 -1
  262. package/dist/infra/orchestrator/SmartRouter.d.ts +0 -90
  263. package/dist/infra/orchestrator/SmartRouter.d.ts.map +0 -1
  264. package/dist/infra/orchestrator/SmartRouter.js +0 -277
  265. package/dist/infra/orchestrator/SmartRouter.js.map +0 -1
  266. package/dist/infra/orchestrator/SmartRouter.test.d.ts +0 -5
  267. package/dist/infra/orchestrator/SmartRouter.test.d.ts.map +0 -1
  268. package/dist/infra/orchestrator/SmartRouter.test.js +0 -484
  269. package/dist/infra/orchestrator/SmartRouter.test.js.map +0 -1
  270. package/dist/infra/orchestrator/SwarmOrchestrator.d.ts +0 -143
  271. package/dist/infra/orchestrator/SwarmOrchestrator.d.ts.map +0 -1
  272. package/dist/infra/orchestrator/SwarmOrchestrator.js +0 -378
  273. package/dist/infra/orchestrator/SwarmOrchestrator.js.map +0 -1
  274. package/dist/infra/orchestrator/SwarmOrchestrator.test.d.ts +0 -5
  275. package/dist/infra/orchestrator/SwarmOrchestrator.test.d.ts.map +0 -1
  276. package/dist/infra/orchestrator/SwarmOrchestrator.test.js +0 -95
  277. package/dist/infra/orchestrator/SwarmOrchestrator.test.js.map +0 -1
  278. package/dist/infra/orchestrator/agentDiscovery.d.ts +0 -26
  279. package/dist/infra/orchestrator/agentDiscovery.d.ts.map +0 -1
  280. package/dist/infra/orchestrator/agentDiscovery.js +0 -175
  281. package/dist/infra/orchestrator/agentDiscovery.js.map +0 -1
  282. package/dist/infra/orchestrator/backgroundAgent.d.ts +0 -9
  283. package/dist/infra/orchestrator/backgroundAgent.d.ts.map +0 -1
  284. package/dist/infra/orchestrator/backgroundAgent.js +0 -10
  285. package/dist/infra/orchestrator/backgroundAgent.js.map +0 -1
  286. package/dist/infra/orchestrator/index.d.ts +0 -207
  287. package/dist/infra/orchestrator/index.d.ts.map +0 -1
  288. package/dist/infra/orchestrator/index.js +0 -362
  289. package/dist/infra/orchestrator/index.js.map +0 -1
  290. package/dist/infra/orchestrator/orchestrator.d.ts +0 -60
  291. package/dist/infra/orchestrator/orchestrator.d.ts.map +0 -1
  292. package/dist/infra/orchestrator/orchestrator.js +0 -214
  293. package/dist/infra/orchestrator/orchestrator.js.map +0 -1
  294. package/dist/infra/orchestrator/parallelResearch.d.ts +0 -27
  295. package/dist/infra/orchestrator/parallelResearch.d.ts.map +0 -1
  296. package/dist/infra/orchestrator/parallelResearch.js +0 -285
  297. package/dist/infra/orchestrator/parallelResearch.js.map +0 -1
  298. package/dist/infra/orchestrator/types.d.ts +0 -205
  299. package/dist/infra/orchestrator/types.d.ts.map +0 -1
  300. package/dist/infra/orchestrator/types.js +0 -87
  301. package/dist/infra/orchestrator/types.js.map +0 -1
  302. package/dist/infra/orchestrator/types.test.d.ts +0 -2
  303. package/dist/infra/orchestrator/types.test.d.ts.map +0 -1
  304. package/dist/infra/orchestrator/types.test.js +0 -57
  305. package/dist/infra/orchestrator/types.test.js.map +0 -1
  306. package/dist/tools/semantic/analyzeDependencyGraph.d.ts +0 -12
  307. package/dist/tools/semantic/analyzeDependencyGraph.d.ts.map +0 -1
  308. package/dist/tools/semantic/analyzeDependencyGraph.js +0 -359
  309. package/dist/tools/semantic/analyzeDependencyGraph.js.map +0 -1
  310. package/dist/tools/semantic/astGrep.d.ts +0 -25
  311. package/dist/tools/semantic/astGrep.d.ts.map +0 -1
  312. package/dist/tools/semantic/astGrep.js +0 -324
  313. package/dist/tools/semantic/astGrep.js.map +0 -1
  314. package/dist/tools/semantic/astGrep.test.d.ts +0 -2
  315. package/dist/tools/semantic/astGrep.test.d.ts.map +0 -1
  316. package/dist/tools/semantic/astGrep.test.js +0 -74
  317. package/dist/tools/semantic/astGrep.test.js.map +0 -1
  318. package/dist/tools/semantic/findReferences.d.ts +0 -9
  319. package/dist/tools/semantic/findReferences.d.ts.map +0 -1
  320. package/dist/tools/semantic/findReferences.js +0 -200
  321. package/dist/tools/semantic/findReferences.js.map +0 -1
  322. package/dist/tools/semantic/findSymbol.d.ts +0 -8
  323. package/dist/tools/semantic/findSymbol.d.ts.map +0 -1
  324. package/dist/tools/semantic/findSymbol.js +0 -204
  325. package/dist/tools/semantic/findSymbol.js.map +0 -1
  326. package/dist/tools/semantic/index.d.ts +0 -9
  327. package/dist/tools/semantic/index.d.ts.map +0 -1
  328. package/dist/tools/semantic/index.js +0 -11
  329. package/dist/tools/semantic/index.js.map +0 -1
  330. package/dist/tools/semantic/lsp.d.ts +0 -68
  331. package/dist/tools/semantic/lsp.d.ts.map +0 -1
  332. package/dist/tools/semantic/lsp.js +0 -561
  333. package/dist/tools/semantic/lsp.js.map +0 -1
  334. package/dist/tools/spec/e2eTestGenerator.d.ts +0 -61
  335. package/dist/tools/spec/e2eTestGenerator.d.ts.map +0 -1
  336. package/dist/tools/spec/e2eTestGenerator.js +0 -255
  337. package/dist/tools/spec/e2eTestGenerator.js.map +0 -1
  338. package/dist/tools/spec/specVersioning.d.ts +0 -76
  339. package/dist/tools/spec/specVersioning.d.ts.map +0 -1
  340. package/dist/tools/spec/specVersioning.js +0 -236
  341. package/dist/tools/spec/specVersioning.js.map +0 -1
@@ -1,78 +1,3 @@
1
- [2026-06-10T07:48:43.637Z] rm -rf /
2
- [2026-06-10T07:48:43.682Z] ls -la
3
- [2026-06-10T07:48:43.728Z] rm -rf src/infra/lib/autonomy/
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/
@@ -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
- const wait = (ms) => new Promise((r) => setTimeout(r, ms));
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
- async function runInteractionSweep(page) {
656
- const behaviors = { scroll: [], interactive: [] };
659
+ // In-view 등장 애니메이션 diff props
660
+ const INVIEW_PROPS = ['opacity', 'transform', 'visibility', 'filter', 'clip-path'];
657
661
 
658
- // ── Scroll-triggered state (header/nav shrink, background, shadow on scroll) ──
659
- const candidates = await page.evaluate(`(${TAG_SCROLL_CANDIDATES})()`);
660
- if (candidates.length) {
661
- const before = await page.evaluate(`(${SNAP_PROBES})(${JSON.stringify(BEHAVIOR_PROPS)})`);
662
- const innerH = await page.evaluate('window.innerHeight');
663
- const triggerY = Math.min(700, Math.max(200, Math.round(innerH * 0.9)));
664
- await page.evaluate(`window.scrollTo(0, ${triggerY})`);
665
- await wait(500);
666
- const after = await page.evaluate(`(${SNAP_PROBES})(${JSON.stringify(BEHAVIOR_PROPS)})`);
667
- await page.evaluate('window.scrollTo(0, 0)');
668
- await wait(300);
669
- for (const c of candidates) {
670
- const changed = diffStyles(before[c.probe], after[c.probe]);
671
- if (Object.keys(changed).length) {
672
- behaviors.scroll.push({
673
- label: c.cls ? `${c.tag}.${c.cls}` : c.tag,
674
- tag: c.tag, cls: c.cls, triggerScrollY: triggerY, changed,
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
- // ── Click-driven tab groups (content swap detection) ──
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
- behaviors.interactive.push({
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(`[clone-extract] interaction sweep: ${behaviors.scroll.length} scroll-state, ${behaviors.interactive.length} tab-group(s)`);
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
- console.log(`[clone-extract] downloading ${extracted.assets.images.length} images, ${fontDownloadSet.size} fonts (filtered from ${extracted.assets.fonts.length})`);
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 scroll-state background-image diffs.
900
- for (const s of behaviors.scroll) {
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);