ccgauge 1.0.1 → 1.0.3
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/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/app-build-manifest.json +39 -39
- package/.next/standalone/.next/app-path-routes-manifest.json +8 -8
- package/.next/standalone/.next/build-manifest.json +2 -2
- package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/blocks/route.js +1 -1
- package/.next/standalone/.next/server/app/api/blocks/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/blocks/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/export/usage/route.js +1 -1
- package/.next/standalone/.next/server/app/api/export/usage/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/export/usage/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/pricing/route.js +1 -1
- package/.next/standalone/.next/server/app/api/pricing/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/projects/route.js +1 -1
- package/.next/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/scan/route.js +1 -1
- package/.next/standalone/.next/server/app/api/scan/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/scan/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/sessions/route.js +1 -1
- package/.next/standalone/.next/server/app/api/sessions/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/sessions/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/usage/route.js +1 -1
- package/.next/standalone/.next/server/app/api/usage/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/usage/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/models/page.js +2 -2
- package/.next/standalone/.next/server/app/models/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/models/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/page.js +2 -2
- package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/projects/[id]/page.js +2 -2
- package/.next/standalone/.next/server/app/projects/[id]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/projects/[id]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/projects/page.js +1 -1
- package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/sessions/[id]/page.js +2 -2
- package/.next/standalone/.next/server/app/sessions/[id]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/sessions/[id]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/sessions/page.js +1 -1
- package/.next/standalone/.next/server/app/sessions/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/sessions/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/settings/page.js +1 -1
- package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/usage/page.js +3 -3
- package/.next/standalone/.next/server/app/usage/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/usage/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app-paths-manifest.json +8 -8
- package/.next/standalone/.next/server/chunks/567.js +3 -3
- package/.next/standalone/.next/server/chunks/716.js +1 -1
- package/.next/standalone/.next/server/chunks/{775.js → 971.js} +1 -1
- package/.next/standalone/.next/server/chunks/98.js +1 -0
- package/.next/standalone/.next/server/functions-config-manifest.json +1 -1
- package/.next/standalone/.next/server/pages/500.html +1 -1
- package/.next/standalone/.next/static/chunks/148-0a1e1b0207b89e3f.js +1 -0
- package/.next/standalone/.next/static/chunks/app/layout-2512ccdfb13aeb17.js +1 -0
- package/.next/standalone/.next/static/chunks/app/page-19d3e77d4aa35a63.js +1 -0
- package/.next/standalone/.next/static/chunks/app/usage/{page-63c230b1e2c5c63c.js → page-18fd820a3111bd5b.js} +1 -1
- package/.next/standalone/.next/static/css/406e067663b8b429.css +3 -0
- package/.next/standalone/node_modules/next/node_modules/postcss/package.json +0 -0
- package/.next/standalone/package.json +1 -1
- package/.next/standalone/public/claude-logo.webp +0 -0
- package/.next/standalone/public/codex-logo.png +0 -0
- package/CHANGELOG.md +297 -0
- package/README.md +19 -6
- package/README.zh-CN.md +19 -6
- package/bin/cli.mjs +37 -17
- package/dist/mcp/server.mjs +40 -23695
- package/dist/report/index.mjs +42 -18
- package/package.json +16 -18
- package/.next/standalone/.next/server/chunks/155.js +0 -1
- package/.next/standalone/.next/static/chunks/148-d2db1767205d1ca8.js +0 -1
- package/.next/standalone/.next/static/chunks/app/layout-ca9328306c8cbb8e.js +0 -1
- package/.next/standalone/.next/static/chunks/app/page-11fc9a0ded501248.js +0 -1
- package/.next/standalone/.next/static/css/b34dbb2d1cbeaf5e.css +0 -3
- /package/.next/standalone/.next/static/{2kImy5ZkabMplKu3i19s7 → alqi5oQtTQUdpxp2x0yAt}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{2kImy5ZkabMplKu3i19s7 → alqi5oQtTQUdpxp2x0yAt}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgb(59 130 246/0.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgb(59 130 246/0.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }/*
|
|
2
|
+
! tailwindcss v3.4.19 | MIT License | https://tailwindcss.com
|
|
3
|
+
*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}:host,html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:var(--font-sans),ui-sans-serif,system-ui,sans-serif;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:var(--font-mono),ui-monospace,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}.card{border-radius:12px;border-width:1px;--tw-border-opacity:1;border-color:rgb(var(--border)/var(--tw-border-opacity,1));--tw-bg-opacity:1;background-color:rgb(var(--bg-surface)/var(--tw-bg-opacity,1));box-shadow:var(--shadow-card)}.card-elevated{background:rgb(var(--bg-elevated));box-shadow:var(--shadow-popover)}.card-pad{padding:1.25rem}@media (min-width:640px){.card-pad{padding:1.5rem}}.label{font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.06em;--tw-text-opacity:1;color:rgb(var(--text-tertiary)/var(--tw-text-opacity,1))}.num-hero{overflow-wrap:break-word;font-size:1.875rem;line-height:2.25rem;font-weight:600;--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction);letter-spacing:-.025em;--tw-text-opacity:1;color:rgb(var(--text-primary)/var(--tw-text-opacity,1))}@media (min-width:640px){.num-hero{font-size:2rem;line-height:2.25rem}}.num-mid{font-size:1.5rem;line-height:2rem;font-weight:600;--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction);--tw-text-opacity:1;color:rgb(var(--text-primary)/var(--tw-text-opacity,1))}.num-mono{font-family:var(--font-mono),ui-monospace,monospace;--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction)}.pill{display:inline-flex;align-items:center;border-radius:8px;padding:.125rem .5rem;font-size:.75rem;font-weight:500;line-height:1.25rem}.pill-muted{padding:.125rem .5rem;font-size:.75rem;background-color:rgb(var(--bg-surface-hi)/var(--tw-bg-opacity,1));color:rgb(var(--text-secondary)/var(--tw-text-opacity,1))}.btn,.pill-muted{display:inline-flex;align-items:center;border-radius:8px;font-weight:500;line-height:1.25rem;border-width:1px;--tw-border-opacity:1;border-color:rgb(var(--border)/var(--tw-border-opacity,1));--tw-bg-opacity:1;--tw-text-opacity:1}.btn{justify-content:center;gap:.375rem;background-color:rgb(var(--bg-surface)/var(--tw-bg-opacity,1));padding:.375rem .75rem;font-size:.875rem;color:rgb(var(--text-primary)/var(--tw-text-opacity,1));transition:background-color .15s,border-color .15s,color .15s,transform .1s,box-shadow .15s}.btn:hover:not(:disabled){background:rgb(var(--bg-surface-hi));border-color:rgb(var(--border-hi))}.btn:active:not(:disabled){transform:translateY(1px)}.btn:disabled{cursor:not-allowed;opacity:.5}.btn-ghost{display:inline-flex;align-items:center;justify-content:center;gap:.375rem;border-radius:8px;padding:.375rem .75rem;font-size:.875rem;line-height:1.25rem;font-weight:500;--tw-text-opacity:1;color:rgb(var(--text-secondary)/var(--tw-text-opacity,1));transition:background-color .15s,color .15s}.btn-ghost:hover:not(:disabled){color:rgb(var(--text-primary));background:rgb(var(--bg-surface-hi))}.btn-ghost:disabled{cursor:not-allowed;opacity:.4}.section-header{background:linear-gradient(to bottom,rgb(var(--bg-surface)) 0,rgb(var(--bg-surface-hi)/.4) 100%)}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.pointer-events-none{pointer-events:none}.\!visible{visibility:visible!important}.visible{visibility:visible}.collapse{visibility:collapse}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.-bottom-\[12px\]{bottom:-12px}.bottom-0{bottom:0}.left-0{left:0}.left-2{left:.5rem}.right-0{right:0}.right-2{right:.5rem}.top-0{top:0}.z-20{z-index:20}.z-30{z-index:30}.z-50{z-index:50}.mx-auto{margin-left:auto;margin-right:auto}.mb-1{margin-bottom:.25rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.ml-1{margin-left:.25rem}.ml-1\.5{margin-left:.375rem}.ml-auto{margin-left:auto}.mr-1{margin-right:.25rem}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-1\.5{margin-top:.375rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.mt-auto{margin-top:auto}.\!block{display:block!important}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.contents{display:contents}.\!hidden{display:none!important}.hidden{display:none}.aspect-square{aspect-ratio:1/1}.h-1{height:.25rem}.h-1\.5{height:.375rem}.h-12{height:3rem}.h-14{height:3.5rem}.h-2{height:.5rem}.h-2\.5{height:.625rem}.h-3{height:.75rem}.h-3\.5{height:.875rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-64{height:16rem}.h-7{height:1.75rem}.h-72{height:18rem}.h-8{height:2rem}.h-\[2px\]{height:2px}.h-\[3px\]{height:3px}.h-full{height:100%}.max-h-48{max-height:12rem}.max-h-64{max-height:16rem}.max-h-72{max-height:18rem}.min-h-\[132px\]{min-height:132px}.min-h-\[160px\]{min-height:160px}.min-h-\[180px\]{min-height:180px}.min-h-\[280px\]{min-height:280px}.min-h-\[64px\]{min-height:64px}.min-h-screen{min-height:100vh}.w-1\.5{width:.375rem}.w-12{width:3rem}.w-2{width:.5rem}.w-2\.5{width:.625rem}.w-20{width:5rem}.w-24{width:6rem}.w-3\.5{width:.875rem}.w-32{width:8rem}.w-4{width:1rem}.w-48{width:12rem}.w-5{width:1.25rem}.w-56{width:14rem}.w-6{width:1.5rem}.w-7{width:1.75rem}.w-72{width:18rem}.w-8{width:2rem}.w-9{width:2.25rem}.w-\[26px\]{width:26px}.w-full{width:100%}.min-w-0{min-width:0}.min-w-\[120px\]{min-width:120px}.min-w-\[180px\]{min-width:180px}.min-w-\[200px\]{min-width:200px}.min-w-\[80px\]{min-width:80px}.max-w-2xl{max-width:42rem}.max-w-7xl{max-width:80rem}.max-w-\[160px\]{max-width:160px}.max-w-\[180px\]{max-width:180px}.max-w-\[280px\]{max-width:280px}.max-w-\[320px\]{max-width:320px}.max-w-full{max-width:100%}.max-w-md{max-width:28rem}.flex-1{flex:1 1 0%}.flex-shrink-0,.shrink-0{flex-shrink:0}.grow{flex-grow:1}.translate-x-5{--tw-translate-x:1.25rem}.transform,.translate-x-5{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}.cursor-help{cursor:help}.cursor-pointer{cursor:pointer}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.list-inside{list-style-position:inside}.list-disc{list-style-type:disc}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.grid-cols-\[auto_1fr\]{grid-template-columns:auto 1fr}.grid-cols-\[auto_1fr_auto\]{grid-template-columns:auto 1fr auto}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-start{align-items:flex-start}.items-center{align-items:center}.items-baseline{align-items:baseline}.items-stretch{align-items:stretch}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-0\.5{gap:.125rem}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-2\.5{gap:.625rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-5{gap:1.25rem}.gap-\[3px\]{gap:3px}.gap-x-3{-moz-column-gap:.75rem;column-gap:.75rem}.gap-y-0\.5{row-gap:.125rem}.gap-y-1\.5{row-gap:.375rem}.gap-y-\[3px\]{row-gap:3px}.space-y-0\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.125rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.125rem * var(--tw-space-y-reverse))}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem * var(--tw-space-y-reverse))}.space-y-1\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.375rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.375rem * var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.75rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem * var(--tw-space-y-reverse))}.space-y-3\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.875rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.875rem * var(--tw-space-y-reverse))}.space-y-5>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.25rem * var(--tw-space-y-reverse))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem * var(--tw-space-y-reverse))}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.truncate{overflow:hidden;text-overflow:ellipsis}.truncate,.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.break-words{overflow-wrap:break-word}.rounded{border-radius:.25rem}.rounded-\[3px\]{border-radius:3px}.rounded-\[4px\]{border-radius:4px}.rounded-button{border-radius:8px}.rounded-card{border-radius:12px}.rounded-full{border-radius:9999px}.rounded-md{border-radius:.375rem}.rounded-sm{border-radius:.125rem}.border{border-width:1px}.border-b{border-bottom-width:1px}.border-t{border-top-width:1px}.border-dashed{border-style:dashed}.border-border{--tw-border-opacity:1;border-color:rgb(var(--border)/var(--tw-border-opacity,1))}.border-border-hi{--tw-border-opacity:1;border-color:rgb(var(--border-hi)/var(--tw-border-opacity,1))}.border-border\/60{border-color:rgb(var(--border)/.6)}.border-brand{--tw-border-opacity:1;border-color:rgb(var(--brand)/var(--tw-border-opacity,1))}.border-brand\/20{border-color:rgb(var(--brand)/.2)}.border-brand\/40{border-color:rgb(var(--brand)/.4)}.border-danger\/20{border-color:rgb(var(--danger)/.2)}.border-success\/20{border-color:rgb(var(--success)/.2)}.border-warning\/20{border-color:rgb(var(--warning)/.2)}.bg-bg{--tw-bg-opacity:1;background-color:rgb(var(--bg-base)/var(--tw-bg-opacity,1))}.bg-bg-surface{--tw-bg-opacity:1;background-color:rgb(var(--bg-surface)/var(--tw-bg-opacity,1))}.bg-bg-surface-hi{--tw-bg-opacity:1;background-color:rgb(var(--bg-surface-hi)/var(--tw-bg-opacity,1))}.bg-bg-surface-hi\/20{background-color:rgb(var(--bg-surface-hi)/.2)}.bg-bg-surface-hi\/30{background-color:rgb(var(--bg-surface-hi)/.3)}.bg-bg-surface-hi\/40{background-color:rgb(var(--bg-surface-hi)/.4)}.bg-bg-surface-hi\/60{background-color:rgb(var(--bg-surface-hi)/.6)}.bg-brand{--tw-bg-opacity:1;background-color:rgb(var(--brand)/var(--tw-bg-opacity,1))}.bg-brand-strong{--tw-bg-opacity:1;background-color:rgb(var(--brand-strong)/var(--tw-bg-opacity,1))}.bg-brand\/10{background-color:rgb(var(--brand)/.1)}.bg-chart-cache-create{--tw-bg-opacity:1;background-color:rgb(var(--chart-cache-create)/var(--tw-bg-opacity,1))}.bg-chart-cache-create\/15{background-color:rgb(var(--chart-cache-create)/.15)}.bg-chart-cache-read{--tw-bg-opacity:1;background-color:rgb(var(--chart-cache-read)/var(--tw-bg-opacity,1))}.bg-chart-input{--tw-bg-opacity:1;background-color:rgb(var(--chart-input)/var(--tw-bg-opacity,1))}.bg-chart-output{--tw-bg-opacity:1;background-color:rgb(var(--chart-output)/var(--tw-bg-opacity,1))}.bg-danger{--tw-bg-opacity:1;background-color:rgb(var(--danger)/var(--tw-bg-opacity,1))}.bg-danger\/10{background-color:rgb(var(--danger)/.1)}.bg-success{--tw-bg-opacity:1;background-color:rgb(var(--success)/var(--tw-bg-opacity,1))}.bg-success\/10{background-color:rgb(var(--success)/.1)}.bg-warning{--tw-bg-opacity:1;background-color:rgb(var(--warning)/var(--tw-bg-opacity,1))}.bg-warning\/10{background-color:rgb(var(--warning)/.1)}.bg-gradient-to-l{background-image:linear-gradient(to left,var(--tw-gradient-stops))}.bg-gradient-to-r{background-image:linear-gradient(to right,var(--tw-gradient-stops))}.from-bg-surface{--tw-gradient-from:rgb(var(--bg-surface)/1) var(--tw-gradient-from-position);--tw-gradient-to:rgb(var(--bg-surface)/0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.from-brand{--tw-gradient-from:rgb(var(--brand)/1) var(--tw-gradient-from-position);--tw-gradient-to:rgb(var(--brand)/0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.from-brand\/0{--tw-gradient-from:rgb(var(--brand)/0) var(--tw-gradient-from-position);--tw-gradient-to:rgb(var(--brand)/0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.from-success\/0{--tw-gradient-from:rgb(var(--success)/0) var(--tw-gradient-from-position);--tw-gradient-to:rgb(var(--success)/0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.from-warning\/0{--tw-gradient-from:rgb(var(--warning)/0) var(--tw-gradient-from-position);--tw-gradient-to:rgb(var(--warning)/0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.via-brand\/70{--tw-gradient-to:rgb(var(--brand)/0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),rgb(var(--brand)/0.7) var(--tw-gradient-via-position),var(--tw-gradient-to)}.via-success\/70{--tw-gradient-to:rgb(var(--success)/0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),rgb(var(--success)/0.7) var(--tw-gradient-via-position),var(--tw-gradient-to)}.via-warning\/70{--tw-gradient-to:rgb(var(--warning)/0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),rgb(var(--warning)/0.7) var(--tw-gradient-via-position),var(--tw-gradient-to)}.to-brand-hover{--tw-gradient-to:rgb(var(--brand-hover)/1) var(--tw-gradient-to-position)}.to-brand\/0{--tw-gradient-to:rgb(var(--brand)/0) var(--tw-gradient-to-position)}.to-success\/0{--tw-gradient-to:rgb(var(--success)/0) var(--tw-gradient-to-position)}.to-transparent{--tw-gradient-to:transparent var(--tw-gradient-to-position)}.to-warning\/0{--tw-gradient-to:rgb(var(--warning)/0) var(--tw-gradient-to-position)}.fill-brand{fill:rgb(var(--brand)/1)}.fill-white{fill:#fff}.object-contain{-o-object-fit:contain;object-fit:contain}.p-0{padding:0}.p-0\.5{padding:.125rem}.p-1{padding:.25rem}.p-2{padding:.5rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-5{padding:1.25rem}.px-1{padding-left:.25rem;padding-right:.25rem}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-2\.5{padding-left:.625rem;padding-right:.625rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-3\.5{padding-left:.875rem;padding-right:.875rem}.px-4{padding-left:1rem;padding-right:1rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-12{padding-top:3rem;padding-bottom:3rem}.py-14{padding-top:3.5rem;padding-bottom:3.5rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-6{padding-top:1.5rem;padding-bottom:1.5rem}.py-8{padding-top:2rem;padding-bottom:2rem}.pb-1\.5{padding-bottom:.375rem}.pb-3{padding-bottom:.75rem}.pl-2{padding-left:.5rem}.pl-4{padding-left:1rem}.pr-1\.5{padding-right:.375rem}.pr-2{padding-right:.5rem}.pr-2\.5{padding-right:.625rem}.pt-2{padding-top:.5rem}.pt-3{padding-top:.75rem}.pt-4{padding-top:1rem}.pt-\[18px\]{padding-top:18px}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.text-2xl{font-size:1.5rem;line-height:2rem}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-\[15px\]{font-size:15px}.text-\[9px\]{font-size:9px}.text-base{font-size:1rem;line-height:1.5rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.lowercase{text-transform:lowercase}.capitalize{text-transform:capitalize}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction)}.leading-none{line-height:1}.leading-relaxed{line-height:1.625}.leading-snug{line-height:1.375}.leading-tight{line-height:1.25}.tracking-\[0\.06em\]{letter-spacing:.06em}.tracking-tight{letter-spacing:-.025em}.tracking-wide{letter-spacing:.025em}.text-brand{--tw-text-opacity:1;color:rgb(var(--brand)/var(--tw-text-opacity,1))}.text-brand\/70{color:rgb(var(--brand)/.7)}.text-chart-cache-create{--tw-text-opacity:1;color:rgb(var(--chart-cache-create)/var(--tw-text-opacity,1))}.text-danger{--tw-text-opacity:1;color:rgb(var(--danger)/var(--tw-text-opacity,1))}.text-success{--tw-text-opacity:1;color:rgb(var(--success)/var(--tw-text-opacity,1))}.text-text-primary{--tw-text-opacity:1;color:rgb(var(--text-primary)/var(--tw-text-opacity,1))}.text-text-secondary{--tw-text-opacity:1;color:rgb(var(--text-secondary)/var(--tw-text-opacity,1))}.text-text-tertiary{--tw-text-opacity:1;color:rgb(var(--text-tertiary)/var(--tw-text-opacity,1))}.text-warning{--tw-text-opacity:1;color:rgb(var(--warning)/var(--tw-text-opacity,1))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.accent-brand{accent-color:rgb(var(--brand)/1)}.opacity-0{opacity:0}.opacity-100{opacity:1}.shadow-lg{--tw-shadow:0 10px 15px -3px rgb(0 0 0/0.1),0 4px 6px -4px rgb(0 0 0/0.1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color)}.shadow-lg,.shadow-sm{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 2px 0 rgb(0 0 0/0.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color)}.shadow-xl{--tw-shadow:0 20px 25px -5px rgb(0 0 0/0.1),0 8px 10px -6px rgb(0 0 0/0.1);--tw-shadow-colored:0 20px 25px -5px var(--tw-shadow-color),0 8px 10px -6px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.outline-none{outline:2px solid transparent;outline-offset:2px}.ring-1{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.ring-bg-surface{--tw-ring-opacity:1;--tw-ring-color:rgb(var(--bg-surface)/var(--tw-ring-opacity,1))}.ring-brand\/40{--tw-ring-color:rgb(var(--brand)/0.4)}.ring-white\/40{--tw-ring-color:rgb(255 255 255/0.4)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.backdrop-blur-md{--tw-backdrop-blur:blur(12px)}.backdrop-blur-md,.backdrop-filter{backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-100{transition-duration:.1s}.duration-150{transition-duration:.15s}.duration-500{transition-duration:.5s}.ease-out-soft{transition-timing-function:cubic-bezier(.16,1,.3,1)}.\[ccgauge\:api\]{ccgauge:api}.\[ccgauge\:indexer\]{ccgauge:indexer}.\[grid-template-columns\:auto_1fr\]{grid-template-columns:auto 1fr}.\[grid-template-columns\:repeat\(24\2c minmax\(0\2c 1fr\)\)\]{grid-template-columns:repeat(24,minmax(0,1fr))}.theme-dark,:root{--bg-base:10 10 10;--bg-surface:22 22 22;--bg-surface-hi:32 32 34;--bg-elevated:38 38 42;--border:38 38 42;--border-hi:64 64 70;--text-primary:250 250 250;--text-secondary:168 168 174;--text-tertiary:120 120 128;--brand:129 140 248;--brand-hover:165 180 252;--brand-strong:99 102 241;--success:34 197 94;--warning:250 204 21;--danger:248 113 113;--chart-input:96 165 250;--chart-output:251 146 60;--chart-cache-read:52 211 153;--chart-cache-create:167 139 250;--chart-grid:38 38 42;--chart-axis:120 120 128;--shadow-card:0 1px 0 0 rgb(255 255 255/0.02),0 4px 12px -4px rgb(0 0 0/0.4);--shadow-card-hover:0 1px 0 0 rgb(255 255 255/0.04),0 8px 24px -8px rgb(0 0 0/0.6);--shadow-popover:0 4px 12px -2px rgb(0 0 0/0.4),0 16px 48px -8px rgb(0 0 0/0.6);--ring-focus:129 140 248}.theme-light{--bg-base:252 252 253;--bg-surface:255 255 255;--bg-surface-hi:247 247 249;--bg-elevated:250 250 252;--border:226 226 232;--border-hi:200 200 208;--text-primary:17 17 23;--text-secondary:82 82 91;--text-tertiary:145 145 156;--brand:79 70 229;--brand-hover:67 56 202;--brand-strong:79 70 229;--success:22 163 74;--warning:217 119 6;--danger:220 38 38;--chart-input:37 99 235;--chart-output:234 88 12;--chart-cache-read:22 163 74;--chart-cache-create:124 58 237;--chart-grid:232 232 238;--chart-axis:113 113 122;--shadow-card:0 1px 2px 0 rgb(15 23 42/0.04),0 1px 3px 0 rgb(15 23 42/0.04);--shadow-card-hover:0 4px 12px -2px rgb(15 23 42/0.08),0 8px 32px -8px rgb(15 23 42/0.06);--shadow-popover:0 8px 24px -4px rgb(15 23 42/0.08),0 16px 48px -8px rgb(15 23 42/0.08);--ring-focus:79 70 229}:root{--font-sans:"Geist Sans","Inter",-apple-system,BlinkMacSystemFont,"Segoe UI",system-ui,"PingFang SC","Hiragino Sans GB","Microsoft YaHei",sans-serif;--font-mono:"Geist Mono","JetBrains Mono",ui-monospace,SFMono-Regular,Menlo,monospace}*{border-color:rgb(var(--border))}html{overflow-y:scroll;scrollbar-gutter:stable}body,html{background:rgb(var(--bg-base));color:rgb(var(--text-primary));font-family:var(--font-sans);font-feature-settings:"cv11","ss01","ss03";-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-rendering:optimizeLegibility}body{min-height:100vh}::-moz-selection{background:rgb(var(--brand)/.25);color:rgb(var(--text-primary))}::selection{background:rgb(var(--brand)/.25);color:rgb(var(--text-primary))}::-webkit-scrollbar{width:10px;height:10px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:rgb(var(--border-hi)/.7);border:2px solid transparent;background-clip:padding-box;border-radius:6px}::-webkit-scrollbar-thumb:hover{background:rgb(var(--text-tertiary)/.7);background-clip:padding-box}.scrollbar-thin::-webkit-scrollbar{width:6px;height:6px}.scrollbar-thin::-webkit-scrollbar-thumb{background:rgb(var(--border-hi)/.5);border:0;border-radius:3px}.nav-scroller{scrollbar-width:none}.nav-scroller::-webkit-scrollbar{display:none;width:0;height:0}:where(button,a,input,select,textarea,[tabindex]):focus-visible{outline:2px solid rgb(var(--ring-focus)/.6);outline-offset:2px;border-radius:6px}@media (prefers-reduced-motion:reduce){*,:after,:before{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important;scroll-behavior:auto!important}}.divider-soft{border-top:1px solid rgb(var(--border))}html[data-usage-overview=hidden] .usage-overview-block{display:none}.placeholder\:text-text-tertiary::-moz-placeholder{--tw-text-opacity:1;color:rgb(var(--text-tertiary)/var(--tw-text-opacity,1))}.placeholder\:text-text-tertiary::placeholder{--tw-text-opacity:1;color:rgb(var(--text-tertiary)/var(--tw-text-opacity,1))}.last\:border-b-0:last-child{border-bottom-width:0}.hover\:z-10:hover{z-index:10}.hover\:scale-125:hover{--tw-scale-x:1.25;--tw-scale-y:1.25;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.hover\:border-border-hi:hover{--tw-border-opacity:1;border-color:rgb(var(--border-hi)/var(--tw-border-opacity,1))}.hover\:border-brand\/60:hover{border-color:rgb(var(--brand)/.6)}.hover\:border-text-tertiary:hover{--tw-border-opacity:1;border-color:rgb(var(--text-tertiary)/var(--tw-border-opacity,1))}.hover\:bg-bg-surface-hi:hover{--tw-bg-opacity:1;background-color:rgb(var(--bg-surface-hi)/var(--tw-bg-opacity,1))}.hover\:bg-bg-surface-hi\/30:hover{background-color:rgb(var(--bg-surface-hi)/.3)}.hover\:bg-bg-surface-hi\/40:hover{background-color:rgb(var(--bg-surface-hi)/.4)}.hover\:bg-bg-surface-hi\/60:hover{background-color:rgb(var(--bg-surface-hi)/.6)}.hover\:bg-brand\/15:hover{background-color:rgb(var(--brand)/.15)}.hover\:bg-brand\/20:hover{background-color:rgb(var(--brand)/.2)}.hover\:text-brand:hover{--tw-text-opacity:1;color:rgb(var(--brand)/var(--tw-text-opacity,1))}.hover\:text-text-primary:hover{--tw-text-opacity:1;color:rgb(var(--text-primary)/var(--tw-text-opacity,1))}.hover\:opacity-90:hover{opacity:.9}.hover\:ring-1:hover{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.hover\:ring-brand\/60:hover{--tw-ring-color:rgb(var(--brand)/0.6)}.focus\:border-border-hi:focus{--tw-border-opacity:1;border-color:rgb(var(--border-hi)/var(--tw-border-opacity,1))}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus-visible\:ring-2:focus-visible{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.focus-visible\:ring-brand\/40:focus-visible{--tw-ring-color:rgb(var(--brand)/0.4)}.disabled\:opacity-40:disabled{opacity:.4}.group:hover .group-hover\:text-brand{--tw-text-opacity:1;color:rgb(var(--brand)/var(--tw-text-opacity,1))}.group:hover .group-hover\:brightness-110{--tw-brightness:brightness(1.1);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}@media (min-width:640px){.sm\:mt-0{margin-top:0}.sm\:inline{display:inline}.sm\:flex{display:flex}.sm\:flex-row{flex-direction:row}.sm\:items-start{align-items:flex-start}.sm\:items-end{align-items:flex-end}.sm\:items-baseline{align-items:baseline}.sm\:justify-between{justify-content:space-between}.sm\:gap-2\.5{gap:.625rem}.sm\:gap-4{gap:1rem}.sm\:space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem * var(--tw-space-y-reverse))}.sm\:p-6{padding:1.5rem}.sm\:px-3{padding-left:.75rem;padding-right:.75rem}.sm\:px-6{padding-left:1.5rem;padding-right:1.5rem}.sm\:py-16{padding-top:4rem;padding-bottom:4rem}.sm\:py-8{padding-top:2rem;padding-bottom:2rem}.sm\:pt-5{padding-top:1.25rem}.sm\:pt-\[22px\]{padding-top:22px}.sm\:text-\[1\.75rem\]{font-size:1.75rem}}@media (min-width:768px){.md\:flex{display:flex}.md\:inline-flex{display:inline-flex}.md\:w-\[170px\]{width:170px}.md\:shrink-0{flex-shrink:0}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.md\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.md\:flex-row{flex-direction:row}.md\:flex-col{flex-direction:column}.md\:gap-8{gap:2rem}}@media (min-width:1024px){.lg\:col-span-2{grid-column:span 2/span 2}.lg\:inline{display:inline}.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.lg\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}}
|
|
File without changes
|
|
Binary file
|
|
Binary file
|
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,301 @@ All notable changes to **ccgauge** are documented here.
|
|
|
5
5
|
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and
|
|
6
6
|
this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.0.3] — 2026-05-15
|
|
9
|
+
|
|
10
|
+
A focused **MCP server** correctness + performance + ergonomics pass,
|
|
11
|
+
plus a docs catch-up for the marketing site and the bundled READMEs.
|
|
12
|
+
Dashboard runtime is unchanged from 1.0.2. The MCP server adds a 9th
|
|
13
|
+
tool (`cost_estimator`), gets ~4× faster on weekly summaries, halves
|
|
14
|
+
its bundle size, and ships a `ccgauge mcp --check` self-test.
|
|
15
|
+
|
|
16
|
+
### Highlights
|
|
17
|
+
|
|
18
|
+
- **9 MCP tools** — added `cost_estimator(source, model, input_tokens,
|
|
19
|
+
output_tokens, …)` for pure pricing what-ifs (no record lookup).
|
|
20
|
+
Pairs with `usage_summary` for "if I run X more on Opus 4.7, what
|
|
21
|
+
does it add to my month-to-date?".
|
|
22
|
+
- **`weekly_summary` is ~4× faster.** Rewrote the per-day trend from
|
|
23
|
+
8 full record-set passes (1 totals + 7 daily totals × 2 internal
|
|
24
|
+
source filters) down to a single `timeBuckets('day')` call + a
|
|
25
|
+
7-slot skeleton merge. Same JSON shape out, including zero-fill
|
|
26
|
+
for empty days.
|
|
27
|
+
- **MCP bundle 810 KB → 379 KB.** esbuild `minify: true` +
|
|
28
|
+
`external: ['fsevents']` shaves 53% off the published tarball's
|
|
29
|
+
MCP slice with no runtime behaviour change.
|
|
30
|
+
- **`ccgauge mcp --check`** — verifies the bundle, boots the indexer,
|
|
31
|
+
and prints one line per provider (files / records / scanned dirs).
|
|
32
|
+
Lets users debug "Claude Desktop doesn't see ccgauge tools"
|
|
33
|
+
without spinning up an MCP client first.
|
|
34
|
+
|
|
35
|
+
### Added
|
|
36
|
+
|
|
37
|
+
- `cost_estimator` MCP tool — uses the provider's built-in
|
|
38
|
+
per-1M-token pricing table; does NOT consult usage history.
|
|
39
|
+
Useful for budgeting and cap planning.
|
|
40
|
+
- `ccgauge mcp --check` self-test command.
|
|
41
|
+
- README cross-references for both new entry points (`mcp --check`,
|
|
42
|
+
`cost_estimator`) in en + zh.
|
|
43
|
+
- `__SERVER_VERSION__` injected by esbuild from `package.json#version`
|
|
44
|
+
so the server's MCP handshake always agrees with the npm release.
|
|
45
|
+
|
|
46
|
+
### Changed
|
|
47
|
+
|
|
48
|
+
- **`ccgauge mcp` runs in-process.** The CLI subcommand used to
|
|
49
|
+
spawn a second Node process for the bundled server (`spawn(node,
|
|
50
|
+
[bundle])`); it now `await import()`s the bundle and calls
|
|
51
|
+
`runStdioServer()` directly. Saves ~80–150 ms per invocation and
|
|
52
|
+
removes a brittle signal-forwarding shim.
|
|
53
|
+
- **MCP responses are compact JSON.** Drop the `JSON.stringify(...,
|
|
54
|
+
null, 2)` pretty-print on every tool response — LLMs don't read
|
|
55
|
+
indentation but pay for it. ~30–50% smaller responses for the
|
|
56
|
+
heavier tools (`weekly_summary`, `usage_by_session`).
|
|
57
|
+
`CCGAUGE_MCP_PRETTY=1` re-enables.
|
|
58
|
+
- **Default limits on `usage_by_model` (20) and `usage_by_project`
|
|
59
|
+
(20).** The cap existed as a max; the default is now the same
|
|
60
|
+
value. A user asking "what did I work on this year" with hundreds
|
|
61
|
+
of projects no longer gets a 200-entry payload.
|
|
62
|
+
- **`recent_activity` defaults to a 30-day window** (`days` arg to
|
|
63
|
+
widen). Previously aggregated every session across the user's
|
|
64
|
+
full CLI lifetime just to return the top 10 by `end_time` — cost
|
|
65
|
+
grew linearly with history.
|
|
66
|
+
- **Day-aligned named ranges.** `7d` / `30d` / `90d` now map to
|
|
67
|
+
`[start-of(N-1 days ago), end-of-today]` like `today` /
|
|
68
|
+
`yesterday` / `this_week` already did. Previously `7d` was a
|
|
69
|
+
rolling 7×24h window, so summing seven `daily_summary` calls
|
|
70
|
+
didn't equal one `usage_summary({range:"7d"})` — they do now.
|
|
71
|
+
- **README Highlights refreshed** (en + zh). New top-level subsections
|
|
72
|
+
for `ccgauge report` (CLI) and `ccgauge mcp` (MCP server) so the
|
|
73
|
+
two no-server entry points are visible in the first scroll.
|
|
74
|
+
Cross-provider section updated for 1.0.2's tri-state switcher +
|
|
75
|
+
real provider logos + worktree-aware Projects collapsing.
|
|
76
|
+
Drill-down section mentions the Tokens / Conversations trend toggle.
|
|
77
|
+
|
|
78
|
+
### Fixed
|
|
79
|
+
|
|
80
|
+
- **`parseDateLike` no longer accepts calendar-overflow dates with
|
|
81
|
+
a time suffix.** `2026-02-31T00:00:00` used to silently roll
|
|
82
|
+
forward to March 3 (JS `new Date()` normalises invalid dates);
|
|
83
|
+
now both the bare-date branch and the time-suffix branch reject
|
|
84
|
+
it. Affects every MCP date arg, the dashboard's `from`/`to` URL
|
|
85
|
+
params, and `ccgauge report --since`/`--until`.
|
|
86
|
+
- **`SERVER_VERSION` no longer hardcoded** to `0.4.0`. Now sourced
|
|
87
|
+
from `package.json#version` at bundle time, so the MCP server's
|
|
88
|
+
`initialize` response reports the same version as the npm release
|
|
89
|
+
it shipped in.
|
|
90
|
+
- **README `range: "14d"` example was bogus** — the schema enum
|
|
91
|
+
doesn't accept `14d`, so following the README's project-breakdown
|
|
92
|
+
prompt produced an error. Replaced with the explicit-`from`/`to`
|
|
93
|
+
form. Same fix in `README.zh-CN.md`.
|
|
94
|
+
|
|
95
|
+
### Performance
|
|
96
|
+
|
|
97
|
+
| Metric | Before | After |
|
|
98
|
+
| --- | --- | --- |
|
|
99
|
+
| `dist/mcp/server.mjs` size | 810 KB | **379 KB** (-53%) |
|
|
100
|
+
| `weekly_summary` record-set passes | 8 (+ 2 internal source filters each) | **2** |
|
|
101
|
+
| `recent_activity` aggregation scope | every session ever | **last 30 days** |
|
|
102
|
+
| MCP response JSON byte count (typical) | indented | **~half** |
|
|
103
|
+
| Aggregator `withinRange` Date#toISOString() calls | per record × N filters | **once per call** |
|
|
104
|
+
|
|
105
|
+
### Security / privacy
|
|
106
|
+
|
|
107
|
+
- **MCP tool errors are scrubbed of `$HOME` paths** before they
|
|
108
|
+
reach the SDK's error envelope. Belt-and-suspenders today (the
|
|
109
|
+
only user-visible throws are clean date-arg validators), but
|
|
110
|
+
defends against future error paths that might wrap an indexer
|
|
111
|
+
error. Extracted the existing `sanitizeForUser` from the indexer
|
|
112
|
+
module into a shared `lib/sanitize` so both layers use one
|
|
113
|
+
definition.
|
|
114
|
+
|
|
115
|
+
### Internal
|
|
116
|
+
|
|
117
|
+
- `lib/aggregator/index.ts` — entry-point functions now hoist
|
|
118
|
+
`from/to → ISO string` and `models/projects → Set` once per
|
|
119
|
+
call instead of recomputing them per record. Measurable on the
|
|
120
|
+
`weekly_summary` hot path; invisible for the dashboard's
|
|
121
|
+
single-pass aggregators.
|
|
122
|
+
- New `lib/mcp/text-result.ts` — single source of truth for the
|
|
123
|
+
MCP response wrapper. `lib/mcp/safe-handler.ts` — HOF that wraps
|
|
124
|
+
tool callbacks with the path-scrub guard.
|
|
125
|
+
- `parseDayArg` moved from `tools/activity.ts` to `mcp/context.ts`
|
|
126
|
+
next to `parseDateRange` so the two share a single implementation
|
|
127
|
+
of the "today / yesterday / monday / YYYY-MM-DD" parser.
|
|
128
|
+
- 30 s polling fallback in the indexer is now **off by default for
|
|
129
|
+
the MCP instance** and **on by default for the dashboard**.
|
|
130
|
+
Override with `CCGAUGE_POLL_FALLBACK={0,1}`. The MCP server runs
|
|
131
|
+
in a background daemon spawned by an LLM client and shouldn't
|
|
132
|
+
keep the host warm just to catch the rare `fs.watch(recursive)`
|
|
133
|
+
miss.
|
|
134
|
+
- `AGENTS.md` documents the `site/` sub-project, the v4 sidechain
|
|
135
|
+
merge invariant, a release checklist, and the
|
|
136
|
+
`raw.githubusercontent.com` hero-image fragility. Two new
|
|
137
|
+
"intentionally NOT supported" items: folding `site/` into a pnpm
|
|
138
|
+
workspace, and letting `site/` leak into the npm tarball.
|
|
139
|
+
|
|
140
|
+
### Docs (doesn't ship to npm)
|
|
141
|
+
|
|
142
|
+
- Marketing site (`site/`) catches up to 1.0.2: features page
|
|
143
|
+
covers All view + conversation-count toggle + worktree merging;
|
|
144
|
+
homepage hero, "Multi-source analytics" card, and ScreenshotFrame
|
|
145
|
+
now use three distinct screenshots; hardcoded `v1.0.0` eyebrows
|
|
146
|
+
removed.
|
|
147
|
+
- `site/public/images/README.md` rewritten as a single-source-of-
|
|
148
|
+
truth inventory (file → used-by → source), with the prompt
|
|
149
|
+
catalogue trimmed to filenames that actually exist. Legacy
|
|
150
|
+
placeholder SVGs moved to an explicit "kept but unused"
|
|
151
|
+
subsection.
|
|
152
|
+
- `site/public/robots.txt` no longer points at a non-existent
|
|
153
|
+
`sitemap-index.xml`.
|
|
154
|
+
|
|
155
|
+
## [1.0.2] — 2026-05-15
|
|
156
|
+
|
|
157
|
+
This release brings the dashboard the long-requested **All view** (one
|
|
158
|
+
nav tab to see Claude + Codex merged), real provider logos in place of
|
|
159
|
+
the old colored-letter chips, and a switchable **Usage trend** that
|
|
160
|
+
finally lets you look at *conversations per day* the same way you'd
|
|
161
|
+
count rows in the usage table.
|
|
162
|
+
|
|
163
|
+
### Highlights
|
|
164
|
+
|
|
165
|
+
- **Tri-state source switcher** in the nav: `全部 · Claude · Codex`,
|
|
166
|
+
with the All button leading so the merged-scope option reads first.
|
|
167
|
+
Each button now shows the provider's real brand mark (Claude's
|
|
168
|
+
orange burst, Codex's blue cloud) instead of a `C`/`X` letter chip.
|
|
169
|
+
Persists via `?source=all` URL param + cookie; hides itself entirely
|
|
170
|
+
when only one provider is detected on disk.
|
|
171
|
+
- **All-view dispatch pattern.** The aggregator contract is unchanged
|
|
172
|
+
(still requires a single `ProviderId`); the page layer runs it per
|
|
173
|
+
provider and merges via new `lib/source-merge.ts` helpers
|
|
174
|
+
(`combineTotals` / `combineTimeBuckets`). List aggregations concat
|
|
175
|
+
per source and re-sort. All seven pages and five API routes
|
|
176
|
+
dispatch this way; `ProjectSummary` / `SessionSummary` carry a
|
|
177
|
+
`source` field so mixed-source rows are unambiguous.
|
|
178
|
+
- **Usage trend: Tokens / Conversations toggle** on the overview. The
|
|
179
|
+
trend section title changed to "Usage trend" with a segmented
|
|
180
|
+
control between the existing stacked-token view and a new
|
|
181
|
+
per-day **conversation count**. The conversation metric rolls API
|
|
182
|
+
calls up to their user-prompt root via `buildTurnIndex`, then
|
|
183
|
+
groups turns by the day of their earliest record — so the bar
|
|
184
|
+
values match the usage-table row count 1:1.
|
|
185
|
+
- **Worktree-aware Projects.** All worktrees of the same repo now
|
|
186
|
+
collapse into a single project row. Detection is pure-path first
|
|
187
|
+
(matches both standard `/.git/worktrees/` and Claude Code's
|
|
188
|
+
`/.claude/worktrees/` layout, so even worktree directories that
|
|
189
|
+
have since been deleted from disk still merge correctly via their
|
|
190
|
+
historical `cwd`). The detail page filters records by canonical
|
|
191
|
+
match, so old bookmarks pointing at a worktree path still resolve;
|
|
192
|
+
the session count is reconciled via sessionId Set union so the
|
|
193
|
+
card matches the detail-page KPIs.
|
|
194
|
+
|
|
195
|
+
### Added
|
|
196
|
+
|
|
197
|
+
- `public/claude-logo.webp` and `public/codex-logo.png` — provider
|
|
198
|
+
brand marks shipped as static assets. `ProviderAdapter` gets a new
|
|
199
|
+
`logoSrc` field; settings page data-source list, Projects card
|
|
200
|
+
source badges (All view), and Models card source badges all
|
|
201
|
+
consume it.
|
|
202
|
+
- `lib/source-merge.ts` — `combineTotals` and `combineTimeBuckets`
|
|
203
|
+
helpers that merge per-source aggregator output into a single
|
|
204
|
+
flat view for the All scope.
|
|
205
|
+
- `lib/source.ts` — `EffectiveSource = ProviderId | 'all'` type;
|
|
206
|
+
`resolveSource()` now decodes `?source=all` / `cookie=all`;
|
|
207
|
+
`filterBySource()` short-circuits for `'all'`; `expandSources()`
|
|
208
|
+
hands back the dispatch list `['claude'] | ['codex'] |
|
|
209
|
+
['claude','codex']`.
|
|
210
|
+
- `components/overview-trend-card.tsx` — client wrapper that holds
|
|
211
|
+
the Tokens / Conversations toggle state and swaps between the
|
|
212
|
+
existing `TokenStackChart` and the new `ConversationsBarChart`.
|
|
213
|
+
- `components/charts/conversations-bar-chart.tsx` — single-color
|
|
214
|
+
brand bar chart whose `dataKey` is `turns`. Tooltip highlights
|
|
215
|
+
the conversation count and surfaces the raw request count as a
|
|
216
|
+
footnote so users can cross-check the two metrics in place.
|
|
217
|
+
- `components/block-progress-switcher.tsx` — client wrapper that
|
|
218
|
+
renders the 5h-block card with an in-header tab control for the
|
|
219
|
+
All view (switches between Claude's and Codex's blocks in place,
|
|
220
|
+
replacing the inactive "live" pill in the top-right slot).
|
|
221
|
+
- `lib/project-label.ts` — `canonicalCwd` field on `LabelResult` and
|
|
222
|
+
exported `resolveCanonicalCwd(cwd)` helper. Path-pattern matching
|
|
223
|
+
(`<repo>/.git/worktrees/<name>` and `<repo>/.claude/worktrees/<name>`)
|
|
224
|
+
runs ahead of the `fs.readFileSync('.git')` lookup so deleted
|
|
225
|
+
worktrees still resolve to their main repo.
|
|
226
|
+
|
|
227
|
+
### Changed
|
|
228
|
+
|
|
229
|
+
- **Source switcher button order is now `All · Claude · Codex`**
|
|
230
|
+
(previously `Claude · Codex · All` or single-provider). Plain
|
|
231
|
+
letter chips are replaced with logo images everywhere — settings
|
|
232
|
+
page data-source list, Projects card source badges, Models card
|
|
233
|
+
source badges.
|
|
234
|
+
- **Usage trend section retitled** "用量趋势" / "Usage trend"
|
|
235
|
+
(was "Token 用量趋势" / "Token usage trend"); description is
|
|
236
|
+
now metric-dependent ("stacked by token type" vs "conversations
|
|
237
|
+
per day").
|
|
238
|
+
- **Overview 5h block panel** for the All view is now a single
|
|
239
|
+
card with an in-header tab switcher between providers. Defaults
|
|
240
|
+
to whichever side has the heavier current block by cost so the
|
|
241
|
+
user lands on the more interesting number. The original two-card
|
|
242
|
+
side-by-side layout was tried and rejected — 5h windows can't be
|
|
243
|
+
summed across providers (different rate-limit clocks), so a single
|
|
244
|
+
switchable card communicates the constraint better.
|
|
245
|
+
- **Usage table default columns** trimmed to
|
|
246
|
+
`Time · Prompt · Model · Project · Total` (Duration and Tools
|
|
247
|
+
moved out of defaults). Storage key bumped `cols.v3 → cols.v4`
|
|
248
|
+
so existing visibility prefs are reset to the new defaults.
|
|
249
|
+
- **Projects detail page** filter changed from exact `r.cwd === cwd`
|
|
250
|
+
to canonical match (`resolveCanonicalCwd(r.cwd) === canonicalCwd`),
|
|
251
|
+
so a single page now serves records from every worktree of the
|
|
252
|
+
same repo. Old bookmarks pointing at a worktree path still work
|
|
253
|
+
— they resolve to the same canonical and find the union of
|
|
254
|
+
records.
|
|
255
|
+
- **Overview KPI tiles for All view** sum across providers via
|
|
256
|
+
`combineTotals`; the Cost footnote is hidden in the All view
|
|
257
|
+
(decided UX) because the merged number mixes Codex's "API
|
|
258
|
+
equivalent" with Claude's API-exact value, so any single
|
|
259
|
+
disclaimer would mislead one side.
|
|
260
|
+
- **Marketing site** got a `features` page with a bilingual
|
|
261
|
+
screenshot gallery (`ScreenshotGallery.astro` + new screenshots
|
|
262
|
+
under `docs/screenshots/` and `site/public/images/screenshots/`).
|
|
263
|
+
Homepage feature cards now use the new feature thumbnails
|
|
264
|
+
(`feature-cli/heatmap/i18n/mcp/privacy`); Open Graph images
|
|
265
|
+
shipped as `og-default.png` and `og-cli.png`.
|
|
266
|
+
|
|
267
|
+
### Fixed
|
|
268
|
+
|
|
269
|
+
- **Usage table horizontal jitter on row expand.** Child rows in
|
|
270
|
+
the Time column carried a `pl-5` (left-padding) for visual indent,
|
|
271
|
+
which fed `table-layout: auto` and forced every column to
|
|
272
|
+
re-balance widths each time a row toggled open. Replaced with
|
|
273
|
+
`inline-block translate-x-5` — pure visual offset, doesn't enter
|
|
274
|
+
the layout-box measurement, so column widths stay pinned and the
|
|
275
|
+
table no longer jitters horizontally when you click a row.
|
|
276
|
+
- **Worktree projects double-counted** — multiple worktree `cwd`s
|
|
277
|
+
for the same repo previously appeared as separate cards on the
|
|
278
|
+
Projects page with their tokens / cost split between them. They
|
|
279
|
+
now collapse to a single canonical card; the detail page unions
|
|
280
|
+
records across all worktree `cwd`s of the same repo. Session
|
|
281
|
+
count is reconciled via `sessionId` Set union so the card matches
|
|
282
|
+
the detail page's KPIs.
|
|
283
|
+
|
|
284
|
+
### Internal
|
|
285
|
+
|
|
286
|
+
- `TokenStackDatum` got an optional `turns?: number` field so the
|
|
287
|
+
same payload shape can drive both the stacked-token and
|
|
288
|
+
conversation charts; consumers that don't care (sessions /
|
|
289
|
+
models / projects detail pages) can leave it unset.
|
|
290
|
+
- `OverviewTrendCard` is a client component, but `Section` stays
|
|
291
|
+
server-rendered — only the trend card's content + right-slot
|
|
292
|
+
cross the client boundary, so the page header and SEO surface
|
|
293
|
+
don't lose SSR.
|
|
294
|
+
- `mergeWorktreeProjects` in `app/projects/page.tsx` recomputes
|
|
295
|
+
unique session counts by scanning the underlying records (Set of
|
|
296
|
+
`sessionId` per `(source, canonicalCwd)` key) instead of summing
|
|
297
|
+
pre-aggregated counts — the latter double-counts sessions that
|
|
298
|
+
span multiple worktree cwds.
|
|
299
|
+
- Ad-hoc `*.png` files dropped at the repo root by playwright-mcp
|
|
300
|
+
verification runs and the `.playwright-mcp/` artefact directory
|
|
301
|
+
are now `.gitignore`d.
|
|
302
|
+
|
|
8
303
|
## [1.0.1] — 2026-05-13
|
|
9
304
|
|
|
10
305
|
### Fixed
|
|
@@ -383,6 +678,8 @@ of HTML to the browser.
|
|
|
383
678
|
- Initial public release as `ccgauge`: local Next.js dashboard for
|
|
384
679
|
Claude Code token usage, cost, and 5-hour block tracking.
|
|
385
680
|
|
|
681
|
+
[1.0.3]: https://github.com/chengzuopeng/ccgauge/compare/v1.0.2...v1.0.3
|
|
682
|
+
[1.0.2]: https://github.com/chengzuopeng/ccgauge/compare/v1.0.1...v1.0.2
|
|
386
683
|
[1.0.1]: https://github.com/chengzuopeng/ccgauge/compare/v1.0.0...v1.0.1
|
|
387
684
|
[1.0.0]: https://github.com/chengzuopeng/ccgauge/compare/v0.4.0...v1.0.0
|
|
388
685
|
[0.4.0]: https://github.com/chengzuopeng/ccgauge/compare/v0.3.1...v0.4.0
|
package/README.md
CHANGED
|
@@ -38,8 +38,9 @@ Everything runs locally as a Next.js app. Your conversation transcripts never le
|
|
|
38
38
|
## Highlights
|
|
39
39
|
|
|
40
40
|
### Cross-provider analytics
|
|
41
|
-
- One dashboard for both **Claude Code** and **OpenAI Codex CLI**
|
|
42
|
-
- Toggle data source from the nav bar; URL persists via `?source=`, last choice cached in cookie
|
|
41
|
+
- One dashboard for both **Claude Code** and **OpenAI Codex CLI**, plus an **All view** that merges the two
|
|
42
|
+
- Toggle data source from the nav bar (Claude · Codex · All), each button rendered with the real provider logo; URL persists via `?source=`, last choice cached in cookie
|
|
43
|
+
- **Worktree-aware Projects** — all worktrees of the same repo collapse into a single project row
|
|
43
44
|
- Built-in **provider adapter layer** (`lib/providers/`) — adding a third CLI (Gemini CLI, Cursor, Aider, …) is one new file plus a single registry line
|
|
44
45
|
|
|
45
46
|
### At-a-glance KPIs
|
|
@@ -51,7 +52,7 @@ Everything runs locally as a Next.js app. Your conversation transcripts never le
|
|
|
51
52
|
- **Sessions** — per-conversation list with model / tokens / cost / duration, plus a message-level timeline
|
|
52
53
|
- **Projects** — per-`cwd` aggregation cards with sparkline and spend share
|
|
53
54
|
- **Models** — side-by-side comparison: cost share, tokens share, cache hit, USD pricing
|
|
54
|
-
- **Usage** — turn-grouped table with expandable tool-call breakdown, CSV export
|
|
55
|
+
- **Usage** — turn-grouped table with expandable tool-call breakdown, CSV export. **Tokens / Conversations** toggle on the trend chart so you can count rows the way the usage table counts them
|
|
55
56
|
|
|
56
57
|
### Cost transparency
|
|
57
58
|
- **Cache savings** is its own KPI — quantifies how much Anthropic prompt caching saved you vs. paying full input price
|
|
@@ -63,6 +64,17 @@ Everything runs locally as a Next.js app. Your conversation transcripts never le
|
|
|
63
64
|
- **English / 中文** (cookie + localStorage)
|
|
64
65
|
- Filters: time range (today / 7d / 30d / 90d / all), granularity (hour / day / week / month), model and project multi-select
|
|
65
66
|
|
|
67
|
+
### CLI report (no server)
|
|
68
|
+
- `ccgauge report` prints a colored, aligned terminal usage report in ~0.2 s from the same JSONL the dashboard reads
|
|
69
|
+
- `--range / --source / --by / --since / --until / --model / --project` filters
|
|
70
|
+
- `--json` for machine-readable output; `--no-color` auto-applied when piped — drops cleanly into shell scripts and CI
|
|
71
|
+
|
|
72
|
+
### MCP server (for LLMs)
|
|
73
|
+
- `ccgauge mcp` runs a stdio JSON-RPC server so **Claude Desktop / Cursor / Cline** can query your local usage directly
|
|
74
|
+
- Nine MCP tools: `usage_summary`, `usage_by_time`, `usage_by_model`, `usage_by_project`, `usage_by_session`, `daily_summary`, `weekly_summary`, `recent_activity`, `cost_estimator`
|
|
75
|
+
- Reasoning-token breakdown surfaced for the models that emit one
|
|
76
|
+
- Separate named cache (`index-mcp-v2.json`) so MCP runs don't contend with the dashboard
|
|
77
|
+
|
|
66
78
|
### Privacy by design
|
|
67
79
|
- 100 % local: read-only access to existing JSONL files, zero outbound network calls
|
|
68
80
|
- Open source, MIT-licensed
|
|
@@ -217,6 +229,7 @@ English with real numbers from your machine.
|
|
|
217
229
|
| `daily_summary` | "What did I do today / yesterday / Monday / on YYYY-MM-DD?" Sessions grouped by project + models + top tool calls. |
|
|
218
230
|
| `weekly_summary` | 7-day roll-up: per-day cost trend, top sessions, top projects, models. `week_offset=-1` for last week. |
|
|
219
231
|
| `recent_activity` | The N most recently active sessions across providers. |
|
|
232
|
+
| `cost_estimator` | Compute the USD cost of a hypothetical request (`{ source, model, input_tokens, output_tokens, cache_* }`). Uses built-in per-1M-token pricing; does NOT consult usage history. |
|
|
220
233
|
|
|
221
234
|
| Resource URI | Content |
|
|
222
235
|
| --- | --- |
|
|
@@ -334,8 +347,8 @@ debug "why did it answer X".
|
|
|
334
347
|
→ `daily_summary({ date: "yesterday" })`
|
|
335
348
|
- *"Generate a Monday stand-up bullet list of what I shipped last week."*
|
|
336
349
|
→ `weekly_summary({ week_offset: -1 })`
|
|
337
|
-
- *"Which 3 projects have I touched most in the last
|
|
338
|
-
→ `usage_by_project({
|
|
350
|
+
- *"Which 3 projects have I touched most in the last two weeks?"*
|
|
351
|
+
→ `usage_by_project({ from: "2026-05-01", to: "2026-05-15", limit: 3 })` — pass explicit `from`/`to` for any window not covered by the named ranges (`7d` / `30d` / `90d` / `this_week` / `last_week` / …).
|
|
339
352
|
- *"What was my last coding session about?"*
|
|
340
353
|
→ `recent_activity({ limit: 1 })`
|
|
341
354
|
|
|
@@ -351,7 +364,7 @@ debug "why did it answer X".
|
|
|
351
364
|
- *"At my current burn rate, how much will I spend this month?"*
|
|
352
365
|
→ `usage_summary({ range: "this_month" })` + `usage_by_time({ range: "this_month", granularity: "day" })` — LLM extrapolates.
|
|
353
366
|
- *"If I run another 200K input + 50K output on Opus 4.7 today, what does that add to my month-to-date cost?"*
|
|
354
|
-
→ `usage_summary({ range: "this_month" })`
|
|
367
|
+
→ `cost_estimator({ source: "claude", model: "claude-opus-4-7", input_tokens: 200000, output_tokens: 50000 })` + `usage_summary({ range: "this_month" })` — the estimator returns the dollar cost for the hypothetical request without touching your usage history.
|
|
355
368
|
|
|
356
369
|
#### Cross-source comparisons
|
|
357
370
|
|
package/README.zh-CN.md
CHANGED
|
@@ -38,8 +38,9 @@ npx ccgauge
|
|
|
38
38
|
## 亮点
|
|
39
39
|
|
|
40
40
|
### 多 CLI 数据源
|
|
41
|
-
- 一份看板覆盖 **Claude Code** 与 **OpenAI Codex CLI**
|
|
42
|
-
-
|
|
41
|
+
- 一份看板覆盖 **Claude Code** 与 **OpenAI Codex CLI**,并提供 **All 视图**把两者合并查看
|
|
42
|
+
- 顶部三档切换(Claude · Codex · All),每个按钮都带真品牌 logo;URL 用 `?source=` 持久化,cookie 记忆上次选择
|
|
43
|
+
- **Worktree 感知的 Projects 合并** —— 同一个 repo 的所有 worktree 自动并到同一个项目行
|
|
43
44
|
- 内置 **Provider 适配层**(`lib/providers/`)—— 增加第三个 CLI(Gemini CLI / Cursor / Aider …)只需一个新文件加注册表一行
|
|
44
45
|
|
|
45
46
|
### KPI 一眼看完
|
|
@@ -51,7 +52,7 @@ npx ccgauge
|
|
|
51
52
|
- **会话页** —— 每场对话单独成行(模型 / token / 花费 / 时长),点进去看消息级时间线
|
|
52
53
|
- **项目页** —— 按 `cwd` 聚合成卡片网格,含趋势条与花费占比
|
|
53
54
|
- **模型页** —— 各模型并排对比:成本占比、token 占比、缓存命中、官方单价
|
|
54
|
-
- **用量页** —— 按对话轮次分组的明细表,可展开看每次工具调用,支持 CSV
|
|
55
|
+
- **用量页** —— 按对话轮次分组的明细表,可展开看每次工具调用,支持 CSV 导出。趋势图支持 **Token / 对话数** 切换,让条形图行数和用量表 1:1 对齐
|
|
55
56
|
|
|
56
57
|
### 成本透明
|
|
57
58
|
- **缓存节省** 单独成卡 —— 量化 Anthropic prompt caching 实际帮你节省了多少美元
|
|
@@ -63,6 +64,17 @@ npx ccgauge
|
|
|
63
64
|
- **English / 中文** 双语,cookie + localStorage 双向同步
|
|
64
65
|
- 完整筛选:时间区间(今天 / 7 天 / 30 天 / 90 天 / 全部)、粒度(小时 / 天 / 周 / 月)、模型 / 项目 multi-select
|
|
65
66
|
|
|
67
|
+
### 命令行报告(无 server)
|
|
68
|
+
- `ccgauge report` 读取同一份 JSONL,在 ~0.2 秒内打出彩色对齐的终端报告
|
|
69
|
+
- `--range / --source / --by / --since / --until / --model / --project` 滤波参数
|
|
70
|
+
- `--json` 输出给脚本;`--no-color` 走管道时自动开启 —— 可以直接塞进 shell 和 CI
|
|
71
|
+
|
|
72
|
+
### MCP 服务(给 LLM 用)
|
|
73
|
+
- `ccgauge mcp` 起一个 stdio JSON-RPC 服务,让 **Claude Desktop / Cursor / Cline** 等 MCP 客户端直接查你本地的 ccgauge 历史
|
|
74
|
+
- 9 个 MCP tool:`usage_summary`、`usage_by_time`、`usage_by_model`、`usage_by_project`、`usage_by_session`、`daily_summary`、`weekly_summary`、`recent_activity`、`cost_estimator`
|
|
75
|
+
- 支持模型有 reasoning token 时单独折算
|
|
76
|
+
- 独立命名缓存(`index-mcp-v2.json`),MCP 进程不会和仪表盘抢同一份磁盘索引
|
|
77
|
+
|
|
66
78
|
### 隐私优先
|
|
67
79
|
- 100 % 本地:只读访问已有 JSONL 文件,零外网调用
|
|
68
80
|
- 开源,MIT 协议
|
|
@@ -213,7 +225,8 @@ LLM 会自动选合适的 tool、本地调用、用大白话给你带真实数
|
|
|
213
225
|
| `usage_by_session` | 会话列表,含标题(首条用户消息)/ 模型 / 时长 / 花费。可按 recent / cost / tokens / duration 排序。 |
|
|
214
226
|
| `daily_summary` | "今天 / 昨天 / 周一 / YYYY-MM-DD 我都干了啥?" 按项目分组的会话 + 模型 + top 工具调用。 |
|
|
215
227
|
| `weekly_summary` | 7 天 roll-up:每日花费趋势 + top 会话 + top 项目 + 模型分布。`week_offset=-1` 看上周。 |
|
|
216
|
-
| `recent_activity` | 最近 N
|
|
228
|
+
| `recent_activity` | 最近 N 条活跃会话(默认最近 30 天,可显式给 `from`/`to`)。 |
|
|
229
|
+
| `cost_estimator` | 计算"假设我用 X 模型发 N 个 token 要花多少钱"。直接读内置 per-1M-token 单价表,不查历史。常用于额度规划 / what-if。 |
|
|
217
230
|
|
|
218
231
|
| Resource URI | 内容 |
|
|
219
232
|
| --- | --- |
|
|
@@ -329,7 +342,7 @@ LLM 大概率会调的工具——方便你"为什么会这样回答"反查。
|
|
|
329
342
|
- *"给我一份周一 standup 用的 bullet list,列我上周完成的事。"*
|
|
330
343
|
→ `weekly_summary({ week_offset: -1 })`
|
|
331
344
|
- *"过去两周我接触最多的 3 个项目是什么?"*
|
|
332
|
-
→ `usage_by_project({
|
|
345
|
+
→ `usage_by_project({ from: "2026-05-01", to: "2026-05-15", limit: 3 })`——非 `7d` / `30d` / `90d` / `this_week` / `last_week` 等命名窗口时,传显式 `from` / `to`。
|
|
333
346
|
- *"我最近一次的编码会话是关于什么的?"*
|
|
334
347
|
→ `recent_activity({ limit: 1 })`
|
|
335
348
|
|
|
@@ -345,7 +358,7 @@ LLM 大概率会调的工具——方便你"为什么会这样回答"反查。
|
|
|
345
358
|
- *"按当前消耗速度,本月预计花多少?"*
|
|
346
359
|
→ `usage_summary({ range: "this_month" })` + `usage_by_time({ range: "this_month", granularity: "day" })`——LLM 自己外推。
|
|
347
360
|
- *"如果我今天再在 Opus 4.7 上跑 200K input + 50K output,本月累计要多少?"*
|
|
348
|
-
→ `
|
|
361
|
+
→ `cost_estimator({ source: "claude", model: "claude-opus-4-7", input_tokens: 200000, output_tokens: 50000 })` + `usage_summary({ range: "this_month" })`——estimator 直接按内置单价表返回这笔假设请求的美元成本,不查历史。
|
|
349
362
|
|
|
350
363
|
#### 跨数据源对比
|
|
351
364
|
|
package/bin/cli.mjs
CHANGED
|
@@ -142,8 +142,9 @@ program
|
|
|
142
142
|
program
|
|
143
143
|
.command('mcp')
|
|
144
144
|
.description('start the MCP server (stdio) so LLMs can query usage data')
|
|
145
|
-
.
|
|
146
|
-
|
|
145
|
+
.option('--check', 'verify the bundle + indexer; print one line per provider and exit')
|
|
146
|
+
.action(async (opts) => {
|
|
147
|
+
await startMcp(opts);
|
|
147
148
|
});
|
|
148
149
|
|
|
149
150
|
function addReportOptions(cmd) {
|
|
@@ -438,7 +439,7 @@ or run the full build with
|
|
|
438
439
|
}
|
|
439
440
|
}
|
|
440
441
|
|
|
441
|
-
async function startMcp() {
|
|
442
|
+
async function startMcp(opts = {}) {
|
|
442
443
|
const bundle = join(packageRoot, 'dist', 'mcp', 'server.mjs');
|
|
443
444
|
if (!existsSync(bundle)) {
|
|
444
445
|
console.error(`
|
|
@@ -455,20 +456,39 @@ or run the full build with
|
|
|
455
456
|
`);
|
|
456
457
|
process.exit(1);
|
|
457
458
|
}
|
|
458
|
-
|
|
459
|
-
//
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
459
|
+
|
|
460
|
+
// --check: don't actually run the JSON-RPC server — load the bundle,
|
|
461
|
+
// boot the indexer, print one line per provider, and exit. Lets users
|
|
462
|
+
// verify their install without wiring up an MCP client.
|
|
463
|
+
if (opts.check) {
|
|
464
|
+
const mod = await import(pathToFileURL(bundle).href);
|
|
465
|
+
if (typeof mod.printCheck !== 'function') {
|
|
466
|
+
console.error('[ccgauge-mcp] this bundle was built without --check support');
|
|
467
|
+
process.exit(1);
|
|
468
|
+
}
|
|
469
|
+
const code = await mod.printCheck();
|
|
470
|
+
process.exit(typeof code === 'number' ? code : 0);
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
// Run the bundled MCP server **in this process** — the bundle exposes a
|
|
474
|
+
// top-level `runStdioServer()` so we just import + invoke it. Spawning a
|
|
475
|
+
// second Node process here is wasted memory/latency (LLM clients already
|
|
476
|
+
// spawn `ccgauge mcp` per conversation), and forwarding signals across
|
|
477
|
+
// processes is brittle (e.g. SIGHUP isn't covered by the old shim).
|
|
478
|
+
try {
|
|
479
|
+
const mod = await import(pathToFileURL(bundle).href);
|
|
480
|
+
if (typeof mod.runStdioServer !== 'function') {
|
|
481
|
+
console.error('[ccgauge-mcp] bundle missing runStdioServer export');
|
|
482
|
+
process.exit(1);
|
|
483
|
+
}
|
|
484
|
+
await mod.runStdioServer();
|
|
485
|
+
// runStdioServer keeps the loop alive via the stdio transport; if it
|
|
486
|
+
// ever returns it means the transport closed cleanly.
|
|
487
|
+
process.exit(0);
|
|
488
|
+
} catch (err) {
|
|
489
|
+
console.error('[ccgauge-mcp] failed to start:', err?.message ?? err);
|
|
490
|
+
process.exit(1);
|
|
491
|
+
}
|
|
472
492
|
}
|
|
473
493
|
|
|
474
494
|
async function resolvePort(opts) {
|