claude-cli-analytics 0.0.1 → 0.0.5

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/README.md CHANGED
@@ -4,8 +4,9 @@ Claude CLI 대화 로그를 분석하여 토큰 효율성, 캐시 활용률, 컨
4
4
 
5
5
  ## ✨ Features
6
6
 
7
- - 📊 **Dashboard**: 전체 효율성 지표, 토큰 분포, 트렌드 차트
8
- - 📝 **Session Detail**: 세션별 대화 타임라인, 질문별 읽은 컨텍스트 로그
7
+ - 📊 **Dashboard**: Anthropic 스킬 평가 프레임워크 기반 지표, 토큰 분포, 트렌드 차트
8
+ - 📝 **Session Detail**: 세션별 대화 타임라인, 도구 사용 내역, 6카테고리 지표 패널
9
+ - 💬 **대화형 도구 표시**: AskUserQuestion 등 대화형 도구의 Q&A 내용을 카드로 표시
9
10
  - 🔄 **Real-time Refresh**: 새로고침 버튼으로 최신 데이터 로드
10
11
  - 🏆 **Engineering Grade**: S/A/B/C 등급 + SEI (Spec Efficiency Index) 분석
11
12
  - 🔍 **Auto-detection**: `.claude/projects` 경로 자동 탐색 — init 불필요
@@ -32,7 +33,7 @@ npx claude-cli-analytics
32
33
  ### 🛠️ 소스에서 빌드 (기여용)
33
34
 
34
35
  ```bash
35
- git clone https://github.com/igeunpyo/claude-analytics.git
36
+ git clone https://github.com/rootTiket/claude-analytics.git
36
37
  cd claude-analytics
37
38
  npm install
38
39
  npm run build
@@ -54,9 +55,38 @@ npm run dev
54
55
 
55
56
  ## 🛠️ Requirements
56
57
 
57
- - Node.js 18+ (권장: 20+)
58
+ - Node.js 20+
58
59
  - npm 9+
59
60
 
61
+ ## 🚀 사용법
62
+
63
+ ### 대시보드 시작
64
+ 기본적으로 **백그라운드 모드**로 실행됩니다:
65
+ ```bash
66
+ claude-cli-analytics
67
+ ```
68
+ 브라우저에서 `http://localhost:3001`이 자동으로 열리며, 서버는 백그라운드에서 실행됩니다.
69
+
70
+ ### 대시보드 중지
71
+ 백그라운드 프로세스를 중지합니다:
72
+ ```bash
73
+ claude-cli-analytics exit
74
+ ```
75
+
76
+ ### 상태 확인
77
+ 대시보드 실행 여부를 확인합니다:
78
+ ```bash
79
+ claude-cli-analytics status
80
+ ```
81
+
82
+ ### 옵션
83
+ ```bash
84
+ claude-cli-analytics --port 8080 # 커스텀 포트로 실행
85
+ claude-cli-analytics --path /foo # 커스텀 프로젝트 디렉토리
86
+ claude-cli-analytics --foreground # 포그라운드 실행 (Ctrl+C로 중지)
87
+ claude-cli-analytics --help # 도움말 표시
88
+ ```
89
+
60
90
  ## 🔍 .claude 경로 자동 탐색
61
91
 
62
92
  **별도의 `init` 과정이 필요 없습니다.** 서버 시작 시 자동으로 Claude Code의 데이터 디렉토리를 탐색합니다.
@@ -81,91 +111,149 @@ Claude Code는 설치 방법에 관계없이 항상 `~/.claude/projects`에 세
81
111
  ```bash
82
112
  # 환경변수로 지정
83
113
  CLAUDE_PROJECTS_DIR=/path/to/claude/projects claude-cli-analytics
114
+ ```
84
115
 
85
- # CLI 옵션으로 지정
86
- claude-cli-analytics --path /path/to/claude/projects
116
+ ## 📈 분석 지표 (Anthropic Skill Evaluation Framework)
87
117
 
88
- # 포트 변경
89
- claude-cli-analytics --port 8080
90
- ```
118
+ > Anthropic의 공식 스킬 평가 프레임워크를 기반으로 구성된 지표입니다.
91
119
 
92
- ## 📈 분석 지표
120
+ ---
93
121
 
94
- ### 1. 컨텍스트 지표
122
+ ### 📊 정량적 지표 (Quantitative Metrics)
95
123
 
96
- | 지표 | 계산 방식 | 의미 |
97
- |------|----------|------|
98
- | **평균 컨텍스트** | `(input_tokens + cache_read) / 요청수` | 요청당 평균 컨텍스트 크기 |
99
- | **위험 레벨** | `<20K: 안전, 20-50K: 주의, >50K: 위험` | 컨텍스트 과부하 경고 |
100
- | **리미트 영향도** | `(총 컨텍스트 / 44,000) × 100%` | Claude Pro 5시간 한도 대비 사용량 |
124
+ #### 1. 컨텍스트 자동 탐색 성공률 (Skill Trigger Rate)
101
125
 
102
- ### 2. 품질 지표
126
+ > *Anthropic 기준: 관련 쿼리의 90%에서 스킬이 트리거됨*
103
127
 
104
128
  | 지표 | 계산 방식 | 목표 | 의미 |
105
129
  |------|----------|------|------|
106
- | **중복 읽기율** | `(전체읽기 - 고유파일) / 전체읽기 × 100` | <20% | 같은 파일을 여러 번 읽은 비율 |
107
- | **Read/Edit 비율** | `Read도구 횟수 / Edit도구 횟수` | ≥5:1 | 수정 충분한 탐색 여부 |
108
- | **반복 수정율** | `(전체수정 - 고유파일) / 전체수정 × 100` | <20% | 같은 파일을 여러 번 수정한 비율 |
109
- | **수정당 토큰** | `총 컨텍스트 / Edit 횟수` | <50K | 수정 1회당 소비된 토큰 |
130
+ | **캐시 히트율** | `cache_read / (input + cache_read) × 100` | ≥ 70% | 스킬(컨텍스트)이 자동으로 로드된 비율 |
131
+ | **스펙 컨텍스트 활용률** | `spec 파일 읽은 세션 / 전체 세션 × 100` | ≥ 90% | `.claude/` 스펙이 자동 트리거된 비율 |
132
+ | **위험 레벨** | `<20K: 최적, 20-50K: 주의, >50K: 위험` | 최적 | 컨텍스트 과부하 경고 |
133
+ | **리미트 영향도** | `(총 컨텍스트 / 44,000) × 100%` | | Claude Pro 5시간 한도 대비 사용량 |
110
134
 
111
- ### 3. Engineering Grade (S/A/B/C)
135
+ **측정 방법**: 테스트 쿼리 10~20개를 실행하여, 자동으로 캐시 히트가 되는 비율과 스펙 컨텍스트가 로드되는 비율을 추적합니다.
112
136
 
113
- 100점 만점 종합 점수로 산출:
114
- - **Efficiency (40%)**: 캐시 히트율 기반
115
- - **Stability (30%)**: 도구 오류율 기반
116
- - **Precision (30%)**: Read/Edit 비율 기반
117
- - **Penalty**: 팬텀 파일 접근 횟수 × 5
137
+ #### 2. 도구 호출 효율성 (Tool Call Efficiency)
118
138
 
119
- ```
120
- 🏆 S급 (90+): Elite — 최적화된 워크플로우
121
- A급 (80+): Good 우수한 효율성
122
- ✅ B급 (60+): Average — 개선 여지 있음
123
- ⚠️ C급 (40+): Below Average 최적화 필요
124
- ```
139
+ > *Anthropic 기준: X도구 호출로 워크플로우 완료*
140
+
141
+ | 지표 | 계산 방식 | 목표 | 의미 |
142
+ |------|----------|------|------|
143
+ | **Read/Edit 비율** | `Read도구 횟수 / Edit도구 횟수` | ≥ 5:1 | 수정 충분한 탐색 여부 |
144
+ | **수정당 토큰** | `총 컨텍스트 / Edit 횟수` | < 50K | 수정 1회당 소비된 토큰 |
145
+ | **중복 읽기율** | `(전체읽기 - 고유파일) / 전체읽기 × 100` | < 20% | 불필요한 반복 읽기 비율 |
146
+ | **반복 수정율** | `(전체수정 - 고유파일) / 전체수정 × 100` | < 20% | 같은 파일 반복 수정 비율 |
147
+
148
+ **측정 방법**: 스킬(스펙 컨텍스트) 활성화 전후 동일 작업을 비교하여 도구 호출 횟수와 총 토큰 소비량을 집계합니다.
149
+
150
+ #### 3. API 실패율 (Failed API Calls per Workflow)
151
+
152
+ > *Anthropic 기준: 워크플로당 실패한 API 호출 0회*
125
153
 
126
- ### 4. Spec Efficiency Index (SEI)
154
+ | 지표 | 계산 방식 | 목표 | 의미 |
155
+ |------|----------|------|------|
156
+ | **도구 오류율** | `오류 도구 호출 / 전체 도구 호출 × 100` | 0% | 실패한 도구 호출 비율 |
157
+ | **오류 상세** | 도구별 오류 메시지 및 빈도 집계 | — | 재시도율 및 오류 코드 추적 |
158
+ | **세션 종료 유형** | `clean / forced / unknown` | clean | 비정상 종료 여부 |
159
+
160
+ **측정 방법**: 테스트 실행 중 도구 호출 로그를 모니터링하며, 재시도율 및 오류 코드를 추적합니다.
161
+
162
+ ---
163
+
164
+ ### 🎯 정성적 지표 (Qualitative Metrics)
165
+
166
+ #### 4. 사용자 개입 빈도 (User Intervention Frequency)
167
+
168
+ > *Anthropic 기준: 사용자가 Claude에게 다음 단계를 묻지 않아도 됨*
169
+
170
+ | 지표 | 계산 방식 | 목표 | 의미 |
171
+ |------|----------|------|------|
172
+ | **Human Turns** | 사용자 메시지(명령 포함) 횟수 | 최소화 | 사용자가 방향 전환/명확화한 횟수 |
173
+ | **Auto Turns** | 자동 실행된 턴 수 | 최대화 | 사용자 개입 없이 진행된 턴 수 |
174
+ | **HT/Edit 비율** | `Human Turns / Edit 횟수` | < 1.0 | 수정당 사용자 개입 빈도 |
175
+
176
+ **측정 방법**: 테스트 중 사용자가 방향을 전환하거나 명확히 설명해야 하는 빈도를 기록합니다.
177
+
178
+ #### 5. 워크플로우 자립 완료율 (Workflow Autonomy)
179
+
180
+ > *Anthropic 기준: 사용자 수정 없이 완료되는 워크플로우*
181
+
182
+ | 지표 | 계산 방식 | 목표 | 의미 |
183
+ |------|----------|------|------|
184
+ | **반복 수정율** | `(전체수정 - 고유파일) / 전체수정 × 100` | < 20% | 재작업 없이 완료된 비율 |
185
+ | **효율성 점수** | 캐시·오류·작업 효율 종합 (100점) | ≥ 80 | 워크플로우 자립 완성도 |
186
+ | **SEI** | `(Accuracy × 100) / log₁₀(Spec Volume + 1)` | — | 스펙 문서의 실효성 |
187
+
188
+ **측정 방법**: 동일 요청을 3~5회 실행하여 구조적 일관성과 품질 측면에서 출력을 비교합니다.
189
+
190
+ #### 6. 세션 간 일관성 (Cross-Session Consistency)
191
+
192
+ > *Anthropic 기준: 세션 간 일관된 결과*
193
+
194
+ | 지표 | 계산 방식 | 목표 | 의미 |
195
+ |------|----------|------|------|
196
+ | **Engineering Grade** | Efficiency(40%) + Stability(30%) + Precision(30%) - Penalty | S급 | 세션별 품질 등급 일관성 |
197
+ | **등급 분포** | S/A/B/C 세션 비율 | S·A ≥ 80% | 전체 세션의 품질 편차 |
198
+ | **스펙 유무 비교** | 스펙 있는 세션 vs 없는 세션 성과 차이 | — | 컨텍스트 효과의 일관성 |
199
+
200
+ **측정 방법**: 신규 사용자가 최소한의 안내만으로 첫 시도에서 작업을 완료할 수 있는지 평가합니다.
127
201
 
128
202
  ```
129
- SEI = (Accuracy × 100) / log₁₀(Spec Volume + 1)
203
+ 🏆 S급 (90+): Elite 최적화된 워크플로우, 일관된 고품질
204
+ ⭐ A급 (80+): Good — 우수한 효율성, 안정적 결과
205
+ ✅ B급 (60+): Average — 개선 여지 있음, 세션 간 편차 존재
206
+ ⚠️ C급 (40+): Below Average — 최적화 필요, 일관성 부족
130
207
  ```
131
208
 
132
- `.claude/` 컨텍스트 파일 읽기 후 오류율을 측정하여 스펙 문서의 실효성을 평가합니다.
133
-
134
209
  ## 🔧 API Endpoints
135
210
 
136
- | Endpoint | Description |
137
- |----------|-------------|
138
- | `GET /api/analytics` | 전체 요약 통계 |
139
- | `GET /api/sessions` | 세션 목록 (SEI + Grade 포함) |
140
- | `GET /api/sessions/:id` | 세션 상세 (메시지, 토큰, 파일) |
141
- | `GET /api/projects` | 프로젝트 목록 |
142
- | `GET /api/config` | 현재 설정 + 자동 탐색 결과 |
143
- | `GET /api/health` | 서버 상태 확인 |
144
- | `POST /api/refresh` | 데이터 새로고침 |
211
+ | Endpoint | Method | Description |
212
+ |----------|--------|-------------|
213
+ | `/api/analytics` | GET | 전체 요약 통계 |
214
+ | `/api/sessions` | GET | 세션 목록 (SEI + Grade 포함) |
215
+ | `/api/sessions/:id` | GET | 세션 상세 (메시지, 토큰, 파일) |
216
+ | `/api/projects` | GET | 프로젝트 목록 |
217
+ | `/api/config` | GET | 현재 설정 + 자동 탐색 결과 |
218
+ | `/api/config` | POST | 프로젝트 경로 설정 저장 |
219
+ | `/api/health` | GET | 서버 상태 확인 |
220
+ | `/api/refresh` | POST | 데이터 새로고침 |
145
221
 
146
222
  ## 📁 Project Structure
147
223
 
148
224
  ```
149
225
  claude-cli-analytics/
150
- ├── src/ # React Frontend
226
+ ├── src/ # React Frontend
151
227
  │ ├── pages/
152
- │ │ ├── Dashboard.tsx # 메인 대시보드
153
- │ │ └── SessionDetail.tsx # 세션 상세 페이지
154
- ├── App.tsx # 라우팅
155
- └── index.css # Tailwind CSS
228
+ │ │ ├── Dashboard.tsx # 메인 대시보드
229
+ │ │ ├── SessionDetail.tsx # 세션 상세 페이지
230
+ │ └── Setup.tsx # 초기 설정 페이지
231
+ ├── components/
232
+ │ │ ├── InfoTooltip.tsx # 정보 툴팁
233
+ │ │ └── badges/
234
+ │ │ ├── GradeBadge.tsx # 등급 배지
235
+ │ │ └── DangerBadge.tsx # 위험도 배지
236
+ │ ├── types/
237
+ │ │ └── index.ts # 프론트엔드 타입 정의
238
+ │ ├── utils/
239
+ │ │ ├── constants.ts # 도구 아이콘 등 상수
240
+ │ │ └── format.ts # 포맷 유틸리티
241
+ │ ├── App.tsx # 라우팅
242
+ │ └── index.css # Tailwind CSS
156
243
  ├── server/
157
- │ ├── index.ts # Express API 서버
158
- │ ├── config.ts # 설정 + 자동 탐색
159
- │ ├── analyzer.ts # 세션 분석 로직
160
- │ ├── parser.ts # JSONL 파서
161
- │ └── types.ts # 타입 정의
244
+ │ ├── index.ts # Express API 서버
245
+ │ ├── config.ts # 설정 + 자동 탐색
246
+ │ ├── analyzer.ts # 세션 분석 로직
247
+ │ ├── parser.ts # JSONL 파서
248
+ │ └── types.ts # 서버 타입 정의
162
249
  ├── bin/
163
- └── cli.js # CLI 진입점 (--port, --path, --help)
250
+ ├── cli.cjs # CLI 진입점 (--port, --path, --help)
251
+ │ └── sanity.mjs # 설치 검증 스크립트
164
252
  ├── dist/
165
- │ ├── client/ # 빌드된 프론트엔드
166
- │ └── server/ # 빌드된 백엔드
253
+ │ ├── client/ # 빌드된 프론트엔드
254
+ │ └── server/ # 빌드된 백엔드
167
255
  ├── package.json
168
- ├── tsconfig.server.json # 서버 빌드 설정
256
+ ├── tsconfig.server.json # 서버 빌드 설정
169
257
  └── vite.config.ts
170
258
  ```
171
259
 
package/bin/cli.cjs ADDED
@@ -0,0 +1,168 @@
1
+ #!/usr/bin/env node
2
+
3
+ // ── Claude CLI Analytics — CLI Entry Point (CJS) ──
4
+
5
+ const fs = require('fs');
6
+ const path = require('path');
7
+ const os = require('os');
8
+ const { spawn, execSync } = require('child_process');
9
+
10
+ const PID_DIR = path.join(os.homedir(), '.claude-analytics');
11
+ const PID_FILE = path.join(PID_DIR, 'server.pid');
12
+ const LOG_FILE = path.join(PID_DIR, 'server.log');
13
+ const SERVER_SCRIPT = path.resolve(__dirname, '..', 'dist', 'server', 'index.js');
14
+
15
+ const args = process.argv.slice(2);
16
+ const command = args.find(a => !a.startsWith('-'));
17
+
18
+ // ── Help ──
19
+ if (args.includes('--help') || args.includes('-h')) {
20
+ console.log(`
21
+ Claude CLI Analytics Dashboard
22
+
23
+ Usage: claude-cli-analytics [command] [options]
24
+
25
+ Commands:
26
+ (default) Start dashboard (background)
27
+ exit, stop Stop the running dashboard
28
+ status Check if dashboard is running
29
+
30
+ Options:
31
+ --port <number> Server port (default: 3001)
32
+ --path <dir> Claude projects directory
33
+ --foreground, -f Run in foreground (Ctrl+C to stop)
34
+ --help, -h Show this help
35
+
36
+ Examples:
37
+ claude-cli-analytics # background start
38
+ claude-cli-analytics exit # stop
39
+ claude-cli-analytics -f # foreground
40
+ claude-cli-analytics --port 8080 # custom port
41
+ `);
42
+ process.exit(0);
43
+ }
44
+
45
+ // ── Helpers ──
46
+ function readPid() {
47
+ try {
48
+ if (fs.existsSync(PID_FILE)) {
49
+ return parseInt(fs.readFileSync(PID_FILE, 'utf-8').trim(), 10);
50
+ }
51
+ } catch { /* */ }
52
+ return null;
53
+ }
54
+
55
+ function isRunning(pid) {
56
+ try { process.kill(pid, 0); return true; } catch { return false; }
57
+ }
58
+
59
+ function getPort() {
60
+ const i = args.indexOf('--port');
61
+ return (i !== -1 && args[i + 1]) || process.env.PORT || '3001';
62
+ }
63
+
64
+ function cleanPid() {
65
+ try { fs.unlinkSync(PID_FILE); } catch { /* */ }
66
+ }
67
+
68
+ // ── exit / stop ──
69
+ if (command === 'exit' || command === 'stop') {
70
+ const pid = readPid();
71
+ if (pid && isRunning(pid)) {
72
+ try {
73
+ process.kill(pid, 'SIGTERM');
74
+ cleanPid();
75
+ console.log(` ✅ Dashboard stopped (PID: ${pid})`);
76
+ } catch (e) {
77
+ console.error(` ❌ Failed to stop PID ${pid}: ${e.message}`);
78
+ }
79
+ } else {
80
+ cleanPid();
81
+ console.log(' ⚠️ Dashboard is not running');
82
+ }
83
+ process.exit(0);
84
+ }
85
+
86
+ // ── status ──
87
+ if (command === 'status') {
88
+ const pid = readPid();
89
+ if (pid && isRunning(pid)) {
90
+ console.log(` 🟢 Running (PID: ${pid}) → http://localhost:${getPort()}`);
91
+ } else {
92
+ cleanPid();
93
+ console.log(' ⚪ Dashboard is not running');
94
+ }
95
+ process.exit(0);
96
+ }
97
+
98
+ // ── Start ──
99
+ try {
100
+ const existingPid = readPid();
101
+ if (existingPid && isRunning(existingPid)) {
102
+ console.log(` ⚠️ Already running (PID: ${existingPid}) → http://localhost:${getPort()}`);
103
+ console.log(` Run 'claude-cli-analytics exit' to stop`);
104
+ process.exit(0);
105
+ }
106
+
107
+ // Parse env
108
+ const env = { ...process.env };
109
+ const portIdx = args.indexOf('--port');
110
+ if (portIdx !== -1 && args[portIdx + 1]) env.PORT = args[portIdx + 1];
111
+ const pathIdx = args.indexOf('--path');
112
+ if (pathIdx !== -1 && args[pathIdx + 1]) env.CLAUDE_PROJECTS_DIR = args[pathIdx + 1];
113
+
114
+ const foreground = args.includes('--foreground') || args.includes('-f');
115
+
116
+ if (foreground) {
117
+ // Foreground: import directly (CJS can require() the script, but default export handling might differ)
118
+ // Since `dist/server/index.js` is ESM (due to type: module in package.json), we might need `import()`
119
+ // However, we are in CJS now. Dynamic import works in CJS.
120
+ Object.assign(process.env, env);
121
+ (async () => {
122
+ try {
123
+ await import('../dist/server/index.js');
124
+ } catch (e) {
125
+ console.error('[CLI CRASH]', e);
126
+ process.exit(1);
127
+ }
128
+ })();
129
+ } else {
130
+ // Background
131
+ if (!fs.existsSync(PID_DIR)) fs.mkdirSync(PID_DIR, { recursive: true });
132
+
133
+ // Use append mode for log
134
+ const logFd = fs.openSync(LOG_FILE, 'a');
135
+ const port = env.PORT || '3001';
136
+
137
+ const child = spawn(process.execPath, [SERVER_SCRIPT], {
138
+ detached: true,
139
+ stdio: ['ignore', logFd, logFd],
140
+ env,
141
+ });
142
+
143
+ const pid = child.pid;
144
+ if (!pid) throw new Error("Failed to spawn process");
145
+
146
+ fs.writeFileSync(PID_FILE, String(pid));
147
+ child.unref();
148
+
149
+ console.log(`
150
+ 🔍 Claude Analytics Dashboard
151
+ 🌐 http://localhost:${port}
152
+ 📋 PID: ${pid}
153
+
154
+ Stop: claude-cli-analytics exit
155
+ Status: claude-cli-analytics status`);
156
+
157
+ try {
158
+ const cmd = process.platform === 'darwin' ? 'open'
159
+ : process.platform === 'win32' ? 'start' : 'xdg-open';
160
+ execSync(`${cmd} http://localhost:${port}`, { stdio: 'ignore' });
161
+ } catch { /* */ }
162
+
163
+ process.exit(0);
164
+ }
165
+ } catch (err) {
166
+ console.error('[CLI CRASH]', err);
167
+ process.exit(1);
168
+ }
package/bin/sanity.mjs ADDED
@@ -0,0 +1,3 @@
1
+ console.log("Hello World");
2
+ import fs from 'fs';
3
+ console.log("Imports ok");