claude-cli-analytics 0.0.1

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,174 @@
1
+ # Claude CLI Analytics Dashboard
2
+
3
+ Claude CLI 대화 로그를 분석하여 토큰 효율성, 캐시 활용률, 컨텍스트 사용 패턴을 시각화하는 대시보드
4
+
5
+ ## ✨ Features
6
+
7
+ - 📊 **Dashboard**: 전체 효율성 지표, 토큰 분포, 트렌드 차트
8
+ - 📝 **Session Detail**: 세션별 대화 타임라인, 질문별 읽은 컨텍스트 로그
9
+ - 🔄 **Real-time Refresh**: 새로고침 버튼으로 최신 데이터 로드
10
+ - 🏆 **Engineering Grade**: S/A/B/C 등급 + SEI (Spec Efficiency Index) 분석
11
+ - 🔍 **Auto-detection**: `.claude/projects` 경로 자동 탐색 — init 불필요
12
+ - 📦 **NPM 패키지**: `npm install -g`로 어디서든 설치 가능
13
+
14
+ ## 🚀 설치 및 실행
15
+
16
+ ### ✅ NPM (권장)
17
+
18
+ ```bash
19
+ # 글로벌 설치
20
+ npm install -g claude-cli-analytics
21
+
22
+ # 실행 (자동으로 ~/.claude/projects 탐색)
23
+ claude-cli-analytics
24
+ ```
25
+
26
+ ### 📦 npx (설치 없이 실행)
27
+
28
+ ```bash
29
+ npx claude-cli-analytics
30
+ ```
31
+
32
+ ### 🛠️ 소스에서 빌드 (기여용)
33
+
34
+ ```bash
35
+ git clone https://github.com/igeunpyo/claude-analytics.git
36
+ cd claude-analytics
37
+ npm install
38
+ npm run build
39
+ npm start
40
+
41
+ # 또는 글로벌로 링크하여 사용
42
+ npm link
43
+ claude-cli-analytics
44
+ ```
45
+
46
+ ### ⚡ 개발 모드
47
+
48
+ ```bash
49
+ npm run dev
50
+ ```
51
+
52
+ - Frontend: http://localhost:3000
53
+ - Backend API: http://localhost:3001
54
+
55
+ ## 🛠️ Requirements
56
+
57
+ - Node.js 18+ (권장: 20+)
58
+ - npm 9+
59
+
60
+ ## 🔍 .claude 경로 자동 탐색
61
+
62
+ **별도의 `init` 과정이 필요 없습니다.** 서버 시작 시 자동으로 Claude Code의 데이터 디렉토리를 탐색합니다.
63
+
64
+ Claude Code는 설치 방법에 관계없이 항상 `~/.claude/projects`에 세션 데이터를 저장합니다:
65
+
66
+ | 설치 방법 | 데이터 경로 |
67
+ |----------|-----------|
68
+ | `brew install --cask claude-code` | `~/.claude/projects` |
69
+ | `npm install -g @anthropic-ai/claude-code` | `~/.claude/projects` |
70
+ | 직접 다운로드 | `~/.claude/projects` |
71
+
72
+ ### 경로 탐색 우선순위
73
+
74
+ 1. `CLAUDE_PROJECTS_DIR` 환경변수 (최우선)
75
+ 2. 저장된 설정 파일 (`~/.claude-analytics/config.json`)
76
+ 3. 자동 탐색 (`~/.claude/projects`, `$XDG_CONFIG_HOME/claude/projects`)
77
+ 4. 기본 경로 (`~/.claude/projects`)
78
+
79
+ ### 커스텀 경로 사용
80
+
81
+ ```bash
82
+ # 환경변수로 지정
83
+ CLAUDE_PROJECTS_DIR=/path/to/claude/projects claude-cli-analytics
84
+
85
+ # CLI 옵션으로 지정
86
+ claude-cli-analytics --path /path/to/claude/projects
87
+
88
+ # 포트 변경
89
+ claude-cli-analytics --port 8080
90
+ ```
91
+
92
+ ## 📈 분석 지표
93
+
94
+ ### 1. 컨텍스트 지표
95
+
96
+ | 지표 | 계산 방식 | 의미 |
97
+ |------|----------|------|
98
+ | **평균 컨텍스트** | `(input_tokens + cache_read) / 요청수` | 요청당 평균 컨텍스트 크기 |
99
+ | **위험 레벨** | `<20K: 안전, 20-50K: 주의, >50K: 위험` | 컨텍스트 과부하 경고 |
100
+ | **리미트 영향도** | `(총 컨텍스트 / 44,000) × 100%` | Claude Pro 5시간 한도 대비 사용량 |
101
+
102
+ ### 2. 품질 지표
103
+
104
+ | 지표 | 계산 방식 | 목표 | 의미 |
105
+ |------|----------|------|------|
106
+ | **중복 읽기율** | `(전체읽기 - 고유파일) / 전체읽기 × 100` | <20% | 같은 파일을 여러 번 읽은 비율 |
107
+ | **Read/Edit 비율** | `Read도구 횟수 / Edit도구 횟수` | ≥5:1 | 수정 전 충분한 탐색 여부 |
108
+ | **반복 수정율** | `(전체수정 - 고유파일) / 전체수정 × 100` | <20% | 같은 파일을 여러 번 수정한 비율 |
109
+ | **수정당 토큰** | `총 컨텍스트 / Edit 횟수` | <50K | 수정 1회당 소비된 토큰 |
110
+
111
+ ### 3. Engineering Grade (S/A/B/C)
112
+
113
+ 100점 만점 종합 점수로 산출:
114
+ - **Efficiency (40%)**: 캐시 히트율 기반
115
+ - **Stability (30%)**: 도구 오류율 기반
116
+ - **Precision (30%)**: Read/Edit 비율 기반
117
+ - **Penalty**: 팬텀 파일 접근 횟수 × 5
118
+
119
+ ```
120
+ 🏆 S급 (90+): Elite — 최적화된 워크플로우
121
+ ⭐ A급 (80+): Good — 우수한 효율성
122
+ ✅ B급 (60+): Average — 개선 여지 있음
123
+ ⚠️ C급 (40+): Below Average — 최적화 필요
124
+ ```
125
+
126
+ ### 4. Spec Efficiency Index (SEI)
127
+
128
+ ```
129
+ SEI = (Accuracy × 100) / log₁₀(Spec Volume + 1)
130
+ ```
131
+
132
+ `.claude/` 컨텍스트 파일 읽기 후 오류율을 측정하여 스펙 문서의 실효성을 평가합니다.
133
+
134
+ ## 🔧 API Endpoints
135
+
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` | 데이터 새로고침 |
145
+
146
+ ## 📁 Project Structure
147
+
148
+ ```
149
+ claude-cli-analytics/
150
+ ├── src/ # React Frontend
151
+ │ ├── pages/
152
+ │ │ ├── Dashboard.tsx # 메인 대시보드
153
+ │ │ └── SessionDetail.tsx # 세션 상세 페이지
154
+ │ ├── App.tsx # 라우팅
155
+ │ └── index.css # Tailwind CSS
156
+ ├── server/
157
+ │ ├── index.ts # Express API 서버
158
+ │ ├── config.ts # 설정 + 자동 탐색
159
+ │ ├── analyzer.ts # 세션 분석 로직
160
+ │ ├── parser.ts # JSONL 파서
161
+ │ └── types.ts # 타입 정의
162
+ ├── bin/
163
+ │ └── cli.js # CLI 진입점 (--port, --path, --help)
164
+ ├── dist/
165
+ │ ├── client/ # 빌드된 프론트엔드
166
+ │ └── server/ # 빌드된 백엔드
167
+ ├── package.json
168
+ ├── tsconfig.server.json # 서버 빌드 설정
169
+ └── vite.config.ts
170
+ ```
171
+
172
+ ## 📄 License
173
+
174
+ MIT
package/bin/cli.js ADDED
@@ -0,0 +1,44 @@
1
+ #!/usr/bin/env node
2
+
3
+ // ── Claude Analytics CLI ──
4
+ // Supports: --port <number>, --path <dir>, --help
5
+
6
+ const args = process.argv.slice(2);
7
+
8
+ // Handle --help
9
+ if (args.includes('--help') || args.includes('-h')) {
10
+ console.log(`
11
+ Claude Analytics Dashboard
12
+
13
+ Usage: claude-cli-analytics [options]
14
+
15
+ Options:
16
+ --port <number> Server port (default: 3001)
17
+ --path <dir> Claude projects directory (overrides auto-detection)
18
+ --help, -h Show this help message
19
+
20
+ Auto-detection:
21
+ Automatically finds Claude Code data at ~/.claude/projects
22
+ Works with all installation methods (homebrew, npm, direct install)
23
+
24
+ Environment variables:
25
+ CLAUDE_PROJECTS_DIR Override projects directory path
26
+ PORT Override server port
27
+ `);
28
+ process.exit(0);
29
+ }
30
+
31
+ // Parse --port
32
+ const portIdx = args.indexOf('--port');
33
+ if (portIdx !== -1 && args[portIdx + 1]) {
34
+ process.env.PORT = args[portIdx + 1];
35
+ }
36
+
37
+ // Parse --path
38
+ const pathIdx = args.indexOf('--path');
39
+ if (pathIdx !== -1 && args[pathIdx + 1]) {
40
+ process.env.CLAUDE_PROJECTS_DIR = args[pathIdx + 1];
41
+ }
42
+
43
+ // Start the server
44
+ import('../dist/server/index.js');
@@ -0,0 +1 @@
1
+ @import"https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap";:root{--bg-primary: #ffffff;--bg-secondary: #f8f9fa;--bg-tertiary: #f1f3f4;--bg-surface: #ffffff;--text-primary: #202124;--text-secondary: #5f6368;--text-tertiary: #9aa0a6;--blue-primary: #1a73e8;--blue-light: #e8f0fe;--blue-dark: #1557b0;--green-primary: #1e8e3e;--green-light: #e6f4ea;--orange-primary: #e37400;--orange-light: #fef7e0;--purple-primary: #7b1fa2;--purple-light: #f3e8fd;--red-primary: #d93025;--red-light: #fce8e6;--border-color: #e8eaed;--border-light: #f1f3f4;--shadow-sm: 0 1px 3px rgba(32, 33, 36, .04);--shadow-md: 0 4px 12px rgba(32, 33, 36, .06);--shadow-lg: 0 8px 24px rgba(32, 33, 36, .08);--shadow-xl: 0 12px 40px rgba(32, 33, 36, .1);--radius-sm: 12px;--radius-md: 20px;--radius-lg: 24px;--radius-xl: 32px;--radius-pill: 999px;--transition-fast: .15s cubic-bezier(.4, 0, .2, 1);--transition-normal: .25s cubic-bezier(.4, 0, .2, 1);--transition-slow: .35s cubic-bezier(.4, 0, .2, 1)}*{box-sizing:border-box;margin:0;padding:0}body{font-family:Inter,-apple-system,BlinkMacSystemFont,system-ui,Segoe UI,sans-serif;background-color:var(--bg-secondary);color:var(--text-primary);line-height:1.6;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;letter-spacing:-.011em}.app-container{min-height:100vh}.header{background:#ffffffb8;backdrop-filter:blur(20px) saturate(180%);-webkit-backdrop-filter:blur(20px) saturate(180%);border-bottom:1px solid rgba(232,234,237,.6);padding:0 32px;height:64px;position:sticky;top:0;z-index:100;transition:background var(--transition-normal)}.header-content{max-width:1200px;margin:0 auto;display:flex;align-items:center;justify-content:space-between;height:100%}.logo{font-size:17px;font-weight:600;color:var(--text-primary);display:flex;align-items:center;gap:10px;text-decoration:none;letter-spacing:-.02em}.logo-icon{display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;border-radius:10px;background:var(--text-primary);color:#fff;font-size:12px;font-weight:700;letter-spacing:.5px}.nav{display:flex;align-items:center;gap:4px}.nav-link{font-size:14px;font-weight:500;color:var(--text-secondary);text-decoration:none;padding:8px 16px;border-radius:var(--radius-pill);transition:all var(--transition-fast)}.nav-link:hover{background:var(--bg-tertiary);color:var(--text-primary)}.main{min-height:calc(100vh - 130px)}.container{max-width:1200px;margin:0 auto;padding:40px 32px}.footer{text-align:center;padding:32px;color:var(--text-tertiary);font-size:13px;font-weight:400}.card{background:var(--bg-primary);border-radius:var(--radius-lg);border:none;box-shadow:var(--shadow-sm);padding:28px;transition:all var(--transition-normal)}.card:hover{box-shadow:var(--shadow-md)}.card-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:24px}.card-title{font-size:16px;font-weight:600;color:var(--text-primary);letter-spacing:-.02em}.stat-card{background:var(--bg-primary);border-radius:var(--radius-lg);border:none;box-shadow:var(--shadow-sm);padding:28px;display:flex;flex-direction:column;gap:8px;transition:all var(--transition-normal)}.stat-card:hover{box-shadow:var(--shadow-md);transform:translateY(-2px)}.stat-label{font-size:13px;color:var(--text-tertiary);font-weight:500}.stat-value{font-size:32px;font-weight:700;color:var(--text-primary);line-height:1.2;letter-spacing:-.03em}.stat-value.blue{color:var(--blue-primary)}.stat-value.green{color:var(--green-primary)}.stat-value.orange{color:var(--orange-primary)}.stat-value.purple{color:var(--purple-primary)}.btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;padding:10px 24px;border-radius:var(--radius-pill);font-size:14px;font-weight:500;cursor:pointer;transition:all var(--transition-fast);border:none;letter-spacing:-.01em}.btn-primary{background:var(--text-primary);color:#fff}.btn-primary:hover{background:#3c4043;box-shadow:var(--shadow-md)}.btn-secondary{background:var(--bg-primary);color:var(--text-primary);border:1px solid var(--border-color)}.btn-secondary:hover{background:var(--bg-tertiary);border-color:#dadce0}.select,.input{padding:10px 18px;border-radius:var(--radius-sm);border:1px solid var(--border-color);background:var(--bg-primary);color:var(--text-primary);font-size:14px;font-weight:400;font-family:inherit;cursor:pointer;transition:all var(--transition-fast)}.select{padding-right:40px;appearance:none;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%235f6368' stroke-width='2'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 14px center}.select:focus,.input:focus{outline:none;border-color:var(--blue-primary);box-shadow:0 0 0 3px #1a73e81f}.tag{display:inline-flex;align-items:center;padding:4px 12px;border-radius:var(--radius-pill);font-size:12px;font-weight:500}.tag-blue{background:var(--blue-light);color:var(--blue-primary)}.tag-green{background:var(--green-light);color:var(--green-primary)}.tag-orange{background:var(--orange-light);color:var(--orange-primary)}.tag-purple{background:var(--purple-light);color:var(--purple-primary)}.table-container{overflow-x:auto;border-radius:var(--radius-sm)}table{width:100%;border-collapse:collapse}table th{text-align:left;font-size:12px;font-weight:600;color:var(--text-tertiary);padding:12px 16px;text-transform:uppercase;letter-spacing:.04em;border-bottom:1px solid var(--border-color)}table td{padding:14px 16px;border-bottom:1px solid var(--border-light);font-size:14px;color:var(--text-secondary);transition:background var(--transition-fast)}table tr:last-child td{border-bottom:none}table tbody tr{transition:background var(--transition-fast)}table tbody tr:hover td{background:var(--bg-secondary)}.chart-container{padding:20px 0}.message-card{background:var(--bg-primary);border-radius:var(--radius-md);border:none;box-shadow:var(--shadow-sm);padding:20px;margin-bottom:12px;transition:box-shadow var(--transition-fast)}.message-card:hover{box-shadow:var(--shadow-md)}.message-card.user{border-left:3px solid var(--blue-primary)}.message-card.assistant{border-left:3px solid var(--purple-primary)}.message-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px}.message-content{font-size:14px;color:var(--text-secondary);line-height:1.7;white-space:pre-wrap}.file-tags{display:flex;flex-wrap:wrap;gap:6px;margin:8px 0}.file-tag{display:inline-flex;align-items:center;padding:4px 10px;background:var(--bg-tertiary);border-radius:var(--radius-pill);font-size:11px;font-family:SF Mono,Fira Code,Monaco,monospace;color:var(--text-secondary);max-width:200px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.file-tag.spec{background:var(--purple-light);color:var(--purple-primary)}.grid-4{display:grid;grid-template-columns:repeat(4,1fr);gap:20px}.grid-3{display:grid;grid-template-columns:repeat(3,1fr);gap:20px}.grid-2{display:grid;grid-template-columns:repeat(2,1fr);gap:24px}@media(max-width:1200px){.grid-4,.grid-3{grid-template-columns:repeat(2,1fr)}}@media(max-width:768px){.grid-4,.grid-3,.grid-2{grid-template-columns:1fr}.container{padding:20px 16px}.header{padding:0 16px}}.spinner,.loading-spinner{width:36px;height:36px;border:3px solid var(--border-color);border-top-color:var(--text-primary);border-radius:50%;animation:spin .7s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}@keyframes fadeIn{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}@keyframes pulse{0%,to{opacity:1}50%{opacity:.3}}::-webkit-scrollbar{width:6px;height:6px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:var(--border-color);border-radius:3px}::-webkit-scrollbar-thumb:hover{background:var(--text-tertiary)}.info-tooltip{position:relative;display:inline-flex;align-items:center;margin-left:4px;cursor:help}.info-tooltip-icon{width:15px;height:15px;border-radius:50%;background:var(--bg-tertiary);color:var(--text-tertiary);font-size:10px;font-weight:600;display:inline-flex;align-items:center;justify-content:center;transition:all var(--transition-fast)}.info-tooltip:hover .info-tooltip-icon{background:var(--text-primary);color:#fff}.info-tooltip-text{display:none;position:absolute;bottom:calc(100% + 8px);left:50%;transform:translate(-50%);background:var(--text-primary);color:#fff;padding:10px 14px;border-radius:var(--radius-sm);font-size:12px;line-height:1.5;white-space:pre-wrap;min-width:220px;max-width:320px;z-index:1000;box-shadow:var(--shadow-lg)}.info-tooltip:hover .info-tooltip-text{display:block}