@su-record/vibe 3.2.59 → 3.2.61

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 (69) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/.codex-plugin/plugin.json +1 -1
  3. package/CLAUDE.md +7 -3
  4. package/README.en.md +1 -1
  5. package/README.md +1 -1
  6. package/dist/cli/commands/codex-proxy.d.ts.map +1 -1
  7. package/dist/cli/commands/codex-proxy.js +8 -7
  8. package/dist/cli/commands/codex-proxy.js.map +1 -1
  9. package/dist/cli/commands/config.d.ts.map +1 -1
  10. package/dist/cli/commands/config.js +19 -18
  11. package/dist/cli/commands/config.js.map +1 -1
  12. package/dist/cli/commands/evolution.d.ts.map +1 -1
  13. package/dist/cli/commands/evolution.js +35 -34
  14. package/dist/cli/commands/evolution.js.map +1 -1
  15. package/dist/cli/commands/figma.d.ts.map +1 -1
  16. package/dist/cli/commands/figma.js +21 -20
  17. package/dist/cli/commands/figma.js.map +1 -1
  18. package/dist/cli/commands/info.js +4 -4
  19. package/dist/cli/commands/info.js.map +1 -1
  20. package/dist/cli/commands/llm.d.ts.map +1 -1
  21. package/dist/cli/commands/llm.js +11 -10
  22. package/dist/cli/commands/llm.js.map +1 -1
  23. package/dist/cli/commands/remove.js +13 -13
  24. package/dist/cli/commands/remove.js.map +1 -1
  25. package/dist/cli/commands/sentinel.d.ts +10 -1
  26. package/dist/cli/commands/sentinel.d.ts.map +1 -1
  27. package/dist/cli/commands/sentinel.js +51 -49
  28. package/dist/cli/commands/sentinel.js.map +1 -1
  29. package/dist/cli/commands/skills.js +3 -3
  30. package/dist/cli/commands/skills.js.map +1 -1
  31. package/dist/cli/commands/slack.d.ts.map +1 -1
  32. package/dist/cli/commands/slack.js +16 -15
  33. package/dist/cli/commands/slack.js.map +1 -1
  34. package/dist/cli/commands/stats.d.ts.map +1 -1
  35. package/dist/cli/commands/stats.js +30 -29
  36. package/dist/cli/commands/stats.js.map +1 -1
  37. package/dist/cli/commands/telegram.d.ts.map +1 -1
  38. package/dist/cli/commands/telegram.js +26 -25
  39. package/dist/cli/commands/telegram.js.map +1 -1
  40. package/dist/cli/commands/upgrade.d.ts.map +1 -1
  41. package/dist/cli/commands/upgrade.js +18 -3
  42. package/dist/cli/commands/upgrade.js.map +1 -1
  43. package/dist/cli/postinstall/main.d.ts +11 -0
  44. package/dist/cli/postinstall/main.d.ts.map +1 -1
  45. package/dist/cli/postinstall/main.js +29 -0
  46. package/dist/cli/postinstall/main.js.map +1 -1
  47. package/dist/cli/setup/CodexHooks.d.ts +16 -0
  48. package/dist/cli/setup/CodexHooks.d.ts.map +1 -1
  49. package/dist/cli/setup/CodexHooks.js +21 -0
  50. package/dist/cli/setup/CodexHooks.js.map +1 -1
  51. package/dist/cli/setup.d.ts +1 -1
  52. package/dist/cli/setup.d.ts.map +1 -1
  53. package/dist/cli/setup.js +1 -1
  54. package/dist/cli/setup.js.map +1 -1
  55. package/dist/infra/lib/browser/launch.d.ts.map +1 -1
  56. package/dist/infra/lib/browser/launch.js +0 -1
  57. package/dist/infra/lib/browser/launch.js.map +1 -1
  58. package/dist/tools/memory/getMemoryGraph.d.ts.map +1 -1
  59. package/dist/tools/memory/getMemoryGraph.js.map +1 -1
  60. package/dist/tools/spec/specGenerator.js +3 -5
  61. package/dist/tools/spec/specGenerator.js.map +1 -1
  62. package/hooks/scripts/figma-extract.js +6 -2
  63. package/hooks/scripts/figma-to-scss.js +10 -3
  64. package/hooks/scripts/llm-orchestrate.js +2 -2
  65. package/hooks/scripts/session-start.js +30 -23
  66. package/hooks/scripts/utils.js +4 -5
  67. package/package.json +14 -8
  68. package/skills/vibe.spec/SKILL.md +37 -3
  69. package/vibe/templates/spec-template.md +15 -0
@@ -96,19 +96,11 @@ async function main() {
96
96
  getLatestVersionCached(),
97
97
  ]);
98
98
 
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.continue`);
108
- }
109
- } catch { /* progress index is best-effort */ }
110
-
111
- console.log('\n[Memory Index — bodies on demand via recall_memory]');
99
+ // ─── 안정 블록 먼저 ────────────────────────────────────────────────
100
+ // 세션마다 값이 달라지는 것(현재 시각·진행 카운터·버전 체크)은 아래 휘발 블록으로
101
+ // 모아 뒤에 붙인다. 세션 컨텍스트의 앞부분을 가능한 한 세션 간 동일하게 유지하려는
102
+ // 배치다 — 휘발 데이터를 앞에 두면 어떤 합성 방식에서도 이득이 없다.
103
+ console.log('[Memory Index — bodies on demand via recall_memory]');
112
104
  console.log(memories.content[0].text);
113
105
 
114
106
  // Phase 3 — Recipes + anti-patterns 인덱스 (post-task curation)
@@ -130,15 +122,6 @@ async function main() {
130
122
  }
131
123
  } catch { /* curation is best-effort */ }
132
124
 
133
- // Version check
134
- if (latestVersion) {
135
- const currentVersion = getCurrentVersion();
136
- if (currentVersion && compareVersions(latestVersion, currentVersion) > 0) {
137
- console.log(`\n⬆️ Harness update available: v${currentVersion} → v${latestVersion}`);
138
- console.log(' Run: vibe upgrade');
139
- }
140
- }
141
-
142
125
  // Scope sync — 기본 OFF (opt-in: scopeGuard.enabled=true). SSOT: scope-from-spec.js.
143
126
  try {
144
127
  const { syncScopeFile, isScopeGuardEnabled } = await import('./lib/scope-from-spec.js');
@@ -214,8 +197,32 @@ async function main() {
214
197
 
215
198
  // Evolution 상태 요약은 제거 — evolution 은 동결(opt-in) 상태이며
216
199
  // 사용자는 `vibe evolution` CLI 로 명시적으로 조회한다 (P3-3).
200
+
201
+ // ─── 휘발 블록 마지막 ──────────────────────────────────────────────
202
+ // 현재 시각·진행 카운터·버전 체크는 세션마다 값이 달라진다. 위의 안정 블록을
203
+ // 앞에 두기 위해 여기로 모았다. 내용은 이전과 동일하고 순서만 바뀐다.
204
+ console.log(`\n${time.content[0].text}`);
205
+
206
+ try {
207
+ const LIB_BASE_P = (await import('./utils.js')).getLibBaseUrl();
208
+ const iterMod = await import(`${LIB_BASE_P}IterationTracker.js`);
209
+ const progressLine = iterMod.getProgressSummary(PROJECT_DIR);
210
+ if (progressLine) {
211
+ console.log(`📋 ${progressLine} — resume full context: /vibe.continue`);
212
+ }
213
+ } catch { /* progress index is best-effort */ }
214
+
215
+ if (latestVersion) {
216
+ const currentVersion = getCurrentVersion();
217
+ if (currentVersion && compareVersions(latestVersion, currentVersion) > 0) {
218
+ console.log(`\n⬆️ Harness update available: v${currentVersion} → v${latestVersion}`);
219
+ console.log(' Run: vibe upgrade');
220
+ }
221
+ }
217
222
  } catch (e) {
218
- console.log('[Session] Error:', e.message);
223
+ // 훅 실패를 stdout 으로 보내면 "실패 신호" 가 아니라 모델에게 주입되는
224
+ // 컨텍스트 문자열이 된다 — 가드의 생사가 관측 불가능해진다.
225
+ console.error('[Session] Error:', e.message);
219
226
  }
220
227
  }
221
228
 
@@ -372,12 +372,11 @@ const DEFAULT_COST = { input: 0.003, output: 0.010 };
372
372
  *
373
373
  * @param {string} provider - 프로바이더 (gpt, antigravity)
374
374
  * @param {string} model - 모델명
375
- * @param {number} inputLen - 입력 문자 수
376
- * @param {number} outputLen - 출력 문자 수
377
- * @param {number} durationMs - 호출 소요 시간
378
- * @param {boolean} cached - 캐시 히트 여부
375
+ * @param {{ inputLen: number, outputLen: number, durationMs: number, cached: boolean }} call
376
+ * inputLen/outputLen 은 문자 수, durationMs 는 호출 소요 시간, cached 는 캐시 히트 여부
379
377
  */
380
- export function logLlmCost(provider, model, inputLen, outputLen, durationMs, cached) {
378
+ export function logLlmCost(provider, model, call) {
379
+ const { inputLen, outputLen, durationMs, cached } = call;
381
380
  try {
382
381
  if (fs.existsSync(LLM_COST_PATH)) {
383
382
  const stat = fs.statSync(LLM_COST_PATH);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@su-record/vibe",
3
- "version": "3.2.59",
3
+ "version": "3.2.61",
4
4
  "description": "AI Coding Framework for Claude Code — 7+ agents, 52 skills, multi-LLM orchestration",
5
5
  "type": "module",
6
6
  "main": "dist/cli/index.js",
@@ -23,12 +23,15 @@
23
23
  "scripts": {
24
24
  "build": "tsc -p tsconfig.build.json && chmod +x dist/cli/index.js",
25
25
  "dev": "tsc --watch",
26
- "gen:skill-docs": "npx tsx scripts/gen-skill-docs.ts",
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
- "validate:skill-invocation": "npx tsx scripts/validate-skill-invocation.ts",
31
- "validate:counts": "npx tsx scripts/validate-counts.ts",
26
+ "gen:skill-docs": "tsx scripts/gen-skill-docs.ts",
27
+ "gen:skill-docs:check": "tsx scripts/gen-skill-docs.ts --check",
28
+ "sync:agent-models": "tsx scripts/sync-agent-models.ts",
29
+ "sync:agent-models:check": "tsx scripts/sync-agent-models.ts --check",
30
+ "validate:skill-invocation": "tsx scripts/validate-skill-invocation.ts",
31
+ "validate:counts": "tsx scripts/validate-counts.ts",
32
+ "lint": "oxlint",
33
+ "lint:ratchet": "tsx scripts/lint-ratchet.ts",
34
+ "verify:all": "pnpm lint && pnpm lint:ratchet && pnpm gen:skill-docs:check && pnpm sync:agent-models:check && pnpm validate:skill-invocation && pnpm validate:counts",
32
35
  "test": "vitest run",
33
36
  "test:watch": "vitest",
34
37
  "test:coverage": "vitest run --coverage",
@@ -100,6 +103,8 @@
100
103
  "ajv": "^8.17.1",
101
104
  "jsdom": "^25.0.1",
102
105
  "mermaid": "^11.17.2",
106
+ "oxlint": "^1.76.0",
107
+ "tsx": "^4.23.5",
103
108
  "typescript": "^5.9.3",
104
109
  "vitest": "^4.1.10"
105
110
  },
@@ -121,7 +126,8 @@
121
126
  ],
122
127
  "pnpm": {
123
128
  "onlyBuiltDependencies": [
124
- "better-sqlite3"
129
+ "better-sqlite3",
130
+ "esbuild"
125
131
  ]
126
132
  }
127
133
  }
@@ -182,16 +182,30 @@ relevant files, and patterns in under 200 tokens.
182
182
  "이 요구사항으로 SPEC 을 쓸 때 결정이 필요한 지점" 을 **개수 제한 없이** 열거한다. 각 항목에 제안 기본값을 붙인다:
183
183
 
184
184
  ```
185
- {결정 지점} → {제안 기본값} → {갈라짐: Done Criteria 가 실제로 달라지는가 yes/no}
185
+ {결정 지점} → {제안 기본값} → {갈라짐: Done Criteria 가 실제로 달라지는가 yes/no} → {되돌림: 싸다 | 비싸다 | 못 되돌린다}
186
186
  ```
187
187
 
188
- 훑을 축(최소): 범위 경계 · 데이터 모델의 필수 필드 · 외부 연동 여부 · 인증/권한 · 오류 처리 방침 · 수치 파라미터(타임아웃·크기·재시도) · 하위 호환 · 기존 테스트/계약 영향 · 산출물 위치 · 언어·표기 규약.
188
+ 훑을 축(최소): 범위 경계 · 데이터 모델의 필수 필드 · 외부 연동 여부 · 인증/권한 · 오류 처리 방침 · 수치 파라미터(타임아웃·크기·재시도) · 하위 호환 · 기존 테스트/계약 영향 · 산출물 위치 · 언어·표기 규약 · **데이터 보존과 마이그레이션 경로** · **실패했을 때 사용자에게 보이는 것** · **부하가 늘면 먼저 깨지는 곳**.
189
+
190
+ 뒤의 세 축은 운영 축이다. 앞의 열 축은 "무엇을 만드는가" 를 훑지만, 만든 것이 오래 돌 때 비싼 값을 치르게 하는 결정은 대부분 이 셋에서 나온다. 3-a 는 내부 단계라 축을 늘려도 사용자가 답할 것은 늘지 않는다.
191
+
192
+ **되돌림 등급**은 "이 결정을 나중에 뒤집을 때 무엇을 치르는가" 로 판정한다. 결정 지점이 안 보이는 이유는 지식이 없어서가 아니라 **어느 결정이 비싼지 구분할 수단이 없어서**다 — 버튼 색과 저장 스키마가 같은 무게로 보인다. 등급이 그 구분을 대신한다.
193
+
194
+ | 등급 | 뜻 | 예 |
195
+ |---|---|---|
196
+ | 싸다 | 코드만 고치면 된다 | 타임아웃 값, 페이지 크기, 문구 |
197
+ | 비싸다 | 고치려면 여러 곳을 함께 바꿔야 한다 | 모듈 경계, 공개 API 형태 |
198
+ | 못 되돌린다 | 이미 쌓인 데이터·외부 계약이 남아 마이그레이션이 필요하다 | 저장 스키마, 식별자 체계, 과금 단위 |
199
+
200
+ 판정이 애매하면 **위로 올린다** — 싼 것을 비싸게 잘못 본 비용은 질문 1개고, 반대는 마이그레이션이다.
189
201
 
190
202
  이 목록 자체는 출력하지 않는다. 출력 대상은 3-b 의 질문과 최종 SPEC 의 Assumptions 뿐이다.
191
203
 
192
204
  #### 3-b. 답변 요청 (사용자에게 출력)
193
205
 
194
- 3-a 결과에서 `갈라짐: yes` 인 항목만 남기고, 그중 **최대 3개**만 묻는다. 3개를 넘으면 영향 범위가 큰 순으로 3개를 고르고 나머지는 기본값을 채택한다.
206
+ 3-a 결과에서 `갈라짐: yes` 인 항목만 남기고, 그중 **최대 3개**만 묻는다. 3개를 넘으면 **되돌림 등급이 높은 순**(`못 되돌린다` > `비싸다` > `싸다`)으로 고르고, 같은 등급 안에서는 영향 범위가 큰 순으로 고른다. 나머지는 기본값을 채택한다.
207
+
208
+ > 상한을 늘리지 않고 **순서만** 바꾼다. 사용자에게 주어진 3번의 답변 기회를 되돌리기 가장 비싼 결정에 먼저 쓰는 것이 목적이다 — 되돌릴 수 있는 결정은 틀려도 나중에 고치면 된다.
195
209
 
196
210
  - 질문은 **한 번에 묶어서** (번호 목록), 각 질문에 제안 기본값을 붙인다.
197
211
  - **3-b 로 묻지 않은 3-a 항목은 전부** SPEC 의 Assumptions 섹션에 기록한다. 누락 0건 — Step 5 체크리스트가 이를 점검한다.
@@ -214,6 +228,7 @@ relevant files, and patterns in under 200 tokens.
214
228
  - **Scenarios** — Given-When-Then. Happy path + 주요 edge case. 각 시나리오는 Done Criteria 중 하나에 매핑.
215
229
  - **Out of Scope** — 이번에 하지 않는 것을 명시 (비어 있으면 스코프 팽창 신호).
216
230
  - **Assumptions** — 3단계에서 채택한 기본값 전부.
231
+ - **되돌리기 어려운 결정** (해당 시에만) — 3-a 에서 `되돌림: 못 되돌린다` 로 판정한 항목. 각 줄은 `{무엇을 정했는가} → {나중에 뒤집으면 치를 비용}` 평문 1줄. Assumptions 안의 하위 목록이 아니라 **별도 섹션**으로 둔다 — 하류가 헤딩으로 찾을 수 있어야 한다. 해당 항목이 0건이면 섹션을 통째로 지운다.
217
232
  - **Constraints** — 구현·보안·호환성 경계. execution packet으로 압축돼도 반드시 보존한다.
218
233
  - **Rejected Alternatives (Traps)** — 검토했으나 기각한 설계 접근 + **기계적 기각 사유** 1줄씩 ("확장 안 됨" 같은 라벨이 아니라 "shelve 는 multi-writer 에서 thread-safe 하지 않다" 수준). 루프가 같은 막다른 길을 재방문하지 않기 위한 섹션 — Constraints 처럼 execution packet 압축에도 보존한다. 실질적 설계 선택지가 없었거나 demo/prototype 이면 생략.
219
234
  - **API Contract** (해당 시에만) — 엔드포인트/요청/응답 형태. 이 섹션이 있으면 이후 `/vibe.contract` 가 drift 를 검사한다.
@@ -236,6 +251,7 @@ relevant files, and patterns in under 200 tokens.
236
251
  - [ ] Out of Scope 가 비어 있지 않은가
237
252
  - [ ] 요구사항에 있던 것 중 SPEC 에서 빠진 것이 없는가
238
253
  - [ ] 3-a 커버리지 스윕에서 나온 결정 지점이 **전부** 3-b 질문 또는 Assumptions 중 하나로 귀결됐는가 (누락 0건)
254
+ - [ ] 3-a 의 모든 항목에 되돌림 등급이 붙었고, `못 되돌린다` 항목이 SPEC 의 `되돌리기 어려운 결정` 섹션과 승인 메시지에 **둘 다** 반영됐는가 (0건이면 섹션·블록 모두 없어야 통과)
239
255
  - [ ] 설계 선택지가 있었던 결정에 기각 대안이 Rejected Alternatives (Traps) 로 남았는가 — 기계적 사유 포함 (production 만; 선택지가 없었으면 통과)
240
256
  - [ ] 헤더에 `Stakes:` 필드가 있고, demo/prototype 인데 SPEC 이 분할·대형화되지 않았는가
241
257
 
@@ -252,6 +268,7 @@ SPEC 요약(Goal, Done Criteria, 시나리오 수, Out of Scope, 열린 Assumpti
252
268
  Done Criteria: {N}개 (전부 결정론 게이트)
253
269
  Scenarios: {M}개 · Out of Scope: {K}항목
254
270
  Assumptions: {3개 이하면 전부 · 초과면 핵심 3개 + "그 외 N건은 SPEC 참조"}
271
+ {되돌림 노출 블록 — 아래 규칙 참조. 해당 없으면 이 줄을 통째로 없앤다}
255
272
 
256
273
  승인하면 이 SPEC 이 루프의 Done 정의가 됩니다.
257
274
  [1] 승인 → 이 세션에서 계속 [2] 승인 → 새 세션에서 run{권장 표시}
@@ -261,6 +278,23 @@ SPEC 요약(Goal, Done Criteria, 시나리오 수, Out of Scope, 열린 Assumpti
261
278
  - 수정 요청 → 반영 후 재제시 (사용자 주도 반복 — 자동 루프 아님).
262
279
  - `automationLevel: autonomous` → 승인 생략, 요약만 출력하고 `[1]` 로 진행 (세션 경계 권고 없음 — 비대화형이라 리셋 불가).
263
280
 
281
+ #### 되돌림 노출 블록
282
+
283
+ 승인 직전은 되돌릴 수 없는 결정이 아직 공짜인 마지막 지점이다. 그 지점에서 "SPEC 하단 Assumptions 를 읽으라" 고 하는 것은 읽지 않는 쪽에 걸고 있는 것과 같다 — 그래서 승인 메시지로 끌어올린다.
284
+
285
+ - **노출 게이트는 `못 되돌린다` 하나뿐이다.** `비싸다` 는 3-b 정렬에만 쓰고 노출하지 않는다.
286
+ - **0건이면 블록을 통째로 생략한다.** 빈 블록도, "없음" 표기도 출력하지 않는다.
287
+ - 최대 3줄. 초과분은 `그 외 N건은 SPEC 참조` 로 접는다 (Assumptions 접기와 같은 임계 — 서로 다른 두 상한이 공존하지 않게).
288
+ - 각 줄은 전문용어 없는 평문 1줄. 읽는 사람이 기술 배경이 없다는 전제로 쓴다.
289
+ - `automationLevel: autonomous` 에서는 승인 메시지 자체가 없으므로 노출도 없다. 등급 판정과 SPEC 섹션 기록은 그대로 한다.
290
+
291
+ ```
292
+ ⚠️ 나중에 바꾸기 비싼 결정 ({N}건 — 지금 정하면 나중엔 데이터 마이그레이션이 필요합니다):
293
+ · {무엇을 정했는가} → {나중에 뒤집으면 치를 비용}
294
+ ```
295
+
296
+ 왜 게이트를 좁게 잡는가: 넓히면 거의 모든 SPEC 에서 블록이 뜨고, 매번 뜨는 경고는 읽히지 않는다. 위 Structure 절이 조건부인 것과 같은 이유다 — **해당 없는 SPEC 에서 침묵하지 않으면 통과 의식이 된다.** 자체 점검: 버그 수정 SPEC 에서 이 블록이 뜨면 등급 판정이 과하게 잡힌 것이다.
297
+
264
298
  #### 세션 경계 선택지 (`[2]`)
265
299
 
266
300
  승인 게이트에 **편승하는 선택지**다. 별도 프롬프트를 만들지 않는다 — loop-contract 의 "의무적 사람 개입은 SPEC 승인 1회" 불변식을 지킨다.
@@ -34,6 +34,21 @@
34
34
 
35
35
  - {Default adopted without asking — e.g., session expiry 24h}
36
36
 
37
+ ### 되돌리기 어려운 결정
38
+
39
+ > 3-a 커버리지 스윕에서 `되돌림: 못 되돌린다` 로 판정한 항목만 적는다. **해당 항목이
40
+ > 없으면 이 절을 통째로 지운다** — 해당 없는데 남겨두면 통과 의식이 된다 (Structure
41
+ > 절과 같은 조건부 규약).
42
+ >
43
+ > 여기 오는 것은 이미 쌓인 데이터나 외부 계약 때문에 코드만 고쳐서는 못 되돌리는
44
+ > 결정이다: 저장 스키마, 식별자 체계, 과금 단위 등. 각 줄은 전문용어 없이
45
+ > `{무엇을 정했는가} → {나중에 뒤집으면 치를 비용}` 한 줄로 쓴다.
46
+ >
47
+ > 이 절의 내용은 `vibe.spec` Step 6 승인 메시지에도 최대 3줄로 노출된다 — SPEC 을
48
+ > 열어보지 않는 사람에게 승인 직전에 한 번은 보이게 하기 위해서다.
49
+
50
+ - {무엇을 정했는가} → {나중에 뒤집으면 치를 비용}
51
+
37
52
  ### Constraints
38
53
 
39
54
  - {Invariant or implementation boundary that every execution packet must preserve}