@su-record/vibe 3.2.13 → 3.2.15

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 (305) hide show
  1. package/CLAUDE.md +15 -14
  2. package/README.en.md +1 -1
  3. package/README.md +1 -1
  4. package/dist/cli/setup/ProjectSetup.d.ts +6 -0
  5. package/dist/cli/setup/ProjectSetup.d.ts.map +1 -1
  6. package/dist/cli/setup/ProjectSetup.js +19 -13
  7. package/dist/cli/setup/ProjectSetup.js.map +1 -1
  8. package/dist/infra/lib/codex-proxy.d.ts +126 -0
  9. package/dist/infra/lib/codex-proxy.d.ts.map +1 -1
  10. package/dist/infra/lib/codex-proxy.js +16 -16
  11. package/dist/infra/lib/codex-proxy.js.map +1 -1
  12. package/dist/infra/lib/figma/audit.d.ts.map +1 -1
  13. package/dist/infra/lib/figma/audit.js +0 -2
  14. package/dist/infra/lib/figma/audit.js.map +1 -1
  15. package/dist/infra/lib/figma/extract.d.ts +6 -1
  16. package/dist/infra/lib/figma/extract.d.ts.map +1 -1
  17. package/dist/infra/lib/figma/extract.js +17 -15
  18. package/dist/infra/lib/figma/extract.js.map +1 -1
  19. package/dist/infra/lib/figma/types.d.ts +103 -0
  20. package/dist/infra/lib/figma/types.d.ts.map +1 -1
  21. package/dist/infra/lib/figma/types.js +8 -0
  22. package/dist/infra/lib/figma/types.js.map +1 -1
  23. package/hooks/hooks.json +1 -1
  24. package/hooks/scripts/clone-extract.js +16 -1
  25. package/hooks/scripts/code-check.js +72 -55
  26. package/hooks/scripts/lib/anchor.js +74 -0
  27. package/hooks/scripts/lib/console-allow.js +66 -0
  28. package/hooks/scripts/lib/dispatcher.js +71 -19
  29. package/hooks/scripts/lib/inbox.js +60 -0
  30. package/hooks/scripts/loop-ledger.js +24 -1
  31. package/hooks/scripts/post-edit-dispatcher.js +4 -3
  32. package/hooks/scripts/post-edit.js +2 -2
  33. package/package.json +13 -9
  34. package/skills/vibe/SKILL.md +2 -1
  35. package/skills/vibe.clone/references/verification-loops.md +6 -3
  36. package/skills/vibe.loop/SKILL.md +7 -4
  37. package/skills/vibe.review/SKILL.md +5 -1
  38. package/skills/vibe.run/references/e2e-and-autofix.md +1 -1
  39. package/skills/vibe.run/references/process-steps.md +1 -1
  40. package/vibe/constitution.md +1 -1
  41. package/vibe/rules/loop-contract.md +40 -3
  42. package/vibe/rules/quality/checklist.md +3 -3
  43. package/vibe/templates/constitution-template.md +1 -1
  44. package/dist/__tests__/agent-model-sync.test.d.ts +0 -2
  45. package/dist/__tests__/agent-model-sync.test.d.ts.map +0 -1
  46. package/dist/__tests__/agent-model-sync.test.js +0 -71
  47. package/dist/__tests__/agent-model-sync.test.js.map +0 -1
  48. package/dist/__tests__/architecture.test.d.ts +0 -2
  49. package/dist/__tests__/architecture.test.d.ts.map +0 -1
  50. package/dist/__tests__/architecture.test.js +0 -207
  51. package/dist/__tests__/architecture.test.js.map +0 -1
  52. package/dist/__tests__/skill-namespace.test.d.ts +0 -2
  53. package/dist/__tests__/skill-namespace.test.d.ts.map +0 -1
  54. package/dist/__tests__/skill-namespace.test.js +0 -60
  55. package/dist/__tests__/skill-namespace.test.js.map +0 -1
  56. package/dist/__tests__/stakes-contract.test.d.ts +0 -2
  57. package/dist/__tests__/stakes-contract.test.d.ts.map +0 -1
  58. package/dist/__tests__/stakes-contract.test.js +0 -166
  59. package/dist/__tests__/stakes-contract.test.js.map +0 -1
  60. package/dist/__tests__/stuck-semantics.test.d.ts +0 -2
  61. package/dist/__tests__/stuck-semantics.test.d.ts.map +0 -1
  62. package/dist/__tests__/stuck-semantics.test.js +0 -109
  63. package/dist/__tests__/stuck-semantics.test.js.map +0 -1
  64. package/dist/__tests__/wiring-integrity.test.d.ts +0 -2
  65. package/dist/__tests__/wiring-integrity.test.d.ts.map +0 -1
  66. package/dist/__tests__/wiring-integrity.test.js +0 -160
  67. package/dist/__tests__/wiring-integrity.test.js.map +0 -1
  68. package/dist/cli/commands/info.test.d.ts +0 -2
  69. package/dist/cli/commands/info.test.d.ts.map +0 -1
  70. package/dist/cli/commands/info.test.js +0 -74
  71. package/dist/cli/commands/info.test.js.map +0 -1
  72. package/dist/cli/commands/upgrade.test.d.ts +0 -2
  73. package/dist/cli/commands/upgrade.test.d.ts.map +0 -1
  74. package/dist/cli/commands/upgrade.test.js +0 -99
  75. package/dist/cli/commands/upgrade.test.js.map +0 -1
  76. package/dist/cli/design/design-md-parser.test.d.ts +0 -2
  77. package/dist/cli/design/design-md-parser.test.d.ts.map +0 -1
  78. package/dist/cli/design/design-md-parser.test.js +0 -149
  79. package/dist/cli/design/design-md-parser.test.js.map +0 -1
  80. package/dist/cli/detect.characterization.test.d.ts +0 -7
  81. package/dist/cli/detect.characterization.test.d.ts.map +0 -1
  82. package/dist/cli/detect.characterization.test.js +0 -294
  83. package/dist/cli/detect.characterization.test.js.map +0 -1
  84. package/dist/cli/postinstall/fs-utils.test.d.ts +0 -2
  85. package/dist/cli/postinstall/fs-utils.test.d.ts.map +0 -1
  86. package/dist/cli/postinstall/fs-utils.test.js +0 -259
  87. package/dist/cli/postinstall/fs-utils.test.js.map +0 -1
  88. package/dist/cli/setup/CodexHooks.test.d.ts +0 -2
  89. package/dist/cli/setup/CodexHooks.test.d.ts.map +0 -1
  90. package/dist/cli/setup/CodexHooks.test.js +0 -52
  91. package/dist/cli/setup/CodexHooks.test.js.map +0 -1
  92. package/dist/cli/setup/GlobalInstaller.test.d.ts +0 -2
  93. package/dist/cli/setup/GlobalInstaller.test.d.ts.map +0 -1
  94. package/dist/cli/setup/GlobalInstaller.test.js +0 -16
  95. package/dist/cli/setup/GlobalInstaller.test.js.map +0 -1
  96. package/dist/cli/utils/cli-detector.test.d.ts +0 -2
  97. package/dist/cli/utils/cli-detector.test.d.ts.map +0 -1
  98. package/dist/cli/utils/cli-detector.test.js +0 -52
  99. package/dist/cli/utils/cli-detector.test.js.map +0 -1
  100. package/dist/infra/lib/SkillFrontmatter.test.d.ts +0 -2
  101. package/dist/infra/lib/SkillFrontmatter.test.d.ts.map +0 -1
  102. package/dist/infra/lib/SkillFrontmatter.test.js +0 -60
  103. package/dist/infra/lib/SkillFrontmatter.test.js.map +0 -1
  104. package/dist/infra/lib/__tests__/AutomationLevel.test.d.ts +0 -2
  105. package/dist/infra/lib/__tests__/AutomationLevel.test.d.ts.map +0 -1
  106. package/dist/infra/lib/__tests__/AutomationLevel.test.js +0 -297
  107. package/dist/infra/lib/__tests__/AutomationLevel.test.js.map +0 -1
  108. package/dist/infra/lib/__tests__/ComponentRegistry.test.d.ts +0 -2
  109. package/dist/infra/lib/__tests__/ComponentRegistry.test.d.ts.map +0 -1
  110. package/dist/infra/lib/__tests__/ComponentRegistry.test.js +0 -99
  111. package/dist/infra/lib/__tests__/ComponentRegistry.test.js.map +0 -1
  112. package/dist/infra/lib/__tests__/DecisionTracer.test.d.ts +0 -2
  113. package/dist/infra/lib/__tests__/DecisionTracer.test.d.ts.map +0 -1
  114. package/dist/infra/lib/__tests__/DecisionTracer.test.js +0 -274
  115. package/dist/infra/lib/__tests__/DecisionTracer.test.js.map +0 -1
  116. package/dist/infra/lib/__tests__/InteractiveCheckpoint.test.d.ts +0 -2
  117. package/dist/infra/lib/__tests__/InteractiveCheckpoint.test.d.ts.map +0 -1
  118. package/dist/infra/lib/__tests__/InteractiveCheckpoint.test.js +0 -350
  119. package/dist/infra/lib/__tests__/InteractiveCheckpoint.test.js.map +0 -1
  120. package/dist/infra/lib/__tests__/LoopBreaker.test.d.ts +0 -2
  121. package/dist/infra/lib/__tests__/LoopBreaker.test.d.ts.map +0 -1
  122. package/dist/infra/lib/__tests__/LoopBreaker.test.js +0 -340
  123. package/dist/infra/lib/__tests__/LoopBreaker.test.js.map +0 -1
  124. package/dist/infra/lib/__tests__/VerificationLoop.test.d.ts +0 -2
  125. package/dist/infra/lib/__tests__/VerificationLoop.test.d.ts.map +0 -1
  126. package/dist/infra/lib/__tests__/VerificationLoop.test.js +0 -486
  127. package/dist/infra/lib/__tests__/VerificationLoop.test.js.map +0 -1
  128. package/dist/infra/lib/config/GlobalConfigManager.test.d.ts +0 -2
  129. package/dist/infra/lib/config/GlobalConfigManager.test.d.ts.map +0 -1
  130. package/dist/infra/lib/config/GlobalConfigManager.test.js +0 -9
  131. package/dist/infra/lib/config/GlobalConfigManager.test.js.map +0 -1
  132. package/dist/infra/lib/embedding/__tests__/EmbeddingProvider.test.d.ts +0 -2
  133. package/dist/infra/lib/embedding/__tests__/EmbeddingProvider.test.d.ts.map +0 -1
  134. package/dist/infra/lib/embedding/__tests__/EmbeddingProvider.test.js +0 -43
  135. package/dist/infra/lib/embedding/__tests__/EmbeddingProvider.test.js.map +0 -1
  136. package/dist/infra/lib/embedding/__tests__/VectorStore.test.d.ts +0 -2
  137. package/dist/infra/lib/embedding/__tests__/VectorStore.test.d.ts.map +0 -1
  138. package/dist/infra/lib/embedding/__tests__/VectorStore.test.js +0 -94
  139. package/dist/infra/lib/embedding/__tests__/VectorStore.test.js.map +0 -1
  140. package/dist/infra/lib/embedding/__tests__/cosine.test.d.ts +0 -2
  141. package/dist/infra/lib/embedding/__tests__/cosine.test.d.ts.map +0 -1
  142. package/dist/infra/lib/embedding/__tests__/cosine.test.js +0 -73
  143. package/dist/infra/lib/embedding/__tests__/cosine.test.js.map +0 -1
  144. package/dist/infra/lib/evolution/__tests__/deprecation.test.d.ts +0 -2
  145. package/dist/infra/lib/evolution/__tests__/deprecation.test.d.ts.map +0 -1
  146. package/dist/infra/lib/evolution/__tests__/deprecation.test.js +0 -251
  147. package/dist/infra/lib/evolution/__tests__/deprecation.test.js.map +0 -1
  148. package/dist/infra/lib/evolution/__tests__/eval.test.d.ts +0 -2
  149. package/dist/infra/lib/evolution/__tests__/eval.test.d.ts.map +0 -1
  150. package/dist/infra/lib/evolution/__tests__/eval.test.js +0 -603
  151. package/dist/infra/lib/evolution/__tests__/eval.test.js.map +0 -1
  152. package/dist/infra/lib/evolution/__tests__/generation.test.d.ts +0 -2
  153. package/dist/infra/lib/evolution/__tests__/generation.test.d.ts.map +0 -1
  154. package/dist/infra/lib/evolution/__tests__/generation.test.js +0 -396
  155. package/dist/infra/lib/evolution/__tests__/generation.test.js.map +0 -1
  156. package/dist/infra/lib/evolution/__tests__/insight.test.d.ts +0 -2
  157. package/dist/infra/lib/evolution/__tests__/insight.test.d.ts.map +0 -1
  158. package/dist/infra/lib/evolution/__tests__/insight.test.js +0 -204
  159. package/dist/infra/lib/evolution/__tests__/insight.test.js.map +0 -1
  160. package/dist/infra/lib/evolution/__tests__/integration.test.d.ts +0 -2
  161. package/dist/infra/lib/evolution/__tests__/integration.test.d.ts.map +0 -1
  162. package/dist/infra/lib/evolution/__tests__/integration.test.js +0 -206
  163. package/dist/infra/lib/evolution/__tests__/integration.test.js.map +0 -1
  164. package/dist/infra/lib/evolution/__tests__/lifecycle.test.d.ts +0 -2
  165. package/dist/infra/lib/evolution/__tests__/lifecycle.test.d.ts.map +0 -1
  166. package/dist/infra/lib/evolution/__tests__/lifecycle.test.js +0 -350
  167. package/dist/infra/lib/evolution/__tests__/lifecycle.test.js.map +0 -1
  168. package/dist/infra/lib/evolution/__tests__/parity.test.d.ts +0 -2
  169. package/dist/infra/lib/evolution/__tests__/parity.test.d.ts.map +0 -1
  170. package/dist/infra/lib/evolution/__tests__/parity.test.js +0 -319
  171. package/dist/infra/lib/evolution/__tests__/parity.test.js.map +0 -1
  172. package/dist/infra/lib/llm/auth/AuthProfileManager.test.d.ts +0 -5
  173. package/dist/infra/lib/llm/auth/AuthProfileManager.test.d.ts.map +0 -1
  174. package/dist/infra/lib/llm/auth/AuthProfileManager.test.js +0 -168
  175. package/dist/infra/lib/llm/auth/AuthProfileManager.test.js.map +0 -1
  176. package/dist/infra/lib/llm/auth/TokenRefresher.test.d.ts +0 -2
  177. package/dist/infra/lib/llm/auth/TokenRefresher.test.d.ts.map +0 -1
  178. package/dist/infra/lib/llm/auth/TokenRefresher.test.js +0 -120
  179. package/dist/infra/lib/llm/auth/TokenRefresher.test.js.map +0 -1
  180. package/dist/infra/lib/llm/timeout.test.d.ts +0 -2
  181. package/dist/infra/lib/llm/timeout.test.d.ts.map +0 -1
  182. package/dist/infra/lib/llm/timeout.test.js +0 -50
  183. package/dist/infra/lib/llm/timeout.test.js.map +0 -1
  184. package/dist/infra/lib/llm-availability.test.d.ts +0 -2
  185. package/dist/infra/lib/llm-availability.test.d.ts.map +0 -1
  186. package/dist/infra/lib/llm-availability.test.js +0 -37
  187. package/dist/infra/lib/llm-availability.test.js.map +0 -1
  188. package/dist/infra/lib/memory/KnowledgeGraph.test.d.ts +0 -2
  189. package/dist/infra/lib/memory/KnowledgeGraph.test.d.ts.map +0 -1
  190. package/dist/infra/lib/memory/KnowledgeGraph.test.js +0 -189
  191. package/dist/infra/lib/memory/KnowledgeGraph.test.js.map +0 -1
  192. package/dist/infra/lib/memory/MemorySearch.test.d.ts +0 -2
  193. package/dist/infra/lib/memory/MemorySearch.test.d.ts.map +0 -1
  194. package/dist/infra/lib/memory/MemorySearch.test.js +0 -149
  195. package/dist/infra/lib/memory/MemorySearch.test.js.map +0 -1
  196. package/dist/infra/lib/memory/MemoryStorage.test.d.ts +0 -2
  197. package/dist/infra/lib/memory/MemoryStorage.test.d.ts.map +0 -1
  198. package/dist/infra/lib/memory/MemoryStorage.test.js +0 -198
  199. package/dist/infra/lib/memory/MemoryStorage.test.js.map +0 -1
  200. package/dist/infra/lib/memory/SessionRAGRetriever.test.d.ts +0 -2
  201. package/dist/infra/lib/memory/SessionRAGRetriever.test.d.ts.map +0 -1
  202. package/dist/infra/lib/memory/SessionRAGRetriever.test.js +0 -180
  203. package/dist/infra/lib/memory/SessionRAGRetriever.test.js.map +0 -1
  204. package/dist/infra/lib/memory/SessionRAGStore.test.d.ts +0 -2
  205. package/dist/infra/lib/memory/SessionRAGStore.test.d.ts.map +0 -1
  206. package/dist/infra/lib/memory/SessionRAGStore.test.js +0 -326
  207. package/dist/infra/lib/memory/SessionRAGStore.test.js.map +0 -1
  208. package/dist/infra/lib/memory/__tests__/InMemoryStorage.test.d.ts +0 -2
  209. package/dist/infra/lib/memory/__tests__/InMemoryStorage.test.d.ts.map +0 -1
  210. package/dist/infra/lib/memory/__tests__/InMemoryStorage.test.js +0 -114
  211. package/dist/infra/lib/memory/__tests__/InMemoryStorage.test.js.map +0 -1
  212. package/dist/infra/lib/memory/__tests__/ReflectionStore.test.d.ts +0 -2
  213. package/dist/infra/lib/memory/__tests__/ReflectionStore.test.d.ts.map +0 -1
  214. package/dist/infra/lib/memory/__tests__/ReflectionStore.test.js +0 -196
  215. package/dist/infra/lib/memory/__tests__/ReflectionStore.test.js.map +0 -1
  216. package/dist/infra/lib/memory/index.test.d.ts +0 -2
  217. package/dist/infra/lib/memory/index.test.d.ts.map +0 -1
  218. package/dist/infra/lib/memory/index.test.js +0 -23
  219. package/dist/infra/lib/memory/index.test.js.map +0 -1
  220. package/dist/infra/lib/telemetry/SkillTelemetry.test.d.ts +0 -2
  221. package/dist/infra/lib/telemetry/SkillTelemetry.test.d.ts.map +0 -1
  222. package/dist/infra/lib/telemetry/SkillTelemetry.test.js +0 -124
  223. package/dist/infra/lib/telemetry/SkillTelemetry.test.js.map +0 -1
  224. package/dist/infra/lib/ui-ux/Bm25Engine.test.d.ts +0 -2
  225. package/dist/infra/lib/ui-ux/Bm25Engine.test.d.ts.map +0 -1
  226. package/dist/infra/lib/ui-ux/Bm25Engine.test.js +0 -159
  227. package/dist/infra/lib/ui-ux/Bm25Engine.test.js.map +0 -1
  228. package/dist/infra/lib/ui-ux/CsvDataLoader.test.d.ts +0 -2
  229. package/dist/infra/lib/ui-ux/CsvDataLoader.test.d.ts.map +0 -1
  230. package/dist/infra/lib/ui-ux/CsvDataLoader.test.js +0 -141
  231. package/dist/infra/lib/ui-ux/CsvDataLoader.test.js.map +0 -1
  232. package/dist/infra/lib/ui-ux/DesignSystemGenerator.test.d.ts +0 -2
  233. package/dist/infra/lib/ui-ux/DesignSystemGenerator.test.d.ts.map +0 -1
  234. package/dist/infra/lib/ui-ux/DesignSystemGenerator.test.js +0 -370
  235. package/dist/infra/lib/ui-ux/DesignSystemGenerator.test.js.map +0 -1
  236. package/dist/infra/lib/ui-ux/SearchService.test.d.ts +0 -2
  237. package/dist/infra/lib/ui-ux/SearchService.test.d.ts.map +0 -1
  238. package/dist/infra/lib/ui-ux/SearchService.test.js +0 -215
  239. package/dist/infra/lib/ui-ux/SearchService.test.js.map +0 -1
  240. package/dist/test-helpers/index.d.ts +0 -36
  241. package/dist/test-helpers/index.d.ts.map +0 -1
  242. package/dist/test-helpers/index.js +0 -85
  243. package/dist/test-helpers/index.js.map +0 -1
  244. package/dist/test-helpers/index.test.d.ts +0 -2
  245. package/dist/test-helpers/index.test.d.ts.map +0 -1
  246. package/dist/test-helpers/index.test.js +0 -92
  247. package/dist/test-helpers/index.test.js.map +0 -1
  248. package/dist/tests/curated-release-notes.test.d.ts +0 -2
  249. package/dist/tests/curated-release-notes.test.d.ts.map +0 -1
  250. package/dist/tests/curated-release-notes.test.js +0 -160
  251. package/dist/tests/curated-release-notes.test.js.map +0 -1
  252. package/dist/tools/convention/analyzeComplexity.test.d.ts +0 -2
  253. package/dist/tools/convention/analyzeComplexity.test.d.ts.map +0 -1
  254. package/dist/tools/convention/analyzeComplexity.test.js +0 -207
  255. package/dist/tools/convention/analyzeComplexity.test.js.map +0 -1
  256. package/dist/tools/convention/validateCodeQuality.test.d.ts +0 -2
  257. package/dist/tools/convention/validateCodeQuality.test.d.ts.map +0 -1
  258. package/dist/tools/convention/validateCodeQuality.test.js +0 -230
  259. package/dist/tools/convention/validateCodeQuality.test.js.map +0 -1
  260. package/dist/tools/loop/validateLoopDefinition.test.d.ts +0 -14
  261. package/dist/tools/loop/validateLoopDefinition.test.d.ts.map +0 -1
  262. package/dist/tools/loop/validateLoopDefinition.test.js +0 -229
  263. package/dist/tools/loop/validateLoopDefinition.test.js.map +0 -1
  264. package/dist/tools/spec/executionPacket.test.d.ts +0 -2
  265. package/dist/tools/spec/executionPacket.test.d.ts.map +0 -1
  266. package/dist/tools/spec/executionPacket.test.js +0 -374
  267. package/dist/tools/spec/executionPacket.test.js.map +0 -1
  268. package/dist/tools/spec/prdParser.test.d.ts +0 -6
  269. package/dist/tools/spec/prdParser.test.d.ts.map +0 -1
  270. package/dist/tools/spec/prdParser.test.js +0 -332
  271. package/dist/tools/spec/prdParser.test.js.map +0 -1
  272. package/dist/tools/spec/specGenerator.test.d.ts +0 -2
  273. package/dist/tools/spec/specGenerator.test.d.ts.map +0 -1
  274. package/dist/tools/spec/specGenerator.test.js +0 -130
  275. package/dist/tools/spec/specGenerator.test.js.map +0 -1
  276. package/dist/tools/spec/traceabilityMatrix.path-resolution.test.d.ts +0 -10
  277. package/dist/tools/spec/traceabilityMatrix.path-resolution.test.d.ts.map +0 -1
  278. package/dist/tools/spec/traceabilityMatrix.path-resolution.test.js +0 -120
  279. package/dist/tools/spec/traceabilityMatrix.path-resolution.test.js.map +0 -1
  280. package/dist/tools/spec/traceabilityMatrix.test.d.ts +0 -6
  281. package/dist/tools/spec/traceabilityMatrix.test.d.ts.map +0 -1
  282. package/dist/tools/spec/traceabilityMatrix.test.js +0 -359
  283. package/dist/tools/spec/traceabilityMatrix.test.js.map +0 -1
  284. package/hooks/scripts/__tests__/.vibe/command-log.txt +0 -3
  285. package/hooks/scripts/__tests__/auto-test-debounce.test.js +0 -145
  286. package/hooks/scripts/__tests__/clone-behaviors.test.js +0 -152
  287. package/hooks/scripts/__tests__/clone-merge-responsive.test.js +0 -106
  288. package/hooks/scripts/__tests__/code-check-detectors.test.js +0 -213
  289. package/hooks/scripts/__tests__/code-check-memory-write.test.js +0 -81
  290. package/hooks/scripts/__tests__/codex-hook-adapter.test.js +0 -64
  291. package/hooks/scripts/__tests__/curation-index.test.js +0 -157
  292. package/hooks/scripts/__tests__/dispatcher-inprocess.test.js +0 -99
  293. package/hooks/scripts/__tests__/figma-extract.test.js +0 -338
  294. package/hooks/scripts/__tests__/hook-payload.test.js +0 -29
  295. package/hooks/scripts/__tests__/llm-orchestrate-antigravity.test.js +0 -66
  296. package/hooks/scripts/__tests__/loop-ledger.test.js +0 -321
  297. package/hooks/scripts/__tests__/post-edit-dispatcher.test.js +0 -139
  298. package/hooks/scripts/__tests__/pre-tool-guard.test.js +0 -523
  299. package/hooks/scripts/__tests__/recipe-extractor.test.js +0 -244
  300. package/hooks/scripts/__tests__/run-ledger-verify-required.test.js +0 -151
  301. package/hooks/scripts/__tests__/run-ledger.test.js +0 -481
  302. package/hooks/scripts/__tests__/scope-from-spec.test.js +0 -215
  303. package/hooks/scripts/__tests__/sentinel-guard.test.js +0 -263
  304. package/hooks/scripts/__tests__/step-counter.test.js +0 -459
  305. package/hooks/scripts/__tests__/utils-npm-root.test.js +0 -99
@@ -1,152 +0,0 @@
1
- /**
2
- * clone active-interaction-sweep helpers
3
- * - diffStyles: before/after computed-style differ (clone-extract.js)
4
- * - sectionHasNode / behaviorsBlock: behavior→section attachment (clone-spec.js)
5
- */
6
-
7
- import { describe, it, expect } from 'vitest';
8
- import { collectSubUrls, diffStyles } from '../clone-extract.js';
9
- import { sectionHasNode, behaviorsBlock } from '../clone-spec.js';
10
-
11
- describe('diffStyles', () => {
12
- it('reports only changed props with from/to', () => {
13
- const a = { 'background-color': 'rgba(0, 0, 0, 0)', height: '80px' };
14
- const b = { 'background-color': 'rgb(255, 255, 255)', height: '80px' };
15
- expect(diffStyles(a, b)).toEqual({
16
- 'background-color': { from: 'rgba(0, 0, 0, 0)', to: 'rgb(255, 255, 255)' },
17
- });
18
- });
19
-
20
- it('captures props that appear or disappear', () => {
21
- const d = diffStyles({}, { 'box-shadow': '0 4px 20px rgba(0,0,0,0.1)' });
22
- expect(d['box-shadow']).toEqual({ from: null, to: '0 4px 20px rgba(0,0,0,0.1)' });
23
- });
24
-
25
- it('returns empty when nothing changed or a snapshot is missing', () => {
26
- expect(diffStyles({ color: 'red' }, { color: 'red' })).toEqual({});
27
- expect(diffStyles(null, { color: 'red' })).toEqual({});
28
- });
29
- });
30
-
31
- describe('collectSubUrls', () => {
32
- it('keeps same-origin locale menu links and drops footer/external links', () => {
33
- const urls = collectSubUrls('https://www.lgdisplay.com/kor', [
34
- { href: '/kor/company/info/outline/greeting', text: '기업개요' },
35
- { href: '/kor/product/tv/oled', text: 'TV' },
36
- { href: '/eng', text: 'ENG' },
37
- { href: '/kor/privacy', text: '개인정보처리방침' },
38
- { href: 'https://news.lgdisplay.com/news', text: 'Newsroom' },
39
- { href: 'https://www.youtube.com/@lgdisplay', text: 'You Tube' },
40
- { href: '#top', text: 'TOP' },
41
- ]);
42
-
43
- expect(urls).toEqual([
44
- 'https://www.lgdisplay.com/kor',
45
- 'https://www.lgdisplay.com/kor/company/info/outline/greeting',
46
- 'https://www.lgdisplay.com/kor/product/tv/oled',
47
- ]);
48
- });
49
-
50
- it('deduplicates links after dropping query strings and hashes', () => {
51
- const urls = collectSubUrls('https://example.com/kor', [
52
- { href: '/kor/company?utm_source=x', text: 'Company' },
53
- { href: '/kor/company#ceo', text: 'Company' },
54
- ]);
55
-
56
- expect(urls).toEqual([
57
- 'https://example.com/kor',
58
- 'https://example.com/kor/company',
59
- ]);
60
- });
61
- });
62
-
63
- describe('behavior → section attachment', () => {
64
- const section = {
65
- name: 'Header',
66
- children: [{ tag: 'header', classes: 'site-nav top', children: [{ tag: 'button', classes: 'tab', children: [] }] }],
67
- };
68
-
69
- it('matches a node by tag and class', () => {
70
- expect(sectionHasNode(section, 'header', 'site-nav')).toBe(true);
71
- expect(sectionHasNode(section, 'header', 'missing')).toBe(false);
72
- expect(sectionHasNode(section, 'button')).toBe(true);
73
- });
74
-
75
- it('attaches a scroll behavior to the matching section only', () => {
76
- const behaviors = {
77
- scroll: [{ label: 'header.site-nav', tag: 'header', cls: 'site-nav', triggerScrollY: 700, changed: { height: { from: '80px', to: '56px' } } }],
78
- interactive: [{ kind: 'tab-group', count: 3, tabLabels: ['A', 'B', 'C'], contentSwapsOnClick: true }],
79
- };
80
- const block = behaviorsBlock(section, behaviors);
81
- expect(block).toContain('Scroll-triggered');
82
- expect(block).toContain('height');
83
- expect(block).toContain('content SWAPS on click');
84
-
85
- const footer = { name: 'Footer', children: [{ tag: 'p', classes: '', children: [] }] };
86
- expect(behaviorsBlock(footer, behaviors)).toBeNull();
87
- });
88
-
89
- it('renders hover / in-view / time-driven / scroll-lib behavior kinds', () => {
90
- const behaviors = {
91
- scroll: [],
92
- interactive: [],
93
- 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)' } } }],
94
- inview: [{ label: 'div.fade', tag: 'div', cls: 'fade', triggerY: 1400, changed: { opacity: { from: '0', to: '1' } } }],
95
- timeDriven: [{ label: 'div.slide', tag: 'div', cls: 'slide', mutations: 12, kinds: ['class'] }],
96
- scrollLib: { name: 'lenis', evidence: 'html.lenis' },
97
- };
98
- const hero = {
99
- name: 'Hero',
100
- children: [{ tag: 'div', classes: 'fade slide', children: [{ tag: 'a', classes: 'cta', children: [] }] }],
101
- };
102
- const block = behaviorsBlock(hero, behaviors);
103
- expect(block).toContain('**Hover** on `a.cta`');
104
- expect(block).toContain('transition: `all 0.3s ease 0s`');
105
- expect(block).toContain('**In-view entrance** on `div.fade` (enters at ~1400px)');
106
- expect(block).toContain('opacity: `0` → `1`');
107
- expect(block).toContain('**Time-driven** `div.slide` — 12 mutations/3s');
108
- expect(block).toContain('lenis');
109
- });
110
-
111
- it('renders a page-level scroll-lib note even when no section-scoped behavior matches', () => {
112
- const onlyLib = { scroll: [], interactive: [], scrollLib: { name: 'lenis', evidence: 'window.Lenis' } };
113
- const footer = { name: 'Footer', children: [{ tag: 'p', classes: '', children: [] }] };
114
- expect(behaviorsBlock(footer, onlyLib)).toContain('lenis');
115
- });
116
-
117
- it('suppresses the default transition value on hover entries', () => {
118
- const behaviors = {
119
- 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)' } } }],
120
- };
121
- const sec = { name: 'S', children: [{ tag: 'button', classes: 'x', children: [] }] };
122
- expect(behaviorsBlock(sec, behaviors)).not.toContain('transition:');
123
- });
124
- });
125
-
126
- describe('clone-spec CLI --real-content', () => {
127
- const runCli = async (extraArgs) => {
128
- const [fs, os, path, url, cp] = await Promise.all([
129
- import('fs'), import('os'), import('path'), import('url'), import('child_process'),
130
- ]);
131
- const tmp = fs.default.mkdtempSync(path.default.join(os.default.tmpdir(), 'clone-spec-'));
132
- const sections = path.default.join(tmp, 'sections.json');
133
- fs.default.writeFileSync(sections, JSON.stringify({
134
- meta: { feature: 'f', bp: 'mo', url: 'https://x.test' },
135
- sections: [{ name: 'Hero', nodeRef: '0', tag: 'section', css: {}, children: [] }],
136
- }));
137
- const script = url.default.fileURLToPath(new URL('../clone-spec.js', import.meta.url));
138
- cp.default.execFileSync('node', [script, sections, `--out=${tmp}/specs`, ...extraArgs]);
139
- return fs.default.readFileSync(path.default.join(tmp, 'specs', 'Hero.spec.md'), 'utf8');
140
- };
141
-
142
- it('defaults to placeholder replacement wording', async () => {
143
- const spec = await runCli([]);
144
- expect(spec).toContain('(replace copyrighted copy with placeholders)');
145
- });
146
-
147
- it('switches to verbatim wording with --real-content', async () => {
148
- const spec = await runCli(['--real-content']);
149
- expect(spec).toContain('(verbatim — user confirmed rights to reuse this copy)');
150
- expect(spec).not.toContain('(replace copyrighted copy with placeholders)');
151
- });
152
- });
@@ -1,106 +0,0 @@
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
- });
@@ -1,213 +0,0 @@
1
- /**
2
- * code-check.js 정밀 탐지기 테스트
3
- *
4
- * 검증 대상:
5
- * - any 탐지: 단어 경계 기반 (false positive: 'company', 'anything' 등)
6
- * - any 탐지: `: any`, `as any`, `@ts-ignore`, `<any>` (true positive)
7
- * - console.log 정책: 경로별 허용/차단
8
- * - run-ledger verifyRequired round-trip + pass 시 clear
9
- * - auto-commit verifyRequired skip
10
- */
11
- import { describe, it, expect, beforeEach, afterEach } from 'vitest';
12
- import { fileURLToPath } from 'url';
13
- import path from 'path';
14
- import fs from 'fs';
15
- import os from 'os';
16
-
17
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
18
-
19
- // ─── any 탐지 정규식 (code-check.js와 동일) ──────────────────────────────
20
- const P1_DETECTORS = [
21
- /:\s*any\b/,
22
- /\bas\s+any\b/,
23
- /<any[\s,>]/,
24
- /@ts-ignore\b/,
25
- ];
26
-
27
- function detectsAny(line) {
28
- return P1_DETECTORS.some(re => re.test(line));
29
- }
30
-
31
- describe('any 탐지: true positive', () => {
32
- it(': any — 타입 어노테이션', () => {
33
- expect(detectsAny('function foo(x: any): void {}')).toBe(true);
34
- });
35
-
36
- it(': any — 공백 포함', () => {
37
- expect(detectsAny('const x: any = 1;')).toBe(true);
38
- });
39
-
40
- it('as any — 타입 캐스트', () => {
41
- expect(detectsAny('const y = x as any;')).toBe(true);
42
- });
43
-
44
- it('<any> — 제네릭', () => {
45
- expect(detectsAny('const z = foo<any>();')).toBe(true);
46
- });
47
-
48
- it('<any, — 제네릭 다중 파라미터', () => {
49
- expect(detectsAny('const m = new Map<any, string>();')).toBe(true);
50
- });
51
-
52
- it('@ts-ignore — 라인 직전', () => {
53
- expect(detectsAny('// @ts-ignore')).toBe(true);
54
- });
55
-
56
- it('@ts-ignore — 인라인', () => {
57
- expect(detectsAny(' @ts-ignore ')).toBe(true);
58
- });
59
- });
60
-
61
- describe('any 탐지: false negative (탐지 안 됨)', () => {
62
- it('"company" 단어 포함 — 탐지 안 됨', () => {
63
- expect(detectsAny('const company = "Acme";')).toBe(false);
64
- });
65
-
66
- it('"anything" 식별자 — 탐지 안 됨', () => {
67
- expect(detectsAny('if (anything) return;')).toBe(false);
68
- });
69
-
70
- it('"manyThings" — 탐지 안 됨', () => {
71
- expect(detectsAny('const manyThings = [];')).toBe(false);
72
- });
73
-
74
- it('"fantasy" — 탐지 안 됨', () => {
75
- expect(detectsAny('const fantasy = "world";')).toBe(false);
76
- });
77
-
78
- it('문자열 리터럴 "any" — 정규식은 문자열 내부도 매칭할 수 있음 (알려진 한계, 문서화)', () => {
79
- // NOTE: 현재 구현은 문자열 내 "any"를 완전히 제외하지 않음.
80
- // 실제 코드에서 ": any" 패턴이 문자열로 존재하는 경우는 극히 드물어 허용.
81
- // 이 테스트는 동작을 문서화하는 것이 목적.
82
- const result = detectsAny('const msg = "type: any is bad";');
83
- // 문자열 내 ": any" 도 탐지될 수 있음 — false positive지만 드문 케이스
84
- expect(typeof result).toBe('boolean');
85
- });
86
- });
87
-
88
- // ─── console.log 경로 정책 ────────────────────────────────────────────────
89
- describe('console.log 허용 경로 정책', () => {
90
- // 허용 glob 패턴 (code-check.js 기본값과 동일)
91
- const DEFAULT_ALLOW_GLOBS = [
92
- 'hooks/scripts/**',
93
- 'scripts/**',
94
- '**/cli/**',
95
- '**/*.test.*',
96
- '**/*.spec.*',
97
- '**/__tests__/**',
98
- ];
99
-
100
- function globToRegExp(glob) {
101
- const normalized = glob.replace(/\\/g, '/');
102
- let out = '';
103
- for (let i = 0; i < normalized.length; i++) {
104
- const c = normalized[i];
105
- if (c === '*') {
106
- if (normalized[i + 1] === '*') {
107
- out += '.*';
108
- i++;
109
- if (normalized[i + 1] === '/') i++;
110
- } else {
111
- out += '[^/]*';
112
- }
113
- } else if (c === '?') {
114
- out += '[^/]';
115
- } else if ('.+^$()|{}[]\\'.includes(c)) {
116
- out += '\\' + c;
117
- } else {
118
- out += c;
119
- }
120
- }
121
- return new RegExp('^' + out + '$');
122
- }
123
-
124
- function isConsoleAllowed(relPath) {
125
- return DEFAULT_ALLOW_GLOBS.some(g => globToRegExp(g).test(relPath));
126
- }
127
-
128
- it('hooks/scripts/auto-test.js → 허용', () => {
129
- expect(isConsoleAllowed('hooks/scripts/auto-test.js')).toBe(true);
130
- });
131
-
132
- it('hooks/scripts/lib/run-ledger.js → 허용', () => {
133
- expect(isConsoleAllowed('hooks/scripts/lib/run-ledger.js')).toBe(true);
134
- });
135
-
136
- it('src/cli/index.ts → 허용 (**/cli/**)', () => {
137
- expect(isConsoleAllowed('src/cli/index.ts')).toBe(true);
138
- });
139
-
140
- it('src/tools/foo.test.ts → 허용 (**/*.test.*)', () => {
141
- expect(isConsoleAllowed('src/tools/foo.test.ts')).toBe(true);
142
- });
143
-
144
- it('src/__tests__/bar.ts → 허용 (**/__tests__/**)', () => {
145
- expect(isConsoleAllowed('src/__tests__/bar.ts')).toBe(true);
146
- });
147
-
148
- it('src/tools/convention/validateCodeQuality.ts → 차단', () => {
149
- expect(isConsoleAllowed('src/tools/convention/validateCodeQuality.ts')).toBe(false);
150
- });
151
-
152
- it('src/infra/lib/MemoryManager.ts → 차단', () => {
153
- expect(isConsoleAllowed('src/infra/lib/MemoryManager.ts')).toBe(false);
154
- });
155
- });
156
-
157
- // ─── 확장자 게이트 (문서 안의 코드 스니펫 오탐 방지) ──────────────────────
158
- /**
159
- * SKILL.md 등 문서에 인용된 `console.log(` 는 커밋되면 안 되는 디버그 코드가
160
- * 아니라 예시다. 확장자 게이트가 없으면 문서를 편집할 때마다 고칠 수도 없는
161
- * P1 이 주입되고, 반복되는 오탐이 게이트 신뢰도를 깎는다.
162
- *
163
- * 재구현이 아니라 실제 code-check.js 의 run() 을 통과시켜 검증한다.
164
- */
165
- describe('console.log 확장자 게이트', () => {
166
- let tempDir;
167
- let runCodeCheck;
168
-
169
- beforeEach(async () => {
170
- tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'vibe-codecheck-ext-'));
171
- ({ run: runCodeCheck } = await import('../code-check.js'));
172
- });
173
-
174
- afterEach(() => {
175
- fs.rmSync(tempDir, { recursive: true, force: true });
176
- });
177
-
178
- /** 허용 glob 에 걸리지 않는 경로를 쓰기 위해 src/feature/ 아래에 만든다 */
179
- function writeFixture(name, body) {
180
- const dir = path.join(tempDir, 'src', 'feature');
181
- fs.mkdirSync(dir, { recursive: true });
182
- const full = path.join(dir, name);
183
- fs.writeFileSync(full, body);
184
- return full;
185
- }
186
-
187
- it('마크다운 안의 console.log 는 findings 를 만들지 않는다', async () => {
188
- const filePath = writeFixture(
189
- 'guide.md',
190
- ['# Guide', '', '```bash', 'node -e "console.log(1)"', '```', ''].join('\n'),
191
- );
192
-
193
- const { findings } = await runCodeCheck({ filePath });
194
-
195
- expect(findings.filter(f => /console\.log/.test(f))).toEqual([]);
196
- });
197
-
198
- it('JSON 안의 console.log 문자열도 findings 를 만들지 않는다', async () => {
199
- const filePath = writeFixture('fixture.json', '{ "cmd": "console.log(1)" }\n');
200
-
201
- const { findings } = await runCodeCheck({ filePath });
202
-
203
- expect(findings.filter(f => /console\.log/.test(f))).toEqual([]);
204
- });
205
-
206
- it('코드 확장자에서는 여전히 탐지한다 (게이트가 탐지 자체를 죽이지 않음)', async () => {
207
- const filePath = writeFixture('service.ts', 'export const f = () => { console.log(1); };\n');
208
-
209
- const { findings } = await runCodeCheck({ filePath });
210
-
211
- expect(findings.some(f => /console\.log/.test(f))).toBe(true);
212
- });
213
- });
@@ -1,81 +0,0 @@
1
- /**
2
- * code-check.js — C1 회귀 테스트: SQLite addObservation 조건화
3
- *
4
- * 검증 대상:
5
- * - 무위반(clean) Edit → memories.db 자체가 생성되지 않음 (SQLite write 없음)
6
- * - 위반(violation) Edit → memories.db 생성 (addObservation 기록)
7
- * - 코드 확장자가 아닌 파일 → 동적 import 전 조기 반환 (write 없음)
8
- *
9
- * dist 빌드 필요 (BASE_URL = dist/tools) — `npm run build` 이후 실행.
10
- * 패턴: 훅 스크립트 공통의 spawnSync 방식 (post-edit-dispatcher.test.js 참고).
11
- */
12
- import { describe, it, expect, beforeEach, afterEach } from 'vitest';
13
- import { spawnSync } from 'child_process';
14
- import fs from 'fs';
15
- import os from 'os';
16
- import path from 'path';
17
- import { fileURLToPath } from 'url';
18
-
19
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
20
- const SCRIPT = path.resolve(__dirname, '..', 'code-check.js');
21
-
22
- /**
23
- * 격리된 임시 프로젝트에서 code-check 를 1회 실행.
24
- * stdin 으로 PostToolUse payload 전달.
25
- */
26
- function runCodeCheck({ filePath, projectDir }) {
27
- const payload = { tool_name: 'Edit', tool_input: { file_path: filePath } };
28
- return spawnSync('node', [SCRIPT], {
29
- input: JSON.stringify(payload),
30
- encoding: 'utf-8',
31
- timeout: 15000,
32
- env: { ...process.env, CLAUDE_PROJECT_DIR: projectDir },
33
- });
34
- }
35
-
36
- function memoriesDbPath(projectDir) {
37
- return path.join(projectDir, '.vibe', 'memories', 'memories.db');
38
- }
39
-
40
- describe('code-check.js: 위반 시에만 SQLite 기록 (C1)', () => {
41
- let projectDir;
42
-
43
- beforeEach(() => {
44
- projectDir = fs.mkdtempSync(path.join(os.tmpdir(), 'vibe-code-check-'));
45
- });
46
-
47
- afterEach(() => {
48
- try { fs.rmSync(projectDir, { recursive: true, force: true }); } catch { /* ignore */ }
49
- });
50
-
51
- it('무위반 TS 파일 편집 → memories.db 미생성 (SQLite write 없음)', () => {
52
- const filePath = path.join(projectDir, 'clean.ts');
53
- fs.writeFileSync(filePath, 'export function add(a: number, b: number): number {\n return a + b;\n}\n');
54
-
55
- const result = runCodeCheck({ filePath, projectDir });
56
-
57
- expect(result.status).toBe(0);
58
- expect(fs.existsSync(memoriesDbPath(projectDir))).toBe(false);
59
- });
60
-
61
- it('any 타입 위반이 있는 TS 파일 편집 → memories.db 생성 (SQLite write 발생)', () => {
62
- const filePath = path.join(projectDir, 'dirty.ts');
63
- fs.writeFileSync(filePath, 'export function foo(x: any): any {\n return x;\n}\n');
64
-
65
- const result = runCodeCheck({ filePath, projectDir });
66
-
67
- expect(result.status).toBe(0);
68
- expect(result.stdout).toContain('any-type');
69
- expect(fs.existsSync(memoriesDbPath(projectDir))).toBe(true);
70
- });
71
-
72
- it('코드 확장자가 아닌 파일(.md) → 동적 import 조기 반환, memories.db 미생성', () => {
73
- const filePath = path.join(projectDir, 'notes.md');
74
- fs.writeFileSync(filePath, "console.log('should not trigger memory write')\n");
75
-
76
- const result = runCodeCheck({ filePath, projectDir });
77
-
78
- expect(result.status).toBe(0);
79
- expect(fs.existsSync(memoriesDbPath(projectDir))).toBe(false);
80
- });
81
- });
@@ -1,64 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { spawnSync } from 'child_process';
3
- import fs from 'fs';
4
- import os from 'os';
5
- import path from 'path';
6
- import { fileURLToPath } from 'url';
7
-
8
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
9
- const ADAPTER = path.resolve(__dirname, '..', 'codex-hook-adapter.js');
10
-
11
- describe('codex-hook-adapter', () => {
12
- it('converts a PreToolUse denial into Codex permission output', () => {
13
- const cwd = fs.mkdtempSync(path.join(os.tmpdir(), 'vibe-codex-adapter-'));
14
- const payload = JSON.stringify({
15
- tool_name: 'Bash',
16
- tool_input: { command: 'rm -rf /' },
17
- });
18
-
19
- const result = spawnSync(process.execPath, [ADAPTER, 'PreToolUse'], {
20
- cwd,
21
- input: payload,
22
- encoding: 'utf-8',
23
- timeout: 5000,
24
- });
25
-
26
- expect(result.status).toBe(2);
27
- const output = JSON.parse(result.stdout.trim());
28
- expect(output.hookSpecificOutput.permissionDecision).toBe('deny');
29
- expect(output.hookSpecificOutput.permissionDecisionReason).toContain('Deleting root or home directory');
30
- });
31
-
32
- /**
33
- * Codex 에는 CC 의 context_window_* Notification 등가물이 없어, PreCompact 를
34
- * 붙이기 전까지 압축 전 체크포인트가 아예 저장되지 않았다.
35
- */
36
- it('handles PreCompact without failing or injecting context', () => {
37
- const cwd = fs.mkdtempSync(path.join(os.tmpdir(), 'vibe-codex-precompact-'));
38
-
39
- const result = spawnSync(process.execPath, [ADAPTER, 'PreCompact'], {
40
- cwd,
41
- input: JSON.stringify({ cwd }),
42
- encoding: 'utf-8',
43
- timeout: 30000,
44
- });
45
-
46
- expect(result.status).toBe(0);
47
- // 압축 직전에 컨텍스트를 더 늘리면 역효과 — stdout 주입이 없어야 한다
48
- expect(result.stdout.trim()).toBe('');
49
- });
50
-
51
- it('ignores unknown events instead of erroring', () => {
52
- const cwd = fs.mkdtempSync(path.join(os.tmpdir(), 'vibe-codex-unknown-'));
53
-
54
- const result = spawnSync(process.execPath, [ADAPTER, 'SubagentStop'], {
55
- cwd,
56
- input: JSON.stringify({ cwd }),
57
- encoding: 'utf-8',
58
- timeout: 10000,
59
- });
60
-
61
- expect(result.status).toBe(0);
62
- expect(result.stdout.trim()).toBe('');
63
- });
64
- });