@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.
- package/.env.example +37 -37
- package/CLAUDE.md +153 -134
- package/LICENSE +21 -21
- package/README.md +449 -449
- package/agents/architect-low.md +41 -41
- package/agents/architect-medium.md +59 -59
- package/agents/architect.md +80 -80
- package/agents/build-error-resolver.md +115 -115
- package/agents/compounder.md +261 -261
- package/agents/diagrammer.md +178 -178
- package/agents/docs/api-documenter.md +99 -99
- package/agents/docs/changelog-writer.md +93 -93
- package/agents/e2e-tester.md +294 -294
- package/agents/explorer-low.md +42 -42
- package/agents/explorer-medium.md +59 -59
- package/agents/explorer.md +48 -48
- package/agents/implementer-low.md +43 -43
- package/agents/implementer-medium.md +52 -52
- package/agents/implementer.md +54 -54
- package/agents/junior-mentor.md +141 -141
- package/agents/planning/requirements-analyst.md +84 -84
- package/agents/planning/ux-advisor.md +83 -83
- package/agents/qa/acceptance-tester.md +86 -86
- package/agents/qa/edge-case-finder.md +93 -93
- package/agents/refactor-cleaner.md +143 -143
- package/agents/research/best-practices-agent.md +199 -199
- package/agents/research/codebase-patterns-agent.md +157 -157
- package/agents/research/framework-docs-agent.md +188 -188
- package/agents/research/security-advisory-agent.md +213 -213
- package/agents/review/architecture-reviewer.md +107 -107
- package/agents/review/complexity-reviewer.md +116 -116
- package/agents/review/data-integrity-reviewer.md +88 -88
- package/agents/review/git-history-reviewer.md +103 -103
- package/agents/review/performance-reviewer.md +86 -86
- package/agents/review/python-reviewer.md +150 -150
- package/agents/review/rails-reviewer.md +139 -139
- package/agents/review/react-reviewer.md +144 -144
- package/agents/review/security-reviewer.md +80 -80
- package/agents/review/simplicity-reviewer.md +140 -140
- package/agents/review/test-coverage-reviewer.md +116 -116
- package/agents/review/typescript-reviewer.md +127 -127
- package/agents/searcher.md +54 -54
- package/agents/simplifier.md +120 -120
- package/agents/tester.md +49 -49
- package/agents/ui/ui-a11y-auditor.md +93 -93
- package/agents/ui/ui-antipattern-detector.md +94 -94
- package/agents/ui/ui-dataviz-advisor.md +69 -69
- package/agents/ui/ui-design-system-gen.md +57 -57
- package/agents/ui/ui-industry-analyzer.md +49 -49
- package/agents/ui/ui-layout-architect.md +65 -65
- package/agents/ui/ui-stack-implementer.md +68 -68
- package/agents/ui/ux-compliance-reviewer.md +81 -81
- package/agents/ui-previewer.md +258 -258
- package/commands/vibe.analyze.md +379 -379
- package/commands/vibe.review.md +607 -607
- package/commands/vibe.run.md +2124 -2124
- package/commands/vibe.spec.md +1195 -1195
- package/commands/vibe.spec.review.md +569 -569
- package/commands/vibe.utils.md +413 -413
- package/commands/vibe.verify.md +484 -484
- package/dist/cli/collaborator.js +52 -52
- package/dist/cli/commands/evolution.js +12 -12
- package/dist/cli/commands/info.js +51 -51
- package/dist/cli/commands/init.js +5 -5
- package/dist/cli/commands/remove.js +14 -14
- package/dist/cli/commands/sentinel.js +27 -27
- package/dist/cli/commands/skills.js +5 -5
- package/dist/cli/commands/slack.js +10 -10
- package/dist/cli/commands/telegram.js +12 -12
- package/dist/cli/commands/upgrade.d.ts +3 -3
- package/dist/cli/commands/upgrade.d.ts.map +1 -1
- package/dist/cli/commands/upgrade.js +24 -3
- package/dist/cli/commands/upgrade.js.map +1 -1
- package/dist/cli/detect.js +32 -32
- package/dist/cli/index.js +51 -51
- package/dist/cli/llm/claude-commands.js +16 -16
- package/dist/cli/llm/config.js +18 -18
- package/dist/cli/llm/gemini-commands.js +16 -16
- package/dist/cli/llm/gpt-commands.js +19 -19
- package/dist/cli/llm/help.js +21 -21
- package/dist/cli/postinstall/cursor-agents.js +32 -32
- package/dist/cli/postinstall/cursor-rules.js +83 -83
- package/dist/cli/postinstall/cursor-skills.js +743 -743
- package/dist/cli/setup/Provisioner.js +42 -42
- package/dist/infra/lib/DeepInit.js +24 -24
- package/dist/infra/lib/IterationTracker.js +11 -11
- package/dist/infra/lib/PythonParser.js +108 -108
- package/dist/infra/lib/ReviewRace.js +96 -96
- package/dist/infra/lib/SkillFrontmatter.js +28 -28
- package/dist/infra/lib/SkillQualityGate.js +9 -9
- package/dist/infra/lib/SkillRepository.js +159 -159
- package/dist/infra/lib/UltraQA.js +99 -99
- package/dist/infra/lib/autonomy/AuditStore.js +41 -41
- package/dist/infra/lib/autonomy/ConfirmationStore.js +30 -30
- package/dist/infra/lib/autonomy/EventOutbox.js +38 -38
- package/dist/infra/lib/autonomy/PolicyEngine.js +18 -18
- package/dist/infra/lib/autonomy/SecuritySentinel.js +1 -1
- package/dist/infra/lib/autonomy/SuggestionStore.js +33 -33
- package/dist/infra/lib/embedding/VectorStore.js +22 -22
- package/dist/infra/lib/evolution/AgentAnalyzer.js +10 -10
- package/dist/infra/lib/evolution/DescriptionOptimizer.js +21 -21
- package/dist/infra/lib/evolution/GenerationRegistry.js +36 -36
- package/dist/infra/lib/evolution/InsightStore.js +90 -90
- package/dist/infra/lib/evolution/RollbackManager.js +5 -5
- package/dist/infra/lib/evolution/SkillBenchmark.js +23 -23
- package/dist/infra/lib/evolution/SkillEvalRunner.js +50 -50
- package/dist/infra/lib/evolution/SkillGapDetector.js +10 -10
- package/dist/infra/lib/evolution/UsageTracker.js +28 -28
- package/dist/infra/lib/gemini/orchestration.js +5 -5
- package/dist/infra/lib/gpt/orchestration.js +4 -4
- package/dist/infra/lib/memory/KnowledgeGraph.js +4 -4
- package/dist/infra/lib/memory/MemorySearch.js +57 -57
- package/dist/infra/lib/memory/MemoryStorage.js +181 -181
- package/dist/infra/lib/memory/ObservationStore.js +28 -28
- package/dist/infra/lib/memory/ReflectionStore.js +30 -30
- package/dist/infra/lib/memory/SessionRAGRetriever.js +7 -7
- package/dist/infra/lib/memory/SessionRAGStore.js +225 -225
- package/dist/infra/lib/memory/SessionSummarizer.js +9 -9
- package/dist/infra/lib/telemetry/SkillTelemetry.d.ts +52 -0
- package/dist/infra/lib/telemetry/SkillTelemetry.d.ts.map +1 -0
- package/dist/infra/lib/telemetry/SkillTelemetry.js +117 -0
- package/dist/infra/lib/telemetry/SkillTelemetry.js.map +1 -0
- package/dist/infra/lib/telemetry/SkillTelemetry.test.d.ts +2 -0
- package/dist/infra/lib/telemetry/SkillTelemetry.test.d.ts.map +1 -0
- package/dist/infra/lib/telemetry/SkillTelemetry.test.js +91 -0
- package/dist/infra/lib/telemetry/SkillTelemetry.test.js.map +1 -0
- package/dist/infra/orchestrator/AgentManager.js +12 -12
- package/dist/infra/orchestrator/AgentRegistry.js +65 -65
- package/dist/infra/orchestrator/MultiLlmResearch.js +8 -8
- package/dist/infra/orchestrator/SwarmOrchestrator.test.js +16 -16
- package/dist/infra/orchestrator/parallelResearch.js +24 -24
- package/dist/test-helpers/index.d.ts +36 -0
- package/dist/test-helpers/index.d.ts.map +1 -0
- package/dist/test-helpers/index.js +85 -0
- package/dist/test-helpers/index.js.map +1 -0
- package/dist/test-helpers/index.test.d.ts +2 -0
- package/dist/test-helpers/index.test.d.ts.map +1 -0
- package/dist/test-helpers/index.test.js +92 -0
- package/dist/test-helpers/index.test.js.map +1 -0
- package/dist/tools/convention/analyzeComplexity.test.js +115 -115
- package/dist/tools/convention/validateCodeQuality.test.js +104 -104
- package/dist/tools/memory/createMemoryTimeline.js +10 -10
- package/dist/tools/memory/getMemoryGraph.js +12 -12
- package/dist/tools/memory/getSessionContext.js +9 -9
- package/dist/tools/memory/linkMemories.js +14 -14
- package/dist/tools/memory/listMemories.js +4 -4
- package/dist/tools/memory/recallMemory.js +4 -4
- package/dist/tools/memory/saveMemory.js +4 -4
- package/dist/tools/memory/searchMemoriesAdvanced.js +23 -23
- package/dist/tools/semantic/analyzeDependencyGraph.js +12 -12
- package/dist/tools/semantic/astGrep.test.js +6 -6
- package/dist/tools/spec/prdParser.test.js +171 -171
- package/dist/tools/spec/specGenerator.js +169 -169
- package/dist/tools/spec/traceabilityMatrix.js +64 -64
- package/dist/tools/spec/traceabilityMatrix.test.js +28 -28
- package/hooks/gemini-hooks.json +73 -73
- package/hooks/hooks.json +137 -137
- package/hooks/scripts/code-check.js +77 -77
- package/hooks/scripts/context-save.js +212 -212
- package/hooks/scripts/hud-status.js +291 -291
- package/hooks/scripts/keyword-detector.js +214 -214
- package/hooks/scripts/llm-orchestrate.js +475 -475
- package/hooks/scripts/post-edit.js +32 -32
- package/hooks/scripts/pre-tool-guard.js +125 -125
- package/hooks/scripts/prompt-dispatcher.js +185 -185
- package/hooks/scripts/sentinel-guard.js +104 -104
- package/hooks/scripts/session-start.js +106 -106
- package/hooks/scripts/stop-notify.js +209 -209
- package/hooks/scripts/utils.js +100 -100
- package/languages/csharp-unity.md +515 -515
- package/languages/gdscript-godot.md +470 -470
- package/languages/ruby-rails.md +489 -489
- package/languages/typescript-angular.md +433 -433
- package/languages/typescript-astro.md +416 -416
- package/languages/typescript-electron.md +406 -406
- package/languages/typescript-nestjs.md +524 -524
- package/languages/typescript-svelte.md +407 -407
- package/languages/typescript-tauri.md +365 -365
- package/package.json +123 -121
- package/skills/agents-md/SKILL.md +120 -120
- package/skills/arch-guard/SKILL.md +180 -180
- package/skills/brand-assets/SKILL.md +146 -146
- package/skills/capability-loop/SKILL.md +167 -167
- package/skills/characterization-test/SKILL.md +206 -206
- package/skills/commerce-patterns/SKILL.md +63 -63
- package/skills/commit-push-pr/SKILL.md +75 -75
- package/skills/context7-usage/SKILL.md +105 -105
- package/skills/core-capabilities/SKILL.md +13 -13
- package/skills/e2e-commerce/SKILL.md +61 -61
- package/skills/exec-plan/SKILL.md +147 -147
- package/skills/frontend-design/SKILL.md +12 -12
- package/skills/git-worktree/SKILL.md +72 -72
- package/skills/handoff/SKILL.md +109 -109
- package/skills/parallel-research/SKILL.md +87 -87
- package/skills/priority-todos/SKILL.md +63 -63
- package/skills/seo-checklist/SKILL.md +57 -57
- package/skills/techdebt/SKILL.md +122 -122
- package/skills/tool-fallback/SKILL.md +103 -103
- package/skills/typescript-advanced-types/SKILL.md +66 -66
- package/skills/ui-ux-pro-max/SKILL.md +221 -221
- package/skills/vercel-react-best-practices/SKILL.md +59 -59
- package/skills/video-production/SKILL.md +51 -51
- package/vibe/config.json +29 -29
- package/vibe/constitution.md +227 -227
- package/vibe/rules/principles/communication-guide.md +98 -98
- package/vibe/rules/principles/development-philosophy.md +52 -52
- package/vibe/rules/principles/quick-start.md +102 -102
- package/vibe/rules/quality/bdd-contract-testing.md +393 -393
- package/vibe/rules/quality/checklist.md +276 -276
- package/vibe/rules/quality/performance.md +236 -236
- package/vibe/rules/quality/testing-strategy.md +440 -440
- package/vibe/rules/standards/anti-patterns.md +541 -541
- package/vibe/rules/standards/code-structure.md +291 -291
- package/vibe/rules/standards/complexity-metrics.md +313 -313
- package/vibe/rules/standards/git-workflow.md +237 -237
- package/vibe/rules/standards/naming-conventions.md +198 -198
- package/vibe/rules/standards/security.md +305 -305
- package/vibe/rules/writing/document-style.md +74 -74
- package/vibe/setup.sh +31 -31
- package/vibe/templates/constitution-template.md +252 -252
- package/vibe/templates/contract-backend-template.md +526 -526
- package/vibe/templates/contract-frontend-template.md +599 -599
- package/vibe/templates/feature-template.md +96 -96
- package/vibe/templates/spec-template.md +221 -221
- package/vibe/ui-ux-data/charts.csv +26 -26
- package/vibe/ui-ux-data/colors.csv +97 -97
- package/vibe/ui-ux-data/icons.csv +101 -101
- package/vibe/ui-ux-data/landing.csv +31 -31
- package/vibe/ui-ux-data/products.csv +96 -96
- package/vibe/ui-ux-data/react-performance.csv +45 -45
- package/vibe/ui-ux-data/stacks/astro.csv +54 -54
- package/vibe/ui-ux-data/stacks/flutter.csv +53 -53
- package/vibe/ui-ux-data/stacks/html-tailwind.csv +56 -56
- package/vibe/ui-ux-data/stacks/jetpack-compose.csv +53 -53
- package/vibe/ui-ux-data/stacks/nextjs.csv +53 -53
- package/vibe/ui-ux-data/stacks/nuxt-ui.csv +51 -51
- package/vibe/ui-ux-data/stacks/nuxtjs.csv +59 -59
- package/vibe/ui-ux-data/stacks/react-native.csv +52 -52
- package/vibe/ui-ux-data/stacks/react.csv +54 -54
- package/vibe/ui-ux-data/stacks/shadcn.csv +61 -61
- package/vibe/ui-ux-data/stacks/svelte.csv +54 -54
- package/vibe/ui-ux-data/stacks/swiftui.csv +51 -51
- package/vibe/ui-ux-data/stacks/vue.csv +50 -50
- package/vibe/ui-ux-data/styles.csv +68 -68
- package/vibe/ui-ux-data/typography.csv +57 -57
- package/vibe/ui-ux-data/ui-reasoning.csv +101 -101
- package/vibe/ui-ux-data/ux-guidelines.csv +99 -99
- package/vibe/ui-ux-data/version.json +31 -31
- package/vibe/ui-ux-data/web-interface.csv +31 -31
|
@@ -17,45 +17,45 @@ export function createResearchTasks(feature, techStack = []) {
|
|
|
17
17
|
{
|
|
18
18
|
name: 'best-practices-agent',
|
|
19
19
|
category: 'best-practices',
|
|
20
|
-
prompt: `Research best practices for implementing "${feature}" with ${stackStr}. Focus on:
|
|
21
|
-
1. Industry-standard patterns
|
|
22
|
-
2. Common pitfalls to avoid
|
|
23
|
-
3. Recommended libraries/tools
|
|
24
|
-
4. Testing strategies
|
|
25
|
-
|
|
20
|
+
prompt: `Research best practices for implementing "${feature}" with ${stackStr}. Focus on:
|
|
21
|
+
1. Industry-standard patterns
|
|
22
|
+
2. Common pitfalls to avoid
|
|
23
|
+
3. Recommended libraries/tools
|
|
24
|
+
4. Testing strategies
|
|
25
|
+
|
|
26
26
|
Provide actionable recommendations.`
|
|
27
27
|
},
|
|
28
28
|
{
|
|
29
29
|
name: 'framework-docs-agent',
|
|
30
30
|
category: 'framework-docs',
|
|
31
|
-
prompt: `Find the latest documentation for ${stackStr} related to "${feature}". Include:
|
|
32
|
-
1. Official API references
|
|
33
|
-
2. Configuration options
|
|
34
|
-
3. Migration guides if applicable
|
|
35
|
-
4. Code examples from official docs
|
|
36
|
-
|
|
31
|
+
prompt: `Find the latest documentation for ${stackStr} related to "${feature}". Include:
|
|
32
|
+
1. Official API references
|
|
33
|
+
2. Configuration options
|
|
34
|
+
3. Migration guides if applicable
|
|
35
|
+
4. Code examples from official docs
|
|
36
|
+
|
|
37
37
|
Use context7 MCP if available for up-to-date documentation.`
|
|
38
38
|
},
|
|
39
39
|
{
|
|
40
40
|
name: 'codebase-patterns-agent',
|
|
41
41
|
category: 'codebase-patterns',
|
|
42
|
-
prompt: `Analyze the current codebase for patterns related to "${feature}". Look for:
|
|
43
|
-
1. Similar existing implementations
|
|
44
|
-
2. Established conventions
|
|
45
|
-
3. Reusable utilities
|
|
46
|
-
4. Potential conflicts or dependencies
|
|
47
|
-
|
|
42
|
+
prompt: `Analyze the current codebase for patterns related to "${feature}". Look for:
|
|
43
|
+
1. Similar existing implementations
|
|
44
|
+
2. Established conventions
|
|
45
|
+
3. Reusable utilities
|
|
46
|
+
4. Potential conflicts or dependencies
|
|
47
|
+
|
|
48
48
|
Use Glob and Grep to search the codebase.`
|
|
49
49
|
},
|
|
50
50
|
{
|
|
51
51
|
name: 'security-advisory-agent',
|
|
52
52
|
category: 'security-advisory',
|
|
53
|
-
prompt: `Review security considerations for "${feature}" with ${stackStr}. Check:
|
|
54
|
-
1. OWASP Top 10 relevance
|
|
55
|
-
2. Authentication/authorization requirements
|
|
56
|
-
3. Data validation needs
|
|
57
|
-
4. Known vulnerabilities in dependencies
|
|
58
|
-
|
|
53
|
+
prompt: `Review security considerations for "${feature}" with ${stackStr}. Check:
|
|
54
|
+
1. OWASP Top 10 relevance
|
|
55
|
+
2. Authentication/authorization requirements
|
|
56
|
+
3. Data validation needs
|
|
57
|
+
4. Known vulnerabilities in dependencies
|
|
58
|
+
|
|
59
59
|
Provide security recommendations.`
|
|
60
60
|
}
|
|
61
61
|
];
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 공유 테스트 헬퍼 — 모든 테스트에서 재사용 가능한 유틸리티
|
|
3
|
+
*/
|
|
4
|
+
/** 고유한 임시 테스트 디렉토리 생성 */
|
|
5
|
+
export declare function createTempDir(prefix?: string): string;
|
|
6
|
+
/** 임시 디렉토리 정리 (afterEach에서 사용) */
|
|
7
|
+
export declare function cleanupTempDir(dir: string): void;
|
|
8
|
+
export interface TestVibeConfig {
|
|
9
|
+
stackTypes: string[];
|
|
10
|
+
capabilities: string[];
|
|
11
|
+
projectName?: string;
|
|
12
|
+
details?: string;
|
|
13
|
+
}
|
|
14
|
+
/** 테스트용 vibe 프로젝트 설정 생성 */
|
|
15
|
+
export declare function createTestConfig(overrides?: Partial<TestVibeConfig>): TestVibeConfig;
|
|
16
|
+
/** 디스크에 테스트 설정 파일 생성 */
|
|
17
|
+
export declare function writeTestConfig(dir: string, config?: Partial<TestVibeConfig>): string;
|
|
18
|
+
export interface TestSkillOptions {
|
|
19
|
+
name: string;
|
|
20
|
+
description?: string;
|
|
21
|
+
triggers?: string[];
|
|
22
|
+
priority?: number;
|
|
23
|
+
body?: string;
|
|
24
|
+
}
|
|
25
|
+
/** 테스트용 SKILL.md 생성 */
|
|
26
|
+
export declare function createTestSkill(dir: string, options: TestSkillOptions): string;
|
|
27
|
+
/** JSONL 파일에서 이벤트 파싱 */
|
|
28
|
+
export declare function parseJsonl<T = Record<string, unknown>>(content: string): T[];
|
|
29
|
+
/** 지정 시간(ms) 대기 */
|
|
30
|
+
export declare function sleep(ms: number): Promise<void>;
|
|
31
|
+
/** 함수 실행 시간 측정 (ms) */
|
|
32
|
+
export declare function measureTime<T>(fn: () => T | Promise<T>): Promise<{
|
|
33
|
+
result: T;
|
|
34
|
+
durationMs: number;
|
|
35
|
+
}>;
|
|
36
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/test-helpers/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAQH,yBAAyB;AACzB,wBAAgB,aAAa,CAAC,MAAM,SAAc,GAAG,MAAM,CAI1D;AAED,kCAAkC;AAClC,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAQhD;AAID,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,2BAA2B;AAC3B,wBAAgB,gBAAgB,CAAC,SAAS,GAAE,OAAO,CAAC,cAAc,CAAM,GAAG,cAAc,CAQxF;AAED,wBAAwB;AACxB,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,GAAG,MAAM,CAMrF;AAID,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,uBAAuB;AACvB,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,gBAAgB,GAAG,MAAM,CAqB9E;AAID,wBAAwB;AACxB,wBAAgB,UAAU,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,EAAE,MAAM,GAAG,CAAC,EAAE,CAM5E;AAID,mBAAmB;AACnB,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE/C;AAED,uBAAuB;AACvB,wBAAsB,WAAW,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,CAAC,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC,CAKzG"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 공유 테스트 헬퍼 — 모든 테스트에서 재사용 가능한 유틸리티
|
|
3
|
+
*/
|
|
4
|
+
import { rmSync, mkdirSync, writeFileSync, existsSync } from 'fs';
|
|
5
|
+
import { join } from 'path';
|
|
6
|
+
import { tmpdir } from 'os';
|
|
7
|
+
// ─── 임시 디렉토리 관리 ───
|
|
8
|
+
/** 고유한 임시 테스트 디렉토리 생성 */
|
|
9
|
+
export function createTempDir(prefix = 'vibe-test') {
|
|
10
|
+
const dir = join(tmpdir(), `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
11
|
+
mkdirSync(dir, { recursive: true });
|
|
12
|
+
return dir;
|
|
13
|
+
}
|
|
14
|
+
/** 임시 디렉토리 정리 (afterEach에서 사용) */
|
|
15
|
+
export function cleanupTempDir(dir) {
|
|
16
|
+
try {
|
|
17
|
+
if (existsSync(dir)) {
|
|
18
|
+
rmSync(dir, { recursive: true, force: true });
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
// Ignore cleanup errors on Windows (file locking)
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/** 테스트용 vibe 프로젝트 설정 생성 */
|
|
26
|
+
export function createTestConfig(overrides = {}) {
|
|
27
|
+
return {
|
|
28
|
+
stackTypes: ['typescript-react'],
|
|
29
|
+
capabilities: [],
|
|
30
|
+
projectName: 'test-project',
|
|
31
|
+
details: 'Test project for unit tests',
|
|
32
|
+
...overrides,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/** 디스크에 테스트 설정 파일 생성 */
|
|
36
|
+
export function writeTestConfig(dir, config) {
|
|
37
|
+
const configDir = join(dir, '.claude', 'vibe');
|
|
38
|
+
mkdirSync(configDir, { recursive: true });
|
|
39
|
+
const configPath = join(configDir, 'config.json');
|
|
40
|
+
writeFileSync(configPath, JSON.stringify(createTestConfig(config), null, 2));
|
|
41
|
+
return configPath;
|
|
42
|
+
}
|
|
43
|
+
/** 테스트용 SKILL.md 생성 */
|
|
44
|
+
export function createTestSkill(dir, options) {
|
|
45
|
+
const skillDir = join(dir, options.name);
|
|
46
|
+
mkdirSync(skillDir, { recursive: true });
|
|
47
|
+
const frontmatter = [
|
|
48
|
+
'---',
|
|
49
|
+
`name: ${options.name}`,
|
|
50
|
+
`description: "${options.description ?? `Test skill ${options.name}`}"`,
|
|
51
|
+
];
|
|
52
|
+
if (options.triggers) {
|
|
53
|
+
frontmatter.push(`triggers: [${options.triggers.join(', ')}]`);
|
|
54
|
+
}
|
|
55
|
+
if (options.priority !== undefined) {
|
|
56
|
+
frontmatter.push(`priority: ${options.priority}`);
|
|
57
|
+
}
|
|
58
|
+
frontmatter.push('---');
|
|
59
|
+
const content = frontmatter.join('\n') + '\n\n' + (options.body ?? `# ${options.name}\n\nTest skill content.\n`);
|
|
60
|
+
const filePath = join(skillDir, 'SKILL.md');
|
|
61
|
+
writeFileSync(filePath, content);
|
|
62
|
+
return filePath;
|
|
63
|
+
}
|
|
64
|
+
// ─── JSONL 헬퍼 ───
|
|
65
|
+
/** JSONL 파일에서 이벤트 파싱 */
|
|
66
|
+
export function parseJsonl(content) {
|
|
67
|
+
return content
|
|
68
|
+
.trim()
|
|
69
|
+
.split('\n')
|
|
70
|
+
.filter(line => line.trim().length > 0)
|
|
71
|
+
.map(line => JSON.parse(line));
|
|
72
|
+
}
|
|
73
|
+
// ─── 타이밍 유틸 ───
|
|
74
|
+
/** 지정 시간(ms) 대기 */
|
|
75
|
+
export function sleep(ms) {
|
|
76
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
77
|
+
}
|
|
78
|
+
/** 함수 실행 시간 측정 (ms) */
|
|
79
|
+
export async function measureTime(fn) {
|
|
80
|
+
const start = performance.now();
|
|
81
|
+
const result = await fn();
|
|
82
|
+
const durationMs = Math.round(performance.now() - start);
|
|
83
|
+
return { result, durationMs };
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/test-helpers/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../../src/test-helpers/index.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { describe, it, expect, afterEach } from 'vitest';
|
|
2
|
+
import { existsSync, readFileSync } from 'fs';
|
|
3
|
+
import { createTempDir, cleanupTempDir, createTestConfig, writeTestConfig, createTestSkill, parseJsonl, measureTime, } from './index.js';
|
|
4
|
+
describe('test-helpers', () => {
|
|
5
|
+
const dirs = [];
|
|
6
|
+
afterEach(() => {
|
|
7
|
+
for (const dir of dirs)
|
|
8
|
+
cleanupTempDir(dir);
|
|
9
|
+
dirs.length = 0;
|
|
10
|
+
});
|
|
11
|
+
describe('createTempDir / cleanupTempDir', () => {
|
|
12
|
+
it('should create a unique temporary directory', () => {
|
|
13
|
+
const dir = createTempDir();
|
|
14
|
+
dirs.push(dir);
|
|
15
|
+
expect(existsSync(dir)).toBe(true);
|
|
16
|
+
expect(dir).toContain('vibe-test');
|
|
17
|
+
});
|
|
18
|
+
it('should accept custom prefix', () => {
|
|
19
|
+
const dir = createTempDir('custom-prefix');
|
|
20
|
+
dirs.push(dir);
|
|
21
|
+
expect(dir).toContain('custom-prefix');
|
|
22
|
+
});
|
|
23
|
+
it('should cleanup directory', () => {
|
|
24
|
+
const dir = createTempDir();
|
|
25
|
+
expect(existsSync(dir)).toBe(true);
|
|
26
|
+
cleanupTempDir(dir);
|
|
27
|
+
expect(existsSync(dir)).toBe(false);
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
describe('createTestConfig', () => {
|
|
31
|
+
it('should return default config', () => {
|
|
32
|
+
const config = createTestConfig();
|
|
33
|
+
expect(config.stackTypes).toEqual(['typescript-react']);
|
|
34
|
+
expect(config.capabilities).toEqual([]);
|
|
35
|
+
expect(config.projectName).toBe('test-project');
|
|
36
|
+
});
|
|
37
|
+
it('should accept overrides', () => {
|
|
38
|
+
const config = createTestConfig({ stackTypes: ['python-django'], capabilities: ['commerce'] });
|
|
39
|
+
expect(config.stackTypes).toEqual(['python-django']);
|
|
40
|
+
expect(config.capabilities).toEqual(['commerce']);
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
describe('writeTestConfig', () => {
|
|
44
|
+
it('should write config file to disk', () => {
|
|
45
|
+
const dir = createTempDir();
|
|
46
|
+
dirs.push(dir);
|
|
47
|
+
const configPath = writeTestConfig(dir, { projectName: 'my-project' });
|
|
48
|
+
expect(existsSync(configPath)).toBe(true);
|
|
49
|
+
const content = JSON.parse(readFileSync(configPath, 'utf-8'));
|
|
50
|
+
expect(content.projectName).toBe('my-project');
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
describe('createTestSkill', () => {
|
|
54
|
+
it('should create SKILL.md with frontmatter', () => {
|
|
55
|
+
const dir = createTempDir();
|
|
56
|
+
dirs.push(dir);
|
|
57
|
+
const skillPath = createTestSkill(dir, {
|
|
58
|
+
name: 'test-skill',
|
|
59
|
+
description: 'A test skill',
|
|
60
|
+
triggers: ['test', 'demo'],
|
|
61
|
+
priority: 50,
|
|
62
|
+
});
|
|
63
|
+
expect(existsSync(skillPath)).toBe(true);
|
|
64
|
+
const content = readFileSync(skillPath, 'utf-8');
|
|
65
|
+
expect(content).toContain('name: test-skill');
|
|
66
|
+
expect(content).toContain('triggers: [test, demo]');
|
|
67
|
+
expect(content).toContain('priority: 50');
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
describe('parseJsonl', () => {
|
|
71
|
+
it('should parse JSONL content', () => {
|
|
72
|
+
const content = '{"a":1}\n{"a":2}\n{"a":3}\n';
|
|
73
|
+
const result = parseJsonl(content);
|
|
74
|
+
expect(result).toHaveLength(3);
|
|
75
|
+
expect(result[0].a).toBe(1);
|
|
76
|
+
expect(result[2].a).toBe(3);
|
|
77
|
+
});
|
|
78
|
+
it('should skip empty lines', () => {
|
|
79
|
+
const content = '{"a":1}\n\n{"a":2}\n';
|
|
80
|
+
const result = parseJsonl(content);
|
|
81
|
+
expect(result).toHaveLength(2);
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
describe('measureTime', () => {
|
|
85
|
+
it('should measure sync function duration', async () => {
|
|
86
|
+
const { result, durationMs } = await measureTime(() => 42);
|
|
87
|
+
expect(result).toBe(42);
|
|
88
|
+
expect(durationMs).toBeGreaterThanOrEqual(0);
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
//# sourceMappingURL=index.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.test.js","sourceRoot":"","sources":["../../src/test-helpers/index.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,10 +4,10 @@ import { analyzeComplexity } from './analyzeComplexity.js';
|
|
|
4
4
|
describe('analyzeComplexity', () => {
|
|
5
5
|
describe('code analysis', () => {
|
|
6
6
|
it('should analyze simple code', async () => {
|
|
7
|
-
const code = `
|
|
8
|
-
function add(a, b) {
|
|
9
|
-
return a + b;
|
|
10
|
-
}
|
|
7
|
+
const code = `
|
|
8
|
+
function add(a, b) {
|
|
9
|
+
return a + b;
|
|
10
|
+
}
|
|
11
11
|
`;
|
|
12
12
|
const result = await analyzeComplexity({ code });
|
|
13
13
|
expect(result.content).toBeDefined();
|
|
@@ -15,70 +15,70 @@ function add(a, b) {
|
|
|
15
15
|
expect(result.content[0].text).toContain('Complexity');
|
|
16
16
|
});
|
|
17
17
|
it('should detect high cyclomatic complexity', async () => {
|
|
18
|
-
const code = `
|
|
19
|
-
function complex(a, b, c, d) {
|
|
20
|
-
if (a > 0) {
|
|
21
|
-
if (b > 0) {
|
|
22
|
-
if (c > 0) {
|
|
23
|
-
if (d > 0) {
|
|
24
|
-
for (let i = 0; i < 10; i++) {
|
|
25
|
-
while (true) {
|
|
26
|
-
switch (i) {
|
|
27
|
-
case 1: break;
|
|
28
|
-
case 2: break;
|
|
29
|
-
case 3: break;
|
|
30
|
-
}
|
|
31
|
-
break;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
}
|
|
18
|
+
const code = `
|
|
19
|
+
function complex(a, b, c, d) {
|
|
20
|
+
if (a > 0) {
|
|
21
|
+
if (b > 0) {
|
|
22
|
+
if (c > 0) {
|
|
23
|
+
if (d > 0) {
|
|
24
|
+
for (let i = 0; i < 10; i++) {
|
|
25
|
+
while (true) {
|
|
26
|
+
switch (i) {
|
|
27
|
+
case 1: break;
|
|
28
|
+
case 2: break;
|
|
29
|
+
case 3: break;
|
|
30
|
+
}
|
|
31
|
+
break;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
39
|
`;
|
|
40
40
|
const result = await analyzeComplexity({ code });
|
|
41
41
|
expect(result.content[0].text).toContain('Complexity');
|
|
42
42
|
// High complexity code should have lower score or issues
|
|
43
43
|
});
|
|
44
44
|
it('should calculate cyclomatic metrics only', async () => {
|
|
45
|
-
const code = `
|
|
46
|
-
function test() {
|
|
47
|
-
if (true) return 1;
|
|
48
|
-
return 0;
|
|
49
|
-
}
|
|
45
|
+
const code = `
|
|
46
|
+
function test() {
|
|
47
|
+
if (true) return 1;
|
|
48
|
+
return 0;
|
|
49
|
+
}
|
|
50
50
|
`;
|
|
51
51
|
const result = await analyzeComplexity({ code, metrics: 'cyclomatic' });
|
|
52
52
|
expect(result.content[0].text).toContain('Complexity');
|
|
53
53
|
});
|
|
54
54
|
it('should calculate cognitive metrics only', async () => {
|
|
55
|
-
const code = `
|
|
56
|
-
function test() {
|
|
57
|
-
if (true) {
|
|
58
|
-
for (let i = 0; i < 10; i++) {
|
|
59
|
-
console.log(i);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
55
|
+
const code = `
|
|
56
|
+
function test() {
|
|
57
|
+
if (true) {
|
|
58
|
+
for (let i = 0; i < 10; i++) {
|
|
59
|
+
console.log(i);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
63
|
`;
|
|
64
64
|
const result = await analyzeComplexity({ code, metrics: 'cognitive' });
|
|
65
65
|
expect(result.content[0].text).toContain('Complexity');
|
|
66
66
|
});
|
|
67
67
|
it('should calculate halstead metrics only', async () => {
|
|
68
|
-
const code = `
|
|
69
|
-
const x = 1 + 2 * 3 - 4 / 5;
|
|
68
|
+
const code = `
|
|
69
|
+
const x = 1 + 2 * 3 - 4 / 5;
|
|
70
70
|
`;
|
|
71
71
|
const result = await analyzeComplexity({ code, metrics: 'halstead' });
|
|
72
72
|
expect(result.content[0].text).toContain('Complexity');
|
|
73
73
|
});
|
|
74
74
|
it('should calculate all metrics', async () => {
|
|
75
|
-
const code = `
|
|
76
|
-
function calculate(a, b) {
|
|
77
|
-
if (a > b) {
|
|
78
|
-
return a - b;
|
|
79
|
-
}
|
|
80
|
-
return b - a;
|
|
81
|
-
}
|
|
75
|
+
const code = `
|
|
76
|
+
function calculate(a, b) {
|
|
77
|
+
if (a > b) {
|
|
78
|
+
return a - b;
|
|
79
|
+
}
|
|
80
|
+
return b - a;
|
|
81
|
+
}
|
|
82
82
|
`;
|
|
83
83
|
const result = await analyzeComplexity({ code, metrics: 'all' });
|
|
84
84
|
expect(result.content[0].text).toContain('Complexity');
|
|
@@ -102,18 +102,18 @@ function calculate(a, b) {
|
|
|
102
102
|
});
|
|
103
103
|
describe('Python code detection', () => {
|
|
104
104
|
it('should detect and analyze Python code', async () => {
|
|
105
|
-
const pythonCode = `
|
|
106
|
-
def calculate(a, b):
|
|
107
|
-
if a > b:
|
|
108
|
-
return a - b
|
|
109
|
-
return b - a
|
|
110
|
-
|
|
111
|
-
class Calculator:
|
|
112
|
-
def __init__(self):
|
|
113
|
-
self.value = 0
|
|
114
|
-
|
|
115
|
-
def add(self, x):
|
|
116
|
-
self.value += x
|
|
105
|
+
const pythonCode = `
|
|
106
|
+
def calculate(a, b):
|
|
107
|
+
if a > b:
|
|
108
|
+
return a - b
|
|
109
|
+
return b - a
|
|
110
|
+
|
|
111
|
+
class Calculator:
|
|
112
|
+
def __init__(self):
|
|
113
|
+
self.value = 0
|
|
114
|
+
|
|
115
|
+
def add(self, x):
|
|
116
|
+
self.value += x
|
|
117
117
|
`;
|
|
118
118
|
const result = await analyzeComplexity({ code: pythonCode });
|
|
119
119
|
expect(result.content[0].text).toContain('Python');
|
|
@@ -121,34 +121,34 @@ class Calculator:
|
|
|
121
121
|
});
|
|
122
122
|
describe('score calculation', () => {
|
|
123
123
|
it('should give high score for simple code', async () => {
|
|
124
|
-
const simpleCode = `
|
|
125
|
-
function simple() {
|
|
126
|
-
return 42;
|
|
127
|
-
}
|
|
124
|
+
const simpleCode = `
|
|
125
|
+
function simple() {
|
|
126
|
+
return 42;
|
|
127
|
+
}
|
|
128
128
|
`;
|
|
129
129
|
const result = await analyzeComplexity({ code: simpleCode });
|
|
130
130
|
// Simple code should have good score
|
|
131
131
|
expect(result.content[0].text).toContain('Score');
|
|
132
132
|
});
|
|
133
133
|
it('should give lower score for complex code', async () => {
|
|
134
|
-
const complexCode = `
|
|
135
|
-
function veryComplex(a, b, c, d, e, f, g, h) {
|
|
136
|
-
if (a && b || c && d || e && f || g && h) {
|
|
137
|
-
for (let i = 0; i < 10; i++) {
|
|
138
|
-
for (let j = 0; j < 10; j++) {
|
|
139
|
-
if (i > j) {
|
|
140
|
-
switch (i) {
|
|
141
|
-
case 1: break;
|
|
142
|
-
case 2: break;
|
|
143
|
-
case 3: break;
|
|
144
|
-
case 4: break;
|
|
145
|
-
case 5: break;
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
}
|
|
134
|
+
const complexCode = `
|
|
135
|
+
function veryComplex(a, b, c, d, e, f, g, h) {
|
|
136
|
+
if (a && b || c && d || e && f || g && h) {
|
|
137
|
+
for (let i = 0; i < 10; i++) {
|
|
138
|
+
for (let j = 0; j < 10; j++) {
|
|
139
|
+
if (i > j) {
|
|
140
|
+
switch (i) {
|
|
141
|
+
case 1: break;
|
|
142
|
+
case 2: break;
|
|
143
|
+
case 3: break;
|
|
144
|
+
case 4: break;
|
|
145
|
+
case 5: break;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
152
|
`;
|
|
153
153
|
const result = await analyzeComplexity({ code: complexCode });
|
|
154
154
|
expect(result.content[0].text).toContain('Score');
|
|
@@ -157,46 +157,46 @@ function veryComplex(a, b, c, d, e, f, g, h) {
|
|
|
157
157
|
});
|
|
158
158
|
describe('TypeScript code analysis', () => {
|
|
159
159
|
it('should analyze TypeScript code', async () => {
|
|
160
|
-
const tsCode = `
|
|
161
|
-
interface User {
|
|
162
|
-
name: string;
|
|
163
|
-
age: number;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
function greet(user: User): string {
|
|
167
|
-
if (user.age > 18) {
|
|
168
|
-
return \`Hello, \${user.name}!\`;
|
|
169
|
-
}
|
|
170
|
-
return 'Hello!';
|
|
171
|
-
}
|
|
160
|
+
const tsCode = `
|
|
161
|
+
interface User {
|
|
162
|
+
name: string;
|
|
163
|
+
age: number;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function greet(user: User): string {
|
|
167
|
+
if (user.age > 18) {
|
|
168
|
+
return \`Hello, \${user.name}!\`;
|
|
169
|
+
}
|
|
170
|
+
return 'Hello!';
|
|
171
|
+
}
|
|
172
172
|
`;
|
|
173
173
|
const result = await analyzeComplexity({ code: tsCode });
|
|
174
174
|
expect(result.content[0].text).toContain('Complexity');
|
|
175
175
|
});
|
|
176
176
|
it('should handle class definitions', async () => {
|
|
177
177
|
// Use explicit TypeScript syntax that won't be mistaken for Python
|
|
178
|
-
const tsCode = `
|
|
179
|
-
// TypeScript class
|
|
180
|
-
export class Calculator {
|
|
181
|
-
private value: number = 0;
|
|
182
|
-
|
|
183
|
-
public add(x: number): this {
|
|
184
|
-
this.value += x;
|
|
185
|
-
return this;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
public subtract(x: number): this {
|
|
189
|
-
if (x > this.value) {
|
|
190
|
-
throw new Error('Cannot be negative');
|
|
191
|
-
}
|
|
192
|
-
this.value -= x;
|
|
193
|
-
return this;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
public getValue(): number {
|
|
197
|
-
return this.value;
|
|
198
|
-
}
|
|
199
|
-
}
|
|
178
|
+
const tsCode = `
|
|
179
|
+
// TypeScript class
|
|
180
|
+
export class Calculator {
|
|
181
|
+
private value: number = 0;
|
|
182
|
+
|
|
183
|
+
public add(x: number): this {
|
|
184
|
+
this.value += x;
|
|
185
|
+
return this;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
public subtract(x: number): this {
|
|
189
|
+
if (x > this.value) {
|
|
190
|
+
throw new Error('Cannot be negative');
|
|
191
|
+
}
|
|
192
|
+
this.value -= x;
|
|
193
|
+
return this;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
public getValue(): number {
|
|
197
|
+
return this.value;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
200
|
`;
|
|
201
201
|
const result = await analyzeComplexity({ code: tsCode });
|
|
202
202
|
// Should analyze as TypeScript, not Python
|