@su-record/vibe 2.12.5 → 2.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +8 -2
- package/README.en.md +11 -11
- package/README.md +7 -7
- package/dist/cli/postinstall/fs-utils.d.ts +23 -0
- package/dist/cli/postinstall/fs-utils.d.ts.map +1 -1
- package/dist/cli/postinstall/fs-utils.js +71 -0
- package/dist/cli/postinstall/fs-utils.js.map +1 -1
- package/dist/cli/postinstall/fs-utils.test.js +69 -1
- package/dist/cli/postinstall/fs-utils.test.js.map +1 -1
- package/dist/cli/postinstall/main.d.ts.map +1 -1
- package/dist/cli/postinstall/main.js +12 -2
- package/dist/cli/postinstall/main.js.map +1 -1
- package/dist/cli/setup/CodexHooks.test.js +27 -0
- package/dist/cli/setup/CodexHooks.test.js.map +1 -1
- package/dist/cli/setup/ProjectSetup.js +2 -2
- package/dist/cli/setup/ProjectSetup.js.map +1 -1
- package/dist/infra/lib/DecisionTracer.d.ts +4 -0
- package/dist/infra/lib/DecisionTracer.d.ts.map +1 -1
- package/dist/infra/lib/DecisionTracer.js +4 -0
- package/dist/infra/lib/DecisionTracer.js.map +1 -1
- package/dist/infra/lib/LoopBreaker.d.ts +4 -0
- package/dist/infra/lib/LoopBreaker.d.ts.map +1 -1
- package/dist/infra/lib/LoopBreaker.js +4 -0
- package/dist/infra/lib/LoopBreaker.js.map +1 -1
- package/dist/infra/lib/ReviewRace.d.ts +4 -0
- package/dist/infra/lib/ReviewRace.d.ts.map +1 -1
- package/dist/infra/lib/ReviewRace.js +4 -0
- package/dist/infra/lib/ReviewRace.js.map +1 -1
- package/dist/infra/lib/SkillQualityGate.d.ts +4 -0
- package/dist/infra/lib/SkillQualityGate.d.ts.map +1 -1
- package/dist/infra/lib/SkillQualityGate.js +4 -0
- package/dist/infra/lib/SkillQualityGate.js.map +1 -1
- package/dist/infra/lib/UltraQA.d.ts +4 -0
- package/dist/infra/lib/UltraQA.d.ts.map +1 -1
- package/dist/infra/lib/UltraQA.js +4 -0
- package/dist/infra/lib/UltraQA.js.map +1 -1
- package/dist/infra/lib/VerificationLoop.d.ts +4 -0
- package/dist/infra/lib/VerificationLoop.d.ts.map +1 -1
- package/dist/infra/lib/VerificationLoop.js +4 -0
- package/dist/infra/lib/VerificationLoop.js.map +1 -1
- package/dist/infra/orchestrator/index.d.ts.map +1 -1
- package/dist/infra/orchestrator/index.js +1 -3
- package/dist/infra/orchestrator/index.js.map +1 -1
- package/dist/infra/orchestrator/parallelResearch.d.ts.map +1 -1
- package/dist/infra/orchestrator/parallelResearch.js +1 -4
- package/dist/infra/orchestrator/parallelResearch.js.map +1 -1
- package/dist/tools/convention/validateCodeQuality.d.ts.map +1 -1
- package/dist/tools/convention/validateCodeQuality.js +5 -4
- package/dist/tools/convention/validateCodeQuality.js.map +1 -1
- package/dist/tools/spec/traceabilityMatrix.d.ts +2 -0
- package/dist/tools/spec/traceabilityMatrix.d.ts.map +1 -1
- package/dist/tools/spec/traceabilityMatrix.js +50 -1
- package/dist/tools/spec/traceabilityMatrix.js.map +1 -1
- package/dist/tools/spec/traceabilityMatrix.path-resolution.test.d.ts +10 -0
- package/dist/tools/spec/traceabilityMatrix.path-resolution.test.d.ts.map +1 -0
- package/dist/tools/spec/traceabilityMatrix.path-resolution.test.js +89 -0
- package/dist/tools/spec/traceabilityMatrix.path-resolution.test.js.map +1 -0
- package/dist/tools/spec/traceabilityMatrix.test.js +19 -0
- package/dist/tools/spec/traceabilityMatrix.test.js.map +1 -1
- package/hooks/hooks.json +1 -0
- package/hooks/scripts/__tests__/.vibe/command-log.txt +39 -0
- package/hooks/scripts/__tests__/.vibe/memories/memories.db +0 -0
- package/hooks/scripts/__tests__/.vibe/memories/memories.db-shm +0 -0
- package/hooks/scripts/__tests__/.vibe/memories/memories.db-wal +0 -0
- package/hooks/scripts/__tests__/auto-test-debounce.test.js +145 -0
- package/hooks/scripts/__tests__/code-check-detectors.test.js +155 -0
- package/hooks/scripts/__tests__/dispatcher-inprocess.test.js +99 -0
- package/hooks/scripts/__tests__/post-edit-dispatcher.test.js +139 -0
- package/hooks/scripts/__tests__/pre-tool-guard.test.js +115 -1
- package/hooks/scripts/__tests__/run-ledger-verify-required.test.js +146 -0
- package/hooks/scripts/__tests__/run-ledger.test.js +330 -0
- package/hooks/scripts/__tests__/scope-from-spec.test.js +215 -0
- package/hooks/scripts/__tests__/sentinel-guard.test.js +79 -24
- package/hooks/scripts/__tests__/step-counter.test.js +95 -15
- package/hooks/scripts/__tests__/utils-npm-root.test.js +98 -0
- package/hooks/scripts/auto-commit.js +27 -1
- package/hooks/scripts/auto-format.js +85 -20
- package/hooks/scripts/auto-test.js +187 -37
- package/hooks/scripts/code-check.js +286 -90
- package/hooks/scripts/codex-hook-adapter.js +12 -1
- package/hooks/scripts/command-log.js +26 -16
- package/hooks/scripts/lib/dispatcher.js +38 -0
- package/hooks/scripts/lib/hook-context.js +101 -0
- package/hooks/scripts/lib/pr-gate-runner.js +62 -0
- package/hooks/scripts/lib/run-ledger.js +169 -0
- package/hooks/scripts/lib/scope-from-spec.js +40 -7
- package/hooks/scripts/post-edit-dispatcher.js +93 -20
- package/hooks/scripts/post-edit.js +40 -19
- package/hooks/scripts/pr-test-gate.js +8 -37
- package/hooks/scripts/pre-tool-dispatcher.js +18 -16
- package/hooks/scripts/pre-tool-guard.js +55 -52
- package/hooks/scripts/prompt-dispatcher.js +10 -0
- package/hooks/scripts/scope-guard.js +40 -39
- package/hooks/scripts/sentinel-guard.js +41 -41
- package/hooks/scripts/session-start.js +13 -1
- package/hooks/scripts/step-counter.js +100 -7
- package/hooks/scripts/stop-dispatcher.js +26 -0
- package/hooks/scripts/utils.js +63 -21
- package/hooks/scripts/verify-ledger.js +22 -0
- package/package.json +2 -2
- package/skills/spec/references/templates.md +11 -6
- package/skills/vibe.run/SKILL.md +144 -1681
- package/skills/vibe.run/references/brand-assets.md +59 -0
- package/skills/vibe.run/references/parallel-agents.md +326 -0
- package/skills/vibe.run/references/race-review.md +272 -0
- package/skills/vibe.run/references/ralph-loop.md +172 -0
- package/skills/vibe.run/references/ultrawork-mode.md +148 -0
- package/skills/vibe.trace/SKILL.md +25 -38
- package/skills/vibe.verify/SKILL.md +15 -0
- package/hooks/scripts/figma-guard.js +0 -219
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
# Ralph Loop — Full Reference
|
|
2
|
+
|
|
3
|
+
> Loaded by vibe.run SKILL.md when Ralph Loop or ULTRAWORK is active (coverage verification).
|
|
4
|
+
|
|
5
|
+
## Ralph Loop (Completion Verification)
|
|
6
|
+
|
|
7
|
+
> **Inspired by [ghuntley.com/ralph](https://ghuntley.com/ralph)**: "Deterministically bad in an undeterministic world" — Keep iterating until TRULY complete.
|
|
8
|
+
|
|
9
|
+
**Problem**: AI often claims "complete" when implementation is partial.
|
|
10
|
+
|
|
11
|
+
**Solution**: RTM-based automated coverage verification with iteration tracking.
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
15
|
+
│ RALPH LOOP (Mandatory) │
|
|
16
|
+
│ │
|
|
17
|
+
│ After ALL phases complete: │
|
|
18
|
+
│ │
|
|
19
|
+
│ ┌──────────────────────────────────────────────────────────┐ │
|
|
20
|
+
│ │ RTM COVERAGE VERIFICATION [Iteration {{ITER}}/{{MAX}}] │ │
|
|
21
|
+
│ │ │ │
|
|
22
|
+
│ │ Generate RTM via core tools: │ │
|
|
23
|
+
│ │ → generateTraceabilityMatrix("{feature-name}") │ │
|
|
24
|
+
│ │ │ │
|
|
25
|
+
│ │ Coverage Metrics (automated): │ │
|
|
26
|
+
│ │ □ Requirements coverage: {coveragePercent}% │ │
|
|
27
|
+
│ │ □ SPEC → Feature mapping: {featureCovered}/{total} │ │
|
|
28
|
+
│ │ □ Feature → Test mapping: {testCovered}/{total} │ │
|
|
29
|
+
│ │ □ Build successful? │ │
|
|
30
|
+
│ │ □ Tests passing? │ │
|
|
31
|
+
│ │ │ │
|
|
32
|
+
│ │ UNCOVERED: {uncoveredRequirements[]} │ │
|
|
33
|
+
│ └──────────────────────────────────────────────────────────┘ │
|
|
34
|
+
│ │ │
|
|
35
|
+
│ ┌──────────┴──────────┐ │
|
|
36
|
+
│ │ Coverage == 100%? │ │
|
|
37
|
+
│ └──────────┬──────────┘ │
|
|
38
|
+
│ │ │ │
|
|
39
|
+
│ NO YES │
|
|
40
|
+
│ │ │ │
|
|
41
|
+
│ ↓ ↓ │
|
|
42
|
+
│ ┌────────────────┐ ┌────────────────┐ │
|
|
43
|
+
│ │ IMPLEMENT │ │ TRULY DONE │ │
|
|
44
|
+
│ │ UNCOVERED │ │ │ │
|
|
45
|
+
│ │ REQUIREMENTS │ │ Report final │ │
|
|
46
|
+
│ │ (auto-extract) │ │ RTM coverage │ │
|
|
47
|
+
│ └───────┬────────┘ └────────────────┘ │
|
|
48
|
+
│ │ │
|
|
49
|
+
│ └──────────→ [Re-generate RTM] │
|
|
50
|
+
│ │
|
|
51
|
+
│ │ │
|
|
52
|
+
│ ↓ │
|
|
53
|
+
│ Stuck? (coverage unchanged from prev iteration) │
|
|
54
|
+
│ │ │
|
|
55
|
+
│ ├─ Interactive: Ask user │
|
|
56
|
+
│ │ 1. Provide resolution → retry │
|
|
57
|
+
│ │ 2. "proceed" → TODO + done │
|
|
58
|
+
│ │ 3. "abort" → stop │
|
|
59
|
+
│ └─ ultrawork: TODO + done │
|
|
60
|
+
│ │
|
|
61
|
+
│ NO iteration cap — loop until 100% OR stuck │
|
|
62
|
+
│ ZERO TOLERANCE for silent scope reduction │
|
|
63
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## RTM Invocation
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
# Generate RTM for coverage verification (generateTraceabilityMatrix is synchronous — no .then())
|
|
70
|
+
node -e "import('{{VIBE_PATH_URL}}/node_modules/@su-record/vibe/dist/tools/index.js').then(t => { const r = t.generateTraceabilityMatrix('{feature-name}', {projectPath: process.cwd()}); console.log(JSON.stringify(r, null, 2)); })"
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
> **Note:** Default SPEC path is `.vibe/specs/<feature>.md` (falls back to `.claude/vibe/specs/` then `.claude/specs/` for legacy projects).
|
|
74
|
+
> `status === 'empty'` means the gate MUST be treated as failed/not-applicable, never as 100% pass.
|
|
75
|
+
|
|
76
|
+
## RTM Metrics
|
|
77
|
+
|
|
78
|
+
| Metric | Description |
|
|
79
|
+
|--------|-------------|
|
|
80
|
+
| `totalRequirements` | Total REQ-* items in SPEC |
|
|
81
|
+
| `specCovered` | Requirements with SPEC mapping |
|
|
82
|
+
| `featureCovered` | Requirements with Feature scenarios |
|
|
83
|
+
| `testCovered` | Requirements with test files |
|
|
84
|
+
| `coveragePercent` | Overall coverage percentage |
|
|
85
|
+
| `uncoveredRequirements` | List of missing REQ-* IDs |
|
|
86
|
+
|
|
87
|
+
## Ralph Loop Rules
|
|
88
|
+
|
|
89
|
+
| Rule | Description |
|
|
90
|
+
|------|-------------|
|
|
91
|
+
| **No Scope Reduction** | Never say "simplified" or "basic version" — implement FULL request |
|
|
92
|
+
| **Iteration Tracking** | Display `[{{ITER}}]` to show progress (no max — loop until done) |
|
|
93
|
+
| **RTM-Based Gap List** | Use `uncoveredRequirements` array — no manual comparison |
|
|
94
|
+
| **Coverage Threshold** | Must reach 100% coverage to complete |
|
|
95
|
+
| **No Iteration Cap** | Loop until 100% coverage OR stuck (convergence detected) |
|
|
96
|
+
| **Stuck Handling** | If coverage % unchanged between iterations → ask user (proceed/abort/fix), or ultrawork → TODO + done |
|
|
97
|
+
| **Diminishing Returns** | Iteration 3+ → focus on core requirements (REQ-*-001~003) first; P2/P3 continue but lower priority |
|
|
98
|
+
|
|
99
|
+
## Ralph Loop Output Format
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
103
|
+
RALPH VERIFICATION [Iteration 1]
|
|
104
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
105
|
+
|
|
106
|
+
RTM Coverage Report: login
|
|
107
|
+
|
|
108
|
+
Requirements Traceability:
|
|
109
|
+
Total Requirements: 9
|
|
110
|
+
SPEC Covered: 9/9 (100%)
|
|
111
|
+
Feature Covered: 5/9 (55%)
|
|
112
|
+
Test Covered: 4/9 (44%)
|
|
113
|
+
|
|
114
|
+
REQ-login-001: Login form UI → Scenario 1 → login.test.ts
|
|
115
|
+
REQ-login-002: Email validation → Scenario 2 → validation.test.ts
|
|
116
|
+
REQ-login-003: Password validation → Scenario 2 → validation.test.ts
|
|
117
|
+
REQ-login-004: Remember me checkbox → NOT IMPLEMENTED
|
|
118
|
+
REQ-login-005: Forgot password link → NOT IMPLEMENTED
|
|
119
|
+
REQ-login-006: API integration → Scenario 3 → api.test.ts
|
|
120
|
+
REQ-login-007: Loading state → NOT IMPLEMENTED
|
|
121
|
+
REQ-login-008: Error toast → NOT IMPLEMENTED
|
|
122
|
+
REQ-login-009: Session storage → Scenario 4 → (no test)
|
|
123
|
+
|
|
124
|
+
Overall Coverage: 55% BELOW 100% TARGET
|
|
125
|
+
|
|
126
|
+
UNCOVERED REQUIREMENTS (auto-extracted from RTM):
|
|
127
|
+
1. REQ-login-004: Remember me checkbox
|
|
128
|
+
2. REQ-login-005: Forgot password link
|
|
129
|
+
3. REQ-login-007: Loading state
|
|
130
|
+
4. REQ-login-008: Error toast notifications
|
|
131
|
+
|
|
132
|
+
NOT COMPLETE — Implementing uncovered requirements...
|
|
133
|
+
|
|
134
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
135
|
+
RALPH VERIFICATION [Iteration 2]
|
|
136
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
137
|
+
|
|
138
|
+
RTM Coverage Report: login
|
|
139
|
+
|
|
140
|
+
Requirements Traceability:
|
|
141
|
+
Total Requirements: 9
|
|
142
|
+
SPEC Covered: 9/9 (100%)
|
|
143
|
+
Feature Covered: 9/9 (100%)
|
|
144
|
+
Test Covered: 9/9 (100%)
|
|
145
|
+
|
|
146
|
+
Overall Coverage: 100% TARGET REACHED
|
|
147
|
+
|
|
148
|
+
Build: Passed
|
|
149
|
+
Tests: 12/12 Passed
|
|
150
|
+
Type Check: No errors
|
|
151
|
+
|
|
152
|
+
RALPH VERIFIED COMPLETE!
|
|
153
|
+
|
|
154
|
+
RTM saved: .vibe/rtm/login-rtm.md
|
|
155
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## When to Trigger Ralph Loop
|
|
159
|
+
|
|
160
|
+
1. After all phases complete
|
|
161
|
+
2. Before final quality report
|
|
162
|
+
3. Whenever user says "ultrawork" or "ralph"
|
|
163
|
+
|
|
164
|
+
## Forbidden Responses (VIOLATIONS)
|
|
165
|
+
|
|
166
|
+
| NEVER Say | Instead |
|
|
167
|
+
|-----------|---------|
|
|
168
|
+
| "I've implemented a basic version" | Implement the FULL version |
|
|
169
|
+
| "This is a simplified approach" | Implement as specified |
|
|
170
|
+
| "You can add X later" | Add X now |
|
|
171
|
+
| "For demonstration purposes" | Implement production-ready |
|
|
172
|
+
| "The core functionality is done" | ALL functionality must be done |
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# ULTRAWORK Mode — Full Reference
|
|
2
|
+
|
|
3
|
+
> Loaded by vibe.run SKILL.md when user includes `ultrawork` or `ulw` keyword.
|
|
4
|
+
|
|
5
|
+
## What ULTRAWORK Enables
|
|
6
|
+
|
|
7
|
+
When you include `ultrawork` (or `ulw`), ALL of these activate automatically:
|
|
8
|
+
|
|
9
|
+
| Feature | Description |
|
|
10
|
+
|---------|-------------|
|
|
11
|
+
| **Parallel Exploration** | 3+ Task(haiku) agents run simultaneously |
|
|
12
|
+
| **Boulder Loop** | Auto-continues until ALL phases complete |
|
|
13
|
+
| **Context Compression** | Aggressive auto-save at 70%+ context |
|
|
14
|
+
| **No Pause** | Doesn't wait for confirmation between phases |
|
|
15
|
+
| **External LLMs** | Auto-consults GPT/Antigravity if enabled |
|
|
16
|
+
| **Error Recovery** | Loops until 100% or stuck; on stuck auto-records TODO and proceeds (no user prompt) |
|
|
17
|
+
| **Race Review (v2.6.9)** | Multi-LLM review (GPT+Antigravity) with cross-validation |
|
|
18
|
+
|
|
19
|
+
## Boulder Loop (Inspired by Sisyphus)
|
|
20
|
+
|
|
21
|
+
Like Sisyphus rolling the boulder, ULTRAWORK **keeps going until done**:
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
25
|
+
│ BOULDER LOOP (ultrawork) │
|
|
26
|
+
│ │
|
|
27
|
+
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
|
|
28
|
+
│ │ Phase 1 │───→│ Phase 2 │───→│ Phase 3 │───→│ Phase N │ │
|
|
29
|
+
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
|
|
30
|
+
│ │ │ │ │ │
|
|
31
|
+
│ ↓ ↓ ↓ ↓ │
|
|
32
|
+
│ [Parallel] [Parallel] [Parallel] [Parallel] │
|
|
33
|
+
│ [Implement] [Implement] [Implement] [Implement] │
|
|
34
|
+
│ [Test] [Test] [Test] [Test] │
|
|
35
|
+
│ │ │ │ │ │
|
|
36
|
+
│ └───────────────┴───────────────┴───────────────┘ │
|
|
37
|
+
│ │ │
|
|
38
|
+
│ ↓ │
|
|
39
|
+
│ ┌──────────────┐ │
|
|
40
|
+
│ │ ALL DONE? │ │
|
|
41
|
+
│ └──────────────┘ │
|
|
42
|
+
│ │ │ │
|
|
43
|
+
│ NO YES │
|
|
44
|
+
│ │ │ │
|
|
45
|
+
│ ↓ ↓ │
|
|
46
|
+
│ [Continue] [Complete!] │
|
|
47
|
+
│ │
|
|
48
|
+
│ NO STOPPING until acceptance criteria met or error limit hit │
|
|
49
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## ULTRAWORK Example Session
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
User: /vibe.run "brick-game" ultrawork
|
|
56
|
+
|
|
57
|
+
Claude:
|
|
58
|
+
ULTRAWORK MODE ACTIVATED
|
|
59
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
60
|
+
|
|
61
|
+
SPEC: .vibe/specs/brick-game.md
|
|
62
|
+
4 Phases detected
|
|
63
|
+
Boulder Loop: ENABLED (will continue until all phases complete)
|
|
64
|
+
Auto-retry: ON (loop until 100% or stuck → auto-TODO)
|
|
65
|
+
Context compression: AGGRESSIVE
|
|
66
|
+
|
|
67
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
68
|
+
BOULDER ROLLING... Phase 1/4
|
|
69
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
70
|
+
|
|
71
|
+
[PARALLEL] Launching 3 exploration agents...
|
|
72
|
+
Exploration complete (7.2s)
|
|
73
|
+
Implementing...
|
|
74
|
+
Phase 1 complete
|
|
75
|
+
|
|
76
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
77
|
+
BOULDER ROLLING... Phase 2/4
|
|
78
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
79
|
+
|
|
80
|
+
[PARALLEL] Launching 3 exploration agents...
|
|
81
|
+
Exploration complete (6.8s)
|
|
82
|
+
Implementing...
|
|
83
|
+
Test failed: collision detection
|
|
84
|
+
Auto-retry [iteration 1]...
|
|
85
|
+
Fixing...
|
|
86
|
+
Phase 2 complete
|
|
87
|
+
|
|
88
|
+
[...continues automatically...]
|
|
89
|
+
|
|
90
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
91
|
+
BOULDER REACHED THE TOP!
|
|
92
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
93
|
+
|
|
94
|
+
All 4 phases complete
|
|
95
|
+
All acceptance criteria passed
|
|
96
|
+
Build succeeded
|
|
97
|
+
Tests passed
|
|
98
|
+
|
|
99
|
+
Total: 8m 24s
|
|
100
|
+
Retries: 2
|
|
101
|
+
Context saved: 3 checkpoints
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Normal vs ULTRAWORK Comparison
|
|
105
|
+
|
|
106
|
+
| Aspect | Normal | ULTRAWORK |
|
|
107
|
+
|--------|--------|-----------|
|
|
108
|
+
| Phase transition | May pause | Auto-continues |
|
|
109
|
+
| On error | Reports and stops | Auto-retries (3x) |
|
|
110
|
+
| Context 70%+ | Warning only | Auto-compress + save |
|
|
111
|
+
| Exploration | Sequential possible | FORCED parallel |
|
|
112
|
+
| Completion | Phase-by-phase | Until ALL done |
|
|
113
|
+
|
|
114
|
+
## Automation Level System
|
|
115
|
+
|
|
116
|
+
Magic keywords in the user input automatically set the **AutomationLevel**, which controls how much the AI self-advances vs. pausing for confirmation.
|
|
117
|
+
|
|
118
|
+
### Level Definitions
|
|
119
|
+
|
|
120
|
+
| Level | Name | Keyword(s) | Auto-advance | Auto-retry | Stuck Behavior | Parallel Agents | Checkpoints |
|
|
121
|
+
|-------|------|------------|--------------|------------|----------------|-----------------|-------------|
|
|
122
|
+
| L0 | Manual | `manual` | No | No | Ask user every step | No | All |
|
|
123
|
+
| L1 | Guided | `guided`, `verify` | No | No | Ask user on stuck | No | All |
|
|
124
|
+
| L2 | Semi-auto | `quick` (default) | Yes | Yes (low cap: 2) | Ask user after 2 retries | No | Key points |
|
|
125
|
+
| L3 | Auto | `ultrawork`, `ulw` | Yes | Yes (no cap) | Auto-TODO + proceed | Yes | Checkpoint-only |
|
|
126
|
+
| L4 | Full-auto | `ralph`, `ralplan` | Yes | Yes (no cap) | Auto-TODO + proceed | Yes | None |
|
|
127
|
+
|
|
128
|
+
### Detection Rule
|
|
129
|
+
|
|
130
|
+
```
|
|
131
|
+
/vibe.run "login" → L2 Semi-auto (default)
|
|
132
|
+
/vibe.run "login" ultrawork → L3 Auto
|
|
133
|
+
/vibe.run "login" ralph → L4 Full-auto
|
|
134
|
+
/vibe.run "login" verify → L1 Guided
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Confirmation Matrix
|
|
138
|
+
|
|
139
|
+
| Action | L0 | L1 | L2 | L3 | L4 |
|
|
140
|
+
|--------|----|----|----|----|-----|
|
|
141
|
+
| `destructive` | confirm | confirm | confirm | confirm | auto |
|
|
142
|
+
| `architecture_choice` | confirm | confirm | confirm | auto | auto |
|
|
143
|
+
| `implementation_scope` | confirm | confirm | confirm | auto | auto |
|
|
144
|
+
| `phase_advance` | confirm | confirm | auto | auto | auto |
|
|
145
|
+
| `fix_strategy` | confirm | confirm | auto | auto | auto |
|
|
146
|
+
| `retry` | confirm | auto | auto | auto | auto |
|
|
147
|
+
|
|
148
|
+
**Rule**: When confirmation is required, pause and display a checkpoint before proceeding.
|
|
@@ -187,63 +187,50 @@ Loading files:
|
|
|
187
187
|
The RTM generation uses core tools:
|
|
188
188
|
|
|
189
189
|
```bash
|
|
190
|
-
# Generate RTM
|
|
191
|
-
node -e "import('{{VIBE_PATH_URL}}/node_modules/@su-record/vibe/dist/tools/index.js').then(t => t.generateTraceabilityMatrix('login'
|
|
190
|
+
# Generate RTM (generateTraceabilityMatrix is synchronous — no .then())
|
|
191
|
+
node -e "import('{{VIBE_PATH_URL}}/node_modules/@su-record/vibe/dist/tools/index.js').then(t => { const m = t.generateTraceabilityMatrix('login', {projectPath: process.cwd()}); console.log(t.formatMatrixAsMarkdown(m)); })"
|
|
192
192
|
|
|
193
193
|
# Generate HTML
|
|
194
|
-
node -e "import('{{VIBE_PATH_URL}}/node_modules/@su-record/vibe/dist/tools/index.js').then(t => t.generateTraceabilityMatrix('login'
|
|
194
|
+
node -e "import('{{VIBE_PATH_URL}}/node_modules/@su-record/vibe/dist/tools/index.js').then(t => { const m = t.generateTraceabilityMatrix('login', {projectPath: process.cwd()}); console.log(t.formatMatrixAsHtml(m)); })"
|
|
195
195
|
```
|
|
196
196
|
|
|
197
|
-
|
|
197
|
+
> **Note:** Default SPEC path is `.vibe/specs/<feature>.md` (falls back to `.claude/vibe/specs/` then `.claude/specs/` for legacy projects).
|
|
198
|
+
> `status === 'empty'` means the gate MUST be treated as failed/not-applicable, never as 100% pass.
|
|
198
199
|
|
|
199
|
-
|
|
200
|
+
## Post-Trace Gates
|
|
200
201
|
|
|
201
|
-
|
|
202
|
+
After `/vibe.trace` completes and the RTM is displayed, two downstream mechanisms consume the result.
|
|
202
203
|
|
|
203
|
-
|
|
204
|
-
|----------|---------|
|
|
205
|
-
| `createLoop(feature, config?)` | Initialize a new verification loop for a feature |
|
|
206
|
-
| `recordVerification(state, requirements)` | Record RTM results and determine next action |
|
|
207
|
-
| `formatVerificationResult(result, config)` | Format a single iteration result for display |
|
|
208
|
-
| `formatLoopSummary(state)` | Format the full loop history as readable text |
|
|
209
|
-
| `getUnmetRequirements(result)` | Extract failed/partial requirements for targeted fixing |
|
|
210
|
-
| `isImproving(state)` | Detect whether achievement rate is increasing across iterations |
|
|
204
|
+
### Empty-result gate
|
|
211
205
|
|
|
212
|
-
|
|
206
|
+
`generateTraceabilityMatrix` returns `status: 'empty'` when no `REQ-<feature>-NNN` IDs are found in the SPEC. This state **must be treated as a gate failure**, not as 100% coverage. When the matrix status is `empty`, report it explicitly and do not proceed as if the feature is verified.
|
|
213
207
|
|
|
214
208
|
```
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
209
|
+
RTM status === 'empty'
|
|
210
|
+
→ Coverage gate: FAILED (no requirements to trace)
|
|
211
|
+
→ Action: run /vibe.spec to add REQ-IDs before re-running /vibe.trace
|
|
218
212
|
```
|
|
219
213
|
|
|
220
|
-
###
|
|
214
|
+
### Run-ledger flow
|
|
221
215
|
|
|
222
|
-
|
|
216
|
+
`/vibe.verify` records its outcome via `hooks/scripts/verify-ledger.js pass|fail`. This writes `verifyPassed` and `verifyAt` into `.vibe/metrics/run-ledger.json`. Downstream gates consume this record:
|
|
223
217
|
|
|
224
|
-
|
|
|
225
|
-
|
|
226
|
-
| `
|
|
227
|
-
|
|
|
228
|
-
| `max_iterations` | rate < threshold AND no iterations left | Report remaining gaps as TODO |
|
|
218
|
+
| Gate | Behavior |
|
|
219
|
+
|------|----------|
|
|
220
|
+
| `auto-commit` | Commits only when `verifyPassed === true` AND `verifyAt > runStarted` |
|
|
221
|
+
| Stop hook | Warns when `runStarted && !verifyPassed`; blocks once if `verifyGate.mode === 'block'` |
|
|
229
222
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
If the achievement rate does not improve between iterations (`isImproving` returns false), the loop stops early to avoid wasted cycles.
|
|
233
|
-
|
|
234
|
-
### Example Flow
|
|
223
|
+
**To register a passing trace as verified**, run `/vibe.verify` after `/vibe.trace` reports acceptable coverage. The verify skill calls `verify-ledger.js pass` internally — you do not invoke it manually.
|
|
235
224
|
|
|
236
225
|
```
|
|
237
|
-
/vibe.trace "login"
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
→ [fix unmet requirements]
|
|
242
|
-
→ /vibe.trace "login"
|
|
243
|
-
→ recordVerification(...) → action: passed (rate: 100%)
|
|
244
|
-
→ formatVerificationResult → display final report
|
|
226
|
+
/vibe.trace "login" → RTM: 9/9 (100%)
|
|
227
|
+
/vibe.verify "login" → runs checks → calls verify-ledger.js pass
|
|
228
|
+
→ .vibe/metrics/run-ledger.json updated
|
|
229
|
+
auto-commit / Stop gate → verifyPassed=true, gate clears
|
|
245
230
|
```
|
|
246
231
|
|
|
232
|
+
If `/vibe.verify` is skipped, `auto-commit` will log the skip reason and abort the commit.
|
|
233
|
+
|
|
247
234
|
## Options
|
|
248
235
|
|
|
249
236
|
| Option | Description |
|
|
@@ -465,6 +465,21 @@ Load skill `contract` with: check "{feature-name}"
|
|
|
465
465
|
- **P1 drift** → demote verify to fail; auto-call `/vibe.regress register --from-contract`
|
|
466
466
|
- P2 / P3 drift → warning only; verify still passes
|
|
467
467
|
|
|
468
|
+
## Ledger Update (MANDATORY final step)
|
|
469
|
+
|
|
470
|
+
After producing the verification report, record the result to the run ledger:
|
|
471
|
+
|
|
472
|
+
```bash
|
|
473
|
+
# pass 또는 fail — 시나리오 전체 통과 여부에 따라 선택
|
|
474
|
+
HOOKS_DIR="${VIBE_PATH:-$(npm root -g 2>/dev/null)/@su-record/vibe}/hooks/scripts"
|
|
475
|
+
if [ -f "$HOOKS_DIR/verify-ledger.js" ]; then
|
|
476
|
+
node "$HOOKS_DIR/verify-ledger.js" pass # 전체 통과 시
|
|
477
|
+
# node "$HOOKS_DIR/verify-ledger.js" fail # 실패 시
|
|
478
|
+
fi
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
Replace `pass` with `fail` when any scenario fails. This step enables the Stop-hook verify-skip gate and auto-commit verify gate.
|
|
482
|
+
|
|
468
483
|
## Next Step
|
|
469
484
|
|
|
470
485
|
On verification pass:
|
|
@@ -1,219 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* Figma Guard — vibe.figma 작업 시 스킬 우회 차단
|
|
4
|
-
*
|
|
5
|
-
* 차단 대상:
|
|
6
|
-
* 1. /tmp/{feature}/ 하위에 자체 정제/생성 스크립트(.mjs/.js) 작성
|
|
7
|
-
* → figma-refine.js / figma-to-scss.js 호출하라고 차단
|
|
8
|
-
* 2. SCSS 파일을 직접 작성 (figma-to-scss.js 호출 흔적 없이)
|
|
9
|
-
* 3. Vue/React <style> 블록에 figma 관련 SCSS 클래스 직접 작성
|
|
10
|
-
*
|
|
11
|
-
* 작동 조건:
|
|
12
|
-
* - tool: Write 또는 Edit
|
|
13
|
-
* - file_path가 figma 작업 컨텍스트에 해당
|
|
14
|
-
*
|
|
15
|
-
* Exit codes:
|
|
16
|
-
* 0 — 통과
|
|
17
|
-
* 2 — 차단
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
|
-
import fs from 'fs';
|
|
21
|
-
import path from 'path';
|
|
22
|
-
import os from 'os';
|
|
23
|
-
|
|
24
|
-
// ─── stdin 읽기 ─────────────────────────────────────────────────────
|
|
25
|
-
|
|
26
|
-
function readStdinSync() {
|
|
27
|
-
try {
|
|
28
|
-
if (process.stdin.isTTY) return null;
|
|
29
|
-
// fd 0을 직접 사용 (Windows는 '/dev/stdin'이 없음)
|
|
30
|
-
const buf = Buffer.alloc(1024 * 1024); // 1MB
|
|
31
|
-
const bytesRead = fs.readSync(0, buf, 0, buf.length, null);
|
|
32
|
-
if (bytesRead > 0) {
|
|
33
|
-
return JSON.parse(buf.toString('utf-8', 0, bytesRead));
|
|
34
|
-
}
|
|
35
|
-
} catch { /* fallback */ }
|
|
36
|
-
return null;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// ─── 검사 1: /tmp/{feature}/ 자체 작성 스크립트 ─────────────────────
|
|
40
|
-
|
|
41
|
-
const FORBIDDEN_TMP_SCRIPT_PATTERNS = [
|
|
42
|
-
/\/tmp\/[^/]+\/refine[\w-]*\.(mjs|js)$/i,
|
|
43
|
-
/\/tmp\/[^/]+\/.*sections.*\.(mjs|js)$/i,
|
|
44
|
-
/\/tmp\/[^/]+\/.*to-scss.*\.(mjs|js)$/i,
|
|
45
|
-
/\/tmp\/[^/]+\/.*generate-scss.*\.(mjs|js)$/i,
|
|
46
|
-
/\/tmp\/[^/]+\/analyze-tree\.(mjs|js)$/i,
|
|
47
|
-
/\/tmp\/[^/]+\/analyze-section\.(mjs|js)$/i,
|
|
48
|
-
];
|
|
49
|
-
|
|
50
|
-
function checkForbiddenTmpScript(filePath) {
|
|
51
|
-
if (!filePath) return null;
|
|
52
|
-
for (const pattern of FORBIDDEN_TMP_SCRIPT_PATTERNS) {
|
|
53
|
-
if (pattern.test(filePath)) {
|
|
54
|
-
return {
|
|
55
|
-
block: true,
|
|
56
|
-
reason: `자체 작성 figma 스크립트 금지: ${path.basename(filePath)}`,
|
|
57
|
-
suggestion: 'figma-refine.js / figma-to-scss.js / figma-validate.js 사용. ' +
|
|
58
|
-
'결과가 마음에 안 들면 ~/.vibe/hooks/scripts/figma-*.js 자체를 수정하세요.'
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
return null;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// ─── 검사 2: SCSS 직접 작성 ─────────────────────────────────────────
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Figma 작업 컨텍스트인지 판단:
|
|
69
|
-
* - 현재 작업 디렉토리 또는 file_path에 figma 관련 흔적이 있어야 함
|
|
70
|
-
* - /tmp/ 하위에 sections.json이 존재 → 활성 figma 작업으로 판단
|
|
71
|
-
*/
|
|
72
|
-
function isFigmaContext() {
|
|
73
|
-
try {
|
|
74
|
-
const tmpDirs = fs.readdirSync('/tmp', { withFileTypes: true });
|
|
75
|
-
for (const entry of tmpDirs) {
|
|
76
|
-
if (!entry.isDirectory()) continue;
|
|
77
|
-
const moSections = path.join('/tmp', entry.name, 'mo-main', 'sections.json');
|
|
78
|
-
const pcSections = path.join('/tmp', entry.name, 'pc-main', 'sections.json');
|
|
79
|
-
if (fs.existsSync(moSections) || fs.existsSync(pcSections)) {
|
|
80
|
-
return { active: true, feature: entry.name };
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
} catch { /* ignore */ }
|
|
84
|
-
return { active: false };
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* SCSS 파일 작성 시도 검사
|
|
89
|
-
*/
|
|
90
|
-
function checkScssWrite(filePath, content) {
|
|
91
|
-
if (!filePath) return null;
|
|
92
|
-
if (!filePath.endsWith('.scss')) return null;
|
|
93
|
-
|
|
94
|
-
// figma 컨텍스트가 아니면 통과
|
|
95
|
-
const ctx = isFigmaContext();
|
|
96
|
-
if (!ctx.active) return null;
|
|
97
|
-
|
|
98
|
-
// 자동 생성 표시 코멘트 있으면 통과
|
|
99
|
-
if (typeof content === 'string' && content.includes('Auto-generated from sections.json')) {
|
|
100
|
-
return null;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// 빈 파일 또는 @import만 있는 경우 통과
|
|
104
|
-
if (typeof content === 'string') {
|
|
105
|
-
const meaningfulLines = content
|
|
106
|
-
.split('\n')
|
|
107
|
-
.map(l => l.trim())
|
|
108
|
-
.filter(l => l && !l.startsWith('//') && !l.startsWith('/*'));
|
|
109
|
-
const hasOnlyImports = meaningfulLines.every(l =>
|
|
110
|
-
l.startsWith('@import') || l.startsWith('@use') || l.startsWith('@forward')
|
|
111
|
-
);
|
|
112
|
-
if (hasOnlyImports) return null;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
return {
|
|
116
|
-
block: true,
|
|
117
|
-
reason: `SCSS 직접 작성 금지: ${filePath}`,
|
|
118
|
-
suggestion: `figma-to-scss.js로 생성하세요:\n` +
|
|
119
|
-
` node ~/.vibe/hooks/scripts/figma-to-scss.js \\\n` +
|
|
120
|
-
` /tmp/${ctx.feature}/{bp}-main/sections.json \\\n` +
|
|
121
|
-
` --out=$(dirname ${filePath})`
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// ─── 검사 3: Vue/React <style> 블록에 CSS 값 작성 ───────────────────
|
|
126
|
-
|
|
127
|
-
function checkVueStyleBlock(filePath, content) {
|
|
128
|
-
if (!filePath) return null;
|
|
129
|
-
if (!/\.(vue|jsx|tsx)$/.test(filePath)) return null;
|
|
130
|
-
|
|
131
|
-
const ctx = isFigmaContext();
|
|
132
|
-
if (!ctx.active) return null;
|
|
133
|
-
|
|
134
|
-
// 파일 경로에 feature 이름이 있는지 확인
|
|
135
|
-
if (!filePath.includes(ctx.feature)) return null;
|
|
136
|
-
|
|
137
|
-
if (typeof content !== 'string') return null;
|
|
138
|
-
|
|
139
|
-
// <style ...> ... </style> 블록 추출
|
|
140
|
-
const styleBlocks = content.match(/<style[^>]*>([\s\S]*?)<\/style>/g);
|
|
141
|
-
if (!styleBlocks || styleBlocks.length === 0) return null;
|
|
142
|
-
|
|
143
|
-
for (const block of styleBlocks) {
|
|
144
|
-
const inner = block.replace(/<style[^>]*>/, '').replace(/<\/style>/, '');
|
|
145
|
-
const meaningfulLines = inner
|
|
146
|
-
.split('\n')
|
|
147
|
-
.map(l => l.trim())
|
|
148
|
-
.filter(l => l && !l.startsWith('//') && !l.startsWith('/*'));
|
|
149
|
-
|
|
150
|
-
// @import / @use 만 있으면 통과
|
|
151
|
-
const hasOnlyImports = meaningfulLines.every(l =>
|
|
152
|
-
l.startsWith('@import') || l.startsWith('@use') || l.startsWith('@forward')
|
|
153
|
-
);
|
|
154
|
-
if (hasOnlyImports) continue;
|
|
155
|
-
|
|
156
|
-
// CSS 값으로 보이는 라인 검출 (px, rem, color, flex 등)
|
|
157
|
-
const hasCssValue = meaningfulLines.some(l =>
|
|
158
|
-
/:\s*[^;]*(?:px|rem|em|%|vh|vw|#[0-9a-fA-F]|rgba?\(|flex|grid|absolute|relative|inherit)/.test(l)
|
|
159
|
-
);
|
|
160
|
-
if (hasCssValue) {
|
|
161
|
-
return {
|
|
162
|
-
block: true,
|
|
163
|
-
reason: `Vue/React <style> 블록에 CSS 직접 작성 금지: ${path.basename(filePath)}`,
|
|
164
|
-
suggestion: `<style> 블록은 @import만 허용:\n` +
|
|
165
|
-
` <style lang="scss" scoped>\n` +
|
|
166
|
-
` @import '~/assets/scss/${ctx.feature}/index.scss';\n` +
|
|
167
|
-
` </style>`
|
|
168
|
-
};
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
return null;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
// ─── 메인 ───────────────────────────────────────────────────────────
|
|
176
|
-
|
|
177
|
-
const stdinPayload = readStdinSync();
|
|
178
|
-
if (!stdinPayload) {
|
|
179
|
-
process.exit(0);
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
const toolName = stdinPayload.tool_name || '';
|
|
183
|
-
const toolInput = stdinPayload.tool_input || {};
|
|
184
|
-
|
|
185
|
-
// Write 또는 Edit만 검사
|
|
186
|
-
if (toolName !== 'Write' && toolName !== 'Edit') {
|
|
187
|
-
process.exit(0);
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
const filePath = toolInput.file_path || '';
|
|
191
|
-
const content = toolInput.content || toolInput.new_string || '';
|
|
192
|
-
|
|
193
|
-
// 3단계 검사
|
|
194
|
-
const checks = [
|
|
195
|
-
checkForbiddenTmpScript(filePath),
|
|
196
|
-
checkScssWrite(filePath, content),
|
|
197
|
-
checkVueStyleBlock(filePath, content),
|
|
198
|
-
];
|
|
199
|
-
|
|
200
|
-
const violations = checks.filter(c => c !== null);
|
|
201
|
-
|
|
202
|
-
if (violations.length === 0) {
|
|
203
|
-
process.exit(0);
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
// 차단
|
|
207
|
-
const messages = ['🚫 FIGMA GUARD: 스킬 규칙 위반'];
|
|
208
|
-
for (const v of violations) {
|
|
209
|
-
messages.push('');
|
|
210
|
-
messages.push(` ${v.reason}`);
|
|
211
|
-
messages.push(` 💡 ${v.suggestion}`);
|
|
212
|
-
}
|
|
213
|
-
messages.push('');
|
|
214
|
-
messages.push('⛔ vibe.figma 작업 중에는 스크립트 파이프라인을 우회하지 마세요.');
|
|
215
|
-
messages.push(' ~/.vibe/hooks/scripts/figma-{refine,to-scss,validate}.js만 사용.');
|
|
216
|
-
|
|
217
|
-
// PreToolUse hook은 stderr 출력 + exit 2로 차단
|
|
218
|
-
console.error(messages.join('\n'));
|
|
219
|
-
process.exit(2);
|