@sentropic/agent-stats-core 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/aggregations.d.ts +13 -2
- package/dist/aggregations.d.ts.map +1 -1
- package/dist/aggregations.js +31 -6
- package/dist/aggregations.js.map +1 -1
- package/dist/anomalies.d.ts +2 -2
- package/dist/anomalies.d.ts.map +1 -1
- package/dist/cleanser.d.ts +6 -0
- package/dist/cleanser.d.ts.map +1 -1
- package/dist/cleanser.js +2 -1
- package/dist/cleanser.js.map +1 -1
- package/dist/collect.d.ts +5 -3
- package/dist/collect.d.ts.map +1 -1
- package/dist/collect.js +22 -2
- package/dist/collect.js.map +1 -1
- package/dist/index.d.ts +5 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -2
- package/dist/index.js.map +1 -1
- package/dist/parsers/claude.d.ts.map +1 -1
- package/dist/parsers/claude.js +11 -0
- package/dist/parsers/claude.js.map +1 -1
- package/dist/parsers/codex.d.ts.map +1 -1
- package/dist/parsers/codex.js +35 -36
- package/dist/parsers/codex.js.map +1 -1
- package/dist/parsers/cursor.d.ts +42 -0
- package/dist/parsers/cursor.d.ts.map +1 -0
- package/dist/parsers/cursor.js +222 -0
- package/dist/parsers/cursor.js.map +1 -0
- package/dist/rate-card.d.ts.map +1 -1
- package/dist/rate-card.js +15 -4
- package/dist/rate-card.js.map +1 -1
- package/dist/schema.d.ts +5 -1
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js.map +1 -1
- package/dist/secrets.d.ts +40 -9
- package/dist/secrets.d.ts.map +1 -1
- package/dist/secrets.js +96 -10
- package/dist/secrets.js.map +1 -1
- package/dist/series.d.ts +40 -0
- package/dist/series.d.ts.map +1 -0
- package/dist/series.js +51 -0
- package/dist/series.js.map +1 -0
- package/dist/tool-stats.d.ts +21 -0
- package/dist/tool-stats.d.ts.map +1 -0
- package/dist/tool-stats.js +38 -0
- package/dist/tool-stats.js.map +1 -0
- package/package.json +3 -1
package/dist/secrets.js
CHANGED
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Secret scanning. Combines two sources:
|
|
3
|
+
* 1. secretlint preset-recommend (28 rules: AWS, Anthropic, OpenAI, GitHub,
|
|
4
|
+
* GitLab, Slack, Stripe, JWT, private keys, …) — the generic baseline.
|
|
5
|
+
* 2. Optional **custom patterns** (regexes), e.g. an organisation's internal
|
|
6
|
+
* token formats that the generic rules don't know about. These are loaded
|
|
7
|
+
* from a small YAML file (see `loadSecretPatterns`).
|
|
3
8
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
9
|
+
* Returns match ranges so callers can redact in place (cleanser) or report
|
|
10
|
+
* them (audit). The two sources are merged and overlapping ranges are kept
|
|
11
|
+
* once so a string is never double-redacted.
|
|
7
12
|
*/
|
|
13
|
+
import { readFileSync } from 'node:fs';
|
|
8
14
|
import { lintSource } from '@secretlint/core';
|
|
9
15
|
import { creator as presetRecommend } from '@secretlint/secretlint-rule-preset-recommend';
|
|
16
|
+
import yaml from 'js-yaml';
|
|
10
17
|
const DEFAULT_CONFIG = {
|
|
11
18
|
rules: [
|
|
12
19
|
{
|
|
@@ -16,16 +23,93 @@ const DEFAULT_CONFIG = {
|
|
|
16
23
|
],
|
|
17
24
|
};
|
|
18
25
|
/**
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
26
|
+
* Load custom secret patterns from a YAML file. Accepts either a top-level
|
|
27
|
+
* list, or a `patterns:` key holding the list:
|
|
28
|
+
*
|
|
29
|
+
* - id: sentropic-token
|
|
30
|
+
* pattern: "stp_[A-Za-z0-9]{32}"
|
|
31
|
+
* flags: ""
|
|
32
|
+
*
|
|
33
|
+
* Invalid entries are skipped defensively (bad regex, missing fields).
|
|
34
|
+
*/
|
|
35
|
+
export function loadSecretPatterns(filePath) {
|
|
36
|
+
let raw;
|
|
37
|
+
try {
|
|
38
|
+
raw = yaml.load(readFileSync(filePath, 'utf8'));
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return [];
|
|
42
|
+
}
|
|
43
|
+
const list = Array.isArray(raw)
|
|
44
|
+
? raw
|
|
45
|
+
: raw && typeof raw === 'object' && Array.isArray(raw.patterns)
|
|
46
|
+
? raw.patterns
|
|
47
|
+
: [];
|
|
48
|
+
const out = [];
|
|
49
|
+
for (const item of list) {
|
|
50
|
+
if (!item || typeof item !== 'object')
|
|
51
|
+
continue;
|
|
52
|
+
const { id, pattern, flags } = item;
|
|
53
|
+
if (typeof id !== 'string' || typeof pattern !== 'string')
|
|
54
|
+
continue;
|
|
55
|
+
try {
|
|
56
|
+
new RegExp(pattern, typeof flags === 'string' ? flags : ''); // validate
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
out.push({ id, pattern, ...(typeof flags === 'string' ? { flags } : {}) });
|
|
62
|
+
}
|
|
63
|
+
return out;
|
|
64
|
+
}
|
|
65
|
+
function scanCustom(text, patterns) {
|
|
66
|
+
const matches = [];
|
|
67
|
+
for (const p of patterns) {
|
|
68
|
+
let re;
|
|
69
|
+
try {
|
|
70
|
+
const flags = new Set((p.flags ?? '').split(''));
|
|
71
|
+
flags.add('g'); // global is required to walk all occurrences
|
|
72
|
+
re = new RegExp(p.pattern, [...flags].join(''));
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
for (const m of text.matchAll(re)) {
|
|
78
|
+
if (m.index === undefined || m[0].length === 0)
|
|
79
|
+
continue;
|
|
80
|
+
matches.push({
|
|
81
|
+
start: m.index,
|
|
82
|
+
end: m.index + m[0].length,
|
|
83
|
+
ruleId: `custom:${p.id}`,
|
|
84
|
+
message: `custom pattern ${p.id}`,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return matches;
|
|
89
|
+
}
|
|
90
|
+
/** Drop ranges fully covered by an earlier-starting / longer range. */
|
|
91
|
+
function dedupeRanges(matches) {
|
|
92
|
+
const sorted = [...matches].sort((a, b) => a.start - b.start || b.end - a.end);
|
|
93
|
+
const kept = [];
|
|
94
|
+
let lastEnd = -1;
|
|
95
|
+
for (const m of sorted) {
|
|
96
|
+
if (m.start >= lastEnd || m.end > lastEnd) {
|
|
97
|
+
kept.push(m);
|
|
98
|
+
lastEnd = Math.max(lastEnd, m.end);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return kept;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Scan a single string for secrets (preset rules + optional custom patterns).
|
|
105
|
+
* Returns an empty array if nothing looks suspicious. Safe on empty strings.
|
|
22
106
|
*/
|
|
23
|
-
export async function scanString(text,
|
|
107
|
+
export async function scanString(text, opts = {}) {
|
|
24
108
|
if (!text)
|
|
25
109
|
return [];
|
|
26
110
|
const result = await lintSource({
|
|
27
111
|
source: {
|
|
28
|
-
filePath,
|
|
112
|
+
filePath: opts.filePath ?? 'inline.txt',
|
|
29
113
|
content: text,
|
|
30
114
|
contentType: 'text',
|
|
31
115
|
},
|
|
@@ -35,11 +119,13 @@ export async function scanString(text, filePath = 'inline.txt') {
|
|
|
35
119
|
noPhysicFilePath: true,
|
|
36
120
|
},
|
|
37
121
|
});
|
|
38
|
-
|
|
122
|
+
const preset = (result.messages ?? []).map((m) => ({
|
|
39
123
|
start: m.range[0],
|
|
40
124
|
end: m.range[1],
|
|
41
125
|
ruleId: m.ruleId,
|
|
42
126
|
message: m.message,
|
|
43
127
|
}));
|
|
128
|
+
const custom = opts.customPatterns?.length ? scanCustom(text, opts.customPatterns) : [];
|
|
129
|
+
return dedupeRanges([...preset, ...custom]);
|
|
44
130
|
}
|
|
45
131
|
//# sourceMappingURL=secrets.js.map
|
package/dist/secrets.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"secrets.js","sourceRoot":"","sources":["../src/secrets.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"secrets.js","sourceRoot":"","sources":["../src/secrets.ts"],"names":[],"mappings":"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"}
|
package/dist/series.d.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure helpers to turn weekly aggregation rows into single-series chart data
|
|
3
|
+
* (e.g. for the design-system LineChart / Sparkline which take {x,y}[] /
|
|
4
|
+
* number[]). Lives in core (no UI dependency) so it is unit-tested without the
|
|
5
|
+
* SvelteKit toolchain.
|
|
6
|
+
*/
|
|
7
|
+
export type SeriesMetric = 'tokens' | 'credits' | 'quota7d' | 'sessions' | 'inputNew' | 'output' | 'inout' | 'cached';
|
|
8
|
+
export type ToolFilter = 'all' | 'claude' | 'codex' | 'cursor';
|
|
9
|
+
/** The subset of a WeeklyAggregation row the charts need (structural). */
|
|
10
|
+
export interface SeriesRow {
|
|
11
|
+
weekStart: string;
|
|
12
|
+
tool: 'claude' | 'codex' | 'cursor';
|
|
13
|
+
sessions: number;
|
|
14
|
+
totalUsage: {
|
|
15
|
+
newInputTokens: number;
|
|
16
|
+
cachedInputTokens: number;
|
|
17
|
+
cacheWriteTokens: number;
|
|
18
|
+
outputTokens: number;
|
|
19
|
+
reasoningTokens?: number;
|
|
20
|
+
};
|
|
21
|
+
estimatedCost: {
|
|
22
|
+
codexCredits: number;
|
|
23
|
+
};
|
|
24
|
+
rateLimitMax?: {
|
|
25
|
+
secondaryPercent: number;
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
export interface SeriesPoint {
|
|
29
|
+
x: string;
|
|
30
|
+
y: number;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Bucket rows by their bucket start (`weekStart`, which holds the day for daily
|
|
34
|
+
* rows) for one metric and tool filter. Most metrics sum within a bucket;
|
|
35
|
+
* `quota7d` is a rate-limit peak so it takes the max. Sorted ascending.
|
|
36
|
+
*/
|
|
37
|
+
export declare function periodSeries(rows: SeriesRow[], metric: SeriesMetric, tool: ToolFilter): SeriesPoint[];
|
|
38
|
+
/** @deprecated use {@link periodSeries} (granularity-agnostic). */
|
|
39
|
+
export declare const weeklySeries: typeof periodSeries;
|
|
40
|
+
//# sourceMappingURL=series.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"series.d.ts","sourceRoot":"","sources":["../src/series.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,MAAM,YAAY,GAEpB,QAAQ,GACR,SAAS,GACT,SAAS,GACT,UAAU,GAEV,UAAU,GACV,QAAQ,GACR,OAAO,GACP,QAAQ,CAAC;AACb,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,CAAC;AAE/D,0EAA0E;AAC1E,MAAM,WAAW,SAAS;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,QAAQ,GAAG,OAAO,GAAG,QAAQ,CAAC;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE;QACV,cAAc,EAAE,MAAM,CAAC;QACvB,iBAAiB,EAAE,MAAM,CAAC;QAC1B,gBAAgB,EAAE,MAAM,CAAC;QACzB,YAAY,EAAE,MAAM,CAAC;QACrB,eAAe,CAAC,EAAE,MAAM,CAAC;KAC1B,CAAC;IACF,aAAa,EAAE;QAAE,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC;IACxC,YAAY,CAAC,EAAE;QAAE,gBAAgB,EAAE,MAAM,CAAA;KAAE,CAAC;CAC7C;AAED,MAAM,WAAW,WAAW;IAC1B,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AA0BD;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,SAAS,EAAE,EACjB,MAAM,EAAE,YAAY,EACpB,IAAI,EAAE,UAAU,GACf,WAAW,EAAE,CAWf;AAED,mEAAmE;AACnE,eAAO,MAAM,YAAY,qBAAe,CAAC"}
|
package/dist/series.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure helpers to turn weekly aggregation rows into single-series chart data
|
|
3
|
+
* (e.g. for the design-system LineChart / Sparkline which take {x,y}[] /
|
|
4
|
+
* number[]). Lives in core (no UI dependency) so it is unit-tested without the
|
|
5
|
+
* SvelteKit toolchain.
|
|
6
|
+
*/
|
|
7
|
+
function metricValue(r, metric) {
|
|
8
|
+
const u = r.totalUsage;
|
|
9
|
+
const inputNew = u.newInputTokens + u.cacheWriteTokens;
|
|
10
|
+
const output = u.outputTokens + (u.reasoningTokens ?? 0);
|
|
11
|
+
switch (metric) {
|
|
12
|
+
case 'tokens': // legacy headline metric: all input + output (cache included)
|
|
13
|
+
return u.newInputTokens + u.cachedInputTokens + u.cacheWriteTokens + u.outputTokens;
|
|
14
|
+
case 'credits':
|
|
15
|
+
return r.estimatedCost.codexCredits;
|
|
16
|
+
case 'sessions':
|
|
17
|
+
return r.sessions;
|
|
18
|
+
case 'quota7d':
|
|
19
|
+
return r.rateLimitMax?.secondaryPercent ?? 0;
|
|
20
|
+
case 'inputNew':
|
|
21
|
+
return inputNew;
|
|
22
|
+
case 'output':
|
|
23
|
+
return output;
|
|
24
|
+
case 'inout': // cached read excluded
|
|
25
|
+
return inputNew + output;
|
|
26
|
+
case 'cached':
|
|
27
|
+
return u.cachedInputTokens;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Bucket rows by their bucket start (`weekStart`, which holds the day for daily
|
|
32
|
+
* rows) for one metric and tool filter. Most metrics sum within a bucket;
|
|
33
|
+
* `quota7d` is a rate-limit peak so it takes the max. Sorted ascending.
|
|
34
|
+
*/
|
|
35
|
+
export function periodSeries(rows, metric, tool) {
|
|
36
|
+
const filtered = tool === 'all' ? rows : rows.filter((r) => r.tool === tool);
|
|
37
|
+
const isMax = metric === 'quota7d';
|
|
38
|
+
const byWeek = new Map();
|
|
39
|
+
for (const r of filtered) {
|
|
40
|
+
const v = metricValue(r, metric);
|
|
41
|
+
const prev = byWeek.get(r.weekStart);
|
|
42
|
+
if (prev === undefined)
|
|
43
|
+
byWeek.set(r.weekStart, v);
|
|
44
|
+
else
|
|
45
|
+
byWeek.set(r.weekStart, isMax ? Math.max(prev, v) : prev + v);
|
|
46
|
+
}
|
|
47
|
+
return [...byWeek.entries()].sort((a, b) => a[0].localeCompare(b[0])).map(([x, y]) => ({ x, y }));
|
|
48
|
+
}
|
|
49
|
+
/** @deprecated use {@link periodSeries} (granularity-agnostic). */
|
|
50
|
+
export const weeklySeries = periodSeries;
|
|
51
|
+
//# sourceMappingURL=series.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"series.js","sourceRoot":"","sources":["../src/series.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAoCH,SAAS,WAAW,CAAC,CAAY,EAAE,MAAoB;IACrD,MAAM,CAAC,GAAG,CAAC,CAAC,UAAU,CAAC;IACvB,MAAM,QAAQ,GAAG,CAAC,CAAC,cAAc,GAAG,CAAC,CAAC,gBAAgB,CAAC;IACvD,MAAM,MAAM,GAAG,CAAC,CAAC,YAAY,GAAG,CAAC,CAAC,CAAC,eAAe,IAAI,CAAC,CAAC,CAAC;IACzD,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,QAAQ,EAAE,8DAA8D;YAC3E,OAAO,CAAC,CAAC,cAAc,GAAG,CAAC,CAAC,iBAAiB,GAAG,CAAC,CAAC,gBAAgB,GAAG,CAAC,CAAC,YAAY,CAAC;QACtF,KAAK,SAAS;YACZ,OAAO,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC;QACtC,KAAK,UAAU;YACb,OAAO,CAAC,CAAC,QAAQ,CAAC;QACpB,KAAK,SAAS;YACZ,OAAO,CAAC,CAAC,YAAY,EAAE,gBAAgB,IAAI,CAAC,CAAC;QAC/C,KAAK,UAAU;YACb,OAAO,QAAQ,CAAC;QAClB,KAAK,QAAQ;YACX,OAAO,MAAM,CAAC;QAChB,KAAK,OAAO,EAAE,uBAAuB;YACnC,OAAO,QAAQ,GAAG,MAAM,CAAC;QAC3B,KAAK,QAAQ;YACX,OAAO,CAAC,CAAC,iBAAiB,CAAC;IAC/B,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAC1B,IAAiB,EACjB,MAAoB,EACpB,IAAgB;IAEhB,MAAM,QAAQ,GAAG,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;IAC7E,MAAM,KAAK,GAAG,MAAM,KAAK,SAAS,CAAC;IACnC,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;IACzC,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,MAAM,CAAC,GAAG,WAAW,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;QACjC,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QACrC,IAAI,IAAI,KAAK,SAAS;YAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;;YAC9C,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC;IACrE,CAAC;IACD,OAAO,CAAC,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;AACpG,CAAC;AAED,mEAAmE;AACnE,MAAM,CAAC,MAAM,YAAY,GAAG,YAAY,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helpers to surface tool / skill usage as top-N tables.
|
|
3
|
+
*
|
|
4
|
+
* MCP tools are reported as a single `mcp:{server}` bucket rather than one row
|
|
5
|
+
* per leaf tool (e.g. `mcp__playwright__browser_click`), so a chatty server
|
|
6
|
+
* does not flood the table. Native tools (Bash, Read, …) keep their name.
|
|
7
|
+
*/
|
|
8
|
+
/** Collapse an MCP tool id (`mcp__server__tool…`) to a `mcp:{server}` bucket. */
|
|
9
|
+
export declare function mcpBucket(name: string): string;
|
|
10
|
+
/** Sum a list of name→count maps, optionally normalizing each key. */
|
|
11
|
+
export declare function mergeNameCounts(maps: Array<Record<string, number>>, normalize?: (name: string) => string): Record<string, number>;
|
|
12
|
+
export interface NameCount {
|
|
13
|
+
name: string;
|
|
14
|
+
count: number;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Top-N entries from a name→count map. Deterministic ordering: count
|
|
18
|
+
* descending, then name ascending to break ties.
|
|
19
|
+
*/
|
|
20
|
+
export declare function topN(counts: Record<string, number>, n: number): NameCount[];
|
|
21
|
+
//# sourceMappingURL=tool-stats.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-stats.d.ts","sourceRoot":"","sources":["../src/tool-stats.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,iFAAiF;AACjF,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAM9C;AAED,sEAAsE;AACtE,wBAAgB,eAAe,CAC7B,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EACnC,SAAS,GAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAiB,GAC7C,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CASxB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;GAGG;AACH,wBAAgB,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,EAAE,MAAM,GAAG,SAAS,EAAE,CAK3E"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helpers to surface tool / skill usage as top-N tables.
|
|
3
|
+
*
|
|
4
|
+
* MCP tools are reported as a single `mcp:{server}` bucket rather than one row
|
|
5
|
+
* per leaf tool (e.g. `mcp__playwright__browser_click`), so a chatty server
|
|
6
|
+
* does not flood the table. Native tools (Bash, Read, …) keep their name.
|
|
7
|
+
*/
|
|
8
|
+
/** Collapse an MCP tool id (`mcp__server__tool…`) to a `mcp:{server}` bucket. */
|
|
9
|
+
export function mcpBucket(name) {
|
|
10
|
+
if (!name.startsWith('mcp__'))
|
|
11
|
+
return name;
|
|
12
|
+
// The server is always the first `__`-delimited segment after the `mcp__`
|
|
13
|
+
// prefix, even when the tool part contains extra underscores.
|
|
14
|
+
const server = name.slice(5).split('__')[0];
|
|
15
|
+
return server ? `mcp:${server}` : 'mcp:unknown';
|
|
16
|
+
}
|
|
17
|
+
/** Sum a list of name→count maps, optionally normalizing each key. */
|
|
18
|
+
export function mergeNameCounts(maps, normalize = (n) => n) {
|
|
19
|
+
const out = {};
|
|
20
|
+
for (const m of maps) {
|
|
21
|
+
for (const [k, v] of Object.entries(m)) {
|
|
22
|
+
const key = normalize(k);
|
|
23
|
+
out[key] = (out[key] ?? 0) + v;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return out;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Top-N entries from a name→count map. Deterministic ordering: count
|
|
30
|
+
* descending, then name ascending to break ties.
|
|
31
|
+
*/
|
|
32
|
+
export function topN(counts, n) {
|
|
33
|
+
return Object.entries(counts)
|
|
34
|
+
.map(([name, count]) => ({ name, count }))
|
|
35
|
+
.sort((a, b) => b.count - a.count || a.name.localeCompare(b.name))
|
|
36
|
+
.slice(0, n);
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=tool-stats.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-stats.js","sourceRoot":"","sources":["../src/tool-stats.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,iFAAiF;AACjF,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;QAAE,OAAO,IAAI,CAAC;IAC3C,0EAA0E;IAC1E,8DAA8D;IAC9D,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5C,OAAO,MAAM,CAAC,CAAC,CAAC,OAAO,MAAM,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC;AAClD,CAAC;AAED,sEAAsE;AACtE,MAAM,UAAU,eAAe,CAC7B,IAAmC,EACnC,YAAsC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAE9C,MAAM,GAAG,GAA2B,EAAE,CAAC;IACvC,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;QACrB,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;YACvC,MAAM,GAAG,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;YACzB,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;QACjC,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAOD;;;GAGG;AACH,MAAM,UAAU,IAAI,CAAC,MAA8B,EAAE,CAAS;IAC5D,OAAO,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC;SAC1B,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;SACzC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;SACjE,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AACjB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sentropic/agent-stats-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Parsers, aggregations and schema for agent-stats (Claude Code + Codex CLI session analyzer).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -45,9 +45,11 @@
|
|
|
45
45
|
"@secretlint/types": "^13.0.2",
|
|
46
46
|
"@types/better-sqlite3": "^7.6.13",
|
|
47
47
|
"better-sqlite3": "^12.10.0",
|
|
48
|
+
"js-yaml": "^4.1.0",
|
|
48
49
|
"secretlint": "^13.0.2"
|
|
49
50
|
},
|
|
50
51
|
"devDependencies": {
|
|
52
|
+
"@types/js-yaml": "^4.0.9",
|
|
51
53
|
"@vitest/coverage-v8": "^4.1.7"
|
|
52
54
|
}
|
|
53
55
|
}
|