@su-record/vibe 2.16.3 → 3.0.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 (353) hide show
  1. package/.env.example +15 -0
  2. package/CLAUDE.md +8 -8
  3. package/README.en.md +46 -29
  4. package/README.md +41 -24
  5. package/agents/acceptance-tester.md +56 -0
  6. package/agents/architect.md +25 -67
  7. package/agents/build-error-resolver.md +28 -97
  8. package/agents/code-reviewer.md +89 -0
  9. package/agents/diagrammer.md +34 -165
  10. package/agents/documenter.md +43 -0
  11. package/agents/e2e-tester.md +46 -277
  12. package/agents/event/event-ops.md +54 -77
  13. package/agents/event/event-planner.md +63 -0
  14. package/agents/figma/figma-engineer.md +76 -0
  15. package/agents/implementer.md +26 -41
  16. package/agents/security-reviewer.md +56 -0
  17. package/agents/tester.md +37 -33
  18. package/agents/ui/design-reviewer.md +62 -0
  19. package/agents/ui/design-system-gen.md +63 -0
  20. package/dist/__tests__/agent-model-sync.test.d.ts +2 -0
  21. package/dist/__tests__/agent-model-sync.test.d.ts.map +1 -0
  22. package/dist/__tests__/agent-model-sync.test.js +71 -0
  23. package/dist/__tests__/agent-model-sync.test.js.map +1 -0
  24. package/dist/cli/auth.d.ts.map +1 -1
  25. package/dist/cli/auth.js +8 -1
  26. package/dist/cli/auth.js.map +1 -1
  27. package/dist/cli/commands/index.d.ts +1 -0
  28. package/dist/cli/commands/index.d.ts.map +1 -1
  29. package/dist/cli/commands/index.js +1 -0
  30. package/dist/cli/commands/index.js.map +1 -1
  31. package/dist/cli/commands/info.d.ts.map +1 -1
  32. package/dist/cli/commands/info.js +2 -0
  33. package/dist/cli/commands/info.js.map +1 -1
  34. package/dist/cli/commands/llm.d.ts +11 -0
  35. package/dist/cli/commands/llm.d.ts.map +1 -0
  36. package/dist/cli/commands/llm.js +62 -0
  37. package/dist/cli/commands/llm.js.map +1 -0
  38. package/dist/cli/commands/remove.d.ts.map +1 -1
  39. package/dist/cli/commands/remove.js +8 -10
  40. package/dist/cli/commands/remove.js.map +1 -1
  41. package/dist/cli/commands/setup.d.ts.map +1 -1
  42. package/dist/cli/commands/setup.js +35 -1
  43. package/dist/cli/commands/setup.js.map +1 -1
  44. package/dist/cli/index.d.ts +0 -4
  45. package/dist/cli/index.d.ts.map +1 -1
  46. package/dist/cli/index.js +59 -6
  47. package/dist/cli/index.js.map +1 -1
  48. package/dist/cli/llm/config.d.ts.map +1 -1
  49. package/dist/cli/llm/config.js +7 -0
  50. package/dist/cli/llm/config.js.map +1 -1
  51. package/dist/cli/llm/index.d.ts +1 -0
  52. package/dist/cli/llm/index.d.ts.map +1 -1
  53. package/dist/cli/llm/index.js +1 -0
  54. package/dist/cli/llm/index.js.map +1 -1
  55. package/dist/cli/llm/model-refresh.d.ts +29 -0
  56. package/dist/cli/llm/model-refresh.d.ts.map +1 -0
  57. package/dist/cli/llm/model-refresh.js +139 -0
  58. package/dist/cli/llm/model-refresh.js.map +1 -0
  59. package/dist/cli/llm/zai-commands.d.ts +15 -0
  60. package/dist/cli/llm/zai-commands.d.ts.map +1 -0
  61. package/dist/cli/llm/zai-commands.js +64 -0
  62. package/dist/cli/llm/zai-commands.js.map +1 -0
  63. package/dist/cli/postinstall/claude-agents.d.ts.map +1 -1
  64. package/dist/cli/postinstall/claude-agents.js +16 -77
  65. package/dist/cli/postinstall/claude-agents.js.map +1 -1
  66. package/dist/cli/postinstall/constants.d.ts.map +1 -1
  67. package/dist/cli/postinstall/constants.js +81 -296
  68. package/dist/cli/postinstall/constants.js.map +1 -1
  69. package/dist/cli/postinstall/cursor-agents.d.ts +5 -0
  70. package/dist/cli/postinstall/cursor-agents.d.ts.map +1 -1
  71. package/dist/cli/postinstall/cursor-agents.js +26 -68
  72. package/dist/cli/postinstall/cursor-agents.js.map +1 -1
  73. package/dist/cli/postinstall/cursor-skills.d.ts.map +1 -1
  74. package/dist/cli/postinstall/cursor-skills.js +26 -30
  75. package/dist/cli/postinstall/cursor-skills.js.map +1 -1
  76. package/dist/cli/postinstall/main.d.ts.map +1 -1
  77. package/dist/cli/postinstall/main.js +0 -2
  78. package/dist/cli/postinstall/main.js.map +1 -1
  79. package/dist/cli/setup/Provisioner.d.ts.map +1 -1
  80. package/dist/cli/setup/Provisioner.js +19 -21
  81. package/dist/cli/setup/Provisioner.js.map +1 -1
  82. package/dist/cli/types.d.ts +15 -0
  83. package/dist/cli/types.d.ts.map +1 -1
  84. package/dist/cli/utils.d.ts +4 -1
  85. package/dist/cli/utils.d.ts.map +1 -1
  86. package/dist/cli/utils.js +4 -1
  87. package/dist/cli/utils.js.map +1 -1
  88. package/dist/infra/lib/FrameworkDetector.js +4 -4
  89. package/dist/infra/lib/FrameworkDetector.js.map +1 -1
  90. package/dist/infra/lib/OrchestrateWorkflow.js +2 -2
  91. package/dist/infra/lib/OrchestrateWorkflow.js.map +1 -1
  92. package/dist/infra/lib/browser/launch.js +1 -1
  93. package/dist/infra/lib/browser/launch.js.map +1 -1
  94. package/dist/infra/lib/browser/types.d.ts +1 -1
  95. package/dist/infra/lib/browser/types.js +1 -1
  96. package/dist/infra/lib/config/GlobalConfigManager.d.ts +2 -0
  97. package/dist/infra/lib/config/GlobalConfigManager.d.ts.map +1 -1
  98. package/dist/infra/lib/config/GlobalConfigManager.js +6 -0
  99. package/dist/infra/lib/config/GlobalConfigManager.js.map +1 -1
  100. package/dist/infra/lib/constants.d.ts +1 -1
  101. package/dist/infra/lib/constants.d.ts.map +1 -1
  102. package/dist/infra/lib/constants.js +4 -5
  103. package/dist/infra/lib/constants.js.map +1 -1
  104. package/dist/infra/lib/evolution/__tests__/integration.test.js +7 -7
  105. package/dist/infra/lib/evolution/__tests__/integration.test.js.map +1 -1
  106. package/dist/infra/lib/llm-availability.d.ts +4 -0
  107. package/dist/infra/lib/llm-availability.d.ts.map +1 -1
  108. package/dist/infra/lib/llm-availability.js +9 -1
  109. package/dist/infra/lib/llm-availability.js.map +1 -1
  110. package/dist/infra/lib/memory/index.d.ts +0 -2
  111. package/dist/infra/lib/memory/index.d.ts.map +1 -1
  112. package/dist/infra/lib/memory/index.js +0 -2
  113. package/dist/infra/lib/memory/index.js.map +1 -1
  114. package/dist/infra/lib/telemetry/SkillTelemetry.test.js +1 -1
  115. package/dist/infra/lib/telemetry/SkillTelemetry.test.js.map +1 -1
  116. package/dist/infra/lib/zai/client.d.ts +30 -0
  117. package/dist/infra/lib/zai/client.d.ts.map +1 -0
  118. package/dist/infra/lib/zai/client.js +124 -0
  119. package/dist/infra/lib/zai/client.js.map +1 -0
  120. package/dist/infra/lib/zai/index.d.ts +11 -0
  121. package/dist/infra/lib/zai/index.d.ts.map +1 -0
  122. package/dist/infra/lib/zai/index.js +10 -0
  123. package/dist/infra/lib/zai/index.js.map +1 -0
  124. package/dist/infra/lib/zai/orchestration.d.ts +15 -0
  125. package/dist/infra/lib/zai/orchestration.d.ts.map +1 -0
  126. package/dist/infra/lib/zai/orchestration.js +54 -0
  127. package/dist/infra/lib/zai/orchestration.js.map +1 -0
  128. package/dist/infra/lib/zai/types.d.ts +40 -0
  129. package/dist/infra/lib/zai/types.d.ts.map +1 -0
  130. package/dist/infra/lib/zai/types.js +5 -0
  131. package/dist/infra/lib/zai/types.js.map +1 -0
  132. package/dist/infra/orchestrator/SmartRouter.d.ts.map +1 -1
  133. package/dist/infra/orchestrator/SmartRouter.js +16 -34
  134. package/dist/infra/orchestrator/SmartRouter.js.map +1 -1
  135. package/dist/infra/orchestrator/index.d.ts +1 -0
  136. package/dist/infra/orchestrator/index.d.ts.map +1 -1
  137. package/dist/infra/orchestrator/index.js +11 -9
  138. package/dist/infra/orchestrator/index.js.map +1 -1
  139. package/dist/infra/orchestrator/types.d.ts +32 -9
  140. package/dist/infra/orchestrator/types.d.ts.map +1 -1
  141. package/dist/infra/orchestrator/types.js +68 -37
  142. package/dist/infra/orchestrator/types.js.map +1 -1
  143. package/dist/infra/orchestrator/types.test.d.ts +2 -0
  144. package/dist/infra/orchestrator/types.test.d.ts.map +1 -0
  145. package/dist/infra/orchestrator/types.test.js +57 -0
  146. package/dist/infra/orchestrator/types.test.js.map +1 -0
  147. package/dist/tools/index.d.ts +0 -4
  148. package/dist/tools/index.d.ts.map +1 -1
  149. package/dist/tools/index.js +0 -4
  150. package/dist/tools/index.js.map +1 -1
  151. package/dist/tools/memory/autoSaveContext.d.ts +0 -1
  152. package/dist/tools/memory/autoSaveContext.d.ts.map +1 -1
  153. package/dist/tools/memory/autoSaveContext.js +13 -27
  154. package/dist/tools/memory/autoSaveContext.js.map +1 -1
  155. package/hooks/scripts/__tests__/code-check-detectors.test.js +2 -2
  156. package/hooks/scripts/__tests__/run-ledger.test.js +1 -1
  157. package/hooks/scripts/__tests__/scope-from-spec.test.js +12 -12
  158. package/hooks/scripts/__tests__/step-counter.test.js +1 -1
  159. package/hooks/scripts/code-check.js +16 -203
  160. package/hooks/scripts/context-save.js +0 -11
  161. package/hooks/scripts/lib/scope-from-spec.js +9 -6
  162. package/hooks/scripts/llm-orchestrate.js +49 -0
  163. package/hooks/scripts/post-edit-dispatcher.js +1 -1
  164. package/hooks/scripts/prompt-dispatcher.js +7 -18
  165. package/hooks/scripts/session-start.js +25 -35
  166. package/package.json +4 -4
  167. package/skills/agents-md/SKILL.md +62 -15
  168. package/skills/arch-guard/SKILL.md +1 -1
  169. package/skills/brand-assets/SKILL.md +2 -2
  170. package/skills/capability-loop/SKILL.md +1 -1
  171. package/skills/chub-usage/SKILL.md +1 -1
  172. package/skills/commerce-patterns/SKILL.md +2 -2
  173. package/skills/commit-push-pr/SKILL.md +0 -1
  174. package/skills/context7-usage/SKILL.md +1 -1
  175. package/skills/create-prd/agents/edge-case-finder.md +4 -4
  176. package/skills/create-prd/agents/prioritizer.md +4 -4
  177. package/skills/create-prd/agents/requirements-writer.md +3 -3
  178. package/skills/create-prd/agents/researcher.md +3 -3
  179. package/skills/create-prd/agents/reviewer.md +3 -3
  180. package/skills/create-prd/orchestrator.md +2 -0
  181. package/skills/design-refine/SKILL.md +140 -0
  182. package/skills/{design-polish → design-refine}/templates/polish-report.md +1 -1
  183. package/skills/{design-normalize → design-refine}/templates/token-audit.md +3 -3
  184. package/skills/design-review/SKILL.md +143 -0
  185. package/skills/{design-audit → design-review}/agents/a11y-auditor.md +1 -1
  186. package/skills/{design-audit → design-review}/agents/performance-auditor.md +1 -1
  187. package/skills/{design-audit → design-review}/agents/responsive-auditor.md +1 -1
  188. package/skills/{design-audit → design-review}/agents/slop-detector.md +1 -1
  189. package/skills/{design-audit → design-review}/frameworks/core-web-vitals.md +1 -1
  190. package/skills/{design-audit → design-review}/frameworks/wcag-checklist.md +1 -1
  191. package/skills/{design-audit → design-review}/orchestrator.md +5 -3
  192. package/skills/{design-critique → design-review}/templates/critique-report.md +3 -3
  193. package/skills/{design-audit → design-review}/templates/report.md +3 -3
  194. package/skills/design-teach/SKILL.md +11 -11
  195. package/skills/docs/SKILL.md +14 -16
  196. package/skills/e2e-commerce/SKILL.md +1 -1
  197. package/skills/event-comms/SKILL.md +1 -1
  198. package/skills/event-ops/SKILL.md +2 -2
  199. package/skills/event-planning/SKILL.md +1 -1
  200. package/skills/exec-plan/SKILL.md +2 -2
  201. package/skills/exec-plan/orchestrator.md +2 -0
  202. package/skills/figma/SKILL.md +240 -148
  203. package/skills/figma/rubrics/css-mapping.md +125 -0
  204. package/skills/git-worktree/SKILL.md +1 -1
  205. package/skills/handoff/SKILL.md +1 -1
  206. package/skills/parallel-research/SKILL.md +14 -28
  207. package/skills/parallel-research/orchestrator.md +2 -0
  208. package/skills/priority-todos/SKILL.md +1 -1
  209. package/skills/regress/SKILL.md +11 -0
  210. package/skills/restraint/SKILL.md +72 -0
  211. package/skills/seo-checklist/SKILL.md +2 -2
  212. package/skills/spec/SKILL.md +65 -836
  213. package/skills/test/SKILL.md +3 -3
  214. package/skills/tool-fallback/SKILL.md +2 -2
  215. package/skills/vercel-react-best-practices/SKILL.md +1 -1
  216. package/skills/vibe/SKILL.md +20 -35
  217. package/skills/vibe.analyze/SKILL.md +7 -9
  218. package/skills/vibe.docs/SKILL.md +1 -1
  219. package/skills/vibe.event/SKILL.md +27 -27
  220. package/skills/vibe.figma/SKILL.md +14 -18
  221. package/skills/vibe.harness/SKILL.md +5 -5
  222. package/skills/vibe.llm/SKILL.md +50 -0
  223. package/skills/vibe.reason/SKILL.md +0 -2
  224. package/skills/vibe.review/SKILL.md +45 -49
  225. package/skills/vibe.run/SKILL.md +2 -5
  226. package/skills/vibe.run/references/parallel-agents.md +33 -98
  227. package/skills/vibe.spec/SKILL.md +38 -535
  228. package/skills/vibe.utils/SKILL.md +3 -3
  229. package/skills/vibe.verify/SKILL.md +70 -542
  230. package/skills/video-production/SKILL.md +1 -1
  231. package/vibe/rules/orchestrator-contract.md +57 -0
  232. package/vibe/rules/quality/performance.md +1 -1
  233. package/vibe/templates/claudemd-template.md +1 -1
  234. package/vibe/templates/spec-template.md +35 -185
  235. package/agents/architect-low.md +0 -41
  236. package/agents/architect-medium.md +0 -59
  237. package/agents/compounder.md +0 -261
  238. package/agents/docs/api-documenter.md +0 -99
  239. package/agents/docs/changelog-writer.md +0 -93
  240. package/agents/event/event-comms.md +0 -78
  241. package/agents/event/event-content.md +0 -68
  242. package/agents/event/event-image.md +0 -95
  243. package/agents/event/event-scheduler.md +0 -69
  244. package/agents/event/event-speaker.md +0 -86
  245. package/agents/explorer-low.md +0 -42
  246. package/agents/explorer-medium.md +0 -59
  247. package/agents/explorer.md +0 -48
  248. package/agents/figma/figma-analyst.md +0 -52
  249. package/agents/figma/figma-architect.md +0 -112
  250. package/agents/figma/figma-auditor.md +0 -82
  251. package/agents/figma/figma-builder.md +0 -100
  252. package/agents/implementer-low.md +0 -43
  253. package/agents/implementer-medium.md +0 -52
  254. package/agents/junior-mentor.md +0 -141
  255. package/agents/planning/requirements-analyst.md +0 -84
  256. package/agents/planning/ux-advisor.md +0 -83
  257. package/agents/qa/acceptance-tester.md +0 -86
  258. package/agents/qa/edge-case-finder.md +0 -93
  259. package/agents/qa/qa-coordinator.md +0 -131
  260. package/agents/refactor-cleaner.md +0 -143
  261. package/agents/research/best-practices.md +0 -199
  262. package/agents/research/codebase-patterns.md +0 -157
  263. package/agents/research/framework-docs.md +0 -188
  264. package/agents/research/security-advisory.md +0 -213
  265. package/agents/review/architecture-reviewer.md +0 -107
  266. package/agents/review/complexity-reviewer.md +0 -116
  267. package/agents/review/data-integrity-reviewer.md +0 -88
  268. package/agents/review/git-history-reviewer.md +0 -103
  269. package/agents/review/performance-reviewer.md +0 -86
  270. package/agents/review/python-reviewer.md +0 -150
  271. package/agents/review/rails-reviewer.md +0 -139
  272. package/agents/review/react-reviewer.md +0 -144
  273. package/agents/review/security-reviewer.md +0 -80
  274. package/agents/review/simplicity-reviewer.md +0 -140
  275. package/agents/review/test-coverage-reviewer.md +0 -116
  276. package/agents/review/typescript-reviewer.md +0 -127
  277. package/agents/searcher.md +0 -54
  278. package/agents/simplifier.md +0 -120
  279. package/agents/teams/debug-team.md +0 -70
  280. package/agents/teams/dev-team.md +0 -88
  281. package/agents/teams/docs-team.md +0 -80
  282. package/agents/teams/figma-team.md +0 -85
  283. package/agents/teams/fullstack-team.md +0 -83
  284. package/agents/teams/lite-team.md +0 -69
  285. package/agents/teams/migration-team.md +0 -78
  286. package/agents/teams/refactor-team.md +0 -94
  287. package/agents/teams/research-team.md +0 -86
  288. package/agents/teams/review-debate-team.md +0 -125
  289. package/agents/teams/security-team.md +0 -81
  290. package/agents/ui/ui-a11y-auditor.md +0 -93
  291. package/agents/ui/ui-antipattern-detector.md +0 -102
  292. package/agents/ui/ui-dataviz-advisor.md +0 -69
  293. package/agents/ui/ui-design-system-gen.md +0 -57
  294. package/agents/ui/ui-industry-analyzer.md +0 -49
  295. package/agents/ui/ui-layout-architect.md +0 -65
  296. package/agents/ui/ui-stack-implementer.md +0 -68
  297. package/agents/ui/ux-compliance-reviewer.md +0 -81
  298. package/agents/ui-previewer.md +0 -258
  299. package/hooks/scripts/__tests__/keyword-detector.test.js +0 -242
  300. package/hooks/scripts/keyword-detector.js +0 -226
  301. package/skills/characterization-test/SKILL.md +0 -209
  302. package/skills/characterization-test/agents/behavior-capturer.md +0 -50
  303. package/skills/characterization-test/agents/coverage-checker.md +0 -54
  304. package/skills/characterization-test/agents/reporter.md +0 -50
  305. package/skills/characterization-test/agents/test-writer.md +0 -49
  306. package/skills/characterization-test/rubrics/coverage-criteria.md +0 -53
  307. package/skills/characterization-test/templates/test-template.ts +0 -101
  308. package/skills/claude-md-guide/SKILL.md +0 -353
  309. package/skills/claude-md-guide/rubrics/anti-patterns.md +0 -88
  310. package/skills/design-audit/SKILL.md +0 -154
  311. package/skills/design-critique/SKILL.md +0 -140
  312. package/skills/design-distill/SKILL.md +0 -131
  313. package/skills/design-normalize/SKILL.md +0 -135
  314. package/skills/design-polish/SKILL.md +0 -132
  315. package/skills/figma-convert/SKILL.md +0 -236
  316. package/skills/figma-extract/SKILL.md +0 -242
  317. package/skills/interview/SKILL.md +0 -358
  318. package/skills/interview/checklists/api.md +0 -101
  319. package/skills/interview/checklists/feature.md +0 -88
  320. package/skills/interview/checklists/library.md +0 -95
  321. package/skills/interview/checklists/mobile.md +0 -89
  322. package/skills/interview/checklists/webapp.md +0 -97
  323. package/skills/interview/checklists/website.md +0 -99
  324. package/skills/plan/SKILL.md +0 -254
  325. package/skills/rob-pike/SKILL.md +0 -66
  326. package/skills/spec/references/askuser-examples.md +0 -57
  327. package/skills/spec/references/example-session.md +0 -87
  328. package/skills/spec/references/templates.md +0 -194
  329. package/skills/spec-review/SKILL.md +0 -725
  330. package/skills/systematic-debugging/SKILL.md +0 -142
  331. package/skills/techdebt/SKILL.md +0 -126
  332. package/skills/techdebt/agents/analyzer.md +0 -50
  333. package/skills/techdebt/agents/fixer.md +0 -41
  334. package/skills/techdebt/agents/reviewer.md +0 -47
  335. package/skills/techdebt/agents/scanner.md +0 -44
  336. package/skills/techdebt/orchestrator.md +0 -70
  337. package/skills/techdebt/rubrics/severity.md +0 -51
  338. package/skills/techdebt/scripts/scan.js +0 -90
  339. package/skills/techdebt/templates/report.md +0 -86
  340. package/skills/typescript-advanced-types/SKILL.md +0 -68
  341. package/skills/typescript-advanced-types/rubrics/type-patterns.md +0 -109
  342. package/skills/yagni-ladder/SKILL.md +0 -90
  343. /package/skills/{claude-md-guide → agents-md}/templates/claude-md.md +0 -0
  344. /package/skills/{design-polish → design-refine}/rubrics/polish-checklist.md +0 -0
  345. /package/skills/{design-normalize → design-refine}/rubrics/token-naming.md +0 -0
  346. /package/skills/{design-distill → design-refine}/templates/design-system.md +0 -0
  347. /package/skills/{design-audit → design-review}/agents/scorer.md +0 -0
  348. /package/skills/{design-audit → design-review}/rubrics/ai-slop-patterns.md +0 -0
  349. /package/skills/{design-audit → design-review}/rubrics/scoring.md +0 -0
  350. /package/skills/{design-critique → design-review}/rubrics/ux-heuristics.md +0 -0
  351. /package/skills/{figma-convert → figma}/rubrics/conversion-rules.md +0 -0
  352. /package/skills/{figma-extract → figma}/rubrics/image-rules.md +0 -0
  353. /package/skills/{figma-convert → figma}/templates/component.md +0 -0
@@ -37,44 +37,44 @@ function writeSpec(dir, filename, content, status = 'in-progress') {
37
37
  }
38
38
 
39
39
  // ══════════════════════════════════════════════════
40
- // isScopeGuardEnabled — 기본 ON 동작
40
+ // isScopeGuardEnabled — 기본 OFF (opt-in), CLI isScopeGuardOptedIn 과 동일 기본값
41
41
  // ══════════════════════════════════════════════════
42
42
  describe('isScopeGuardEnabled', () => {
43
43
  let tmpDir;
44
44
  beforeEach(() => { tmpDir = makeTempDir(); });
45
45
  afterEach(() => { cleanDir(tmpDir); });
46
46
 
47
- it('config 없음 → true (기본 ON)', () => {
48
- expect(isScopeGuardEnabled(tmpDir)).toBe(true);
47
+ it('config 없음 → false (기본 OFF)', () => {
48
+ expect(isScopeGuardEnabled(tmpDir)).toBe(false);
49
49
  });
50
50
 
51
- it('scopeGuard 키 없는 config → true', () => {
51
+ it('scopeGuard 키 없는 config → false', () => {
52
52
  writeConfig(tmpDir, undefined);
53
- expect(isScopeGuardEnabled(tmpDir)).toBe(true);
53
+ expect(isScopeGuardEnabled(tmpDir)).toBe(false);
54
54
  });
55
55
 
56
- it('scopeGuard.enabled 없는 config → true', () => {
56
+ it('scopeGuard.enabled 없는 config → false', () => {
57
57
  const vibeDir = path.join(tmpDir, '.vibe');
58
58
  fs.mkdirSync(vibeDir, { recursive: true });
59
59
  fs.writeFileSync(path.join(vibeDir, 'config.json'), JSON.stringify({ scopeGuard: {} }));
60
- expect(isScopeGuardEnabled(tmpDir)).toBe(true);
60
+ expect(isScopeGuardEnabled(tmpDir)).toBe(false);
61
61
  });
62
62
 
63
- it('scopeGuard.enabled=true → true', () => {
63
+ it('scopeGuard.enabled=true → true (명시적 opt-in)', () => {
64
64
  writeConfig(tmpDir, { enabled: true });
65
65
  expect(isScopeGuardEnabled(tmpDir)).toBe(true);
66
66
  });
67
67
 
68
- it('scopeGuard.enabled=false → false (명시적 opt-out)', () => {
68
+ it('scopeGuard.enabled=false → false', () => {
69
69
  writeConfig(tmpDir, { enabled: false });
70
70
  expect(isScopeGuardEnabled(tmpDir)).toBe(false);
71
71
  });
72
72
 
73
- it('legacy .claude/vibe/config.json에서도 enabled=false 인식', () => {
73
+ it('legacy .claude/vibe/config.json에서도 enabled=true 인식', () => {
74
74
  const legacyDir = path.join(tmpDir, '.claude', 'vibe');
75
75
  fs.mkdirSync(legacyDir, { recursive: true });
76
- fs.writeFileSync(path.join(legacyDir, 'config.json'), JSON.stringify({ scopeGuard: { enabled: false } }));
77
- expect(isScopeGuardEnabled(tmpDir)).toBe(false);
76
+ fs.writeFileSync(path.join(legacyDir, 'config.json'), JSON.stringify({ scopeGuard: { enabled: true } }));
77
+ expect(isScopeGuardEnabled(tmpDir)).toBe(true);
78
78
  });
79
79
  });
80
80
 
@@ -7,7 +7,7 @@
7
7
  * - 책임 3) error_category 분류기 + 3-fail detector → anti-pattern md (Phase 2)
8
8
  * - 책임 간 독립성, hot-path 안정성
9
9
  *
10
- * 패턴: keyword-detector.test.js 동일한 execFileSync 방식.
10
+ * 패턴: 스크립트 공통의 execFileSync 방식.
11
11
  */
12
12
  import { describe, it, expect, beforeEach } from 'vitest';
13
13
  import { spawnSync } from 'child_process';
@@ -2,14 +2,18 @@
2
2
  * PostToolUse Hook - Write/Edit 후 코드 품질 검사 + 관찰 자동 캡처
3
3
  *
4
4
  * findings를 console.log가 아닌 반환값으로 전달 — 디스패처가 수집해 additionalContext에 주입.
5
- * P1 이슈 발견 시 run-ledger에 verifyRequired 상태 기록.
5
+ *
6
+ * 범위 (harness-review-2026-07-01 P1-4):
7
+ * 오탐률이 낮은 결정론적 하드룰(any/@ts-ignore, console.log)만 탐지한다.
8
+ * 함수 길이·중첩 깊이·매직 넘버 같은 휴리스틱은 모델이 컨텍스트 안에서 더
9
+ * 정확히 판단하므로 주입하지 않으며, 정규식 발견은 커밋 게이트
10
+ * (run-ledger verifyRequired)를 태우지 않는다 — 그 게이트는 결정론적
11
+ * 검증 흐름(vibe.verify) 전용이다.
6
12
  */
7
13
  import { getToolsBaseUrl, PROJECT_DIR, readProjectConfig } from './utils.js';
8
- import { readFileSync, existsSync, writeFileSync } from 'fs';
14
+ import { readFileSync } from 'fs';
9
15
  import path from 'path';
10
- import os from 'os';
11
16
  import { buildCliCtx, isDirectRun } from './lib/hook-context.js';
12
- import { recordVerifyRequired } from './lib/run-ledger.js';
13
17
 
14
18
  const BASE_URL = getToolsBaseUrl();
15
19
 
@@ -176,180 +180,22 @@ function detectConsoleLogs(lines, filePath) {
176
180
  }
177
181
 
178
182
  /**
179
- * P2: 함수 길이 초과 탐지.
180
- * @param {string[]} lines
181
- * @returns {Array<{ line: number, match: string, severity: 'P2' }>}
182
- */
183
- function detectLongFunctions(lines) {
184
- const findings = [];
185
- let fnStart = -1;
186
- let fnName = '';
187
- let depth = 0;
188
-
189
- for (let i = 0; i < lines.length; i++) {
190
- const line = lines[i];
191
- const fnMatch = line.match(/(?:function\s+(\w+)|(?:const|let|var)\s+(\w+)\s*=\s*(?:async\s*)?\()/);
192
- if (fnMatch && depth === 0) {
193
- fnStart = i;
194
- fnName = fnMatch[1] || fnMatch[2] || 'anonymous';
195
- }
196
- depth += (line.match(/\{/g) || []).length - (line.match(/\}/g) || []).length;
197
- if (fnStart !== -1 && depth <= 0) {
198
- const length = i - fnStart + 1;
199
- if (length > 50) {
200
- findings.push({
201
- line: fnStart + 1,
202
- match: `function '${fnName}' is ${length} lines`,
203
- severity: 'P2',
204
- suggestion: `Extract lines ${fnStart + 20}–${i + 1} into a separate helper function`,
205
- });
206
- }
207
- fnStart = -1;
208
- depth = 0;
209
- }
210
- }
211
- return findings;
212
- }
213
-
214
- /**
215
- * P2: 중첩 깊이 초과 탐지.
216
- * @param {string[]} lines
217
- * @returns {Array<{ line: number, match: string, severity: 'P2' }>}
218
- */
219
- function detectDeepNesting(lines) {
220
- const findings = [];
221
- let depth = 0;
222
- let reported = false;
223
-
224
- lines.forEach((line, i) => {
225
- depth += (line.match(/\{/g) || []).length - (line.match(/\}/g) || []).length;
226
- if (depth > 3 && !reported) {
227
- findings.push({
228
- line: i + 1,
229
- match: `nesting depth ${depth} at line ${i + 1}`,
230
- severity: 'P2',
231
- suggestion: 'Use early return pattern: if (!condition) return; — instead of wrapping in else',
232
- });
233
- reported = true;
234
- }
235
- if (depth <= 3) reported = false;
236
- });
237
- return findings;
238
- }
239
-
240
- // magic number 무시 값 목록 (0, 1, -1, 2, 10, 100, 1000)
241
- const MAGIC_NUMBER_IGNORE = new Set(['10', '100', '1000']);
242
-
243
- /**
244
- * advisory: 매직 넘버 탐지 (P3, 스팸 방지 적용).
245
- * 무시 조건: 0/1/-1/2 (단일 digit), ALLCAPS const 선언, 테스트 파일, 배열 인덱스
246
- * @param {string[]} lines
247
- * @param {string} filePath
248
- * @returns {Array<{ line: number, match: string, severity: 'P3' }>}
249
- */
250
- function detectMagicNumbers(lines, filePath) {
251
- // 테스트 파일은 스킵
252
- if (/\.(test|spec)\.[jt]sx?$/.test(filePath) || /\/__tests__\//.test(filePath)) {
253
- return [];
254
- }
255
-
256
- const findings = [];
257
- lines.forEach((line, i) => {
258
- // ALL_CAPS const 선언 줄은 스킵 (예: const LIMIT = 500)
259
- if (/^\s*(?:export\s+)?const\s+[A-Z][A-Z0-9_]+\s*=/.test(line)) return;
260
-
261
- const stripped = line.replace(/\/\/.*$/, '').replace(/(['"`]).*?\1/g, '""');
262
- const nums = (stripped.match(/\b\d{2,}\b/g) || []).filter(n => MAGIC_NUMBER_IGNORE.has(n));
263
- // 배열 인덱스: [NN] 패턴 제외
264
- const nonIndexNums = (stripped.match(/\b\d{2,}\b/g) || []).filter(n => {
265
- if (MAGIC_NUMBER_IGNORE.has(n)) return false;
266
- // 배열 인덱스 [NN] 체크
267
- const idx = stripped.indexOf(n);
268
- if (idx > 0 && stripped[idx - 1] === '[') return false;
269
- return true;
270
- });
271
-
272
- if (nonIndexNums.length > 0) {
273
- findings.push({
274
- line: i + 1,
275
- match: `magic number(s): ${nonIndexNums.join(', ')}`,
276
- severity: 'P3',
277
- suggestion: `Extract to named constant: const LIMIT = ${nonIndexNums[0]};`,
278
- });
279
- }
280
- });
281
- return findings;
282
- }
283
-
284
- // ─── Failure Escalation Tracking ───
285
-
286
- const ESCALATION_THRESHOLD = 3;
287
- const ESCALATION_FILE = path.join(os.homedir(), '.vibe', 'failure-tracker.json');
288
-
289
- function loadFailureTracker() {
290
- try {
291
- if (existsSync(ESCALATION_FILE)) {
292
- return JSON.parse(readFileSync(ESCALATION_FILE, 'utf8'));
293
- }
294
- } catch { /* ignore */ }
295
- return {};
296
- }
297
-
298
- function saveFailureTracker(tracker) {
299
- try {
300
- writeFileSync(ESCALATION_FILE, JSON.stringify(tracker));
301
- } catch { /* ignore */ }
302
- }
303
-
304
- /**
305
- * 실패 추적 — 동일 파일에 P1 이슈가 반복되면 에스컬레이션 메시지 반환.
183
+ * 하드룰 탐지기 실행. findings 배열 반환.
306
184
  * @param {string} filePath
307
- * @param {string[]} issues
308
- * @returns {string|null} 에스컬레이션 메시지 (없으면 null)
309
- */
310
- function trackFailure(filePath, issues) {
311
- const tracker = loadFailureTracker();
312
- const key = filePath;
313
- const entry = tracker[key] || { count: 0, issues: [] };
314
- entry.count += 1;
315
- entry.issues = issues.slice(0, 3);
316
- entry.lastSeen = new Date().toISOString();
317
- tracker[key] = entry;
318
- saveFailureTracker(tracker);
319
-
320
- if (entry.count >= ESCALATION_THRESHOLD) {
321
- const msg = `[ESCALATION] ${path.basename(filePath)}: 동일 이슈 ${entry.count}회 반복 — 수동 개입 필요`;
322
- entry.count = 0;
323
- saveFailureTracker(tracker);
324
- return msg;
325
- }
326
- return null;
327
- }
328
-
329
- function clearFailure(filePath) {
330
- const tracker = loadFailureTracker();
331
- delete tracker[filePath];
332
- saveFailureTracker(tracker);
333
- }
334
-
335
- /**
336
- * 모든 self-heal 탐지기 실행. findings 배열 반환.
337
- * @param {string} filePath
338
- * @returns {{ p1: string[], advisory: string[], escalation: string|null }}
185
+ * @returns {{ p1: string[] }}
339
186
  */
340
187
  function runDetectors(filePath) {
341
188
  let content;
342
189
  try {
343
190
  content = readFileSync(filePath, 'utf-8');
344
191
  } catch {
345
- return { p1: [], advisory: [], escalation: null };
192
+ return { p1: [] };
346
193
  }
347
194
 
348
195
  const lines = content.split('\n');
349
196
  const isTs = TS_EXT_RE.test(filePath);
350
197
 
351
198
  const p1Findings = [];
352
- const advisoryFindings = [];
353
199
 
354
200
  // P1: any 탐지 — TS 파일만
355
201
  if (isTs) {
@@ -365,32 +211,7 @@ function runDetectors(filePath) {
365
211
  p1Findings.push(`P1 console.log line ${f.line}: ${f.match.substring(0, 60)}`);
366
212
  }
367
213
 
368
- // P2: 함수 길이
369
- const fnHits = detectLongFunctions(lines).slice(0, 1);
370
- for (const f of fnHits) {
371
- advisoryFindings.push(`P2 ${f.match}`);
372
- }
373
-
374
- // P2: 중첩 깊이
375
- const nestHits = detectDeepNesting(lines).slice(0, 1);
376
- for (const f of nestHits) {
377
- advisoryFindings.push(`P2 ${f.match}`);
378
- }
379
-
380
- // P3: 매직 넘버 (advisory, 스팸 방지)
381
- const magicHits = detectMagicNumbers(lines, filePath).slice(0, 1);
382
- for (const f of magicHits) {
383
- advisoryFindings.push(`P3 ${f.match}`);
384
- }
385
-
386
- let escalation = null;
387
- if (p1Findings.length > 0) {
388
- escalation = trackFailure(filePath, p1Findings);
389
- } else {
390
- clearFailure(filePath);
391
- }
392
-
393
- return { p1: p1Findings, advisory: advisoryFindings, escalation };
214
+ return { p1: p1Findings };
394
215
  }
395
216
 
396
217
  /**
@@ -404,20 +225,12 @@ export async function run(ctx) {
404
225
  const files = getModifiedFiles(ctx);
405
226
  if (files.length === 0) return { exitCode: 0, findings };
406
227
 
407
- // 1. Self-heal 탐지기 실행 (changed file only)
228
+ // 1. 하드룰 탐지기 실행 (changed file only) — additionalContext 주입만.
229
+ // 커밋 게이트(verifyRequired)는 태우지 않는다: 정규식 오탐 하나가
230
+ // auto-commit을 차단하는 결합은 제거됨 (harness-review-2026-07-01).
408
231
  try {
409
- const { p1, advisory, escalation } = runDetectors(files[0]);
410
-
232
+ const { p1 } = runDetectors(files[0]);
411
233
  for (const msg of p1) findings.push(msg);
412
- for (const msg of advisory) findings.push(msg);
413
- if (escalation) findings.push(escalation);
414
-
415
- // P1 이슈 → run-ledger에 verifyRequired 기록
416
- if (p1.length > 0) {
417
- try {
418
- recordVerifyRequired(PROJECT_DIR, p1[0]);
419
- } catch { /* fail-open */ }
420
- }
421
234
  } catch {
422
235
  // 탐지기 실패 → fail-open, 계속 진행
423
236
  }
@@ -162,17 +162,6 @@ async function main() {
162
162
  // Mark this urgency level as recently saved
163
163
  setDebounceLock(urgency);
164
164
 
165
- // Sync TokenBudgetTracker with current context usage
166
- try {
167
- const { TokenBudgetTracker } = await import(`${LIB_URL}TokenBudgetTracker.js`);
168
- const tracker = TokenBudgetTracker.getInstance(PROJECT_DIR);
169
- const numPercent = Number(percent);
170
- if (!isNaN(numPercent)) {
171
- tracker.syncToPercent(numPercent);
172
- }
173
- } catch {
174
- // TokenBudgetTracker sync is non-critical
175
- }
176
165
  } catch {
177
166
  // 무시
178
167
  }
@@ -28,10 +28,13 @@ function isRecentlyModified(file) {
28
28
  /**
29
29
  * scope-guard auto-derive 활성 여부.
30
30
  *
31
- * 기본값은 **on**. `.vibe/config.json` 의 `scopeGuard.enabled = false` 로
32
- * 명시적으로 때만 SPEC → scope.json 자동 합성을 건너뛴다.
33
- * 노이즈 가드: SPEC 파일이 존재할 때만 scope.json 생성하며,
34
- * SPEC 없이 scope.json 생성이 필요한 경우 수동 작성(auto:false)을 사용한다.
31
+ * 기본값은 **off** `.vibe/config.json` 의 `scopeGuard.enabled = true` 로
32
+ * 명시적 opt-in 했을 때만 SPEC → scope.json 자동 합성을 실행한다.
33
+ * (자동 ON SPEC 편집에 노이즈 경고 회귀를 유발해 CLI 쪽에서 이미
34
+ * 기본 off 수정됐다. 훅이 기본 on 으로 남아 init/update 와
35
+ * SessionStart 가 서로 다른 scope 상태를 만들던 불일치를 통일 —
36
+ * harness-review-2026-07-01 P1-6. SSOT: src/cli/utils.ts `isScopeGuardOptedIn`
37
+ * 과 반드시 같은 기본값 유지.)
35
38
  *
36
39
  * 이미 `auto: false` scope.json 을 직접 만들어 둔 사용자는 영향 없음 — scope-guard.js
37
40
  * 자체는 scope.json 존재 여부만 본다.
@@ -45,10 +48,10 @@ export function isScopeGuardEnabled(projectDir) {
45
48
  for (const p of candidates) {
46
49
  if (!fs.existsSync(p)) continue;
47
50
  const cfg = JSON.parse(fs.readFileSync(p, 'utf-8'));
48
- if (cfg && cfg.scopeGuard && cfg.scopeGuard.enabled === false) return false;
51
+ if (cfg && cfg.scopeGuard && cfg.scopeGuard.enabled === true) return true;
49
52
  }
50
53
  } catch { /* ignore */ }
51
- return true;
54
+ return false;
52
55
  }
53
56
 
54
57
  /**
@@ -105,6 +105,7 @@ function resolveModel(providerName, config) {
105
105
  if (providerName === 'gpt-codex') return config.models?.gptCodex || 'gpt-5.3-codex';
106
106
  if (providerName === 'gpt') return config.models?.gpt || 'gpt-5.5';
107
107
  if (providerName === 'antigravity') return config.models?.antigravity || 'antigravity';
108
+ if (providerName === 'zai') return config.models?.zaiCoding || config.models?.zai || 'glm-5.2';
108
109
  if (providerName === 'claude') return 'claude';
109
110
  return providerName;
110
111
  }
@@ -271,6 +272,46 @@ function callCodexCli(prompt, sysPrompt, jsonMode, model, timeoutMs) {
271
272
  });
272
273
  }
273
274
 
275
+ // ZAI (Z.ai / GLM) — OpenAI 호환 HTTP API (CLI 없음)
276
+ const ZAI_BASE_GENERAL = 'https://api.z.ai/api/paas/v4';
277
+ const ZAI_BASE_CODING = 'https://api.z.ai/api/coding/paas/v4';
278
+
279
+ function callZaiApi(prompt, sysPrompt, jsonMode, model, timeoutMs) {
280
+ const vibeConfig = readVibeConfig();
281
+ const codingKey = vibeConfig.credentials?.zai?.codingApiKey || process.env.ZAI_CODING_API_KEY;
282
+ const generalKey = vibeConfig.credentials?.zai?.apiKey || process.env.ZAI_API_KEY;
283
+ const useCoding = Boolean(codingKey);
284
+ const apiKey = codingKey || generalKey;
285
+ if (!apiKey) return Promise.reject(new Error('ZAI API key not set (vibe zai coding-key <key>)'));
286
+
287
+ const base = useCoding ? ZAI_BASE_CODING : ZAI_BASE_GENERAL;
288
+ const system = sysPrompt && sysPrompt !== DEFAULT_SYSTEM_PROMPT ? sysPrompt : DEFAULT_SYSTEM_PROMPT;
289
+ const content = jsonMode ? `${prompt}\n\nRespond with valid JSON only.` : prompt;
290
+ const controller = new AbortController();
291
+ const timer = setTimeout(() => controller.abort(), timeoutMs || CLI_TIMEOUT_MS);
292
+
293
+ return fetch(`${base}/chat/completions`, {
294
+ method: 'POST',
295
+ headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${apiKey}` },
296
+ body: JSON.stringify({
297
+ model,
298
+ messages: [{ role: 'system', content: system }, { role: 'user', content }],
299
+ max_tokens: 4096,
300
+ temperature: 0,
301
+ }),
302
+ signal: controller.signal,
303
+ }).then(async (res) => {
304
+ if (!res.ok) {
305
+ const body = await res.text().catch(() => '');
306
+ throw new Error(`zai api failed (code ${res.status}): ${body.slice(0, 500)}`);
307
+ }
308
+ const data = await res.json();
309
+ const text = data?.choices?.[0]?.message?.content?.trim();
310
+ if (!text) throw new Error('zai api returned empty response');
311
+ return text;
312
+ }).finally(() => clearTimeout(timer));
313
+ }
314
+
274
315
  function callAntigravityCli(prompt, sysPrompt, jsonMode, timeoutMs) {
275
316
  const fullPrompt = buildCliPrompt(prompt, sysPrompt, jsonMode);
276
317
  const args = ['-p', fullPrompt];
@@ -357,6 +398,14 @@ async function callProvider(providerName, prompt, sysPrompt, jsonMode, timeoutMs
357
398
  return await callAntigravityCli(prompt, sysPrompt, jsonMode, timeoutMs);
358
399
  }
359
400
 
401
+ if (providerName === 'zai') {
402
+ // coding 키가 있으면 coding plan flagship(5.2), 아니면 일반 API 상한(5.1)
403
+ const hasCoding = Boolean(vibeConfig.credentials?.zai?.codingApiKey || process.env.ZAI_CODING_API_KEY);
404
+ const fallback = hasCoding ? 'glm-5.2' : 'glm-5.1';
405
+ const model = vibeConfig.models?.zaiCoding || vibeConfig.models?.zai || process.env.ZAI_MODEL || fallback;
406
+ return await callZaiApi(prompt, sysPrompt, jsonMode, model, timeoutMs);
407
+ }
408
+
360
409
  if (providerName === 'claude') {
361
410
  return await callClaudeCli(prompt, sysPrompt, jsonMode, timeoutMs);
362
411
  }
@@ -8,7 +8,7 @@
8
8
  *
9
9
  * 실행 step (모두 비차단, config.hooks.{name}.enabled로 개별 토글):
10
10
  * auto-format — 코드 스타일 정규화 (변경 시 finding 반환)
11
- * code-check — 린트/품질 검사 + P1 이슈 verifyRequired 기록
11
+ * code-check — 하드룰(any/console.log) 탐지 (additionalContext 주입만, 커밋 게이트 미연동)
12
12
  * auto-test — 관련 테스트 실행 (debounce 지원)
13
13
  * post-edit — console.log 감지
14
14
  *
@@ -69,21 +69,9 @@ if (/^\s*\/vibe\b/i.test(prompt)) {
69
69
 
70
70
  // 패턴 → 실행할 스크립트 매핑
71
71
  // 각 항목: { pattern, script, args, label }
72
+ // (참고: 매직 키워드 배너 주입(keyword-detector)은 제거됨 — deprecated 별칭
73
+ // 매핑은 CLAUDE.md 의 "Deprecated aliases" 표가 SSOT이며 모델이 직접 해석한다.)
72
74
  const DISPATCH_RULES = [
73
- // 항상 실행 (경량 스크립트)
74
- {
75
- pattern: null, // always
76
- script: 'keyword-detector.js',
77
- args: [prompt],
78
- label: 'keyword',
79
- },
80
-
81
- // 패턴 매칭이 필요한 스크립트
82
- {
83
- pattern: /ultrawork|ulw|울트라워크|ralph|ralplan/i,
84
- script: null, // keyword-detector가 이미 처리
85
- label: 'skip',
86
- },
87
75
  // echo 전용 (stdout으로 직접 출력)
88
76
  {
89
77
  pattern: /e2e.*테스트|e2e.*test|playwright|브라우저.*테스트|browser.*test/i,
@@ -176,7 +164,7 @@ for (const rule of DISPATCH_RULES) {
176
164
  // 외부 LLM 호출(llm-orchestrate)은 부모/자식 timeout 을 정합시킨다 (B-2):
177
165
  // 자식은 hook 모드(primary 45s, fallback 없음, retry 없음)로 단일 시도 후 스스로
178
166
  // 정리하고, 부모는 그보다 약간 긴 50s 로 감싸 hard-kill 을 피한다.
179
- // 경량 스크립트(keyword-detector 등)는 기존 30s 유지.
167
+ // 경량 스크립트는 기존 30s 유지.
180
168
  const isLlm = rule.script === 'llm-orchestrate.js';
181
169
  const execTimeout = isLlm ? 50000 : 30000;
182
170
  const childEnv = isLlm
@@ -207,7 +195,6 @@ await Promise.all(execPromises);
207
195
 
208
196
  // Evolution: Gap detection — log unmatched prompts for skill gap analysis
209
197
  const matched = DISPATCH_RULES.some(r =>
210
- r.label !== 'skip' && r.label !== 'keyword' &&
211
198
  r.pattern !== null && r.pattern.test(prompt) &&
212
199
  (r.script || r.echo)
213
200
  );
@@ -218,12 +205,14 @@ if (!matched) {
218
205
  const utils = await import('./utils.js');
219
206
  const projectDir = process.env.CLAUDE_PROJECT_DIR || '.';
220
207
  const configPath = utils.projectVibePath(projectDir, 'config.json');
221
- let gapEnabled = true;
208
+ // Evolution 동결(opt-in) — evolution.enabled === true 로 명시했을 때만
209
+ // gap 로깅을 수행한다 (기본 OFF, P3-3).
210
+ let gapEnabled = false;
222
211
  try {
223
212
  const fs = await import('fs');
224
213
  if (fs.existsSync(configPath)) {
225
214
  const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
226
- gapEnabled = config.evolution?.gapDetection !== false && config.evolution?.enabled !== false;
215
+ gapEnabled = config.evolution?.enabled === true && config.evolution?.gapDetection !== false;
227
216
  }
228
217
  } catch { /* ignore */ }
229
218
 
@@ -86,16 +86,29 @@ async function main() {
86
86
  import(`${BASE_URL}time/index.js`),
87
87
  ]);
88
88
 
89
- const [session, time, memories, latestVersion] = await Promise.all([
90
- memoryModule.startSession({ projectPath: PROJECT_DIR }),
89
+ // 인덱스만 주입 (harness-review-2026-07-01 P1-5):
90
+ // 이전에는 startSession 전체 요약(git log·테스트 상태·관찰·리플렉션·RAG
91
+ // goals/constraints/decisions)을 매 세션 덤프했다. 이제는 1줄 인덱스만
92
+ // 주입하고, 전체 컨텍스트 복원은 명시적 `/vibe.utils --continue` 전용.
93
+ const [time, memories, latestVersion] = await Promise.all([
91
94
  timeModule.getCurrentTime({ format: 'human', timezone: 'Asia/Seoul' }),
92
95
  memoryModule.listMemories({ limit: 5, projectPath: PROJECT_DIR }),
93
96
  getLatestVersionCached(),
94
97
  ]);
95
98
 
96
- console.log(session.content[0].text);
97
- console.log('\n' + time.content[0].text);
98
- console.log('\n[Recent Memories]');
99
+ console.log(time.content[0].text);
100
+
101
+ // Active feature 1줄 인덱스
102
+ try {
103
+ const LIB_BASE_P = (await import('./utils.js')).getLibBaseUrl();
104
+ const iterMod = await import(`${LIB_BASE_P}IterationTracker.js`);
105
+ const progressLine = iterMod.getProgressSummary(PROJECT_DIR);
106
+ if (progressLine) {
107
+ console.log(`\n📋 ${progressLine} — resume full context: /vibe.utils --continue`);
108
+ }
109
+ } catch { /* progress index is best-effort */ }
110
+
111
+ console.log('\n[Memory Index — bodies on demand via recall_memory]');
99
112
  console.log(memories.content[0].text);
100
113
 
101
114
  // Phase 3 — Recipes + anti-patterns 인덱스 (post-task curation)
@@ -126,16 +139,17 @@ async function main() {
126
139
  }
127
140
  }
128
141
 
129
- // Scope sync — 기본 ON. scopeGuard.enabled=false 명시적 opt-out 가능.
142
+ // Scope sync — 기본 OFF (opt-in: scopeGuard.enabled=true). SSOT: scope-from-spec.js.
130
143
  try {
131
144
  const { syncScopeFile, isScopeGuardEnabled } = await import('./lib/scope-from-spec.js');
132
- if (isScopeGuardEnabled(PROJECT_DIR)) {
145
+ const guardOn = isScopeGuardEnabled(PROJECT_DIR);
146
+ if (guardOn) {
133
147
  const result = syncScopeFile(PROJECT_DIR);
134
148
  if (result.action === 'created' || result.action === 'updated' || result.action === 'removed') {
135
149
  console.log(`\n🚧 Scope ${result.action} from active SPECs (${path.relative(PROJECT_DIR, path.join(projectVibeRoot(PROJECT_DIR), 'scope.json'))})`);
136
150
  }
137
151
  }
138
- // scope 상태 1줄 알림 — 컨텍스트에 주입되어 모델이 현재 scope 범위를 인지한다
152
+ // scope 상태 1줄 알림 — 활성 scope.json 있을 때만 (opt-out 사용자에게 노이즈 금지)
139
153
  const scopeJsonPath = path.join(projectVibeRoot(PROJECT_DIR), 'scope.json');
140
154
  if (fs.existsSync(scopeJsonPath)) {
141
155
  try {
@@ -144,7 +158,7 @@ async function main() {
144
158
  const modeLabel = scopeData.mode || 'warn';
145
159
  console.log(`\nscope-guard: ${featureLabel} (${modeLabel})`);
146
160
  } catch { /* ignore */ }
147
- } else {
161
+ } else if (guardOn) {
148
162
  console.log('\nscope-guard: no active scope (no active SPEC or no derivable paths) — out-of-scope edits are not monitored');
149
163
  }
150
164
  } catch { /* scope sync is best-effort */ }
@@ -198,32 +212,8 @@ async function main() {
198
212
  storageA.close();
199
213
  } catch { /* autonomy not yet initialized, skip */ }
200
214
 
201
- // Evolution status summary
202
- try {
203
- const LIB_BASE = (await import('./utils.js')).getLibBaseUrl();
204
- const [memMod, regMod, insMod] = await Promise.all([
205
- import(`${LIB_BASE}memory/MemoryStorage.js`),
206
- import(`${LIB_BASE}evolution/GenerationRegistry.js`),
207
- import(`${LIB_BASE}evolution/InsightStore.js`),
208
- ]);
209
- const storage = new memMod.MemoryStorage(PROJECT_DIR);
210
- const registry = new regMod.GenerationRegistry(storage);
211
- const insightStore = new insMod.InsightStore(storage);
212
-
213
- const genStats = registry.getStats();
214
- const active = genStats.byStatus?.active || 0;
215
- const drafts = genStats.byStatus?.draft || 0;
216
- const gaps = insightStore.getByType('skill_gap').length;
217
-
218
- if (active > 0 || drafts > 0 || gaps > 0) {
219
- const parts = [];
220
- if (active > 0) parts.push(`${active} active skills`);
221
- if (drafts > 0) parts.push(`${drafts} pending approval`);
222
- if (gaps > 0) parts.push(`${gaps} gaps detected`);
223
- console.log(`\n🧬 Evolution: ${parts.join(', ')}`);
224
- }
225
- storage.close();
226
- } catch { /* evolution not yet initialized, skip */ }
215
+ // Evolution 상태 요약은 제거 — evolution 은 동결(opt-in) 상태이며
216
+ // 사용자는 `vibe evolution` CLI 로 명시적으로 조회한다 (P3-3).
227
217
  } catch (e) {
228
218
  console.log('[Session] Error:', e.message);
229
219
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@su-record/vibe",
3
- "version": "2.16.3",
4
- "description": "AI Coding Framework for Claude Code — 42+ agents, 70 skills, multi-LLM orchestration",
3
+ "version": "3.0.0",
4
+ "description": "AI Coding Framework for Claude Code — 10+ agents, 59 skills, multi-LLM orchestration",
5
5
  "type": "module",
6
6
  "main": "dist/cli/index.js",
7
7
  "exports": {
@@ -9,11 +9,9 @@
9
9
  "./tools": "./dist/tools/index.js",
10
10
  "./tools/memory": "./dist/tools/memory/index.js",
11
11
  "./tools/convention": "./dist/tools/convention/index.js",
12
- "./tools/semantic": "./dist/tools/semantic/index.js",
13
12
  "./tools/ui": "./dist/tools/ui/index.js",
14
13
  "./tools/time": "./dist/tools/time/index.js",
15
14
  "./tools/interaction": "./dist/tools/interaction/index.js",
16
- "./orchestrator": "./dist/infra/orchestrator/index.js",
17
15
  "./memory": {
18
16
  "types": "./dist/infra/lib/memory/index.d.ts",
19
17
  "default": "./dist/infra/lib/memory/index.js"
@@ -27,6 +25,8 @@
27
25
  "dev": "tsc --watch",
28
26
  "gen:skill-docs": "npx tsx scripts/gen-skill-docs.ts",
29
27
  "gen:skill-docs:check": "npx tsx scripts/gen-skill-docs.ts --check",
28
+ "sync:agent-models": "npx tsx scripts/sync-agent-models.ts",
29
+ "sync:agent-models:check": "npx tsx scripts/sync-agent-models.ts --check",
30
30
  "validate:skill-invocation": "npx tsx scripts/validate-skill-invocation.ts",
31
31
  "validate:counts": "npx tsx scripts/validate-counts.ts",
32
32
  "test": "vitest run",