@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
|
@@ -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":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AAkCxB,yBAAyB;AAEzB,MAAM,OAAO,cAAc;IACR,OAAO,CAAS;IAChB,OAAO,CAAU;IAElC,YAAY,YAAoB,EAAE,OAAO,GAAG,IAAI;QAC9C,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,mBAAmB,CAAC,CAAC;QAC5D,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QAEvB,IAAI,OAAO,EAAE,CAAC;YACZ,EAAE,CAAC,SAAS,CAAC,YAAY,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAClD,CAAC;IACH,CAAC;IAED,mBAAmB;IACnB,GAAG,CAAC,KAA0C;QAC5C,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO;QAE1B,MAAM,SAAS,GAAe;YAC5B,CAAC,EAAE,CAAC;YACJ,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YAC5B,EAAE,EAAE,OAAO,CAAC,QAAQ;YACpB,GAAG,KAAK;SACT,CAAC;QAEF,IAAI,CAAC;YACH,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,CAAC;QACpE,CAAC;QAAC,MAAM,CAAC;YACP,sDAAsD;QACxD,CAAC;IACH,CAAC;IAED,0BAA0B;IAC1B,UAAU,CAAC,KAAa,EAAE,SAAwB,EAAE,WAAmB;QACrE,IAAI,CAAC,GAAG,CAAC;YACP,UAAU,EAAE,WAAW;YACvB,KAAK;YACL,UAAU,EAAE,SAAS;YACrB,OAAO,EAAE,SAAS;YAClB,YAAY,EAAE,WAAW;SAC1B,CAAC,CAAC;IACL,CAAC;IAED,0BAA0B;IAC1B,QAAQ,CAAC,KAAa,EAAE,SAAwB,EAAE,WAAmB;QACnE,IAAI,CAAC,GAAG,CAAC;YACP,UAAU,EAAE,WAAW;YACvB,KAAK;YACL,UAAU,EAAE,SAAS;YACrB,OAAO,EAAE,OAAO;YAChB,YAAY,EAAE,WAAW;SAC1B,CAAC,CAAC;IACL,CAAC;IAED,gBAAgB;IAChB,OAAO;QACL,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC;YAAE,OAAO,EAAE,CAAC;QAE5C,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YACvD,OAAO,OAAO;iBACX,IAAI,EAAE;iBACN,KAAK,CAAC,IAAI,CAAC;iBACX,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;iBACtC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAe,CAAC,CAAC;QACjD,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;IAED,gBAAgB;IAChB,SAAS;QACP,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;QAC9B,MAAM,GAAG,GAAG,IAAI,GAAG,EAOf,CAAC;QAEL,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,IAAI,KAAK,CAAC,UAAU,KAAK,WAAW;gBAAE,SAAS;YAE/C,MAAM,QAAQ,GAAG,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI;gBACvC,KAAK,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC;gBACxC,aAAa,EAAE,CAAC,EAAE,aAAa,EAAE,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,EAAE;aACvD,CAAC;YAEF,QAAQ,CAAC,KAAK,EAAE,CAAC;YACjB,IAAI,KAAK,CAAC,OAAO,KAAK,SAAS;gBAAE,QAAQ,CAAC,YAAY,EAAE,CAAC;YACzD,IAAI,KAAK,CAAC,OAAO,KAAK,OAAO;gBAAE,QAAQ,CAAC,UAAU,EAAE,CAAC;YACrD,IAAI,KAAK,CAAC,UAAU,KAAK,IAAI,EAAE,CAAC;gBAC9B,QAAQ,CAAC,aAAa,IAAI,KAAK,CAAC,UAAU,CAAC;gBAC3C,QAAQ,CAAC,aAAa,EAAE,CAAC;YAC3B,CAAC;YACD,IAAI,KAAK,CAAC,EAAE,GAAG,QAAQ,CAAC,QAAQ;gBAAE,QAAQ,CAAC,QAAQ,GAAG,KAAK,CAAC,EAAE,CAAC;YAE/D,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;QACjC,CAAC;QAED,OAAO,CAAC,GAAG,GAAG,CAAC,OAAO,EAAE,CAAC;aACtB,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;YACvB,KAAK;YACL,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,YAAY,EAAE,IAAI,CAAC,YAAY;YAC/B,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,YAAY,EAAE,IAAI,CAAC,aAAa,GAAG,CAAC;gBAClC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE;gBACjE,CAAC,CAAC,IAAI;YACR,QAAQ,EAAE,IAAI,CAAC,QAAQ;SACxB,CAAC,CAAC;aACF,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;IACvC,CAAC;IAED,eAAe;IACf,UAAU;QACR,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;CACF"}
|
|
@@ -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
|
});
|