@sentropic/agent-stats-core 0.1.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/README.md +4 -0
- package/dist/aggregations.d.ts +87 -0
- package/dist/aggregations.d.ts.map +1 -0
- package/dist/aggregations.js +242 -0
- package/dist/aggregations.js.map +1 -0
- package/dist/analyze.d.ts +93 -0
- package/dist/analyze.d.ts.map +1 -0
- package/dist/analyze.js +143 -0
- package/dist/analyze.js.map +1 -0
- package/dist/anomalies.d.ts +37 -0
- package/dist/anomalies.d.ts.map +1 -0
- package/dist/anomalies.js +188 -0
- package/dist/anomalies.js.map +1 -0
- package/dist/cleanser.d.ts +56 -0
- package/dist/cleanser.d.ts.map +1 -0
- package/dist/cleanser.js +132 -0
- package/dist/cleanser.js.map +1 -0
- package/dist/collect.d.ts +43 -0
- package/dist/collect.d.ts.map +1 -0
- package/dist/collect.js +140 -0
- package/dist/collect.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/parsers/claude.d.ts +33 -0
- package/dist/parsers/claude.d.ts.map +1 -0
- package/dist/parsers/claude.js +169 -0
- package/dist/parsers/claude.js.map +1 -0
- package/dist/parsers/codex.d.ts +69 -0
- package/dist/parsers/codex.d.ts.map +1 -0
- package/dist/parsers/codex.js +262 -0
- package/dist/parsers/codex.js.map +1 -0
- package/dist/rate-card.d.ts +50 -0
- package/dist/rate-card.d.ts.map +1 -0
- package/dist/rate-card.js +138 -0
- package/dist/rate-card.js.map +1 -0
- package/dist/schema.d.ts +138 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +37 -0
- package/dist/schema.js.map +1 -0
- package/dist/secrets.d.ts +24 -0
- package/dist/secrets.d.ts.map +1 -0
- package/dist/secrets.js +45 -0
- package/dist/secrets.js.map +1 -0
- package/dist/storage.d.ts +33 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/storage.js +112 -0
- package/dist/storage.js.map +1 -0
- package/package.json +53 -0
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Anomaly detection heuristics (no LLM).
|
|
3
|
+
*
|
|
4
|
+
* Operates on a stream of `SessionEvent`s and emits `Anomaly` records
|
|
5
|
+
* flagging sessions that exhibit known costly or stuck patterns:
|
|
6
|
+
* - runaway_compactions : auto-compaction triggered N+ times in one session.
|
|
7
|
+
* - high_error_rate : tool error rate > threshold (min 10 calls).
|
|
8
|
+
* - prompt_retry_loop : same user prompt textHash repeated N+ times.
|
|
9
|
+
* - tool_loop : same tool name called N+ times consecutively.
|
|
10
|
+
* - zombie_session : > N minutes between consecutive turns.
|
|
11
|
+
*
|
|
12
|
+
* Frustration via user-prompt content is intentionally out of scope for
|
|
13
|
+
* WP5; the parser stores only prompt hashes (privacy). That heuristic
|
|
14
|
+
* is deferred to WP7 (LLM phase 2).
|
|
15
|
+
*/
|
|
16
|
+
function emptyAcc(ev) {
|
|
17
|
+
return {
|
|
18
|
+
sessionId: ev.sessionId,
|
|
19
|
+
tool: ev.tool,
|
|
20
|
+
projectCwd: ev.projectCwd,
|
|
21
|
+
compactions: 0,
|
|
22
|
+
toolCallTotal: 0,
|
|
23
|
+
toolCallErrors: 0,
|
|
24
|
+
promptHashCounts: new Map(),
|
|
25
|
+
lastToolName: '',
|
|
26
|
+
lastToolStreak: 0,
|
|
27
|
+
maxToolStreak: { name: '', count: 0 },
|
|
28
|
+
turnTs: [],
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
function severityFromRatio(ratio) {
|
|
32
|
+
if (ratio >= 3)
|
|
33
|
+
return 'high';
|
|
34
|
+
if (ratio >= 2)
|
|
35
|
+
return 'medium';
|
|
36
|
+
return 'low';
|
|
37
|
+
}
|
|
38
|
+
export async function detectAnomalies(events, opts = {}) {
|
|
39
|
+
const runawayCompactions = opts.runawayCompactions ?? 10;
|
|
40
|
+
const errorRateThreshold = opts.errorRateThreshold ?? 0.3;
|
|
41
|
+
const minToolCallsForErrorRate = opts.minToolCallsForErrorRate ?? 10;
|
|
42
|
+
const promptRetryCount = opts.promptRetryCount ?? 4;
|
|
43
|
+
const toolLoopCount = opts.toolLoopCount ?? 5;
|
|
44
|
+
const zombieGapMinutes = opts.zombieGapMinutes ?? 120;
|
|
45
|
+
const sessions = new Map();
|
|
46
|
+
for await (const ev of events) {
|
|
47
|
+
if (!ev.sessionId)
|
|
48
|
+
continue;
|
|
49
|
+
let s = sessions.get(ev.sessionId);
|
|
50
|
+
if (!s) {
|
|
51
|
+
s = emptyAcc(ev);
|
|
52
|
+
sessions.set(ev.sessionId, s);
|
|
53
|
+
}
|
|
54
|
+
// Update fields shared by all session events
|
|
55
|
+
if (ev.projectCwd)
|
|
56
|
+
s.projectCwd = ev.projectCwd;
|
|
57
|
+
s.tool = ev.tool;
|
|
58
|
+
switch (ev.kind) {
|
|
59
|
+
case 'compaction':
|
|
60
|
+
s.compactions += 1;
|
|
61
|
+
break;
|
|
62
|
+
case 'tool_call': {
|
|
63
|
+
s.toolCallTotal += 1;
|
|
64
|
+
if (ev.error)
|
|
65
|
+
s.toolCallErrors += 1;
|
|
66
|
+
if (ev.name === s.lastToolName) {
|
|
67
|
+
s.lastToolStreak += 1;
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
s.lastToolName = ev.name;
|
|
71
|
+
s.lastToolStreak = 1;
|
|
72
|
+
}
|
|
73
|
+
if (s.lastToolStreak > s.maxToolStreak.count) {
|
|
74
|
+
s.maxToolStreak = { name: ev.name, count: s.lastToolStreak };
|
|
75
|
+
}
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
78
|
+
case 'user_prompt': {
|
|
79
|
+
s.promptHashCounts.set(ev.textHash, (s.promptHashCounts.get(ev.textHash) ?? 0) + 1);
|
|
80
|
+
// user prompts also break tool streaks
|
|
81
|
+
s.lastToolName = '';
|
|
82
|
+
s.lastToolStreak = 0;
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
case 'turn': {
|
|
86
|
+
if (ev.ts)
|
|
87
|
+
s.turnTs.push(ev.ts);
|
|
88
|
+
// turns also break tool streaks (different assistant action)
|
|
89
|
+
s.lastToolName = '';
|
|
90
|
+
s.lastToolStreak = 0;
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
case 'session_start':
|
|
94
|
+
case 'session_end':
|
|
95
|
+
case 'skill_invoke':
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
const anomalies = [];
|
|
100
|
+
for (const s of sessions.values()) {
|
|
101
|
+
if (s.compactions >= runawayCompactions) {
|
|
102
|
+
anomalies.push({
|
|
103
|
+
sessionId: s.sessionId,
|
|
104
|
+
tool: s.tool,
|
|
105
|
+
projectCwd: s.projectCwd,
|
|
106
|
+
type: 'runaway_compactions',
|
|
107
|
+
severity: severityFromRatio(s.compactions / runawayCompactions),
|
|
108
|
+
evidence: { compactions: s.compactions, threshold: runawayCompactions },
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
if (s.toolCallTotal >= minToolCallsForErrorRate) {
|
|
112
|
+
const rate = s.toolCallErrors / s.toolCallTotal;
|
|
113
|
+
if (rate >= errorRateThreshold) {
|
|
114
|
+
anomalies.push({
|
|
115
|
+
sessionId: s.sessionId,
|
|
116
|
+
tool: s.tool,
|
|
117
|
+
projectCwd: s.projectCwd,
|
|
118
|
+
type: 'high_error_rate',
|
|
119
|
+
severity: severityFromRatio(rate / errorRateThreshold),
|
|
120
|
+
evidence: {
|
|
121
|
+
errors: s.toolCallErrors,
|
|
122
|
+
total: s.toolCallTotal,
|
|
123
|
+
rate: Number(rate.toFixed(3)),
|
|
124
|
+
threshold: errorRateThreshold,
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
let topHash = '';
|
|
130
|
+
let topHashCount = 0;
|
|
131
|
+
for (const [h, n] of s.promptHashCounts) {
|
|
132
|
+
if (n > topHashCount) {
|
|
133
|
+
topHashCount = n;
|
|
134
|
+
topHash = h;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
if (topHashCount >= promptRetryCount) {
|
|
138
|
+
anomalies.push({
|
|
139
|
+
sessionId: s.sessionId,
|
|
140
|
+
tool: s.tool,
|
|
141
|
+
projectCwd: s.projectCwd,
|
|
142
|
+
type: 'prompt_retry_loop',
|
|
143
|
+
severity: severityFromRatio(topHashCount / promptRetryCount),
|
|
144
|
+
evidence: { textHash: topHash, count: topHashCount, threshold: promptRetryCount },
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
if (s.maxToolStreak.count >= toolLoopCount) {
|
|
148
|
+
anomalies.push({
|
|
149
|
+
sessionId: s.sessionId,
|
|
150
|
+
tool: s.tool,
|
|
151
|
+
projectCwd: s.projectCwd,
|
|
152
|
+
type: 'tool_loop',
|
|
153
|
+
severity: severityFromRatio(s.maxToolStreak.count / toolLoopCount),
|
|
154
|
+
evidence: {
|
|
155
|
+
tool: s.maxToolStreak.name,
|
|
156
|
+
consecutive: s.maxToolStreak.count,
|
|
157
|
+
threshold: toolLoopCount,
|
|
158
|
+
},
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
// zombie gap
|
|
162
|
+
let maxGapMin = 0;
|
|
163
|
+
for (let i = 1; i < s.turnTs.length; i++) {
|
|
164
|
+
const a = Date.parse(s.turnTs[i - 1]);
|
|
165
|
+
const b = Date.parse(s.turnTs[i]);
|
|
166
|
+
if (!Number.isNaN(a) && !Number.isNaN(b)) {
|
|
167
|
+
const gap = (b - a) / 60_000;
|
|
168
|
+
if (gap > maxGapMin)
|
|
169
|
+
maxGapMin = gap;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
if (maxGapMin >= zombieGapMinutes) {
|
|
173
|
+
anomalies.push({
|
|
174
|
+
sessionId: s.sessionId,
|
|
175
|
+
tool: s.tool,
|
|
176
|
+
projectCwd: s.projectCwd,
|
|
177
|
+
type: 'zombie_session',
|
|
178
|
+
severity: severityFromRatio(maxGapMin / zombieGapMinutes),
|
|
179
|
+
evidence: {
|
|
180
|
+
maxGapMinutes: Math.round(maxGapMin),
|
|
181
|
+
threshold: zombieGapMinutes,
|
|
182
|
+
},
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return anomalies;
|
|
187
|
+
}
|
|
188
|
+
//# sourceMappingURL=anomalies.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anomalies.js","sourceRoot":"","sources":["../src/anomalies.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cleanser: redact secrets (and optionally compact verbose tool outputs)
|
|
3
|
+
* from agent-stats session jsonl files.
|
|
4
|
+
*
|
|
5
|
+
* Modes:
|
|
6
|
+
* - `archive` : write a redacted copy into an output dir.
|
|
7
|
+
* - `inplace` : rewrite the file in place after saving a `.bak`.
|
|
8
|
+
* - `llm-input` : same as `archive` plus truncate tool-result strings
|
|
9
|
+
* longer than `maxToolResultBytes`.
|
|
10
|
+
*
|
|
11
|
+
* Replacement marker is `<<SECRET:<ruleId>:<hash>>>` where `<hash>` is the
|
|
12
|
+
* first 16 hex chars of sha256(secret); identical secrets keep the same
|
|
13
|
+
* tag across files, which is handy for dedup analysis.
|
|
14
|
+
*/
|
|
15
|
+
export type CleanMode = 'archive' | 'inplace' | 'llm-input';
|
|
16
|
+
export interface CleanFileOptions {
|
|
17
|
+
/** Absolute path of the source jsonl. */
|
|
18
|
+
filePath: string;
|
|
19
|
+
/** Output mode. */
|
|
20
|
+
mode?: CleanMode;
|
|
21
|
+
/**
|
|
22
|
+
* Output file path; required for `archive` and `llm-input` modes.
|
|
23
|
+
* Ignored for `inplace`.
|
|
24
|
+
*/
|
|
25
|
+
outputPath?: string;
|
|
26
|
+
/**
|
|
27
|
+
* For `llm-input`: truncate any string longer than this many bytes.
|
|
28
|
+
* Default 2048.
|
|
29
|
+
*/
|
|
30
|
+
maxToolResultBytes?: number;
|
|
31
|
+
/**
|
|
32
|
+
* For tests: skip the secret scan and only handle truncation.
|
|
33
|
+
* Default false.
|
|
34
|
+
*/
|
|
35
|
+
skipSecrets?: boolean;
|
|
36
|
+
}
|
|
37
|
+
export interface CleanStats {
|
|
38
|
+
filePath: string;
|
|
39
|
+
outputPath: string;
|
|
40
|
+
/** Number of secret matches found and redacted. */
|
|
41
|
+
secretsFound: number;
|
|
42
|
+
/** Number of strings truncated (llm-input mode). */
|
|
43
|
+
truncations: number;
|
|
44
|
+
/** Number of lines processed. */
|
|
45
|
+
lines: number;
|
|
46
|
+
/** Source byte size. */
|
|
47
|
+
bytesIn: number;
|
|
48
|
+
/** Output byte size. */
|
|
49
|
+
bytesOut: number;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Clean a single jsonl file. Writes the redacted version according to the
|
|
53
|
+
* requested mode and returns aggregate stats.
|
|
54
|
+
*/
|
|
55
|
+
export declare function cleanFile(opts: CleanFileOptions): Promise<CleanStats>;
|
|
56
|
+
//# sourceMappingURL=cleanser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cleanser.d.ts","sourceRoot":"","sources":["../src/cleanser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAQH,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,WAAW,CAAC;AAE5D,MAAM,WAAW,gBAAgB;IAC/B,yCAAyC;IACzC,QAAQ,EAAE,MAAM,CAAC;IACjB,mBAAmB;IACnB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,mDAAmD;IACnD,YAAY,EAAE,MAAM,CAAC;IACrB,oDAAoD;IACpD,WAAW,EAAE,MAAM,CAAC;IACpB,iCAAiC;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,wBAAwB;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,wBAAwB;IACxB,QAAQ,EAAE,MAAM,CAAC;CAClB;AA4DD;;;GAGG;AACH,wBAAsB,SAAS,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,UAAU,CAAC,CA4D3E"}
|
package/dist/cleanser.js
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cleanser: redact secrets (and optionally compact verbose tool outputs)
|
|
3
|
+
* from agent-stats session jsonl files.
|
|
4
|
+
*
|
|
5
|
+
* Modes:
|
|
6
|
+
* - `archive` : write a redacted copy into an output dir.
|
|
7
|
+
* - `inplace` : rewrite the file in place after saving a `.bak`.
|
|
8
|
+
* - `llm-input` : same as `archive` plus truncate tool-result strings
|
|
9
|
+
* longer than `maxToolResultBytes`.
|
|
10
|
+
*
|
|
11
|
+
* Replacement marker is `<<SECRET:<ruleId>:<hash>>>` where `<hash>` is the
|
|
12
|
+
* first 16 hex chars of sha256(secret); identical secrets keep the same
|
|
13
|
+
* tag across files, which is handy for dedup analysis.
|
|
14
|
+
*/
|
|
15
|
+
import { createHash } from 'node:crypto';
|
|
16
|
+
import { copyFile, mkdir, readFile, rename, writeFile } from 'node:fs/promises';
|
|
17
|
+
import path from 'node:path';
|
|
18
|
+
import { scanString } from './secrets.js';
|
|
19
|
+
const sha256short = (text) => createHash('sha256').update(text).digest('hex').slice(0, 16);
|
|
20
|
+
function redact(text, matches) {
|
|
21
|
+
if (matches.length === 0)
|
|
22
|
+
return text;
|
|
23
|
+
const sorted = [...matches].sort((a, b) => b.start - a.start);
|
|
24
|
+
let out = text;
|
|
25
|
+
for (const m of sorted) {
|
|
26
|
+
const secret = out.slice(m.start, m.end);
|
|
27
|
+
const safeRule = m.ruleId.replace(/[^a-zA-Z0-9_-]/g, '_');
|
|
28
|
+
const tag = `<<SECRET:${safeRule}:${sha256short(secret)}>>`;
|
|
29
|
+
out = out.slice(0, m.start) + tag + out.slice(m.end);
|
|
30
|
+
}
|
|
31
|
+
return out;
|
|
32
|
+
}
|
|
33
|
+
async function cleanString(s, ctx) {
|
|
34
|
+
let out = s;
|
|
35
|
+
if (ctx.scanSecrets && s.length >= 8) {
|
|
36
|
+
const matches = await scanString(s);
|
|
37
|
+
if (matches.length > 0) {
|
|
38
|
+
ctx.secretsFound += matches.length;
|
|
39
|
+
out = redact(s, matches);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (ctx.truncate && Buffer.byteLength(out, 'utf8') > ctx.maxToolResultBytes) {
|
|
43
|
+
ctx.truncations += 1;
|
|
44
|
+
const kept = Buffer.from(out, 'utf8').subarray(0, ctx.maxToolResultBytes).toString('utf8');
|
|
45
|
+
const dropped = Buffer.byteLength(out, 'utf8') - Buffer.byteLength(kept, 'utf8');
|
|
46
|
+
out = `${kept}…[${dropped} bytes truncated by agent-stats clean]`;
|
|
47
|
+
}
|
|
48
|
+
return out;
|
|
49
|
+
}
|
|
50
|
+
async function cleanJson(val, ctx) {
|
|
51
|
+
if (typeof val === 'string')
|
|
52
|
+
return cleanString(val, ctx);
|
|
53
|
+
if (Array.isArray(val)) {
|
|
54
|
+
const out = [];
|
|
55
|
+
for (const item of val)
|
|
56
|
+
out.push(await cleanJson(item, ctx));
|
|
57
|
+
return out;
|
|
58
|
+
}
|
|
59
|
+
if (val !== null && typeof val === 'object') {
|
|
60
|
+
const obj = val;
|
|
61
|
+
const out = {};
|
|
62
|
+
for (const [k, v] of Object.entries(obj))
|
|
63
|
+
out[k] = await cleanJson(v, ctx);
|
|
64
|
+
return out;
|
|
65
|
+
}
|
|
66
|
+
return val;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Clean a single jsonl file. Writes the redacted version according to the
|
|
70
|
+
* requested mode and returns aggregate stats.
|
|
71
|
+
*/
|
|
72
|
+
export async function cleanFile(opts) {
|
|
73
|
+
const mode = opts.mode ?? 'archive';
|
|
74
|
+
const src = await readFile(opts.filePath, 'utf8');
|
|
75
|
+
const ctx = {
|
|
76
|
+
secretsFound: 0,
|
|
77
|
+
truncations: 0,
|
|
78
|
+
maxToolResultBytes: opts.maxToolResultBytes ?? 2048,
|
|
79
|
+
truncate: mode === 'llm-input',
|
|
80
|
+
scanSecrets: !opts.skipSecrets,
|
|
81
|
+
};
|
|
82
|
+
const lines = src.split('\n');
|
|
83
|
+
const outLines = [];
|
|
84
|
+
let processed = 0;
|
|
85
|
+
for (const line of lines) {
|
|
86
|
+
if (!line.trim()) {
|
|
87
|
+
outLines.push(line);
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
let parsed;
|
|
91
|
+
try {
|
|
92
|
+
parsed = JSON.parse(line);
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
// Not JSON: scan as raw text (defensive — still redact).
|
|
96
|
+
outLines.push(await cleanString(line, ctx));
|
|
97
|
+
processed += 1;
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
const redacted = await cleanJson(parsed, ctx);
|
|
101
|
+
outLines.push(JSON.stringify(redacted));
|
|
102
|
+
processed += 1;
|
|
103
|
+
}
|
|
104
|
+
const cleaned = outLines.join('\n');
|
|
105
|
+
let outputPath;
|
|
106
|
+
if (mode === 'inplace') {
|
|
107
|
+
outputPath = opts.filePath;
|
|
108
|
+
const bak = `${opts.filePath}.bak`;
|
|
109
|
+
await copyFile(opts.filePath, bak);
|
|
110
|
+
const tmp = `${opts.filePath}.tmp-${process.pid}`;
|
|
111
|
+
await writeFile(tmp, cleaned);
|
|
112
|
+
await rename(tmp, opts.filePath);
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
if (!opts.outputPath) {
|
|
116
|
+
throw new Error(`cleanFile: --output is required for mode "${mode}"`);
|
|
117
|
+
}
|
|
118
|
+
outputPath = opts.outputPath;
|
|
119
|
+
await mkdir(path.dirname(outputPath), { recursive: true });
|
|
120
|
+
await writeFile(outputPath, cleaned);
|
|
121
|
+
}
|
|
122
|
+
return {
|
|
123
|
+
filePath: opts.filePath,
|
|
124
|
+
outputPath,
|
|
125
|
+
secretsFound: ctx.secretsFound,
|
|
126
|
+
truncations: ctx.truncations,
|
|
127
|
+
lines: processed,
|
|
128
|
+
bytesIn: Buffer.byteLength(src, 'utf8'),
|
|
129
|
+
bytesOut: Buffer.byteLength(cleaned, 'utf8'),
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=cleanser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cleanser.js","sourceRoot":"","sources":["../src/cleanser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `collect()` is the public entry point that merges the Claude Code and
|
|
3
|
+
* Codex CLI parsers into a single async iterator of normalized events,
|
|
4
|
+
* filtered by tool / project / time window.
|
|
5
|
+
*
|
|
6
|
+
* Discovery rules:
|
|
7
|
+
* - Claude sessions: scan `~/.claude/projects/<cwd-encoded>/<sessionId>.jsonl`.
|
|
8
|
+
* The directory name encodes the cwd by replacing `/` with `-` and
|
|
9
|
+
* prepending a leading dash (e.g. `/home/u/src/demo` ↔
|
|
10
|
+
* `-home-u-src-demo`). The project filter is applied on the decoded cwd.
|
|
11
|
+
* - Codex sessions: query `~/.codex/state_5.sqlite` via `indexCodexSessions`,
|
|
12
|
+
* then stream each matching rollout.
|
|
13
|
+
*
|
|
14
|
+
* Time filtering is applied at the file level when possible (mtime / DB
|
|
15
|
+
* created_at), then enforced per-event using the event `ts`.
|
|
16
|
+
*/
|
|
17
|
+
import type { SessionEvent } from './schema.js';
|
|
18
|
+
export interface CollectOptions {
|
|
19
|
+
sources?: {
|
|
20
|
+
claude?: boolean;
|
|
21
|
+
codex?: boolean;
|
|
22
|
+
};
|
|
23
|
+
since?: Date;
|
|
24
|
+
until?: Date;
|
|
25
|
+
/**
|
|
26
|
+
* Exact cwd OR cwd prefix when ending with `/`. Applied to BOTH Claude
|
|
27
|
+
* and Codex sources.
|
|
28
|
+
*/
|
|
29
|
+
projectCwd?: string;
|
|
30
|
+
/** Override path for ~/.claude/projects/ */
|
|
31
|
+
claudeProjectsDir?: string;
|
|
32
|
+
/** Override path for the Codex sqlite index. */
|
|
33
|
+
codexDbPath?: string;
|
|
34
|
+
}
|
|
35
|
+
/** Decode a Claude project dir name back to its absolute cwd. */
|
|
36
|
+
export declare function decodeClaudeProjectDir(name: string): string;
|
|
37
|
+
/**
|
|
38
|
+
* Yield events from one or both sources, optionally filtered by project /
|
|
39
|
+
* time window. The order across sources is NOT guaranteed; callers that
|
|
40
|
+
* need a global timeline should sort by `ts` after collecting.
|
|
41
|
+
*/
|
|
42
|
+
export declare function collect(opts?: CollectOptions): AsyncGenerator<SessionEvent, void, unknown>;
|
|
43
|
+
//# sourceMappingURL=collect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collect.d.ts","sourceRoot":"","sources":["../src/collect.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAKH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAIhD,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IAChD,KAAK,CAAC,EAAE,IAAI,CAAC;IACb,KAAK,CAAC,EAAE,IAAI,CAAC;IACb;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4CAA4C;IAC5C,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,gDAAgD;IAChD,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAID,iEAAiE;AACjE,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAG3D;AAoFD;;;;GAIG;AACH,wBAAuB,OAAO,CAC5B,IAAI,GAAE,cAAmB,GACxB,cAAc,CAAC,YAAY,EAAE,IAAI,EAAE,OAAO,CAAC,CAQ7C"}
|
package/dist/collect.js
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `collect()` is the public entry point that merges the Claude Code and
|
|
3
|
+
* Codex CLI parsers into a single async iterator of normalized events,
|
|
4
|
+
* filtered by tool / project / time window.
|
|
5
|
+
*
|
|
6
|
+
* Discovery rules:
|
|
7
|
+
* - Claude sessions: scan `~/.claude/projects/<cwd-encoded>/<sessionId>.jsonl`.
|
|
8
|
+
* The directory name encodes the cwd by replacing `/` with `-` and
|
|
9
|
+
* prepending a leading dash (e.g. `/home/u/src/demo` ↔
|
|
10
|
+
* `-home-u-src-demo`). The project filter is applied on the decoded cwd.
|
|
11
|
+
* - Codex sessions: query `~/.codex/state_5.sqlite` via `indexCodexSessions`,
|
|
12
|
+
* then stream each matching rollout.
|
|
13
|
+
*
|
|
14
|
+
* Time filtering is applied at the file level when possible (mtime / DB
|
|
15
|
+
* created_at), then enforced per-event using the event `ts`.
|
|
16
|
+
*/
|
|
17
|
+
import { promises as fs } from 'node:fs';
|
|
18
|
+
import path from 'node:path';
|
|
19
|
+
import { parseClaudeSession } from './parsers/claude.js';
|
|
20
|
+
import { indexCodexSessions, parseCodexRollout } from './parsers/codex.js';
|
|
21
|
+
const DEFAULT_HOME = () => process.env['HOME'] ?? '';
|
|
22
|
+
/** Decode a Claude project dir name back to its absolute cwd. */
|
|
23
|
+
export function decodeClaudeProjectDir(name) {
|
|
24
|
+
// `-home-u-src-demo` → `/home/u/src/demo`
|
|
25
|
+
return name.startsWith('-') ? name.replace(/-/g, '/') : name;
|
|
26
|
+
}
|
|
27
|
+
function matchesProjectCwd(cwd, filter) {
|
|
28
|
+
if (!filter)
|
|
29
|
+
return true;
|
|
30
|
+
if (filter.endsWith('/'))
|
|
31
|
+
return cwd.startsWith(filter);
|
|
32
|
+
return cwd === filter;
|
|
33
|
+
}
|
|
34
|
+
function eventInWindow(ev, since, until) {
|
|
35
|
+
const t = Date.parse(ev.ts);
|
|
36
|
+
if (Number.isNaN(t))
|
|
37
|
+
return true; // keep events without ts
|
|
38
|
+
if (since && t < since.getTime())
|
|
39
|
+
return false;
|
|
40
|
+
if (until && t > until.getTime())
|
|
41
|
+
return false;
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
async function* collectClaude(opts) {
|
|
45
|
+
const projectsDir = opts.claudeProjectsDir ?? path.join(DEFAULT_HOME(), '.claude', 'projects');
|
|
46
|
+
let entries;
|
|
47
|
+
try {
|
|
48
|
+
entries = await fs.readdir(projectsDir, { withFileTypes: true });
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
for (const entry of entries) {
|
|
54
|
+
if (!entry.isDirectory())
|
|
55
|
+
continue;
|
|
56
|
+
const decoded = decodeClaudeProjectDir(entry.name);
|
|
57
|
+
if (!matchesProjectCwd(decoded, opts.projectCwd))
|
|
58
|
+
continue;
|
|
59
|
+
const dir = path.join(projectsDir, entry.name);
|
|
60
|
+
let files;
|
|
61
|
+
try {
|
|
62
|
+
files = await fs.readdir(dir);
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
for (const f of files) {
|
|
68
|
+
if (!f.endsWith('.jsonl'))
|
|
69
|
+
continue;
|
|
70
|
+
const filePath = path.join(dir, f);
|
|
71
|
+
let stat;
|
|
72
|
+
try {
|
|
73
|
+
stat = await fs.stat(filePath);
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
if (opts.since && stat.mtime < opts.since)
|
|
79
|
+
continue;
|
|
80
|
+
// upper bound on mtime is permissive (a file might still be open).
|
|
81
|
+
for await (const ev of parseClaudeSession({ filePath })) {
|
|
82
|
+
if (!eventInWindow(ev, opts.since, opts.until))
|
|
83
|
+
continue;
|
|
84
|
+
yield ev;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
async function* collectCodex(opts) {
|
|
90
|
+
const indexOpts = {};
|
|
91
|
+
if (opts.codexDbPath !== undefined)
|
|
92
|
+
indexOpts.dbPath = opts.codexDbPath;
|
|
93
|
+
if (opts.since !== undefined)
|
|
94
|
+
indexOpts.since = opts.since;
|
|
95
|
+
if (opts.until !== undefined)
|
|
96
|
+
indexOpts.until = opts.until;
|
|
97
|
+
if (opts.projectCwd !== undefined)
|
|
98
|
+
indexOpts.projectCwd = opts.projectCwd;
|
|
99
|
+
let entries;
|
|
100
|
+
try {
|
|
101
|
+
entries = indexCodexSessions(indexOpts);
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
for (const e of entries) {
|
|
107
|
+
if (!matchesProjectCwd(e.cwd, opts.projectCwd))
|
|
108
|
+
continue;
|
|
109
|
+
try {
|
|
110
|
+
await fs.access(e.rolloutPath);
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
for await (const ev of parseCodexRollout({
|
|
116
|
+
filePath: e.rolloutPath,
|
|
117
|
+
sessionId: e.id,
|
|
118
|
+
projectCwd: e.cwd,
|
|
119
|
+
})) {
|
|
120
|
+
if (!eventInWindow(ev, opts.since, opts.until))
|
|
121
|
+
continue;
|
|
122
|
+
yield ev;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Yield events from one or both sources, optionally filtered by project /
|
|
128
|
+
* time window. The order across sources is NOT guaranteed; callers that
|
|
129
|
+
* need a global timeline should sort by `ts` after collecting.
|
|
130
|
+
*/
|
|
131
|
+
export async function* collect(opts = {}) {
|
|
132
|
+
const sources = { claude: true, codex: true, ...(opts.sources ?? {}) };
|
|
133
|
+
if (sources.claude) {
|
|
134
|
+
yield* collectClaude(opts);
|
|
135
|
+
}
|
|
136
|
+
if (sources.codex) {
|
|
137
|
+
yield* collectCodex(opts);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=collect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collect.js","sourceRoot":"","sources":["../src/collect.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @sentropic/agent-stats-core
|
|
3
|
+
*
|
|
4
|
+
* Public surface: schema types and parsers.
|
|
5
|
+
*/
|
|
6
|
+
export declare const VERSION = "0.1.0";
|
|
7
|
+
export * from './schema.js';
|
|
8
|
+
export { parseClaudeSession } from './parsers/claude.js';
|
|
9
|
+
export { indexCodexSessions, parseCodexRollout, type CodexIndexEntry, type IndexCodexOptions, type ParseCodexRolloutOptions, } from './parsers/codex.js';
|
|
10
|
+
export { collect, decodeClaudeProjectDir, type CollectOptions } from './collect.js';
|
|
11
|
+
export { aggregateSessions, aggregateWeekly, bucketWeekly, cacheEfficiency, weekStartIso, type AggregateOptions, type SessionAggregate, type WeeklyAggregation, } from './aggregations.js';
|
|
12
|
+
export { DEFAULT_RATE_CARD, ZERO_RATES, estimateCost, resolveRates, type CostCurrency, type ModelRates, } from './rate-card.js';
|
|
13
|
+
export { JsonStorage, type JsonStorageOptions, type StorageAdapter, type StorageFilter, } from './storage.js';
|
|
14
|
+
export { scanString, type SecretMatch } from './secrets.js';
|
|
15
|
+
export { cleanFile, type CleanFileOptions, type CleanMode, type CleanStats } from './cleanser.js';
|
|
16
|
+
export { detectAnomalies, type Anomaly, type AnomalySeverity, type AnomalyType, type DetectAnomaliesOptions, } from './anomalies.js';
|
|
17
|
+
export { analyzeWithLlm, benchModels, type AnalysisVerdict, type AnalyzeCache, type AnalyzeOptions, type BenchModelConfig, type BenchModelResult, type BenchOptions, type BenchSampleBaseline, type LlmMeshLike, } from './analyze.js';
|
|
18
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,eAAO,MAAM,OAAO,UAAU,CAAC;AAE/B,cAAc,aAAa,CAAC;AAC5B,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,KAAK,eAAe,EACpB,KAAK,iBAAiB,EACtB,KAAK,wBAAwB,GAC9B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,OAAO,EAAE,sBAAsB,EAAE,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AACpF,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,YAAY,EACZ,eAAe,EACf,YAAY,EACZ,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,GACvB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,iBAAiB,EACjB,UAAU,EACV,YAAY,EACZ,YAAY,EACZ,KAAK,YAAY,EACjB,KAAK,UAAU,GAChB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,WAAW,EACX,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,KAAK,aAAa,GACnB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,UAAU,EAAE,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,KAAK,gBAAgB,EAAE,KAAK,SAAS,EAAE,KAAK,UAAU,EAAE,MAAM,eAAe,CAAC;AAClG,OAAO,EACL,eAAe,EACf,KAAK,OAAO,EACZ,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,KAAK,sBAAsB,GAC5B,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,cAAc,EACd,WAAW,EACX,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,YAAY,EACjB,KAAK,mBAAmB,EACxB,KAAK,WAAW,GACjB,MAAM,cAAc,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @sentropic/agent-stats-core
|
|
3
|
+
*
|
|
4
|
+
* Public surface: schema types and parsers.
|
|
5
|
+
*/
|
|
6
|
+
export const VERSION = '0.1.0';
|
|
7
|
+
export * from './schema.js';
|
|
8
|
+
export { parseClaudeSession } from './parsers/claude.js';
|
|
9
|
+
export { indexCodexSessions, parseCodexRollout, } from './parsers/codex.js';
|
|
10
|
+
export { collect, decodeClaudeProjectDir } from './collect.js';
|
|
11
|
+
export { aggregateSessions, aggregateWeekly, bucketWeekly, cacheEfficiency, weekStartIso, } from './aggregations.js';
|
|
12
|
+
export { DEFAULT_RATE_CARD, ZERO_RATES, estimateCost, resolveRates, } from './rate-card.js';
|
|
13
|
+
export { JsonStorage, } from './storage.js';
|
|
14
|
+
export { scanString } from './secrets.js';
|
|
15
|
+
export { cleanFile } from './cleanser.js';
|
|
16
|
+
export { detectAnomalies, } from './anomalies.js';
|
|
17
|
+
export { analyzeWithLlm, benchModels, } from './analyze.js';
|
|
18
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAC;AAE/B,cAAc,aAAa,CAAC;AAC5B,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EACL,kBAAkB,EAClB,iBAAiB,GAIlB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,OAAO,EAAE,sBAAsB,EAAuB,MAAM,cAAc,CAAC;AACpF,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,YAAY,EACZ,eAAe,EACf,YAAY,GAIb,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,iBAAiB,EACjB,UAAU,EACV,YAAY,EACZ,YAAY,GAGb,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,WAAW,GAIZ,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,UAAU,EAAoB,MAAM,cAAc,CAAC;AAC5D,OAAO,EAAE,SAAS,EAA0D,MAAM,eAAe,CAAC;AAClG,OAAO,EACL,eAAe,GAKhB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,cAAc,EACd,WAAW,GASZ,MAAM,cAAc,CAAC"}
|