cc-size 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/README.md +58 -0
  2. package/cli.mjs +211 -0
  3. package/index.html +235 -0
  4. package/package.json +25 -0
package/README.md ADDED
@@ -0,0 +1,58 @@
1
+ # cc-size
2
+
3
+ How much conversation history have you accumulated? Shows total disk usage and growth rate of your Claude Code sessions.
4
+
5
+ ```
6
+ cc-size — Your Claude Code conversation history
7
+
8
+ Total size: 6.1 GB
9
+ Total files: 755 sessions
10
+ Date range: 2026-01-10 → 2026-03-01
11
+ Daily growth: ~81.8 MB/day (last 30 days)
12
+ Largest file: 1.0 GB
13
+ At this rate: 10 GB by ~2026-04
14
+
15
+ ──────────────────────────────────────────────────────
16
+ Monthly growth
17
+
18
+ 2026-01 ████████████████████████ 3.7 GB
19
+ 2026-02 ██████████████░░░░░░░░░░ 2.2 GB
20
+ 2026-03 █░░░░░░░░░░░░░░░░░░░░░░░ 231.1 MB (in progress)
21
+
22
+ ──────────────────────────────────────────────────────
23
+ By project (top 8)
24
+
25
+ ~/ (home) ████████████████████████ 5.7 GB
26
+ projects-cc-loop █░░░░░░░░░░░░░░░░░░░░░░░ 224.8 MB
27
+ draemorth ░░░░░░░░░░░░░░░░░░░░░░░░ 59.0 MB
28
+ ```
29
+
30
+ ## Usage
31
+
32
+ ```bash
33
+ npx cc-size # Total history size and growth
34
+ npx cc-size --all # Include subagent session files
35
+ npx cc-size --json # JSON output
36
+ ```
37
+
38
+ ## What it shows
39
+
40
+ - **Total size** — cumulative disk usage of all `.jsonl` session files
41
+ - **Sessions** — number of conversation files
42
+ - **Daily growth** — average bytes added per day over the last 30 days
43
+ - **Largest file** — size of your biggest single session
44
+ - **Growth projection** — estimated date to reach 10 GB at current rate
45
+ - **Monthly chart** — month-by-month storage breakdown
46
+ - **By project** — top 8 projects by storage consumed
47
+
48
+ ## Privacy
49
+
50
+ Reads file **metadata only** (size + modification time). No file content is accessed or transmitted. Everything runs locally.
51
+
52
+ ## Browser version
53
+
54
+ Drop your `~/.claude` folder into [cc-size on the web](https://yurukusa.github.io/cc-size/) for the same analysis — no install required.
55
+
56
+ ---
57
+
58
+ Part of [cc-toolkit](https://yurukusa.github.io/cc-toolkit/) — 60 free tools for Claude Code
package/cli.mjs ADDED
@@ -0,0 +1,211 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * cc-size — How much conversation history have you accumulated?
4
+ * Shows total disk usage and growth rate of your Claude Code sessions.
5
+ */
6
+
7
+ import { readdirSync, statSync } from 'fs';
8
+ import { join } from 'path';
9
+ import { homedir } from 'os';
10
+
11
+ const args = process.argv.slice(2);
12
+ const jsonMode = args.includes('--json');
13
+ const showHelp = args.includes('--help') || args.includes('-h');
14
+ const includeSubagents = args.includes('--all'); // include subagent files
15
+
16
+ if (showHelp) {
17
+ console.log(`cc-size — How much conversation history have you accumulated?
18
+
19
+ Usage:
20
+ npx cc-size # Total history size and growth
21
+ npx cc-size --all # Include subagent session files
22
+ npx cc-size --json # JSON output
23
+ `);
24
+ process.exit(0);
25
+ }
26
+
27
+ const claudeDir = join(homedir(), '.claude', 'projects');
28
+
29
+ function humanSize(bytes) {
30
+ if (bytes >= 1024 * 1024 * 1024) return (bytes / (1024 * 1024 * 1024)).toFixed(1) + ' GB';
31
+ if (bytes >= 1024 * 1024) return (bytes / (1024 * 1024)).toFixed(1) + ' MB';
32
+ if (bytes >= 1024) return (bytes / 1024).toFixed(1) + ' KB';
33
+ return bytes + ' B';
34
+ }
35
+
36
+ function getISOMonth(date) {
37
+ return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}`;
38
+ }
39
+
40
+ /**
41
+ * Convert project directory name to human-readable project label.
42
+ * "-home-namakusa-projects-cc-loop" -> "projects-cc-loop"
43
+ * "-home-namakusa" -> "~/ (home)"
44
+ */
45
+ function projectName(dirName) {
46
+ // Remove leading "-home-[username]" prefix (with or without trailing dash)
47
+ const stripped = dirName.replace(/^-home-[^-]+/, '').replace(/^-/, '');
48
+ if (!stripped) return '~/ (home)';
49
+ return stripped;
50
+ }
51
+
52
+ const byProject = {};
53
+ const byMonth = {};
54
+ let totalFiles = 0;
55
+ let totalBytes = 0;
56
+ let oldestDate = null;
57
+ let newestDate = null;
58
+ let largestFile = { size: 0, path: '' };
59
+
60
+ let projectDirs;
61
+ try {
62
+ projectDirs = readdirSync(claudeDir);
63
+ } catch {
64
+ console.error(`Cannot read ${claudeDir}`);
65
+ process.exit(1);
66
+ }
67
+
68
+ for (const projDir of projectDirs) {
69
+ const projPath = join(claudeDir, projDir);
70
+ let stat;
71
+ try {
72
+ stat = statSync(projPath);
73
+ if (!stat.isDirectory()) continue;
74
+ } catch {
75
+ continue;
76
+ }
77
+
78
+ let entries;
79
+ try {
80
+ entries = readdirSync(projPath);
81
+ } catch {
82
+ continue;
83
+ }
84
+
85
+ for (const entry of entries) {
86
+ if (!entry.endsWith('.jsonl')) continue;
87
+ if (!includeSubagents && projPath.includes('/subagents/')) continue;
88
+
89
+ const filePath = join(projPath, entry);
90
+ let fstat;
91
+ try {
92
+ fstat = statSync(filePath);
93
+ if (!fstat.isFile()) continue;
94
+ } catch {
95
+ continue;
96
+ }
97
+
98
+ const size = fstat.size;
99
+ const mtime = new Date(fstat.mtime);
100
+ const month = getISOMonth(mtime);
101
+
102
+ totalFiles++;
103
+ totalBytes += size;
104
+
105
+ // By project
106
+ if (!byProject[projDir]) byProject[projDir] = { bytes: 0, files: 0, name: projectName(projDir) };
107
+ byProject[projDir].bytes += size;
108
+ byProject[projDir].files++;
109
+
110
+ // By month
111
+ byMonth[month] = (byMonth[month] || 0) + size;
112
+
113
+ // Tracking
114
+ if (!oldestDate || mtime < oldestDate) oldestDate = mtime;
115
+ if (!newestDate || mtime > newestDate) newestDate = mtime;
116
+ if (size > largestFile.size) largestFile = { size, path: filePath.replace(homedir(), '~') };
117
+ }
118
+ }
119
+
120
+ if (totalFiles === 0) {
121
+ console.error('No session files found.');
122
+ process.exit(1);
123
+ }
124
+
125
+ // Calculate growth rate from last 30 days
126
+ const now = new Date();
127
+ const thirtyDaysAgo = new Date(now - 30 * 24 * 60 * 60 * 1000);
128
+ let last30DaysBytes = 0;
129
+ for (const [month, bytes] of Object.entries(byMonth)) {
130
+ const [yr, mo] = month.split('-').map(Number);
131
+ const monthStart = new Date(yr, mo - 1, 1);
132
+ if (monthStart >= thirtyDaysAgo) last30DaysBytes += bytes;
133
+ }
134
+ const dailyGrowth = last30DaysBytes / 30;
135
+
136
+ // Sorted projects by size
137
+ const sortedProjects = Object.entries(byProject).sort((a, b) => b[1].bytes - a[1].bytes);
138
+ const sortedMonths = Object.entries(byMonth).sort((a, b) => a[0].localeCompare(b[0]));
139
+
140
+ if (jsonMode) {
141
+ console.log(JSON.stringify({
142
+ total_bytes: totalBytes,
143
+ total_size: humanSize(totalBytes),
144
+ total_files: totalFiles,
145
+ daily_growth_bytes: Math.round(dailyGrowth),
146
+ daily_growth: humanSize(dailyGrowth),
147
+ oldest_session: oldestDate?.toISOString().slice(0, 10),
148
+ newest_session: newestDate?.toISOString().slice(0, 10),
149
+ largest_file: { path: largestFile.path, size: humanSize(largestFile.size) },
150
+ by_month: Object.fromEntries(sortedMonths.map(([m, b]) => [m, humanSize(b)])),
151
+ by_project: sortedProjects.slice(0, 10).map(([dir, d]) => ({
152
+ project: d.name,
153
+ size: humanSize(d.bytes),
154
+ files: d.files,
155
+ })),
156
+ }, null, 2));
157
+ process.exit(0);
158
+ }
159
+
160
+ // Display
161
+ const BAR_WIDTH = 24;
162
+ const maxMonthBytes = Math.max(...Object.values(byMonth));
163
+ const maxProjBytes = sortedProjects[0]?.[1].bytes || 1;
164
+
165
+ function bar(bytes, max) {
166
+ const filled = Math.round((bytes / max) * BAR_WIDTH);
167
+ return '█'.repeat(filled) + '░'.repeat(BAR_WIDTH - filled);
168
+ }
169
+
170
+ function rpad(str, len) {
171
+ return str + ' '.repeat(Math.max(0, len - str.length));
172
+ }
173
+
174
+ console.log('cc-size — Your Claude Code conversation history\n');
175
+
176
+ // Stats header
177
+ console.log(` Total size: ${humanSize(totalBytes)}`);
178
+ console.log(` Total files: ${totalFiles.toLocaleString()} sessions`);
179
+ console.log(` Date range: ${oldestDate?.toISOString().slice(0, 10)} → ${newestDate?.toISOString().slice(0, 10)}`);
180
+ console.log(` Daily growth: ~${humanSize(dailyGrowth)}/day (last 30 days)`);
181
+ console.log(` Largest file: ${humanSize(largestFile.size)}`);
182
+
183
+ // Growth projection
184
+ if (dailyGrowth > 0) {
185
+ const daysTo10GB = (10 * 1024 * 1024 * 1024 - totalBytes) / dailyGrowth;
186
+ if (daysTo10GB > 0 && daysTo10GB < 3650) {
187
+ const projDate = new Date(now.getTime() + daysTo10GB * 86400000);
188
+ console.log(` At this rate: 10 GB by ~${projDate.toISOString().slice(0, 7)}`);
189
+ }
190
+ }
191
+
192
+ console.log('\n' + '─'.repeat(54));
193
+ console.log(' Monthly growth\n');
194
+
195
+ for (const [month, bytes] of sortedMonths.slice(-12)) {
196
+ const current = month === getISOMonth(now);
197
+ const tag = current ? ' (in progress)' : '';
198
+ const sizeStr = humanSize(bytes).padStart(8);
199
+ console.log(` ${month} ${bar(bytes, maxMonthBytes)} ${sizeStr}${tag}`);
200
+ }
201
+
202
+ console.log('\n' + '─'.repeat(54));
203
+ console.log(' By project (top 8)\n');
204
+
205
+ const maxProjLabel = Math.max(...sortedProjects.slice(0, 8).map(([, d]) => d.name.length));
206
+
207
+ for (const [, data] of sortedProjects.slice(0, 8)) {
208
+ const label = rpad(data.name, maxProjLabel);
209
+ const sizeStr = humanSize(data.bytes).padStart(8);
210
+ console.log(` ${label} ${bar(data.bytes, maxProjBytes)} ${sizeStr}`);
211
+ }
package/index.html ADDED
@@ -0,0 +1,235 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>cc-size — Claude Code history size</title>
7
+ <style>
8
+ * { box-sizing: border-box; margin: 0; padding: 0; }
9
+ body {
10
+ background: #0d1117;
11
+ color: #c9d1d9;
12
+ font-family: 'SF Mono', 'Consolas', 'Cascadia Code', monospace;
13
+ min-height: 100vh;
14
+ display: flex;
15
+ flex-direction: column;
16
+ align-items: center;
17
+ padding: 40px 20px;
18
+ }
19
+ h1 { font-size: 1.5rem; color: #79c0ff; margin-bottom: 6px; }
20
+ .subtitle { color: #8b949e; font-size: 0.875rem; margin-bottom: 32px; }
21
+
22
+ .drop-zone {
23
+ border: 2px dashed #30363d;
24
+ border-radius: 12px;
25
+ padding: 48px 64px;
26
+ text-align: center;
27
+ cursor: pointer;
28
+ transition: all 0.2s;
29
+ max-width: 480px;
30
+ width: 100%;
31
+ margin-bottom: 32px;
32
+ }
33
+ .drop-zone:hover, .drop-zone.drag-over { border-color: #79c0ff; background: rgba(121,192,255,0.05); }
34
+ .drop-text { color: #8b949e; font-size: 0.875rem; line-height: 1.6; }
35
+ .drop-text strong { color: #c9d1d9; }
36
+ #file-input { display: none; }
37
+
38
+ .result { display: none; max-width: 600px; width: 100%; }
39
+ .result.visible { display: block; }
40
+ .card { background: #161b22; border: 1px solid #30363d; border-radius: 8px; padding: 20px; margin-bottom: 16px; }
41
+ .card-title { color: #8b949e; font-size: 0.75rem; text-transform: uppercase; letter-spacing: 1px; margin-bottom: 16px; }
42
+
43
+ .stats-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 16px; margin-bottom: 16px; }
44
+ @media (min-width: 500px) { .stats-grid { grid-template-columns: repeat(4, 1fr); } }
45
+ .stat-item { text-align: center; }
46
+ .stat-val { font-size: 1.3rem; color: #79c0ff; font-weight: 700; }
47
+ .stat-lbl { font-size: 0.7rem; color: #8b949e; margin-top: 2px; }
48
+
49
+ .growth-badge {
50
+ text-align: center;
51
+ padding: 10px;
52
+ background: rgba(121,192,255,0.1);
53
+ border: 1px solid rgba(121,192,255,0.3);
54
+ border-radius: 6px;
55
+ font-size: 0.9rem;
56
+ color: #79c0ff;
57
+ }
58
+
59
+ .bar-chart { font-size: 0.78rem; }
60
+ .bar-row { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; }
61
+ .bar-label { width: 72px; text-align: right; color: #8b949e; flex-shrink: 0; }
62
+ .bar-label-wide { width: 160px; text-align: right; color: #c9d1d9; flex-shrink: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
63
+ .bar-track { flex: 1; height: 14px; background: #21262d; border-radius: 3px; overflow: hidden; }
64
+ .bar-fill-month { height: 100%; background: #79c0ff; border-radius: 3px; transition: width 0.5s ease; }
65
+ .bar-fill-proj { height: 100%; background: linear-gradient(90deg, #388bfd, #79c0ff); border-radius: 3px; transition: width 0.5s ease; }
66
+ .bar-count { width: 64px; color: #8b949e; text-align: right; flex-shrink: 0; font-size: 0.72rem; }
67
+
68
+ .section-title { color: #8b949e; font-size: 0.72rem; text-transform: uppercase; letter-spacing: 1px; margin-bottom: 10px; margin-top: 16px; }
69
+ .section-title:first-child { margin-top: 0; }
70
+
71
+ .reset-btn { margin-top: 16px; background: none; border: 1px solid #30363d; color: #8b949e; padding: 8px 16px; border-radius: 6px; cursor: pointer; font-family: inherit; font-size: 0.8rem; display: block; width: 100%; transition: all 0.2s; }
72
+ .reset-btn:hover { border-color: #79c0ff; color: #79c0ff; }
73
+ .footer { color: #8b949e; font-size: 0.75rem; text-align: center; margin-top: 12px; }
74
+ .footer a { color: #79c0ff; text-decoration: none; }
75
+ .footer a:hover { text-decoration: underline; }
76
+ </style>
77
+ </head>
78
+ <body>
79
+ <h1>💾 cc-size</h1>
80
+ <p class="subtitle">How much conversation history have you accumulated?</p>
81
+
82
+ <div class="drop-zone" id="drop-zone">
83
+ <div style="font-size:2.5rem;margin-bottom:12px;">📁</div>
84
+ <div class="drop-text">
85
+ <strong>Drop your ~/.claude folder here</strong><br>
86
+ or click to select<br><br>
87
+ Reads file metadata only (no content).<br>
88
+ Nothing is uploaded.
89
+ </div>
90
+ <input type="file" id="file-input" webkitdirectory multiple accept=".jsonl">
91
+ </div>
92
+
93
+ <div class="result" id="result">
94
+ <div class="card">
95
+ <div class="card-title">History Summary</div>
96
+ <div class="stats-grid">
97
+ <div class="stat-item"><div class="stat-val" id="stat-total">—</div><div class="stat-lbl">total size</div></div>
98
+ <div class="stat-item"><div class="stat-val" id="stat-files">—</div><div class="stat-lbl">sessions</div></div>
99
+ <div class="stat-item"><div class="stat-val" id="stat-growth">—</div><div class="stat-lbl">per day (30d)</div></div>
100
+ <div class="stat-item"><div class="stat-val" id="stat-largest">—</div><div class="stat-lbl">largest file</div></div>
101
+ </div>
102
+ <div class="growth-badge" id="growth-badge">—</div>
103
+ </div>
104
+
105
+ <div class="card">
106
+ <div class="section-title">Monthly growth</div>
107
+ <div class="bar-chart" id="month-chart"></div>
108
+
109
+ <div class="section-title">By project (top 8)</div>
110
+ <div class="bar-chart" id="proj-chart"></div>
111
+ </div>
112
+
113
+ <button class="reset-btn" id="reset-btn">← Analyze another folder</button>
114
+ </div>
115
+
116
+ <div class="footer">
117
+ <a href="https://github.com/yurukusa/cc-size" target="_blank">cc-size</a> ·
118
+ Part of <a href="https://yurukusa.github.io/cc-toolkit/" target="_blank">cc-toolkit</a> · 106 free tools for Claude Code
119
+ </div>
120
+
121
+ <script>
122
+ const dropZone = document.getElementById('drop-zone');
123
+ const fileInput = document.getElementById('file-input');
124
+ const resultEl = document.getElementById('result');
125
+ const resetBtn = document.getElementById('reset-btn');
126
+
127
+ dropZone.addEventListener('click', () => fileInput.click());
128
+ dropZone.addEventListener('dragover', e => { e.preventDefault(); dropZone.classList.add('drag-over'); });
129
+ dropZone.addEventListener('dragleave', () => dropZone.classList.remove('drag-over'));
130
+ dropZone.addEventListener('drop', e => { e.preventDefault(); dropZone.classList.remove('drag-over'); processFiles(e.dataTransfer.files); });
131
+ fileInput.addEventListener('change', () => processFiles(fileInput.files));
132
+ resetBtn.addEventListener('click', () => { resultEl.classList.remove('visible'); dropZone.style.display = ''; fileInput.value = ''; });
133
+
134
+ function humanSize(bytes) {
135
+ if (bytes >= 1024**3) return (bytes/1024**3).toFixed(1) + ' GB';
136
+ if (bytes >= 1024**2) return (bytes/1024**2).toFixed(1) + ' MB';
137
+ if (bytes >= 1024) return (bytes/1024).toFixed(1) + ' KB';
138
+ return bytes + ' B';
139
+ }
140
+
141
+ function projectName(webkitPath) {
142
+ // Extract project dir from path like ".claude/projects/PROJ/file.jsonl"
143
+ const parts = webkitPath.split('/');
144
+ const projIdx = parts.indexOf('projects');
145
+ if (projIdx >= 0 && parts[projIdx + 1]) {
146
+ const dir = parts[projIdx + 1];
147
+ const stripped = dir.replace(/^-home-[^-]+/, '').replace(/^-/, '');
148
+ return stripped || '~/ (home)';
149
+ }
150
+ return 'unknown';
151
+ }
152
+
153
+ function getMonth(file) {
154
+ const d = new Date(file.lastModified);
155
+ return `${d.getFullYear()}-${String(d.getMonth()+1).padStart(2,'0')}`;
156
+ }
157
+
158
+ async function processFiles(files) {
159
+ const jsonlFiles = Array.from(files).filter(f => {
160
+ const p = f.webkitRelativePath || f.name;
161
+ return p.endsWith('.jsonl') && !p.includes('/subagents/');
162
+ });
163
+ if (!jsonlFiles.length) { alert('No session files found.'); return; }
164
+ dropZone.style.display = 'none';
165
+
166
+ let totalBytes = 0, totalFiles = 0;
167
+ let largestSize = 0;
168
+ const byMonth = {}, byProj = {};
169
+ const now = new Date();
170
+ const thirtyAgo = now - 30*86400000;
171
+
172
+ for (const f of jsonlFiles) {
173
+ const size = f.size;
174
+ totalBytes += size;
175
+ totalFiles++;
176
+ if (size > largestSize) largestSize = size;
177
+
178
+ const month = getMonth(f);
179
+ byMonth[month] = (byMonth[month]||0) + size;
180
+
181
+ const proj = projectName(f.webkitRelativePath || f.name);
182
+ if (!byProj[proj]) byProj[proj] = 0;
183
+ byProj[proj] += size;
184
+ }
185
+
186
+ // 30-day growth
187
+ let last30 = 0;
188
+ for (const [month, bytes] of Object.entries(byMonth)) {
189
+ const [yr, mo] = month.split('-').map(Number);
190
+ if (new Date(yr, mo-1, 1) >= new Date(thirtyAgo)) last30 += bytes;
191
+ }
192
+ const dailyGrowth = last30 / 30;
193
+
194
+ document.getElementById('stat-total').textContent = humanSize(totalBytes);
195
+ document.getElementById('stat-files').textContent = totalFiles;
196
+ document.getElementById('stat-growth').textContent = humanSize(dailyGrowth);
197
+ document.getElementById('stat-largest').textContent = humanSize(largestSize);
198
+
199
+ // Growth projection
200
+ const daysTo10GB = (10*1024**3 - totalBytes) / dailyGrowth;
201
+ if (daysTo10GB > 0 && daysTo10GB < 3650) {
202
+ const d = new Date(now.getTime() + daysTo10GB*86400000);
203
+ document.getElementById('growth-badge').textContent = `At this rate → 10 GB by ${d.toISOString().slice(0,7)}`;
204
+ } else {
205
+ document.getElementById('growth-badge').textContent = `${totalFiles} session files · ${humanSize(totalBytes)} total`;
206
+ }
207
+
208
+ // Monthly chart
209
+ const months = Object.entries(byMonth).sort((a,b)=>a[0].localeCompare(b[0])).slice(-12);
210
+ const maxM = Math.max(...months.map(([,b])=>b));
211
+ const curMonth = `${now.getFullYear()}-${String(now.getMonth()+1).padStart(2,'0')}`;
212
+ document.getElementById('month-chart').innerHTML = months.map(([m,b]) =>
213
+ `<div class="bar-row">
214
+ <div class="bar-label">${m}</div>
215
+ <div class="bar-track"><div class="bar-fill-month" style="width:${(b/maxM*100).toFixed(1)}%"></div></div>
216
+ <div class="bar-count">${humanSize(b)}${m===curMonth?' *':''}</div>
217
+ </div>`
218
+ ).join('');
219
+
220
+ // Project chart
221
+ const projs = Object.entries(byProj).sort((a,b)=>b[1]-a[1]).slice(0,8);
222
+ const maxP = projs[0]?.[1]||1;
223
+ document.getElementById('proj-chart').innerHTML = projs.map(([name,bytes]) =>
224
+ `<div class="bar-row">
225
+ <div class="bar-label-wide">${name}</div>
226
+ <div class="bar-track"><div class="bar-fill-proj" style="width:${(bytes/maxP*100).toFixed(1)}%"></div></div>
227
+ <div class="bar-count">${humanSize(bytes)}</div>
228
+ </div>`
229
+ ).join('');
230
+
231
+ resultEl.classList.add('visible');
232
+ }
233
+ </script>
234
+ </body>
235
+ </html>
package/package.json ADDED
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "cc-size",
3
+ "version": "1.0.0",
4
+ "description": "How much conversation history have you accumulated? Total disk usage and growth rate of your Claude Code sessions.",
5
+ "type": "module",
6
+ "bin": {
7
+ "cc-size": "./cli.mjs"
8
+ },
9
+ "scripts": {
10
+ "start": "node cli.mjs"
11
+ },
12
+ "keywords": [
13
+ "claude",
14
+ "claude-code",
15
+ "ai",
16
+ "developer-tools",
17
+ "analytics",
18
+ "productivity"
19
+ ],
20
+ "author": "yurukusa",
21
+ "license": "MIT",
22
+ "engines": {
23
+ "node": ">=18"
24
+ }
25
+ }