ccgauge 1.0.3 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/app-build-manifest.json +42 -42
- package/.next/standalone/.next/app-path-routes-manifest.json +9 -9
- package/.next/standalone/.next/build-manifest.json +2 -2
- package/.next/standalone/.next/server/app/_not-found/page.js +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_client-reference-manifest.js +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_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_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_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 +9 -9
- package/.next/standalone/.next/server/chunks/287.js +1 -0
- package/.next/standalone/.next/server/chunks/517.js +1 -1
- package/.next/standalone/.next/server/chunks/567.js +2 -2
- package/.next/standalone/.next/server/chunks/730.js +1 -0
- package/.next/standalone/.next/server/chunks/98.js +1 -1
- package/.next/standalone/.next/server/functions-config-manifest.json +2 -2
- package/.next/standalone/.next/server/pages/500.html +1 -1
- package/.next/standalone/.next/static/chunks/148-6c2eaf5508bfe739.js +1 -0
- package/.next/standalone/.next/static/chunks/930-ca5c6f8b5cb6ac3d.js +1 -0
- package/.next/standalone/.next/static/chunks/app/layout-4f3538437c5e8366.js +1 -0
- package/.next/standalone/.next/static/chunks/app/page-3cda7f70ecf5017a.js +1 -0
- package/.next/standalone/.next/static/chunks/app/settings/page-1ba7c4a4c0fae2f8.js +1 -0
- package/.next/standalone/.next/static/css/{406e067663b8b429.css → fbd2c395e5bf32cb.css} +1 -1
- package/.next/standalone/node_modules/next/node_modules/@img/sharp-darwin-arm64/LICENSE +191 -0
- package/.next/standalone/node_modules/next/node_modules/@img/sharp-darwin-arm64/lib/sharp-darwin-arm64.node +0 -0
- package/.next/standalone/node_modules/next/node_modules/@img/sharp-darwin-arm64/package.json +40 -0
- package/.next/standalone/node_modules/next/node_modules/@img/sharp-libvips-darwin-arm64/lib/index.js +1 -0
- package/.next/standalone/node_modules/next/node_modules/@img/sharp-libvips-darwin-arm64/lib/libvips-cpp.8.17.3.dylib +0 -0
- package/.next/standalone/node_modules/next/node_modules/@img/sharp-libvips-darwin-arm64/package.json +36 -0
- package/.next/standalone/node_modules/next/node_modules/@img/sharp-libvips-darwin-arm64/versions.json +30 -0
- package/.next/standalone/node_modules/next/node_modules/sharp/lib/channel.js +177 -0
- package/.next/standalone/node_modules/next/node_modules/sharp/lib/colour.js +195 -0
- package/.next/standalone/node_modules/next/node_modules/sharp/lib/composite.js +212 -0
- package/.next/standalone/node_modules/next/node_modules/sharp/lib/constructor.js +499 -0
- package/.next/standalone/node_modules/next/node_modules/sharp/lib/index.js +16 -0
- package/.next/standalone/node_modules/next/node_modules/sharp/lib/input.js +809 -0
- package/.next/standalone/node_modules/next/node_modules/sharp/lib/is.js +143 -0
- package/.next/standalone/node_modules/next/node_modules/sharp/lib/libvips.js +207 -0
- package/.next/standalone/node_modules/next/node_modules/sharp/lib/operation.js +1016 -0
- package/.next/standalone/node_modules/next/node_modules/sharp/lib/output.js +1666 -0
- package/.next/standalone/node_modules/next/node_modules/sharp/lib/resize.js +595 -0
- package/.next/standalone/node_modules/next/node_modules/sharp/lib/sharp.js +121 -0
- package/.next/standalone/node_modules/next/node_modules/sharp/lib/utility.js +291 -0
- package/.next/standalone/node_modules/next/node_modules/sharp/package.json +202 -0
- package/.next/standalone/node_modules/semver/classes/comparator.js +143 -0
- package/.next/standalone/node_modules/semver/classes/range.js +557 -0
- package/.next/standalone/node_modules/semver/classes/semver.js +333 -0
- package/.next/standalone/node_modules/semver/functions/cmp.js +54 -0
- package/.next/standalone/node_modules/semver/functions/coerce.js +62 -0
- package/.next/standalone/node_modules/semver/functions/compare.js +7 -0
- package/.next/standalone/node_modules/semver/functions/eq.js +5 -0
- package/.next/standalone/node_modules/semver/functions/gt.js +5 -0
- package/.next/standalone/node_modules/semver/functions/gte.js +5 -0
- package/.next/standalone/node_modules/semver/functions/lt.js +5 -0
- package/.next/standalone/node_modules/semver/functions/lte.js +5 -0
- package/.next/standalone/node_modules/semver/functions/neq.js +5 -0
- package/.next/standalone/node_modules/semver/functions/parse.js +18 -0
- package/.next/standalone/node_modules/semver/functions/satisfies.js +12 -0
- package/.next/standalone/node_modules/semver/internal/constants.js +37 -0
- package/.next/standalone/node_modules/semver/internal/debug.js +11 -0
- package/.next/standalone/node_modules/semver/internal/identifiers.js +29 -0
- package/.next/standalone/node_modules/semver/internal/lrucache.js +42 -0
- package/.next/standalone/node_modules/semver/internal/parse-options.js +17 -0
- package/.next/standalone/node_modules/semver/internal/re.js +223 -0
- package/.next/standalone/node_modules/semver/package.json +78 -0
- package/.next/standalone/package.json +13 -2
- package/.next/standalone/public/codex-logo.png +0 -0
- package/.next/standalone/public/favicon.svg +19 -5
- package/CHANGELOG.md +287 -0
- package/README.md +8 -2
- package/README.zh-CN.md +11 -4
- package/bin/cli.mjs +404 -92
- package/dist/mcp/server.mjs +16 -16
- package/dist/report/index.mjs +196 -30
- package/package.json +14 -3
- package/.next/standalone/.next/server/chunks/971.js +0 -1
- package/.next/standalone/.next/static/chunks/148-0a1e1b0207b89e3f.js +0 -1
- package/.next/standalone/.next/static/chunks/930-3035d0b294080d0b.js +0 -1
- package/.next/standalone/.next/static/chunks/app/layout-2512ccdfb13aeb17.js +0 -1
- package/.next/standalone/.next/static/chunks/app/page-19d3e77d4aa35a63.js +0 -1
- package/.next/standalone/.next/static/chunks/app/settings/page-cfeb089549c94f88.js +0 -1
- /package/.next/standalone/.next/static/{alqi5oQtTQUdpxp2x0yAt → kdpS1dOlXPsnKYuNBuMt9}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{alqi5oQtTQUdpxp2x0yAt → kdpS1dOlXPsnKYuNBuMt9}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const {
|
|
4
|
+
MAX_SAFE_COMPONENT_LENGTH,
|
|
5
|
+
MAX_SAFE_BUILD_LENGTH,
|
|
6
|
+
MAX_LENGTH,
|
|
7
|
+
} = require('./constants')
|
|
8
|
+
const debug = require('./debug')
|
|
9
|
+
exports = module.exports = {}
|
|
10
|
+
|
|
11
|
+
// The actual regexps go on exports.re
|
|
12
|
+
const re = exports.re = []
|
|
13
|
+
const safeRe = exports.safeRe = []
|
|
14
|
+
const src = exports.src = []
|
|
15
|
+
const safeSrc = exports.safeSrc = []
|
|
16
|
+
const t = exports.t = {}
|
|
17
|
+
let R = 0
|
|
18
|
+
|
|
19
|
+
const LETTERDASHNUMBER = '[a-zA-Z0-9-]'
|
|
20
|
+
|
|
21
|
+
// Replace some greedy regex tokens to prevent regex dos issues. These regex are
|
|
22
|
+
// used internally via the safeRe object since all inputs in this library get
|
|
23
|
+
// normalized first to trim and collapse all extra whitespace. The original
|
|
24
|
+
// regexes are exported for userland consumption and lower level usage. A
|
|
25
|
+
// future breaking change could export the safer regex only with a note that
|
|
26
|
+
// all input should have extra whitespace removed.
|
|
27
|
+
const safeRegexReplacements = [
|
|
28
|
+
['\\s', 1],
|
|
29
|
+
['\\d', MAX_LENGTH],
|
|
30
|
+
[LETTERDASHNUMBER, MAX_SAFE_BUILD_LENGTH],
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
const makeSafeRegex = (value) => {
|
|
34
|
+
for (const [token, max] of safeRegexReplacements) {
|
|
35
|
+
value = value
|
|
36
|
+
.split(`${token}*`).join(`${token}{0,${max}}`)
|
|
37
|
+
.split(`${token}+`).join(`${token}{1,${max}}`)
|
|
38
|
+
}
|
|
39
|
+
return value
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const createToken = (name, value, isGlobal) => {
|
|
43
|
+
const safe = makeSafeRegex(value)
|
|
44
|
+
const index = R++
|
|
45
|
+
debug(name, index, value)
|
|
46
|
+
t[name] = index
|
|
47
|
+
src[index] = value
|
|
48
|
+
safeSrc[index] = safe
|
|
49
|
+
re[index] = new RegExp(value, isGlobal ? 'g' : undefined)
|
|
50
|
+
safeRe[index] = new RegExp(safe, isGlobal ? 'g' : undefined)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// The following Regular Expressions can be used for tokenizing,
|
|
54
|
+
// validating, and parsing SemVer version strings.
|
|
55
|
+
|
|
56
|
+
// ## Numeric Identifier
|
|
57
|
+
// A single `0`, or a non-zero digit followed by zero or more digits.
|
|
58
|
+
|
|
59
|
+
createToken('NUMERICIDENTIFIER', '0|[1-9]\\d*')
|
|
60
|
+
createToken('NUMERICIDENTIFIERLOOSE', '\\d+')
|
|
61
|
+
|
|
62
|
+
// ## Non-numeric Identifier
|
|
63
|
+
// Zero or more digits, followed by a letter or hyphen, and then zero or
|
|
64
|
+
// more letters, digits, or hyphens.
|
|
65
|
+
|
|
66
|
+
createToken('NONNUMERICIDENTIFIER', `\\d*[a-zA-Z-]${LETTERDASHNUMBER}*`)
|
|
67
|
+
|
|
68
|
+
// ## Main Version
|
|
69
|
+
// Three dot-separated numeric identifiers.
|
|
70
|
+
|
|
71
|
+
createToken('MAINVERSION', `(${src[t.NUMERICIDENTIFIER]})\\.` +
|
|
72
|
+
`(${src[t.NUMERICIDENTIFIER]})\\.` +
|
|
73
|
+
`(${src[t.NUMERICIDENTIFIER]})`)
|
|
74
|
+
|
|
75
|
+
createToken('MAINVERSIONLOOSE', `(${src[t.NUMERICIDENTIFIERLOOSE]})\\.` +
|
|
76
|
+
`(${src[t.NUMERICIDENTIFIERLOOSE]})\\.` +
|
|
77
|
+
`(${src[t.NUMERICIDENTIFIERLOOSE]})`)
|
|
78
|
+
|
|
79
|
+
// ## Pre-release Version Identifier
|
|
80
|
+
// A numeric identifier, or a non-numeric identifier.
|
|
81
|
+
// Non-numeric identifiers include numeric identifiers but can be longer.
|
|
82
|
+
// Therefore non-numeric identifiers must go first.
|
|
83
|
+
|
|
84
|
+
createToken('PRERELEASEIDENTIFIER', `(?:${src[t.NONNUMERICIDENTIFIER]
|
|
85
|
+
}|${src[t.NUMERICIDENTIFIER]})`)
|
|
86
|
+
|
|
87
|
+
createToken('PRERELEASEIDENTIFIERLOOSE', `(?:${src[t.NONNUMERICIDENTIFIER]
|
|
88
|
+
}|${src[t.NUMERICIDENTIFIERLOOSE]})`)
|
|
89
|
+
|
|
90
|
+
// ## Pre-release Version
|
|
91
|
+
// Hyphen, followed by one or more dot-separated pre-release version
|
|
92
|
+
// identifiers.
|
|
93
|
+
|
|
94
|
+
createToken('PRERELEASE', `(?:-(${src[t.PRERELEASEIDENTIFIER]
|
|
95
|
+
}(?:\\.${src[t.PRERELEASEIDENTIFIER]})*))`)
|
|
96
|
+
|
|
97
|
+
createToken('PRERELEASELOOSE', `(?:-?(${src[t.PRERELEASEIDENTIFIERLOOSE]
|
|
98
|
+
}(?:\\.${src[t.PRERELEASEIDENTIFIERLOOSE]})*))`)
|
|
99
|
+
|
|
100
|
+
// ## Build Metadata Identifier
|
|
101
|
+
// Any combination of digits, letters, or hyphens.
|
|
102
|
+
|
|
103
|
+
createToken('BUILDIDENTIFIER', `${LETTERDASHNUMBER}+`)
|
|
104
|
+
|
|
105
|
+
// ## Build Metadata
|
|
106
|
+
// Plus sign, followed by one or more period-separated build metadata
|
|
107
|
+
// identifiers.
|
|
108
|
+
|
|
109
|
+
createToken('BUILD', `(?:\\+(${src[t.BUILDIDENTIFIER]
|
|
110
|
+
}(?:\\.${src[t.BUILDIDENTIFIER]})*))`)
|
|
111
|
+
|
|
112
|
+
// ## Full Version String
|
|
113
|
+
// A main version, followed optionally by a pre-release version and
|
|
114
|
+
// build metadata.
|
|
115
|
+
|
|
116
|
+
// Note that the only major, minor, patch, and pre-release sections of
|
|
117
|
+
// the version string are capturing groups. The build metadata is not a
|
|
118
|
+
// capturing group, because it should not ever be used in version
|
|
119
|
+
// comparison.
|
|
120
|
+
|
|
121
|
+
createToken('FULLPLAIN', `v?${src[t.MAINVERSION]
|
|
122
|
+
}${src[t.PRERELEASE]}?${
|
|
123
|
+
src[t.BUILD]}?`)
|
|
124
|
+
|
|
125
|
+
createToken('FULL', `^${src[t.FULLPLAIN]}$`)
|
|
126
|
+
|
|
127
|
+
// like full, but allows v1.2.3 and =1.2.3, which people do sometimes.
|
|
128
|
+
// also, 1.0.0alpha1 (prerelease without the hyphen) which is pretty
|
|
129
|
+
// common in the npm registry.
|
|
130
|
+
createToken('LOOSEPLAIN', `[v=\\s]*${src[t.MAINVERSIONLOOSE]
|
|
131
|
+
}${src[t.PRERELEASELOOSE]}?${
|
|
132
|
+
src[t.BUILD]}?`)
|
|
133
|
+
|
|
134
|
+
createToken('LOOSE', `^${src[t.LOOSEPLAIN]}$`)
|
|
135
|
+
|
|
136
|
+
createToken('GTLT', '((?:<|>)?=?)')
|
|
137
|
+
|
|
138
|
+
// Something like "2.*" or "1.2.x".
|
|
139
|
+
// Note that "x.x" is a valid xRange identifer, meaning "any version"
|
|
140
|
+
// Only the first item is strictly required.
|
|
141
|
+
createToken('XRANGEIDENTIFIERLOOSE', `${src[t.NUMERICIDENTIFIERLOOSE]}|x|X|\\*`)
|
|
142
|
+
createToken('XRANGEIDENTIFIER', `${src[t.NUMERICIDENTIFIER]}|x|X|\\*`)
|
|
143
|
+
|
|
144
|
+
createToken('XRANGEPLAIN', `[v=\\s]*(${src[t.XRANGEIDENTIFIER]})` +
|
|
145
|
+
`(?:\\.(${src[t.XRANGEIDENTIFIER]})` +
|
|
146
|
+
`(?:\\.(${src[t.XRANGEIDENTIFIER]})` +
|
|
147
|
+
`(?:${src[t.PRERELEASE]})?${
|
|
148
|
+
src[t.BUILD]}?` +
|
|
149
|
+
`)?)?`)
|
|
150
|
+
|
|
151
|
+
createToken('XRANGEPLAINLOOSE', `[v=\\s]*(${src[t.XRANGEIDENTIFIERLOOSE]})` +
|
|
152
|
+
`(?:\\.(${src[t.XRANGEIDENTIFIERLOOSE]})` +
|
|
153
|
+
`(?:\\.(${src[t.XRANGEIDENTIFIERLOOSE]})` +
|
|
154
|
+
`(?:${src[t.PRERELEASELOOSE]})?${
|
|
155
|
+
src[t.BUILD]}?` +
|
|
156
|
+
`)?)?`)
|
|
157
|
+
|
|
158
|
+
createToken('XRANGE', `^${src[t.GTLT]}\\s*${src[t.XRANGEPLAIN]}$`)
|
|
159
|
+
createToken('XRANGELOOSE', `^${src[t.GTLT]}\\s*${src[t.XRANGEPLAINLOOSE]}$`)
|
|
160
|
+
|
|
161
|
+
// Coercion.
|
|
162
|
+
// Extract anything that could conceivably be a part of a valid semver
|
|
163
|
+
createToken('COERCEPLAIN', `${'(^|[^\\d])' +
|
|
164
|
+
'(\\d{1,'}${MAX_SAFE_COMPONENT_LENGTH}})` +
|
|
165
|
+
`(?:\\.(\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?` +
|
|
166
|
+
`(?:\\.(\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?`)
|
|
167
|
+
createToken('COERCE', `${src[t.COERCEPLAIN]}(?:$|[^\\d])`)
|
|
168
|
+
createToken('COERCEFULL', src[t.COERCEPLAIN] +
|
|
169
|
+
`(?:${src[t.PRERELEASE]})?` +
|
|
170
|
+
`(?:${src[t.BUILD]})?` +
|
|
171
|
+
`(?:$|[^\\d])`)
|
|
172
|
+
createToken('COERCERTL', src[t.COERCE], true)
|
|
173
|
+
createToken('COERCERTLFULL', src[t.COERCEFULL], true)
|
|
174
|
+
|
|
175
|
+
// Tilde ranges.
|
|
176
|
+
// Meaning is "reasonably at or greater than"
|
|
177
|
+
createToken('LONETILDE', '(?:~>?)')
|
|
178
|
+
|
|
179
|
+
createToken('TILDETRIM', `(\\s*)${src[t.LONETILDE]}\\s+`, true)
|
|
180
|
+
exports.tildeTrimReplace = '$1~'
|
|
181
|
+
|
|
182
|
+
createToken('TILDE', `^${src[t.LONETILDE]}${src[t.XRANGEPLAIN]}$`)
|
|
183
|
+
createToken('TILDELOOSE', `^${src[t.LONETILDE]}${src[t.XRANGEPLAINLOOSE]}$`)
|
|
184
|
+
|
|
185
|
+
// Caret ranges.
|
|
186
|
+
// Meaning is "at least and backwards compatible with"
|
|
187
|
+
createToken('LONECARET', '(?:\\^)')
|
|
188
|
+
|
|
189
|
+
createToken('CARETTRIM', `(\\s*)${src[t.LONECARET]}\\s+`, true)
|
|
190
|
+
exports.caretTrimReplace = '$1^'
|
|
191
|
+
|
|
192
|
+
createToken('CARET', `^${src[t.LONECARET]}${src[t.XRANGEPLAIN]}$`)
|
|
193
|
+
createToken('CARETLOOSE', `^${src[t.LONECARET]}${src[t.XRANGEPLAINLOOSE]}$`)
|
|
194
|
+
|
|
195
|
+
// A simple gt/lt/eq thing, or just "" to indicate "any version"
|
|
196
|
+
createToken('COMPARATORLOOSE', `^${src[t.GTLT]}\\s*(${src[t.LOOSEPLAIN]})$|^$`)
|
|
197
|
+
createToken('COMPARATOR', `^${src[t.GTLT]}\\s*(${src[t.FULLPLAIN]})$|^$`)
|
|
198
|
+
|
|
199
|
+
// An expression to strip any whitespace between the gtlt and the thing
|
|
200
|
+
// it modifies, so that `> 1.2.3` ==> `>1.2.3`
|
|
201
|
+
createToken('COMPARATORTRIM', `(\\s*)${src[t.GTLT]
|
|
202
|
+
}\\s*(${src[t.LOOSEPLAIN]}|${src[t.XRANGEPLAIN]})`, true)
|
|
203
|
+
exports.comparatorTrimReplace = '$1$2$3'
|
|
204
|
+
|
|
205
|
+
// Something like `1.2.3 - 1.2.4`
|
|
206
|
+
// Note that these all use the loose form, because they'll be
|
|
207
|
+
// checked against either the strict or loose comparator form
|
|
208
|
+
// later.
|
|
209
|
+
createToken('HYPHENRANGE', `^\\s*(${src[t.XRANGEPLAIN]})` +
|
|
210
|
+
`\\s+-\\s+` +
|
|
211
|
+
`(${src[t.XRANGEPLAIN]})` +
|
|
212
|
+
`\\s*$`)
|
|
213
|
+
|
|
214
|
+
createToken('HYPHENRANGELOOSE', `^\\s*(${src[t.XRANGEPLAINLOOSE]})` +
|
|
215
|
+
`\\s+-\\s+` +
|
|
216
|
+
`(${src[t.XRANGEPLAINLOOSE]})` +
|
|
217
|
+
`\\s*$`)
|
|
218
|
+
|
|
219
|
+
// Star ranges basically just allow anything at all.
|
|
220
|
+
createToken('STAR', '(<|>)?=?\\s*\\*')
|
|
221
|
+
// >=0.0.0 is like a star
|
|
222
|
+
createToken('GTE0', '^\\s*>=\\s*0\\.0\\.0\\s*$')
|
|
223
|
+
createToken('GTE0PRE', '^\\s*>=\\s*0\\.0\\.0-0\\s*$')
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "semver",
|
|
3
|
+
"version": "7.7.4",
|
|
4
|
+
"description": "The semantic version parser used by npm.",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "tap",
|
|
8
|
+
"snap": "tap",
|
|
9
|
+
"lint": "npm run eslint",
|
|
10
|
+
"postlint": "template-oss-check",
|
|
11
|
+
"lintfix": "npm run eslint -- --fix",
|
|
12
|
+
"posttest": "npm run lint",
|
|
13
|
+
"template-oss-apply": "template-oss-apply --force",
|
|
14
|
+
"eslint": "eslint \"**/*.{js,cjs,ts,mjs,jsx,tsx}\""
|
|
15
|
+
},
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"@npmcli/eslint-config": "^6.0.0",
|
|
18
|
+
"@npmcli/template-oss": "4.29.0",
|
|
19
|
+
"benchmark": "^2.1.4",
|
|
20
|
+
"tap": "^16.0.0"
|
|
21
|
+
},
|
|
22
|
+
"license": "ISC",
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "git+https://github.com/npm/node-semver.git"
|
|
26
|
+
},
|
|
27
|
+
"bin": {
|
|
28
|
+
"semver": "bin/semver.js"
|
|
29
|
+
},
|
|
30
|
+
"files": [
|
|
31
|
+
"bin/",
|
|
32
|
+
"lib/",
|
|
33
|
+
"classes/",
|
|
34
|
+
"functions/",
|
|
35
|
+
"internal/",
|
|
36
|
+
"ranges/",
|
|
37
|
+
"index.js",
|
|
38
|
+
"preload.js",
|
|
39
|
+
"range.bnf"
|
|
40
|
+
],
|
|
41
|
+
"tap": {
|
|
42
|
+
"timeout": 30,
|
|
43
|
+
"coverage-map": "map.js",
|
|
44
|
+
"nyc-arg": [
|
|
45
|
+
"--exclude",
|
|
46
|
+
"tap-snapshots/**"
|
|
47
|
+
]
|
|
48
|
+
},
|
|
49
|
+
"engines": {
|
|
50
|
+
"node": ">=10"
|
|
51
|
+
},
|
|
52
|
+
"author": "GitHub Inc.",
|
|
53
|
+
"templateOSS": {
|
|
54
|
+
"//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.",
|
|
55
|
+
"version": "4.29.0",
|
|
56
|
+
"engines": ">=10",
|
|
57
|
+
"distPaths": [
|
|
58
|
+
"classes/",
|
|
59
|
+
"functions/",
|
|
60
|
+
"internal/",
|
|
61
|
+
"ranges/",
|
|
62
|
+
"index.js",
|
|
63
|
+
"preload.js",
|
|
64
|
+
"range.bnf"
|
|
65
|
+
],
|
|
66
|
+
"allowPaths": [
|
|
67
|
+
"/classes/",
|
|
68
|
+
"/functions/",
|
|
69
|
+
"/internal/",
|
|
70
|
+
"/ranges/",
|
|
71
|
+
"/index.js",
|
|
72
|
+
"/preload.js",
|
|
73
|
+
"/range.bnf",
|
|
74
|
+
"/benchmarks"
|
|
75
|
+
],
|
|
76
|
+
"publish": "true"
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ccgauge",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"description": "Local web dashboard for Claude Code and OpenAI Codex CLI token usage and cost",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"claude",
|
|
@@ -64,10 +64,16 @@
|
|
|
64
64
|
"start:next": "next start -p 3737",
|
|
65
65
|
"lint": "eslint .",
|
|
66
66
|
"typecheck": "tsc --noEmit",
|
|
67
|
-
"test": "node --experimental-strip-types --no-warnings scripts/test-codex-parser.mjs",
|
|
67
|
+
"test": "node --experimental-strip-types --no-warnings scripts/test-codex-parser.mjs && node --experimental-strip-types --no-warnings scripts/test-turns.mjs && node --experimental-strip-types --no-warnings scripts/test-source-merge.mjs && node --experimental-strip-types --no-warnings scripts/test-cost-from-usage.mjs && node --experimental-strip-types --no-warnings scripts/test-range.mjs && node scripts/check-parser-versions.mjs && node scripts/check-readme-images.mjs",
|
|
68
68
|
"test:mcp": "node scripts/test-mcp-server.mjs",
|
|
69
69
|
"clean": "node -e \"for (const p of ['.next','node_modules','tsconfig.tsbuildinfo']) require('node:fs').rmSync(p,{recursive:true,force:true})\"",
|
|
70
70
|
"screenshots": "node scripts/screenshots.mjs",
|
|
71
|
+
"site:dev": "cd site && astro dev --port 4321",
|
|
72
|
+
"site:build": "cd site && astro build",
|
|
73
|
+
"site:preview": "cd site && astro preview --port 4322",
|
|
74
|
+
"site:check": "cd site && astro check",
|
|
75
|
+
"site:gen:placeholders": "node site/scripts/gen-placeholders.mjs",
|
|
76
|
+
"site:clean": "node -e \"for (const p of ['site/dist','site/.astro','site/node_modules']) require('node:fs').rmSync(p,{recursive:true,force:true})\"",
|
|
71
77
|
"prepack": "pnpm build"
|
|
72
78
|
},
|
|
73
79
|
"dependencies": {
|
|
@@ -77,10 +83,15 @@
|
|
|
77
83
|
"open": "^10.1.0"
|
|
78
84
|
},
|
|
79
85
|
"devDependencies": {
|
|
86
|
+
"@astrojs/check": "^0.9.4",
|
|
87
|
+
"@astrojs/tailwind": "^5.1.4",
|
|
80
88
|
"@eslint/eslintrc": "^3.3.5",
|
|
89
|
+
"@fontsource-variable/geist": "^5.1.1",
|
|
90
|
+
"@fontsource-variable/geist-mono": "^5.1.1",
|
|
81
91
|
"@types/node": "^22.10.0",
|
|
82
92
|
"@types/react": "^19.0.0",
|
|
83
93
|
"@types/react-dom": "^19.0.0",
|
|
94
|
+
"astro": "^4.16.18",
|
|
84
95
|
"autoprefixer": "^10.4.20",
|
|
85
96
|
"clsx": "^2.1.1",
|
|
86
97
|
"date-fns": "^4.1.0",
|
|
Binary file
|
|
@@ -1,7 +1,21 @@
|
|
|
1
1
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" fill="none">
|
|
2
|
-
<
|
|
3
|
-
<
|
|
4
|
-
<
|
|
5
|
-
<
|
|
6
|
-
<
|
|
2
|
+
<title>ccgauge</title>
|
|
3
|
+
<rect x="3" y="3" width="58" height="58" rx="16" fill="#6366F1"/>
|
|
4
|
+
<rect x="3.75" y="3.75" width="56.5" height="56.5" rx="15.25" stroke="#FFFFFF" stroke-opacity="0.18" stroke-width="1.5"/>
|
|
5
|
+
<path d="M15 39.5 A17 17 0 0 1 49 39.5" stroke="#FFFFFF" stroke-opacity="0.24" stroke-width="5" stroke-linecap="round"/>
|
|
6
|
+
<path d="M20.8 39.5 A11.2 11.2 0 0 1 43.2 39.5" stroke="#FFFFFF" stroke-opacity="0.2" stroke-width="1.8" stroke-linecap="round"/>
|
|
7
|
+
<path d="M15 39.5 A17 17 0 0 1 42.8 26" stroke="#FFFFFF" stroke-width="5" stroke-linecap="round"/>
|
|
8
|
+
<g stroke="#FFFFFF" stroke-linecap="round" stroke-width="2" stroke-opacity="0.54">
|
|
9
|
+
<path d="M18.1 34.2 L15 32.4"/>
|
|
10
|
+
<path d="M24 28.5 L22.3 25.5"/>
|
|
11
|
+
<path d="M32 26.2 L32 22.8"/>
|
|
12
|
+
<path d="M40 28.5 L41.7 25.5"/>
|
|
13
|
+
<path d="M45.9 34.2 L49 32.4"/>
|
|
14
|
+
</g>
|
|
15
|
+
<path d="M32 39.5 L42.8 26" stroke="#FFFFFF" stroke-width="3.4" stroke-linecap="round"/>
|
|
16
|
+
<circle cx="32" cy="39.5" r="4.8" fill="#FFFFFF"/>
|
|
17
|
+
<circle cx="32" cy="39.5" r="2" fill="#4F46E5"/>
|
|
18
|
+
<rect x="17" y="46" width="7" height="5" rx="2" fill="#34D399"/>
|
|
19
|
+
<rect x="28.5" y="43" width="7" height="8" rx="2" fill="#FBBF24"/>
|
|
20
|
+
<rect x="40" y="45" width="7" height="6" rx="2" fill="#93C5FD"/>
|
|
7
21
|
</svg>
|
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,291 @@ 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.5] — 2026-05-19
|
|
9
|
+
|
|
10
|
+
CLI ergonomics overhaul + a brand-new `turns` / `conversations`
|
|
11
|
+
metric exposed in MCP and CLI report. Plus one P1 fix that resurrected
|
|
12
|
+
`ccgauge mcp` (silently exiting since 1.0.3's in-process refactor).
|
|
13
|
+
|
|
14
|
+
### Highlights
|
|
15
|
+
|
|
16
|
+
- **`turns` / "Conversations" metric** added to MCP responses and CLI
|
|
17
|
+
report. A turn is one user prompt — the same unit the dashboard's
|
|
18
|
+
usage table rows, and `usage trend → Conversations` toggle, already
|
|
19
|
+
count. A single turn typically fans out to 10–20× more `requests`
|
|
20
|
+
via tool loops, reasoning steps, and sub-agents, so `turns` is the
|
|
21
|
+
better signal for "how often did I actually talk to the model".
|
|
22
|
+
All three surfaces now share `lib/turns.ts → summarizeTurns()`.
|
|
23
|
+
- **15+ CLI fixes + UX polish** — `ccgauge -r 7d` now produces a
|
|
24
|
+
helpful root error instead of `start: unknown option`; bare
|
|
25
|
+
`ccgauge` is the documented shortcut for `ccgauge start` again;
|
|
26
|
+
`ccgauge status` returns systemd-style exit 3 when not running;
|
|
27
|
+
`ccgauge stop` no longer kills unrelated processes after a reboot
|
|
28
|
+
(PID identity is verified); `ccgauge logs -f` no longer
|
|
29
|
+
duplicates lines under heavy write rates; foreground server starts
|
|
30
|
+
via `spawn` (matches background path); and a dozen smaller things.
|
|
31
|
+
- **New `ccgauge doctor` command** — one-screen diagnostic dumping
|
|
32
|
+
version, environment, build artifacts, background-service state,
|
|
33
|
+
and per-provider scan stats. The recommended first step for any
|
|
34
|
+
bug report.
|
|
35
|
+
- **P1 fix: `ccgauge mcp` now stays alive.** 1.0.3 refactored the
|
|
36
|
+
subcommand to run in-process via `await import()`, but a stray
|
|
37
|
+
`process.exit(0)` after `runStdioServer()` killed the process right
|
|
38
|
+
after the JSON-RPC transport opened, before any LLM client could
|
|
39
|
+
finish `initialize`. The smoke test now drives `node bin/cli.mjs
|
|
40
|
+
mcp` directly so this CLI-wrapper layer can never regress silently
|
|
41
|
+
again.
|
|
42
|
+
|
|
43
|
+
### Added
|
|
44
|
+
|
|
45
|
+
- **`ccgauge doctor`** — single-shot diagnostic command. Prints
|
|
46
|
+
ccgauge version + node / platform, ccgauge-relevant env vars
|
|
47
|
+
(`CCGAUGE_*`, `CLAUDE_CONFIG_DIR`, `CODEX_HOME`, `NO_COLOR`,
|
|
48
|
+
`FORCE_COLOR`), build-artifact presence, background-service state,
|
|
49
|
+
and the indexer probe from `ccgauge mcp --check`. Plain text so
|
|
50
|
+
it pastes into a GitHub issue cleanly.
|
|
51
|
+
- **MCP `turns` field** in every analytical tool's response shape:
|
|
52
|
+
- `usage_summary` — `totals.turns`, `bySource.{claude,codex}.turns`.
|
|
53
|
+
- `usage_by_time` — `buckets[i].totals.turns` and per-source
|
|
54
|
+
breakdown; turns attribute to the bucket of their **earliest**
|
|
55
|
+
record (same convention as the dashboard's overview chart).
|
|
56
|
+
- `usage_by_model` — `models[i].turns` (turn is counted under
|
|
57
|
+
the model of its first record; sums across models equal the
|
|
58
|
+
scope's `totals.turns`).
|
|
59
|
+
- `usage_by_project` — `projects[i].turns` (by turn's first cwd).
|
|
60
|
+
- `usage_by_session` — `sessions[i].turns` (one session can hold
|
|
61
|
+
many turns; CLI users / LLMs comparing "long session vs many
|
|
62
|
+
short sessions" finally have the right number).
|
|
63
|
+
- `daily_summary`, `weekly_summary`, `recent_activity` — same
|
|
64
|
+
fields flow through their nested totals / per_day / sessions.
|
|
65
|
+
- `cost_estimator` is unchanged (pure pricing, no turn concept).
|
|
66
|
+
- **CLI report `Convos` field** in `ccgauge report` output:
|
|
67
|
+
- **Tokens section** gets a new `Convos / Requests` line, so the
|
|
68
|
+
two activity counts read side-by-side.
|
|
69
|
+
- **Top-N breakdown table** (model / project / session) gets a
|
|
70
|
+
new `Convos` column between the dimension label and `Reqs`.
|
|
71
|
+
- JSON output (`--json`) carries `totals.turns`, `trend[i].turns`,
|
|
72
|
+
`breakdown[i].turns`.
|
|
73
|
+
- **`lib/turns.ts → summarizeTurns()`** helper — given a (filtered)
|
|
74
|
+
record slice plus the full user / parent context, returns one
|
|
75
|
+
`TurnSummary` per distinct turn root with its `firstTimestamp`,
|
|
76
|
+
`firstModel`, `cwd`, `sessionId`, `source`. The single source of
|
|
77
|
+
truth shared by dashboard / MCP / CLI report.
|
|
78
|
+
- **`SessionSummary.projectLabel`** — worktree-aware display label
|
|
79
|
+
(`"ai-self-web (playwright)"` instead of bare `"playwright"`),
|
|
80
|
+
matching the usage table. Drives the `/sessions` page, the
|
|
81
|
+
session-detail header, and CLI report's session breakdown.
|
|
82
|
+
|
|
83
|
+
### Changed
|
|
84
|
+
|
|
85
|
+
- **`ccgauge` (no subcommand)** is the documented shortcut for
|
|
86
|
+
`ccgauge start` again. A regression in 1.0.4's `normalizeArgv`
|
|
87
|
+
refactor made bare `ccgauge` print root help and exit 1.
|
|
88
|
+
- **`ccgauge status` exit code** is now systemd-style 3 when no
|
|
89
|
+
background service is running, so shell scripts can `if ccgauge
|
|
90
|
+
status; then …`. **`--json` mode** intentionally still exits 0
|
|
91
|
+
(the consumer is a script that should read `payload.running`),
|
|
92
|
+
so `ccgauge status --json | jq` under `set -e` keeps working.
|
|
93
|
+
- **`ccgauge mcp` runs in-process via `await import()` + the bundle
|
|
94
|
+
exports `runStdioServer` / `printCheck`.** Saves ~80–150 ms vs
|
|
95
|
+
the old spawn-a-child design and removes a brittle signal-
|
|
96
|
+
forwarding shim. (1.0.3 introduced this; 1.0.5 fixes the
|
|
97
|
+
`process.exit(0)` regression that broke it for real users.)
|
|
98
|
+
- **`ccgauge mcp --check`** — verifies the bundle, boots the
|
|
99
|
+
indexer, prints one line per provider with scanned dirs + record
|
|
100
|
+
counts, and exits. Lets users debug "Claude Desktop doesn't see
|
|
101
|
+
ccgauge tools" without spinning up an MCP client.
|
|
102
|
+
- **`--color` / `--no-color` / `FORCE_COLOR` / `NO_COLOR`** all
|
|
103
|
+
resolve through a single `shouldUseColor()` helper now, with the
|
|
104
|
+
documented precedence (`--no-color` highest, then env vars, then
|
|
105
|
+
`isTTY`). Previously the report's color flag was hard-AND'd with
|
|
106
|
+
`isTTY`, so `FORCE_COLOR=1 ccgauge report | tee log` lost colour.
|
|
107
|
+
- **`ccgauge start` foreground** uses `spawn` instead of `fork`.
|
|
108
|
+
Next.js standalone doesn't use IPC; `fork` was opening an unused
|
|
109
|
+
channel and the parent's `process.exit(0)` was racing the child's
|
|
110
|
+
teardown on Ctrl+C. Now matches the background path's `spawn` +
|
|
111
|
+
exit-code forwarding.
|
|
112
|
+
- **`--quiet`** silences Next.js's stderr too. Previously only stdout
|
|
113
|
+
was ignored, so warnings still leaked. (Background mode is
|
|
114
|
+
unaffected — it has always logged to a file.)
|
|
115
|
+
- **`ccgauge restart --dir ""`** clears the inherited override
|
|
116
|
+
instead of silently re-reading the previous run's `dataDir` from
|
|
117
|
+
`state.json`. Uses commander's `getOptionValueSource('dir') ===
|
|
118
|
+
'cli'` instead of `!opts.dir` truthy check.
|
|
119
|
+
- **Background-start failure messages** now include the last 5
|
|
120
|
+
lines of `~/.ccgauge/ccgauge.log`, so users don't have to discover
|
|
121
|
+
`ccgauge logs` to learn that EADDRINUSE / their override path
|
|
122
|
+
doesn't exist / etc. caused the silent timeout.
|
|
123
|
+
- **"Build artifact not found"** errors from `start` / `report` /
|
|
124
|
+
`mcp` are unified into one `missingArtifactError(...)` helper.
|
|
125
|
+
Includes `node --version` / `ccgauge --version` / `platform` so
|
|
126
|
+
bug reports don't lose those.
|
|
127
|
+
- **`[ccgauge] error:`** prefix is now consistent on stderr
|
|
128
|
+
diagnostics (was a mix of `[ccgauge]`, `[ccgauge-mcp]`, and bare
|
|
129
|
+
prose). stdout user-facing messages stay unprefixed.
|
|
130
|
+
- **`/sessions` project column** uses `projectLabel` (worktree-aware)
|
|
131
|
+
so rows for `…/.claude/worktrees/playwright` read
|
|
132
|
+
`ai-self-web (playwright)` — matching the usage table.
|
|
133
|
+
- **CLI report's session breakdown** (`--by session`) `sub` text
|
|
134
|
+
also uses `projectLabel`, for the same reason.
|
|
135
|
+
- **README / README.zh-CN** Commands table gains `ccgauge doctor`;
|
|
136
|
+
Troubleshooting gains a "anything unexpected → ccgauge doctor"
|
|
137
|
+
lead; MCP troubleshooting points at `ccgauge mcp --check`.
|
|
138
|
+
|
|
139
|
+
### Fixed
|
|
140
|
+
|
|
141
|
+
- **`ccgauge mcp` exited immediately after the JSON-RPC handshake**
|
|
142
|
+
(P1 regression from 1.0.3): the in-process CLI wrapper called
|
|
143
|
+
`process.exit(0)` after `await runStdioServer()`, but
|
|
144
|
+
`runStdioServer` returns as soon as `server.connect(transport)`
|
|
145
|
+
finishes the handshake — the long-running stdin readline is what
|
|
146
|
+
holds the process alive. Removed the exit; documented with a
|
|
147
|
+
`CRITICAL:` comment so it can't come back. Smoke test now runs
|
|
148
|
+
through `node bin/cli.mjs mcp` so the CLI wrapper is on the
|
|
149
|
+
covered path.
|
|
150
|
+
- **`ccgauge -r 7d -s codex` reported `start: unknown option '-r'`**
|
|
151
|
+
instead of "did you mean `report`?". `normalizeArgv` now only
|
|
152
|
+
injects `start` when every flag belongs to `start`'s own option
|
|
153
|
+
set; otherwise it leaves argv alone and lets commander surface
|
|
154
|
+
its own root-level error (which lists subcommands).
|
|
155
|
+
- **`ccgauge logs -f` duplicated lines under heavy write rates.**
|
|
156
|
+
The follow loop used `stat().size` as the read cursor but didn't
|
|
157
|
+
cap the `createReadStream`'s upper bound, so a chunk written
|
|
158
|
+
between `stat` and the read could appear in both ticks. Now
|
|
159
|
+
pins `end: s.size - 1`.
|
|
160
|
+
- **`ccgauge stop` could kill unrelated processes after a reboot.**
|
|
161
|
+
`process.kill(pid, 0)` only checks PID liveness, and PID space
|
|
162
|
+
recycles aggressively across boots. `state.json` now records a
|
|
163
|
+
`bootId` (~ system uptime) and a `cmdMarker` (`"next-server"`),
|
|
164
|
+
and `isProcessRunning` verifies both — falling back to the bare
|
|
165
|
+
kill(0) on Windows where `ps` isn't available.
|
|
166
|
+
- **`test-mcp-server.mjs` flake** caused by top-N truncation: a
|
|
167
|
+
tool that's in claude-only top-10 can land #11 in the merged
|
|
168
|
+
all top-10 once codex contributes more competitors. The
|
|
169
|
+
per-tool count comparison now skips tools that didn't survive
|
|
170
|
+
the merged truncation (the broader "source filter is a no-op"
|
|
171
|
+
check below catches the real bug it was originally meant to).
|
|
172
|
+
- **`/usage` project filter listed worktree leaves** as if they
|
|
173
|
+
were independent projects (`affectionate-sammet-00dc35`,
|
|
174
|
+
`agitated-diffie-5c15fe`, …), out of sync with `/projects`
|
|
175
|
+
which already collapses worktrees under their canonical repo
|
|
176
|
+
root. The dropdown now lists canonical cwds only; the
|
|
177
|
+
`projects` URL param semantics changed from exact-cwd to
|
|
178
|
+
canonical-cwd matching, and the aggregator's `projects` filter
|
|
179
|
+
is bypassed in favour of a canonical-aware pre-filter so a
|
|
180
|
+
single record under `…/.claude/worktrees/X` still counts when
|
|
181
|
+
the user picks its main repo.
|
|
182
|
+
|
|
183
|
+
### Performance
|
|
184
|
+
|
|
185
|
+
- **Aggregator hot loop** — `withinRange` predicate used to call
|
|
186
|
+
`Date#toISOString()` + `Array.includes()` once per record. Each
|
|
187
|
+
entry-point function now hoists those into a `prepareOpts` step:
|
|
188
|
+
ISO strings computed once, `models` / `projects` materialized as
|
|
189
|
+
`Set` for O(1) membership. Measurable on the MCP `weekly_summary`
|
|
190
|
+
/ `usage_by_*` paths over year-scale histories; invisible for the
|
|
191
|
+
single-pass dashboard aggregators.
|
|
192
|
+
- **MCP indexer's 30 s polling fallback** is now **off by default**.
|
|
193
|
+
fs.watch's `recursive: true` handles changes reliably on modern
|
|
194
|
+
macOS / Linux / Windows; the polling fallback was originally
|
|
195
|
+
there for flaky network mounts and FUSE setups. The web
|
|
196
|
+
dashboard's indexer **keeps polling ON** (user expects fresh
|
|
197
|
+
data when they alt-tab back). Override either default with
|
|
198
|
+
`CCGAUGE_POLL_FALLBACK={0,1}`.
|
|
199
|
+
- **`get-port` / `open` are lazy-imported** — only loaded by `start`
|
|
200
|
+
/ `restart` / `open`. Short-lived commands like `mcp`, `status`,
|
|
201
|
+
`logs`, `report`, `--version` shave ~20–30 ms cold-start each.
|
|
202
|
+
Matters most for `ccgauge mcp`, which LLM clients spawn per
|
|
203
|
+
conversation.
|
|
204
|
+
|
|
205
|
+
### Internal
|
|
206
|
+
|
|
207
|
+
- **`summarizeTurns()`** in `lib/turns.ts` is the single source of
|
|
208
|
+
truth for turn-level metadata; dashboard, MCP, and CLI report all
|
|
209
|
+
consume it. Same parent-chain walk + synthetic-user skip as
|
|
210
|
+
`buildTurnIndex` (which it builds on top of).
|
|
211
|
+
- **`TurnsContext`** in `lib/mcp/formatters.ts` packages
|
|
212
|
+
`{ users, parentMap }` so per-source aggregator helpers can
|
|
213
|
+
re-derive turn boundaries without re-plumbing args through every
|
|
214
|
+
call site.
|
|
215
|
+
- **`SessionSummary` carries `projectLabel`** (worktree-aware) in
|
|
216
|
+
addition to `projectName` (plain basename). Populated once by
|
|
217
|
+
`aggregateBySession` via `resolveProjectLabel` (per-cwd cache).
|
|
218
|
+
- **`bootId()` helper** in `bin/cli.mjs` (`Date.now() - os.uptime()
|
|
219
|
+
* 1000`, rounded) — a coarse system-boot timestamp used to tell
|
|
220
|
+
pre-reboot PIDs from post-reboot ones.
|
|
221
|
+
- **`shouldUseColor()` + `ansiPalette()`** in `bin/cli.mjs` — used
|
|
222
|
+
by `printReady` so the startup banner respects `NO_COLOR` and
|
|
223
|
+
doesn't leave `^[[1m...` mojibake when piped to `tee` / CI.
|
|
224
|
+
- **Smoke test runs through the CLI wrapper.** `scripts/test-mcp-
|
|
225
|
+
server.mjs` now spawns `node bin/cli.mjs mcp` instead of `node
|
|
226
|
+
dist/mcp/server.mjs`, so any regression in the CLI wrapper
|
|
227
|
+
(signal handling, lifecycle, exit-code shaping) is caught here.
|
|
228
|
+
|
|
229
|
+
## [1.0.4] — 2026-05-18
|
|
230
|
+
|
|
231
|
+
Correctness fixes + much stronger test coverage, plus a brand refresh
|
|
232
|
+
and a marketing-site restructure. No new runtime features.
|
|
233
|
+
|
|
234
|
+
### Fixed
|
|
235
|
+
|
|
236
|
+
- **Windows path sanitization.** `sanitizeForUser` now also strips
|
|
237
|
+
forward-slashed, JSON-escaped, and long-path (`\\?\`) variants of
|
|
238
|
+
`homedir()`, not just the literal `C:\Users\<name>` form. macOS /
|
|
239
|
+
Linux behaviour unchanged.
|
|
240
|
+
- **5h-block empty state** follows the active source —
|
|
241
|
+
`?source=codex` no longer says "Send a message in Claude Code".
|
|
242
|
+
Same fix on the Codex tab inside the All view.
|
|
243
|
+
- **`combineTimeBuckets` shared-reference bug.** Shallow-cloned model
|
|
244
|
+
entries were aliased back into the indexer's aggregator cache, so
|
|
245
|
+
downstream mutations could poison subsequent reads. Deep-cloned on
|
|
246
|
+
insertion; pinned by a new test.
|
|
247
|
+
- **`safeMcpHandler` non-Error throws** are now wrapped + scrubbed
|
|
248
|
+
before re-throw; the previous branch silently fell through, shipping
|
|
249
|
+
unscrubbed payloads into the MCP envelope.
|
|
250
|
+
|
|
251
|
+
### Added
|
|
252
|
+
|
|
253
|
+
- **6 test / drift scripts**, all wired into `pnpm test`:
|
|
254
|
+
`test-turns`, `test-source-merge`, `test-cost-from-usage`,
|
|
255
|
+
`test-range` (fixture-based unit tests for the four core code
|
|
256
|
+
paths), plus `check-parser-versions` and `check-readme-images` (CI
|
|
257
|
+
drift guards for silently-stale-cache and broken-npm-image
|
|
258
|
+
regressions).
|
|
259
|
+
|
|
260
|
+
### Changed
|
|
261
|
+
|
|
262
|
+
- **Refined gauge brand mark**, unified across the dashboard, the
|
|
263
|
+
marketing site, and both favicons. Cleaner geometry (centre at
|
|
264
|
+
(32, 41), radius 18; arc + needle terminating on the dial rim),
|
|
265
|
+
Indigo-400 → -600 gradient background, white-ring pivot. New shared
|
|
266
|
+
`<LogoMark>` component on the marketing site so its Nav + Footer
|
|
267
|
+
now use the same mark as the dashboard.
|
|
268
|
+
- **Marketing site is source-only.** Removed `site/package.json` and
|
|
269
|
+
`site/pnpm-lock.yaml`; Astro deps live in root `devDependencies`,
|
|
270
|
+
commands are explicit `pnpm site:*`. Still excluded from the npm
|
|
271
|
+
tarball (`pnpm pack --dry-run | grep -c '^site/'` → `0`).
|
|
272
|
+
- **Theme-aware product screenshots.** New `<ThemedScreenshot>`
|
|
273
|
+
component swaps between dark / light captures via the
|
|
274
|
+
`.theme-light` class on `<html>`. 24 captures (6 pages × 2 locales
|
|
275
|
+
× 2 themes) generated by an expanded `scripts/screenshots.mjs`.
|
|
276
|
+
- **OG cards** regenerated at higher fidelity.
|
|
277
|
+
- **`cost_estimator` MCP tool** description spells out that reasoning
|
|
278
|
+
tokens are already counted inside `output_tokens` — don't
|
|
279
|
+
double-count.
|
|
280
|
+
- **Activity heatmap tooltip** finally renders the share / of-peak
|
|
281
|
+
labels that were defined but never used.
|
|
282
|
+
- **`CacheCreationBlock` type** extracted in `parse-jsonl.ts`.
|
|
283
|
+
- **CLI `readState()`** type-guards `pid` / `url` / `logFile`.
|
|
284
|
+
|
|
285
|
+
### Internal
|
|
286
|
+
|
|
287
|
+
- MCP server warm-up comment clarifies the fire-and-forget
|
|
288
|
+
`getMcpIndexerReady()` is a cold-start shave — tool handlers still
|
|
289
|
+
await the same memoized init promise.
|
|
290
|
+
- `AGENTS.md` + bundled READMEs updated for the source-only site
|
|
291
|
+
layout and the new `pnpm site:*` command set.
|
|
292
|
+
|
|
8
293
|
## [1.0.3] — 2026-05-15
|
|
9
294
|
|
|
10
295
|
A focused **MCP server** correctness + performance + ergonomics pass,
|
|
@@ -678,6 +963,8 @@ of HTML to the browser.
|
|
|
678
963
|
- Initial public release as `ccgauge`: local Next.js dashboard for
|
|
679
964
|
Claude Code token usage, cost, and 5-hour block tracking.
|
|
680
965
|
|
|
966
|
+
[1.0.5]: https://github.com/chengzuopeng/ccgauge/compare/v1.0.4...v1.0.5
|
|
967
|
+
[1.0.4]: https://github.com/chengzuopeng/ccgauge/compare/v1.0.3...v1.0.4
|
|
681
968
|
[1.0.3]: https://github.com/chengzuopeng/ccgauge/compare/v1.0.2...v1.0.3
|
|
682
969
|
[1.0.2]: https://github.com/chengzuopeng/ccgauge/compare/v1.0.1...v1.0.2
|
|
683
970
|
[1.0.1]: https://github.com/chengzuopeng/ccgauge/compare/v1.0.0...v1.0.1
|