@su-record/vibe 2.7.16 → 2.7.18

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 (249) hide show
  1. package/.env.example +37 -37
  2. package/CLAUDE.md +153 -134
  3. package/LICENSE +21 -21
  4. package/README.md +449 -449
  5. package/agents/architect-low.md +41 -41
  6. package/agents/architect-medium.md +59 -59
  7. package/agents/architect.md +80 -80
  8. package/agents/build-error-resolver.md +115 -115
  9. package/agents/compounder.md +261 -261
  10. package/agents/diagrammer.md +178 -178
  11. package/agents/docs/api-documenter.md +99 -99
  12. package/agents/docs/changelog-writer.md +93 -93
  13. package/agents/e2e-tester.md +294 -294
  14. package/agents/explorer-low.md +42 -42
  15. package/agents/explorer-medium.md +59 -59
  16. package/agents/explorer.md +48 -48
  17. package/agents/implementer-low.md +43 -43
  18. package/agents/implementer-medium.md +52 -52
  19. package/agents/implementer.md +54 -54
  20. package/agents/junior-mentor.md +141 -141
  21. package/agents/planning/requirements-analyst.md +84 -84
  22. package/agents/planning/ux-advisor.md +83 -83
  23. package/agents/qa/acceptance-tester.md +86 -86
  24. package/agents/qa/edge-case-finder.md +93 -93
  25. package/agents/refactor-cleaner.md +143 -143
  26. package/agents/research/best-practices-agent.md +199 -199
  27. package/agents/research/codebase-patterns-agent.md +157 -157
  28. package/agents/research/framework-docs-agent.md +188 -188
  29. package/agents/research/security-advisory-agent.md +213 -213
  30. package/agents/review/architecture-reviewer.md +107 -107
  31. package/agents/review/complexity-reviewer.md +116 -116
  32. package/agents/review/data-integrity-reviewer.md +88 -88
  33. package/agents/review/git-history-reviewer.md +103 -103
  34. package/agents/review/performance-reviewer.md +86 -86
  35. package/agents/review/python-reviewer.md +150 -150
  36. package/agents/review/rails-reviewer.md +139 -139
  37. package/agents/review/react-reviewer.md +144 -144
  38. package/agents/review/security-reviewer.md +80 -80
  39. package/agents/review/simplicity-reviewer.md +140 -140
  40. package/agents/review/test-coverage-reviewer.md +116 -116
  41. package/agents/review/typescript-reviewer.md +127 -127
  42. package/agents/searcher.md +54 -54
  43. package/agents/simplifier.md +120 -120
  44. package/agents/tester.md +49 -49
  45. package/agents/ui/ui-a11y-auditor.md +93 -93
  46. package/agents/ui/ui-antipattern-detector.md +94 -94
  47. package/agents/ui/ui-dataviz-advisor.md +69 -69
  48. package/agents/ui/ui-design-system-gen.md +57 -57
  49. package/agents/ui/ui-industry-analyzer.md +49 -49
  50. package/agents/ui/ui-layout-architect.md +65 -65
  51. package/agents/ui/ui-stack-implementer.md +68 -68
  52. package/agents/ui/ux-compliance-reviewer.md +81 -81
  53. package/agents/ui-previewer.md +258 -258
  54. package/commands/vibe.analyze.md +379 -379
  55. package/commands/vibe.review.md +607 -607
  56. package/commands/vibe.run.md +2124 -2124
  57. package/commands/vibe.spec.md +1195 -1195
  58. package/commands/vibe.spec.review.md +569 -569
  59. package/commands/vibe.utils.md +413 -413
  60. package/commands/vibe.verify.md +484 -484
  61. package/dist/cli/collaborator.js +52 -52
  62. package/dist/cli/commands/evolution.js +12 -12
  63. package/dist/cli/commands/info.js +51 -51
  64. package/dist/cli/commands/init.js +5 -5
  65. package/dist/cli/commands/remove.js +14 -14
  66. package/dist/cli/commands/sentinel.js +27 -27
  67. package/dist/cli/commands/skills.js +5 -5
  68. package/dist/cli/commands/slack.js +10 -10
  69. package/dist/cli/commands/telegram.js +12 -12
  70. package/dist/cli/commands/upgrade.d.ts +3 -3
  71. package/dist/cli/commands/upgrade.d.ts.map +1 -1
  72. package/dist/cli/commands/upgrade.js +24 -3
  73. package/dist/cli/commands/upgrade.js.map +1 -1
  74. package/dist/cli/detect.js +32 -32
  75. package/dist/cli/index.js +51 -51
  76. package/dist/cli/llm/claude-commands.js +16 -16
  77. package/dist/cli/llm/config.js +18 -18
  78. package/dist/cli/llm/gemini-commands.js +16 -16
  79. package/dist/cli/llm/gpt-commands.js +19 -19
  80. package/dist/cli/llm/help.js +21 -21
  81. package/dist/cli/postinstall/cursor-agents.js +32 -32
  82. package/dist/cli/postinstall/cursor-rules.js +83 -83
  83. package/dist/cli/postinstall/cursor-skills.js +743 -743
  84. package/dist/cli/setup/Provisioner.js +42 -42
  85. package/dist/infra/lib/DeepInit.js +24 -24
  86. package/dist/infra/lib/IterationTracker.js +11 -11
  87. package/dist/infra/lib/PythonParser.js +108 -108
  88. package/dist/infra/lib/ReviewRace.js +96 -96
  89. package/dist/infra/lib/SkillFrontmatter.js +28 -28
  90. package/dist/infra/lib/SkillQualityGate.js +9 -9
  91. package/dist/infra/lib/SkillRepository.js +159 -159
  92. package/dist/infra/lib/UltraQA.js +99 -99
  93. package/dist/infra/lib/autonomy/AuditStore.js +41 -41
  94. package/dist/infra/lib/autonomy/ConfirmationStore.js +30 -30
  95. package/dist/infra/lib/autonomy/EventOutbox.js +38 -38
  96. package/dist/infra/lib/autonomy/PolicyEngine.js +18 -18
  97. package/dist/infra/lib/autonomy/SecuritySentinel.js +1 -1
  98. package/dist/infra/lib/autonomy/SuggestionStore.js +33 -33
  99. package/dist/infra/lib/embedding/VectorStore.js +22 -22
  100. package/dist/infra/lib/evolution/AgentAnalyzer.js +10 -10
  101. package/dist/infra/lib/evolution/DescriptionOptimizer.js +21 -21
  102. package/dist/infra/lib/evolution/GenerationRegistry.js +36 -36
  103. package/dist/infra/lib/evolution/InsightStore.js +90 -90
  104. package/dist/infra/lib/evolution/RollbackManager.js +5 -5
  105. package/dist/infra/lib/evolution/SkillBenchmark.js +23 -23
  106. package/dist/infra/lib/evolution/SkillEvalRunner.js +50 -50
  107. package/dist/infra/lib/evolution/SkillGapDetector.js +10 -10
  108. package/dist/infra/lib/evolution/UsageTracker.js +28 -28
  109. package/dist/infra/lib/gemini/orchestration.js +5 -5
  110. package/dist/infra/lib/gpt/orchestration.js +4 -4
  111. package/dist/infra/lib/memory/KnowledgeGraph.js +4 -4
  112. package/dist/infra/lib/memory/MemorySearch.js +57 -57
  113. package/dist/infra/lib/memory/MemoryStorage.js +181 -181
  114. package/dist/infra/lib/memory/ObservationStore.js +28 -28
  115. package/dist/infra/lib/memory/ReflectionStore.js +30 -30
  116. package/dist/infra/lib/memory/SessionRAGRetriever.js +7 -7
  117. package/dist/infra/lib/memory/SessionRAGStore.js +225 -225
  118. package/dist/infra/lib/memory/SessionSummarizer.js +9 -9
  119. package/dist/infra/lib/telemetry/SkillTelemetry.d.ts +52 -0
  120. package/dist/infra/lib/telemetry/SkillTelemetry.d.ts.map +1 -0
  121. package/dist/infra/lib/telemetry/SkillTelemetry.js +117 -0
  122. package/dist/infra/lib/telemetry/SkillTelemetry.js.map +1 -0
  123. package/dist/infra/lib/telemetry/SkillTelemetry.test.d.ts +2 -0
  124. package/dist/infra/lib/telemetry/SkillTelemetry.test.d.ts.map +1 -0
  125. package/dist/infra/lib/telemetry/SkillTelemetry.test.js +91 -0
  126. package/dist/infra/lib/telemetry/SkillTelemetry.test.js.map +1 -0
  127. package/dist/infra/orchestrator/AgentManager.js +12 -12
  128. package/dist/infra/orchestrator/AgentRegistry.js +65 -65
  129. package/dist/infra/orchestrator/MultiLlmResearch.js +8 -8
  130. package/dist/infra/orchestrator/SwarmOrchestrator.test.js +16 -16
  131. package/dist/infra/orchestrator/parallelResearch.js +24 -24
  132. package/dist/test-helpers/index.d.ts +36 -0
  133. package/dist/test-helpers/index.d.ts.map +1 -0
  134. package/dist/test-helpers/index.js +85 -0
  135. package/dist/test-helpers/index.js.map +1 -0
  136. package/dist/test-helpers/index.test.d.ts +2 -0
  137. package/dist/test-helpers/index.test.d.ts.map +1 -0
  138. package/dist/test-helpers/index.test.js +92 -0
  139. package/dist/test-helpers/index.test.js.map +1 -0
  140. package/dist/tools/convention/analyzeComplexity.test.js +115 -115
  141. package/dist/tools/convention/validateCodeQuality.test.js +104 -104
  142. package/dist/tools/memory/createMemoryTimeline.js +10 -10
  143. package/dist/tools/memory/getMemoryGraph.js +12 -12
  144. package/dist/tools/memory/getSessionContext.js +9 -9
  145. package/dist/tools/memory/linkMemories.js +14 -14
  146. package/dist/tools/memory/listMemories.js +4 -4
  147. package/dist/tools/memory/recallMemory.js +4 -4
  148. package/dist/tools/memory/saveMemory.js +4 -4
  149. package/dist/tools/memory/searchMemoriesAdvanced.js +23 -23
  150. package/dist/tools/semantic/analyzeDependencyGraph.js +12 -12
  151. package/dist/tools/semantic/astGrep.test.js +6 -6
  152. package/dist/tools/spec/prdParser.test.js +171 -171
  153. package/dist/tools/spec/specGenerator.js +169 -169
  154. package/dist/tools/spec/traceabilityMatrix.js +64 -64
  155. package/dist/tools/spec/traceabilityMatrix.test.js +28 -28
  156. package/hooks/gemini-hooks.json +73 -73
  157. package/hooks/hooks.json +137 -137
  158. package/hooks/scripts/code-check.js +77 -77
  159. package/hooks/scripts/context-save.js +212 -212
  160. package/hooks/scripts/hud-status.js +291 -291
  161. package/hooks/scripts/keyword-detector.js +214 -214
  162. package/hooks/scripts/llm-orchestrate.js +475 -475
  163. package/hooks/scripts/post-edit.js +32 -32
  164. package/hooks/scripts/pre-tool-guard.js +125 -125
  165. package/hooks/scripts/prompt-dispatcher.js +185 -185
  166. package/hooks/scripts/sentinel-guard.js +104 -104
  167. package/hooks/scripts/session-start.js +106 -106
  168. package/hooks/scripts/stop-notify.js +209 -209
  169. package/hooks/scripts/utils.js +100 -100
  170. package/languages/csharp-unity.md +515 -515
  171. package/languages/gdscript-godot.md +470 -470
  172. package/languages/ruby-rails.md +489 -489
  173. package/languages/typescript-angular.md +433 -433
  174. package/languages/typescript-astro.md +416 -416
  175. package/languages/typescript-electron.md +406 -406
  176. package/languages/typescript-nestjs.md +524 -524
  177. package/languages/typescript-svelte.md +407 -407
  178. package/languages/typescript-tauri.md +365 -365
  179. package/package.json +123 -121
  180. package/skills/agents-md/SKILL.md +120 -120
  181. package/skills/arch-guard/SKILL.md +180 -180
  182. package/skills/brand-assets/SKILL.md +146 -146
  183. package/skills/capability-loop/SKILL.md +167 -167
  184. package/skills/characterization-test/SKILL.md +206 -206
  185. package/skills/commerce-patterns/SKILL.md +63 -63
  186. package/skills/commit-push-pr/SKILL.md +75 -75
  187. package/skills/context7-usage/SKILL.md +105 -105
  188. package/skills/core-capabilities/SKILL.md +13 -13
  189. package/skills/e2e-commerce/SKILL.md +61 -61
  190. package/skills/exec-plan/SKILL.md +147 -147
  191. package/skills/frontend-design/SKILL.md +12 -12
  192. package/skills/git-worktree/SKILL.md +72 -72
  193. package/skills/handoff/SKILL.md +109 -109
  194. package/skills/parallel-research/SKILL.md +87 -87
  195. package/skills/priority-todos/SKILL.md +63 -63
  196. package/skills/seo-checklist/SKILL.md +57 -57
  197. package/skills/techdebt/SKILL.md +122 -122
  198. package/skills/tool-fallback/SKILL.md +103 -103
  199. package/skills/typescript-advanced-types/SKILL.md +66 -66
  200. package/skills/ui-ux-pro-max/SKILL.md +221 -221
  201. package/skills/vercel-react-best-practices/SKILL.md +59 -59
  202. package/skills/video-production/SKILL.md +51 -51
  203. package/vibe/config.json +29 -29
  204. package/vibe/constitution.md +227 -227
  205. package/vibe/rules/principles/communication-guide.md +98 -98
  206. package/vibe/rules/principles/development-philosophy.md +52 -52
  207. package/vibe/rules/principles/quick-start.md +102 -102
  208. package/vibe/rules/quality/bdd-contract-testing.md +393 -393
  209. package/vibe/rules/quality/checklist.md +276 -276
  210. package/vibe/rules/quality/performance.md +236 -236
  211. package/vibe/rules/quality/testing-strategy.md +440 -440
  212. package/vibe/rules/standards/anti-patterns.md +541 -541
  213. package/vibe/rules/standards/code-structure.md +291 -291
  214. package/vibe/rules/standards/complexity-metrics.md +313 -313
  215. package/vibe/rules/standards/git-workflow.md +237 -237
  216. package/vibe/rules/standards/naming-conventions.md +198 -198
  217. package/vibe/rules/standards/security.md +305 -305
  218. package/vibe/rules/writing/document-style.md +74 -74
  219. package/vibe/setup.sh +31 -31
  220. package/vibe/templates/constitution-template.md +252 -252
  221. package/vibe/templates/contract-backend-template.md +526 -526
  222. package/vibe/templates/contract-frontend-template.md +599 -599
  223. package/vibe/templates/feature-template.md +96 -96
  224. package/vibe/templates/spec-template.md +221 -221
  225. package/vibe/ui-ux-data/charts.csv +26 -26
  226. package/vibe/ui-ux-data/colors.csv +97 -97
  227. package/vibe/ui-ux-data/icons.csv +101 -101
  228. package/vibe/ui-ux-data/landing.csv +31 -31
  229. package/vibe/ui-ux-data/products.csv +96 -96
  230. package/vibe/ui-ux-data/react-performance.csv +45 -45
  231. package/vibe/ui-ux-data/stacks/astro.csv +54 -54
  232. package/vibe/ui-ux-data/stacks/flutter.csv +53 -53
  233. package/vibe/ui-ux-data/stacks/html-tailwind.csv +56 -56
  234. package/vibe/ui-ux-data/stacks/jetpack-compose.csv +53 -53
  235. package/vibe/ui-ux-data/stacks/nextjs.csv +53 -53
  236. package/vibe/ui-ux-data/stacks/nuxt-ui.csv +51 -51
  237. package/vibe/ui-ux-data/stacks/nuxtjs.csv +59 -59
  238. package/vibe/ui-ux-data/stacks/react-native.csv +52 -52
  239. package/vibe/ui-ux-data/stacks/react.csv +54 -54
  240. package/vibe/ui-ux-data/stacks/shadcn.csv +61 -61
  241. package/vibe/ui-ux-data/stacks/svelte.csv +54 -54
  242. package/vibe/ui-ux-data/stacks/swiftui.csv +51 -51
  243. package/vibe/ui-ux-data/stacks/vue.csv +50 -50
  244. package/vibe/ui-ux-data/styles.csv +68 -68
  245. package/vibe/ui-ux-data/typography.csv +57 -57
  246. package/vibe/ui-ux-data/ui-reasoning.csv +101 -101
  247. package/vibe/ui-ux-data/ux-guidelines.csv +99 -99
  248. package/vibe/ui-ux-data/version.json +31 -31
  249. package/vibe/ui-ux-data/web-interface.csv +31 -31
@@ -0,0 +1,52 @@
1
+ /**
2
+ * SkillTelemetry — 스킬 사용 로컬 JSONL 로깅
3
+ *
4
+ * 모든 데이터는 로컬에만 저장됩니다.
5
+ * 파일: ~/.vibe/analytics/skill-usage.jsonl
6
+ *
7
+ * 원격 전송 기능 없음 — 프라이버시 우선.
8
+ */
9
+ export interface SkillEvent {
10
+ /** Schema version */
11
+ v: 1;
12
+ /** ISO 8601 timestamp */
13
+ ts: string;
14
+ /** Event type */
15
+ event_type: 'skill_run' | 'skill_error' | 'hook_fire';
16
+ /** Skill name */
17
+ skill: string;
18
+ /** Duration in seconds (null if not applicable) */
19
+ duration_s: number | null;
20
+ /** Outcome */
21
+ outcome: 'success' | 'error' | 'abort';
22
+ /** Vibe version */
23
+ vibe_version: string;
24
+ /** OS platform */
25
+ os: string;
26
+ }
27
+ export interface SkillSummary {
28
+ skill: string;
29
+ count: number;
30
+ successCount: number;
31
+ errorCount: number;
32
+ avgDurationS: number | null;
33
+ lastUsed: string;
34
+ }
35
+ export declare class SkillTelemetry {
36
+ private readonly logPath;
37
+ private readonly enabled;
38
+ constructor(analyticsDir: string, enabled?: boolean);
39
+ /** 스킬 실행 이벤트 기록 */
40
+ log(event: Omit<SkillEvent, 'v' | 'ts' | 'os'>): void;
41
+ /** 편의 메서드: 스킬 실행 성공 기록 */
42
+ logSuccess(skill: string, durationS: number | null, vibeVersion: string): void;
43
+ /** 편의 메서드: 스킬 실행 실패 기록 */
44
+ logError(skill: string, durationS: number | null, vibeVersion: string): void;
45
+ /** 전체 이벤트 읽기 */
46
+ readAll(): SkillEvent[];
47
+ /** 스킬별 사용 요약 */
48
+ summarize(): SkillSummary[];
49
+ /** 로그 파일 경로 */
50
+ getLogPath(): string;
51
+ }
52
+ //# sourceMappingURL=SkillTelemetry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SkillTelemetry.d.ts","sourceRoot":"","sources":["../../../../src/infra/lib/telemetry/SkillTelemetry.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAOH,MAAM,WAAW,UAAU;IACzB,qBAAqB;IACrB,CAAC,EAAE,CAAC,CAAC;IACL,yBAAyB;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,iBAAiB;IACjB,UAAU,EAAE,WAAW,GAAG,aAAa,GAAG,WAAW,CAAC;IACtD,iBAAiB;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,mDAAmD;IACnD,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,cAAc;IACd,OAAO,EAAE,SAAS,GAAG,OAAO,GAAG,OAAO,CAAC;IACvC,mBAAmB;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,kBAAkB;IAClB,EAAE,EAAE,MAAM,CAAC;CACZ;AAID,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,QAAQ,EAAE,MAAM,CAAC;CAClB;AAID,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAU;gBAEtB,YAAY,EAAE,MAAM,EAAE,OAAO,UAAO;IAShD,mBAAmB;IACnB,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,UAAU,EAAE,GAAG,GAAG,IAAI,GAAG,IAAI,CAAC,GAAG,IAAI;IAiBrD,0BAA0B;IAC1B,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI;IAU9E,0BAA0B;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI;IAU5E,gBAAgB;IAChB,OAAO,IAAI,UAAU,EAAE;IAevB,gBAAgB;IAChB,SAAS,IAAI,YAAY,EAAE;IA6C3B,eAAe;IACf,UAAU,IAAI,MAAM;CAGrB"}
@@ -0,0 +1,117 @@
1
+ /**
2
+ * SkillTelemetry — 스킬 사용 로컬 JSONL 로깅
3
+ *
4
+ * 모든 데이터는 로컬에만 저장됩니다.
5
+ * 파일: ~/.vibe/analytics/skill-usage.jsonl
6
+ *
7
+ * 원격 전송 기능 없음 — 프라이버시 우선.
8
+ */
9
+ import fs from 'fs';
10
+ import path from 'path';
11
+ // ─── SkillTelemetry ───
12
+ export class SkillTelemetry {
13
+ logPath;
14
+ enabled;
15
+ constructor(analyticsDir, enabled = true) {
16
+ this.logPath = path.join(analyticsDir, 'skill-usage.jsonl');
17
+ this.enabled = enabled;
18
+ if (enabled) {
19
+ fs.mkdirSync(analyticsDir, { recursive: true });
20
+ }
21
+ }
22
+ /** 스킬 실행 이벤트 기록 */
23
+ log(event) {
24
+ if (!this.enabled)
25
+ return;
26
+ const fullEvent = {
27
+ v: 1,
28
+ ts: new Date().toISOString(),
29
+ os: process.platform,
30
+ ...event,
31
+ };
32
+ try {
33
+ fs.appendFileSync(this.logPath, JSON.stringify(fullEvent) + '\n');
34
+ }
35
+ catch {
36
+ // Silent fail — telemetry should never break the tool
37
+ }
38
+ }
39
+ /** 편의 메서드: 스킬 실행 성공 기록 */
40
+ logSuccess(skill, durationS, vibeVersion) {
41
+ this.log({
42
+ event_type: 'skill_run',
43
+ skill,
44
+ duration_s: durationS,
45
+ outcome: 'success',
46
+ vibe_version: vibeVersion,
47
+ });
48
+ }
49
+ /** 편의 메서드: 스킬 실행 실패 기록 */
50
+ logError(skill, durationS, vibeVersion) {
51
+ this.log({
52
+ event_type: 'skill_run',
53
+ skill,
54
+ duration_s: durationS,
55
+ outcome: 'error',
56
+ vibe_version: vibeVersion,
57
+ });
58
+ }
59
+ /** 전체 이벤트 읽기 */
60
+ readAll() {
61
+ if (!fs.existsSync(this.logPath))
62
+ return [];
63
+ try {
64
+ const content = fs.readFileSync(this.logPath, 'utf-8');
65
+ return content
66
+ .trim()
67
+ .split('\n')
68
+ .filter(line => line.trim().length > 0)
69
+ .map(line => JSON.parse(line));
70
+ }
71
+ catch {
72
+ return [];
73
+ }
74
+ }
75
+ /** 스킬별 사용 요약 */
76
+ summarize() {
77
+ const events = this.readAll();
78
+ const map = new Map();
79
+ for (const event of events) {
80
+ if (event.event_type !== 'skill_run')
81
+ continue;
82
+ const existing = map.get(event.skill) ?? {
83
+ count: 0, successCount: 0, errorCount: 0,
84
+ totalDuration: 0, durationCount: 0, lastUsed: event.ts,
85
+ };
86
+ existing.count++;
87
+ if (event.outcome === 'success')
88
+ existing.successCount++;
89
+ if (event.outcome === 'error')
90
+ existing.errorCount++;
91
+ if (event.duration_s !== null) {
92
+ existing.totalDuration += event.duration_s;
93
+ existing.durationCount++;
94
+ }
95
+ if (event.ts > existing.lastUsed)
96
+ existing.lastUsed = event.ts;
97
+ map.set(event.skill, existing);
98
+ }
99
+ return [...map.entries()]
100
+ .map(([skill, data]) => ({
101
+ skill,
102
+ count: data.count,
103
+ successCount: data.successCount,
104
+ errorCount: data.errorCount,
105
+ avgDurationS: data.durationCount > 0
106
+ ? Math.round((data.totalDuration / data.durationCount) * 10) / 10
107
+ : null,
108
+ lastUsed: data.lastUsed,
109
+ }))
110
+ .sort((a, b) => b.count - a.count);
111
+ }
112
+ /** 로그 파일 경로 */
113
+ getLogPath() {
114
+ return this.logPath;
115
+ }
116
+ }
117
+ //# sourceMappingURL=SkillTelemetry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SkillTelemetry.js","sourceRoot":"","sources":["../../../../src/infra/lib/telemetry/SkillTelemetry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=SkillTelemetry.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SkillTelemetry.test.d.ts","sourceRoot":"","sources":["../../../../src/infra/lib/telemetry/SkillTelemetry.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,91 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
+ import { existsSync, readFileSync } from 'fs';
3
+ import { createTempDir, cleanupTempDir, parseJsonl } from '../../../test-helpers/index.js';
4
+ import { SkillTelemetry } from './SkillTelemetry.js';
5
+ describe('SkillTelemetry', () => {
6
+ let telemetry;
7
+ let testDir;
8
+ beforeEach(() => {
9
+ testDir = createTempDir('telemetry-test');
10
+ telemetry = new SkillTelemetry(testDir);
11
+ });
12
+ afterEach(() => {
13
+ cleanupTempDir(testDir);
14
+ });
15
+ describe('log', () => {
16
+ it('should create JSONL log file on first write', () => {
17
+ telemetry.logSuccess('vibe.run', 12.5, '2.7.17');
18
+ expect(existsSync(telemetry.getLogPath())).toBe(true);
19
+ });
20
+ it('should append events as JSONL', () => {
21
+ telemetry.logSuccess('vibe.run', 12.5, '2.7.17');
22
+ telemetry.logError('vibe.spec', 3.2, '2.7.17');
23
+ const content = readFileSync(telemetry.getLogPath(), 'utf-8');
24
+ const events = parseJsonl(content);
25
+ expect(events).toHaveLength(2);
26
+ expect(events[0].skill).toBe('vibe.run');
27
+ expect(events[0].outcome).toBe('success');
28
+ expect(events[0].v).toBe(1);
29
+ expect(events[0].os).toBe(process.platform);
30
+ expect(events[1].skill).toBe('vibe.spec');
31
+ expect(events[1].outcome).toBe('error');
32
+ });
33
+ it('should include ISO timestamp', () => {
34
+ telemetry.logSuccess('vibe.trace', null, '2.7.17');
35
+ const events = telemetry.readAll();
36
+ expect(events[0].ts).toMatch(/^\d{4}-\d{2}-\d{2}T/);
37
+ });
38
+ });
39
+ describe('readAll', () => {
40
+ it('should return empty array for missing file', () => {
41
+ const fresh = new SkillTelemetry(createTempDir('empty'));
42
+ expect(fresh.readAll()).toEqual([]);
43
+ });
44
+ it('should return all logged events', () => {
45
+ telemetry.logSuccess('a', 1, '1.0.0');
46
+ telemetry.logSuccess('b', 2, '1.0.0');
47
+ telemetry.logError('c', null, '1.0.0');
48
+ const events = telemetry.readAll();
49
+ expect(events).toHaveLength(3);
50
+ });
51
+ });
52
+ describe('summarize', () => {
53
+ it('should aggregate by skill name', () => {
54
+ telemetry.logSuccess('vibe.run', 10, '1.0.0');
55
+ telemetry.logSuccess('vibe.run', 20, '1.0.0');
56
+ telemetry.logError('vibe.run', 5, '1.0.0');
57
+ telemetry.logSuccess('vibe.spec', 3, '1.0.0');
58
+ const summary = telemetry.summarize();
59
+ expect(summary).toHaveLength(2);
60
+ const vibeRun = summary.find(s => s.skill === 'vibe.run');
61
+ expect(vibeRun?.count).toBe(3);
62
+ expect(vibeRun?.successCount).toBe(2);
63
+ expect(vibeRun?.errorCount).toBe(1);
64
+ expect(vibeRun?.avgDurationS).toBeCloseTo(11.7, 0);
65
+ const vibeSpec = summary.find(s => s.skill === 'vibe.spec');
66
+ expect(vibeSpec?.count).toBe(1);
67
+ });
68
+ it('should sort by count descending', () => {
69
+ telemetry.logSuccess('rare', 1, '1.0.0');
70
+ telemetry.logSuccess('common', 1, '1.0.0');
71
+ telemetry.logSuccess('common', 1, '1.0.0');
72
+ telemetry.logSuccess('common', 1, '1.0.0');
73
+ const summary = telemetry.summarize();
74
+ expect(summary[0].skill).toBe('common');
75
+ expect(summary[1].skill).toBe('rare');
76
+ });
77
+ it('should handle null durations', () => {
78
+ telemetry.logSuccess('no-duration', null, '1.0.0');
79
+ const summary = telemetry.summarize();
80
+ expect(summary[0].avgDurationS).toBeNull();
81
+ });
82
+ });
83
+ describe('disabled mode', () => {
84
+ it('should not write when disabled', () => {
85
+ const disabled = new SkillTelemetry(testDir, false);
86
+ disabled.logSuccess('should-not-log', 1, '1.0.0');
87
+ expect(existsSync(disabled.getLogPath())).toBe(false);
88
+ });
89
+ });
90
+ });
91
+ //# sourceMappingURL=SkillTelemetry.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SkillTelemetry.test.js","sourceRoot":"","sources":["../../../../src/infra/lib/telemetry/SkillTelemetry.test.ts"],"names":[],"mappings":"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"}
@@ -151,18 +151,18 @@ export class AgentManager {
151
151
  * 리뷰 프롬프트 생성
152
152
  */
153
153
  buildReviewPrompt(agent, filePaths) {
154
- return `You are a ${agent.name}. Review the following files for issues in your domain:
155
-
156
- Files to review:
157
- ${filePaths.map(f => `- ${f}`).join('\n')}
158
-
159
- ${agent.content}
160
-
161
- Provide findings in this format:
162
- - Priority: P1 (Critical), P2 (Important), P3 (Nice-to-have)
163
- - Category: Your specialty area
164
- - Location: file:line
165
- - Issue: Description
154
+ return `You are a ${agent.name}. Review the following files for issues in your domain:
155
+
156
+ Files to review:
157
+ ${filePaths.map(f => `- ${f}`).join('\n')}
158
+
159
+ ${agent.content}
160
+
161
+ Provide findings in this format:
162
+ - Priority: P1 (Critical), P2 (Important), P3 (Nice-to-have)
163
+ - Category: Your specialty area
164
+ - Location: file:line
165
+ - Issue: Description
166
166
  - Fix: Recommendation`;
167
167
  }
168
168
  /**
@@ -57,36 +57,36 @@ export class AgentRegistry {
57
57
  }
58
58
  this.initializeSchema();
59
59
  // Prepare statements
60
- this.insertStmt = this.db.prepare(`
61
- INSERT INTO agent_executions (id, task_id, agent_name, prompt, status, model, started_at, session_id, created_at)
62
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
60
+ this.insertStmt = this.db.prepare(`
61
+ INSERT INTO agent_executions (id, task_id, agent_name, prompt, status, model, started_at, session_id, created_at)
62
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
63
63
  `);
64
- this.updateCompleteStmt = this.db.prepare(`
65
- UPDATE agent_executions SET status = 'completed', result = ?, duration = ?, completed_at = ? WHERE id = ?
64
+ this.updateCompleteStmt = this.db.prepare(`
65
+ UPDATE agent_executions SET status = 'completed', result = ?, duration = ?, completed_at = ? WHERE id = ?
66
66
  `);
67
- this.updateFailStmt = this.db.prepare(`
68
- UPDATE agent_executions SET status = 'failed', error = ?, duration = ?, completed_at = ? WHERE id = ?
67
+ this.updateFailStmt = this.db.prepare(`
68
+ UPDATE agent_executions SET status = 'failed', error = ?, duration = ?, completed_at = ? WHERE id = ?
69
69
  `);
70
70
  }
71
71
  initializeSchema() {
72
- this.db.exec(`
73
- CREATE TABLE IF NOT EXISTS agent_executions (
74
- id TEXT PRIMARY KEY,
75
- task_id TEXT NOT NULL,
76
- agent_name TEXT NOT NULL,
77
- prompt TEXT,
78
- result TEXT,
79
- status TEXT NOT NULL DEFAULT 'pending',
80
- duration INTEGER,
81
- model TEXT,
82
- started_at INTEGER NOT NULL,
83
- completed_at INTEGER,
84
- session_id TEXT,
85
- error TEXT,
86
- created_at INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)
87
- );
88
- CREATE INDEX IF NOT EXISTS idx_status ON agent_executions(status);
89
- CREATE INDEX IF NOT EXISTS idx_agent_name ON agent_executions(agent_name);
72
+ this.db.exec(`
73
+ CREATE TABLE IF NOT EXISTS agent_executions (
74
+ id TEXT PRIMARY KEY,
75
+ task_id TEXT NOT NULL,
76
+ agent_name TEXT NOT NULL,
77
+ prompt TEXT,
78
+ result TEXT,
79
+ status TEXT NOT NULL DEFAULT 'pending',
80
+ duration INTEGER,
81
+ model TEXT,
82
+ started_at INTEGER NOT NULL,
83
+ completed_at INTEGER,
84
+ session_id TEXT,
85
+ error TEXT,
86
+ created_at INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)
87
+ );
88
+ CREATE INDEX IF NOT EXISTS idx_status ON agent_executions(status);
89
+ CREATE INDEX IF NOT EXISTS idx_agent_name ON agent_executions(agent_name);
90
90
  `);
91
91
  }
92
92
  recordStart(execution) {
@@ -102,45 +102,45 @@ export class AgentRegistry {
102
102
  this.updateFailStmt.run(maskedError, duration, Date.now(), id);
103
103
  }
104
104
  getIncompleteExecutions() {
105
- const stmt = this.db.prepare(`
106
- SELECT id, task_id as taskId, agent_name as agentName, status, duration, model,
107
- started_at as startedAt, completed_at as completedAt, error, created_at as createdAt
108
- FROM agent_executions WHERE status = 'running' ORDER BY started_at ASC
105
+ const stmt = this.db.prepare(`
106
+ SELECT id, task_id as taskId, agent_name as agentName, status, duration, model,
107
+ started_at as startedAt, completed_at as completedAt, error, created_at as createdAt
108
+ FROM agent_executions WHERE status = 'running' ORDER BY started_at ASC
109
109
  `);
110
110
  return stmt.all();
111
111
  }
112
112
  markOrphaned(olderThanMs) {
113
113
  const cutoff = Date.now() - olderThanMs;
114
- const stmt = this.db.prepare(`
115
- UPDATE agent_executions SET status = 'failed', error = 'Orphaned (process crash)',
116
- completed_at = ? WHERE status = 'running' AND started_at < ?
114
+ const stmt = this.db.prepare(`
115
+ UPDATE agent_executions SET status = 'failed', error = 'Orphaned (process crash)',
116
+ completed_at = ? WHERE status = 'running' AND started_at < ?
117
117
  `);
118
118
  const result = stmt.run(Date.now(), cutoff);
119
119
  return result.changes;
120
120
  }
121
121
  getHistory(limit = 50, agentName) {
122
122
  if (agentName) {
123
- const stmt = this.db.prepare(`
124
- SELECT id, task_id as taskId, agent_name as agentName, status, duration, model,
125
- started_at as startedAt, completed_at as completedAt, error, created_at as createdAt
126
- FROM agent_executions WHERE agent_name = ? ORDER BY created_at DESC LIMIT ?
123
+ const stmt = this.db.prepare(`
124
+ SELECT id, task_id as taskId, agent_name as agentName, status, duration, model,
125
+ started_at as startedAt, completed_at as completedAt, error, created_at as createdAt
126
+ FROM agent_executions WHERE agent_name = ? ORDER BY created_at DESC LIMIT ?
127
127
  `);
128
128
  return stmt.all(agentName, limit);
129
129
  }
130
- const stmt = this.db.prepare(`
131
- SELECT id, task_id as taskId, agent_name as agentName, status, duration, model,
132
- started_at as startedAt, completed_at as completedAt, error, created_at as createdAt
133
- FROM agent_executions ORDER BY created_at DESC LIMIT ?
130
+ const stmt = this.db.prepare(`
131
+ SELECT id, task_id as taskId, agent_name as agentName, status, duration, model,
132
+ started_at as startedAt, completed_at as completedAt, error, created_at as createdAt
133
+ FROM agent_executions ORDER BY created_at DESC LIMIT ?
134
134
  `);
135
135
  return stmt.all(limit);
136
136
  }
137
137
  getAgentStats(agentName) {
138
- const stmt = this.db.prepare(`
139
- SELECT COUNT(*) as total,
140
- SUM(CASE WHEN status = 'completed' THEN 1 ELSE 0 END) as completed,
141
- SUM(CASE WHEN status = 'failed' THEN 1 ELSE 0 END) as failed,
142
- AVG(CASE WHEN duration IS NOT NULL THEN duration END) as avgDuration
143
- FROM agent_executions WHERE agent_name = ?
138
+ const stmt = this.db.prepare(`
139
+ SELECT COUNT(*) as total,
140
+ SUM(CASE WHEN status = 'completed' THEN 1 ELSE 0 END) as completed,
141
+ SUM(CASE WHEN status = 'failed' THEN 1 ELSE 0 END) as failed,
142
+ AVG(CASE WHEN duration IS NOT NULL THEN duration END) as avgDuration
143
+ FROM agent_executions WHERE agent_name = ?
144
144
  `);
145
145
  const row = stmt.get(agentName);
146
146
  return {
@@ -153,21 +153,21 @@ export class AgentRegistry {
153
153
  }
154
154
  getGlobalStats() {
155
155
  // Overall stats
156
- const overallStmt = this.db.prepare(`
157
- SELECT COUNT(*) as total,
158
- SUM(CASE WHEN status = 'completed' THEN 1 ELSE 0 END) as completed,
159
- SUM(CASE WHEN status = 'failed' THEN 1 ELSE 0 END) as failed,
160
- AVG(CASE WHEN duration IS NOT NULL THEN duration END) as avgDuration
161
- FROM agent_executions
156
+ const overallStmt = this.db.prepare(`
157
+ SELECT COUNT(*) as total,
158
+ SUM(CASE WHEN status = 'completed' THEN 1 ELSE 0 END) as completed,
159
+ SUM(CASE WHEN status = 'failed' THEN 1 ELSE 0 END) as failed,
160
+ AVG(CASE WHEN duration IS NOT NULL THEN duration END) as avgDuration
161
+ FROM agent_executions
162
162
  `);
163
163
  const overall = overallStmt.get();
164
164
  // By agent
165
- const byAgentStmt = this.db.prepare(`
166
- SELECT agent_name as agentName, COUNT(*) as total,
167
- SUM(CASE WHEN status = 'completed' THEN 1 ELSE 0 END) as completed,
168
- SUM(CASE WHEN status = 'failed' THEN 1 ELSE 0 END) as failed,
169
- AVG(CASE WHEN duration IS NOT NULL THEN duration END) as avgDuration
170
- FROM agent_executions GROUP BY agent_name
165
+ const byAgentStmt = this.db.prepare(`
166
+ SELECT agent_name as agentName, COUNT(*) as total,
167
+ SUM(CASE WHEN status = 'completed' THEN 1 ELSE 0 END) as completed,
168
+ SUM(CASE WHEN status = 'failed' THEN 1 ELSE 0 END) as failed,
169
+ AVG(CASE WHEN duration IS NOT NULL THEN duration END) as avgDuration
170
+ FROM agent_executions GROUP BY agent_name
171
171
  `);
172
172
  const agentRows = byAgentStmt.all();
173
173
  const byAgent = {};
@@ -181,10 +181,10 @@ export class AgentRegistry {
181
181
  };
182
182
  }
183
183
  // By model
184
- const byModelStmt = this.db.prepare(`
185
- SELECT model, COUNT(*) as count,
186
- AVG(CASE WHEN duration IS NOT NULL THEN duration END) as avgDuration
187
- FROM agent_executions WHERE model IS NOT NULL GROUP BY model
184
+ const byModelStmt = this.db.prepare(`
185
+ SELECT model, COUNT(*) as count,
186
+ AVG(CASE WHEN duration IS NOT NULL THEN duration END) as avgDuration
187
+ FROM agent_executions WHERE model IS NOT NULL GROUP BY model
188
188
  `);
189
189
  const modelRows = byModelStmt.all();
190
190
  const byModel = {};
@@ -203,9 +203,9 @@ export class AgentRegistry {
203
203
  }
204
204
  cleanup(ttlMs = DEFAULT_CLEANUP_TTL_MS) {
205
205
  const cutoff = Date.now() - ttlMs;
206
- const stmt = this.db.prepare(`
207
- DELETE FROM agent_executions
208
- WHERE (status = 'completed' OR status = 'failed') AND completed_at < ?
206
+ const stmt = this.db.prepare(`
207
+ DELETE FROM agent_executions
208
+ WHERE (status = 'completed' OR status = 'failed') AND completed_at < ?
209
209
  `);
210
210
  const result = stmt.run(cutoff);
211
211
  return result.changes;
@@ -11,19 +11,19 @@ export function createMultiLlmPrompts(feature, techStack) {
11
11
  const stackStr = techStack.length > 0 ? techStack.join(', ') : 'the project';
12
12
  return {
13
13
  bestPractices: {
14
- gpt: `Best practices for implementing "${feature}" with ${stackStr}.
15
- Focus on: architecture patterns, code conventions, design patterns.
14
+ gpt: `Best practices for implementing "${feature}" with ${stackStr}.
15
+ Focus on: architecture patterns, code conventions, design patterns.
16
16
  Return JSON: { patterns: string[], antiPatterns: string[], libraries: string[] }`,
17
- gemini: `Best practices for implementing "${feature}" with ${stackStr}.
18
- Focus on: latest trends, framework updates, modern approaches.
17
+ gemini: `Best practices for implementing "${feature}" with ${stackStr}.
18
+ Focus on: latest trends, framework updates, modern approaches.
19
19
  Return JSON: { patterns: string[], antiPatterns: string[], libraries: string[] }`
20
20
  },
21
21
  security: {
22
- gpt: `Security considerations for "${feature}" with ${stackStr}.
23
- Focus on: CVE database, known vulnerabilities, exploit patterns.
22
+ gpt: `Security considerations for "${feature}" with ${stackStr}.
23
+ Focus on: CVE database, known vulnerabilities, exploit patterns.
24
24
  Return JSON: { vulnerabilities: string[], mitigations: string[], checklist: string[] }`,
25
- gemini: `Security advisories for "${feature}" with ${stackStr}.
26
- Focus on: latest patches, recent incidents, security best practices.
25
+ gemini: `Security advisories for "${feature}" with ${stackStr}.
26
+ Focus on: latest patches, recent incidents, security best practices.
27
27
  Return JSON: { advisories: string[], patches: string[], incidents: string[] }`
28
28
  }
29
29
  };
@@ -10,14 +10,14 @@ describe('SwarmOrchestrator', () => {
10
10
  expect(analysis.score).toBeLessThan(10);
11
11
  });
12
12
  it('복잡한 프롬프트는 높은 복잡도', async () => {
13
- const complexPrompt = `
14
- Implement a complete login feature:
15
- 1. Create the login form UI with React
16
- 2. Add form validation with Zod
17
- 3. Implement the API endpoint with authentication
18
- 4. Add error handling and loading states
19
- 5. Write unit tests for all components
20
- 6. Add security measures against CSRF
13
+ const complexPrompt = `
14
+ Implement a complete login feature:
15
+ 1. Create the login form UI with React
16
+ 2. Add form validation with Zod
17
+ 3. Implement the API endpoint with authentication
18
+ 4. Add error handling and loading states
19
+ 5. Write unit tests for all components
20
+ 6. Add security measures against CSRF
21
21
  `;
22
22
  const analysis = await analyzeTaskComplexity(complexPrompt);
23
23
  expect(analysis.score).toBeGreaterThan(15);
@@ -29,10 +29,10 @@ describe('SwarmOrchestrator', () => {
29
29
  expect(analysis.factors).toContain('5-files');
30
30
  });
31
31
  it('숫자 목록은 분할 제안 생성', async () => {
32
- const prompt = `
33
- 1. First do this task
34
- 2. Then do second task
35
- 3. Finally do third task
32
+ const prompt = `
33
+ 1. First do this task
34
+ 2. Then do second task
35
+ 3. Finally do third task
36
36
  `;
37
37
  const analysis = await analyzeTaskComplexity(prompt);
38
38
  expect(analysis.suggestedSplits?.length).toBeGreaterThanOrEqual(2);
@@ -65,10 +65,10 @@ describe('SwarmOrchestrator', () => {
65
65
  it('maxDepth 도달 시 분할 안함', async () => {
66
66
  // maxDepth: 0으로 설정하면 분할하지 않음
67
67
  const orchestrator = new SwarmOrchestrator({
68
- prompt: `
69
- 1. Task one
70
- 2. Task two
71
- 3. Task three
68
+ prompt: `
69
+ 1. Task one
70
+ 2. Task two
71
+ 3. Task three
72
72
  `,
73
73
  maxDepth: 0
74
74
  });