cchubber 0.3.8 → 0.4.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.
package/package.json
CHANGED
|
@@ -243,7 +243,7 @@ export function aggregateByProject(entries, claudeDir) {
|
|
|
243
243
|
}
|
|
244
244
|
|
|
245
245
|
// Decode project paths from directory names
|
|
246
|
-
// Claude Code encodes paths as: C--Users-
|
|
246
|
+
// Claude Code encodes paths as: C--Users-username-Documents-Project-Name
|
|
247
247
|
// Decode: replace leading drive letter pattern, split on -, take last meaningful segments
|
|
248
248
|
for (const proj of Object.values(byProject)) {
|
|
249
249
|
proj.sessionCount = proj.sessions.size;
|
|
@@ -268,8 +268,8 @@ function cleanModelName(name) {
|
|
|
268
268
|
|
|
269
269
|
/**
|
|
270
270
|
* Decode Claude Code's encoded project directory name into a readable path and name.
|
|
271
|
-
* Format: C--Users-
|
|
272
|
-
* Becomes: C:/Users/
|
|
271
|
+
* Format: C--Users-username-Documents-Projects-My-Project
|
|
272
|
+
* Becomes: C:/Users/username/Documents/.../My-Project → name: "My-Project"
|
|
273
273
|
*/
|
|
274
274
|
function decodeProjectHash(hash) {
|
|
275
275
|
if (!hash || hash === 'unknown') return { path: null, name: 'Unknown' };
|
|
@@ -487,8 +487,9 @@ ${inflection && inflection.multiplier >= 1.5 ? `
|
|
|
487
487
|
<!-- 7. PROJECTS TABLE -->
|
|
488
488
|
${projectBreakdown && projectBreakdown.length > 0 ? `
|
|
489
489
|
<section class="bg-[#1b1c1d] rounded-xl border border-[rgba(70,69,84,0.15)] overflow-hidden">
|
|
490
|
-
<div class="px-8 py-6 border-b border-[rgba(70,69,84,0.15)]">
|
|
490
|
+
<div class="px-8 py-6 border-b border-[rgba(70,69,84,0.15)] flex justify-between items-center">
|
|
491
491
|
<h3 class="text-xl font-bold text-[#e3e2e3]">Projects</h3>
|
|
492
|
+
<button id="toggle-paths" onclick="document.querySelectorAll('.proj-name,.proj-path').forEach(e=>e.style.filter=e.style.filter?'':'blur(8px)');this.textContent=this.textContent==='Hide names'?'Show names':'Hide names'" class="text-[10px] font-mono text-[#908fa0] px-3 py-1 border border-[rgba(70,69,84,0.3)] rounded cursor-pointer hover:text-[#e3e2e3]">Hide names</button>
|
|
492
493
|
</div>
|
|
493
494
|
<div class="overflow-x-auto">
|
|
494
495
|
<table class="w-full text-left" id="proj-tbl">
|
|
@@ -675,8 +676,8 @@ ${cacheHealth.totalCacheBreaks > 0 ? `
|
|
|
675
676
|
for(var i=0;i<P.length;i++){
|
|
676
677
|
var p=P[i];
|
|
677
678
|
h+='<tr class="tbl-row">';
|
|
678
|
-
h+='<td class="px-8 py-4 text-sm font-semibold text-[#e3e2e3]">'+p.name;
|
|
679
|
-
if(p.path)h+='<br><span class="text-[10px] text-[#908fa0] font-mono">'+p.path+'</span>';
|
|
679
|
+
h+='<td class="px-8 py-4 text-sm font-semibold text-[#e3e2e3]"><span class="proj-name">'+p.name+'</span>';
|
|
680
|
+
if(p.path)h+='<br><span class="proj-path text-[10px] text-[#908fa0] font-mono">'+p.path+'</span>';
|
|
680
681
|
h+='</td>';
|
|
681
682
|
h+='<td class="px-8 py-4 font-mono text-sm text-[#c7c4d7]">'+p.messages.toLocaleString()+'</td>';
|
|
682
683
|
h+='<td class="px-8 py-4 font-mono text-sm text-[#c7c4d7]">'+p.sessions+'</td>';
|
package/src/telemetry.js
CHANGED
|
@@ -19,9 +19,23 @@ export function shouldSendTelemetry(flags) {
|
|
|
19
19
|
if (flags.noTelemetry) return false;
|
|
20
20
|
if (process.env.CC_HUBBER_TELEMETRY === '0') return false;
|
|
21
21
|
if (process.env.DO_NOT_TRACK === '1') return false;
|
|
22
|
+
|
|
23
|
+
// Throttle: once per 24 hours per machine
|
|
24
|
+
const stampFile = join(homedir(), '.cchubber-last-telemetry');
|
|
25
|
+
try {
|
|
26
|
+
if (existsSync(stampFile)) {
|
|
27
|
+
const last = parseInt(readFileSync(stampFile, 'utf-8').trim());
|
|
28
|
+
if (Date.now() - last < 86400000) return false; // <24h since last send
|
|
29
|
+
}
|
|
30
|
+
} catch {}
|
|
31
|
+
|
|
22
32
|
return true;
|
|
23
33
|
}
|
|
24
34
|
|
|
35
|
+
function markTelemetrySent() {
|
|
36
|
+
try { writeFileSync(join(homedir(), '.cchubber-last-telemetry'), String(Date.now())); } catch {}
|
|
37
|
+
}
|
|
38
|
+
|
|
25
39
|
export function sendTelemetry(report) {
|
|
26
40
|
const payload = {
|
|
27
41
|
v: '0.3.3',
|
|
@@ -136,6 +150,7 @@ export function sendTelemetry(report) {
|
|
|
136
150
|
req.setTimeout(3000, () => req.destroy());
|
|
137
151
|
req.write(data);
|
|
138
152
|
req.end();
|
|
153
|
+
markTelemetrySent();
|
|
139
154
|
} catch {
|
|
140
155
|
// never crash on telemetry
|
|
141
156
|
}
|