@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,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rate cards used to estimate the credits / cost burnt by each turn.
|
|
3
|
+
*
|
|
4
|
+
* Two distinct currencies coexist:
|
|
5
|
+
* - **Codex credits**: published in OpenAI's Codex rate card (credits /
|
|
6
|
+
* 1M tokens). The Pro weekly bucket sums these.
|
|
7
|
+
* - **Claude USD cents**: Anthropic's public API list price, expressed as
|
|
8
|
+
* `100 × $` per 1M tokens, so a $1.25 input rate becomes 125.
|
|
9
|
+
*
|
|
10
|
+
* Mixing the two in the same aggregate makes no sense; the aggregator splits
|
|
11
|
+
* them into separate sub-totals (`codexCredits` vs `claudeUsdCents`).
|
|
12
|
+
*
|
|
13
|
+
* Sources (May 2026):
|
|
14
|
+
* - Codex rate card (developers.openai.com/codex/pricing,
|
|
15
|
+
* help.openai.com codex-rate-card)
|
|
16
|
+
* - Anthropic pricing page
|
|
17
|
+
* - Cross-referenced with the project memory
|
|
18
|
+
* `reference_codex-quota-equation`
|
|
19
|
+
*
|
|
20
|
+
* All numbers may drift; update from the source when OpenAI / Anthropic
|
|
21
|
+
* change their public pricing.
|
|
22
|
+
*/
|
|
23
|
+
export const ZERO_RATES = {
|
|
24
|
+
newInputPerMillion: 0,
|
|
25
|
+
cachedPerMillion: 0,
|
|
26
|
+
cacheWritePerMillion: 0,
|
|
27
|
+
outputPerMillion: 0,
|
|
28
|
+
currency: 'unknown',
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Default rate card. Keys MUST match the model id reported by the parser
|
|
32
|
+
* (Codex `model_provider` value, Claude `message.model` value). Aliases /
|
|
33
|
+
* fallbacks are resolved by `resolveRates`.
|
|
34
|
+
*/
|
|
35
|
+
export const DEFAULT_RATE_CARD = {
|
|
36
|
+
// ----- Codex / OpenAI (credits per 1M tokens) -----
|
|
37
|
+
'gpt-5.5': {
|
|
38
|
+
newInputPerMillion: 125,
|
|
39
|
+
cachedPerMillion: 12.5,
|
|
40
|
+
cacheWritePerMillion: 0,
|
|
41
|
+
outputPerMillion: 750,
|
|
42
|
+
currency: 'codex_credits',
|
|
43
|
+
},
|
|
44
|
+
'gpt-5.4': {
|
|
45
|
+
newInputPerMillion: 62.5,
|
|
46
|
+
cachedPerMillion: 6.25,
|
|
47
|
+
cacheWritePerMillion: 0,
|
|
48
|
+
outputPerMillion: 375,
|
|
49
|
+
currency: 'codex_credits',
|
|
50
|
+
},
|
|
51
|
+
'gpt-5.4-mini': {
|
|
52
|
+
newInputPerMillion: 18.75,
|
|
53
|
+
cachedPerMillion: 1.875,
|
|
54
|
+
cacheWritePerMillion: 0,
|
|
55
|
+
outputPerMillion: 113,
|
|
56
|
+
currency: 'codex_credits',
|
|
57
|
+
},
|
|
58
|
+
'gpt-5.3-codex': {
|
|
59
|
+
newInputPerMillion: 43.75,
|
|
60
|
+
cachedPerMillion: 4.375,
|
|
61
|
+
cacheWritePerMillion: 0,
|
|
62
|
+
outputPerMillion: 350,
|
|
63
|
+
currency: 'codex_credits',
|
|
64
|
+
},
|
|
65
|
+
'gpt-5.3-codex-spark': {
|
|
66
|
+
// Spark rates are not published; ratio guess based on `gpt-5.4-mini`.
|
|
67
|
+
// Treat with caveat; the aggregator marks this as such via currency.
|
|
68
|
+
newInputPerMillion: 18.75,
|
|
69
|
+
cachedPerMillion: 1.875,
|
|
70
|
+
cacheWritePerMillion: 0,
|
|
71
|
+
outputPerMillion: 113,
|
|
72
|
+
currency: 'codex_credits',
|
|
73
|
+
},
|
|
74
|
+
'codex-auto-review': {
|
|
75
|
+
// Inferred (not published). Treated like mini for the auto-review pass.
|
|
76
|
+
newInputPerMillion: 18.75,
|
|
77
|
+
cachedPerMillion: 1.875,
|
|
78
|
+
cacheWritePerMillion: 0,
|
|
79
|
+
outputPerMillion: 113,
|
|
80
|
+
currency: 'codex_credits',
|
|
81
|
+
},
|
|
82
|
+
// ----- Claude / Anthropic (USD cents per 1M tokens) -----
|
|
83
|
+
'claude-opus-4-7': {
|
|
84
|
+
newInputPerMillion: 1500, // $15
|
|
85
|
+
cachedPerMillion: 150, // $1.50 (cache_read 10%)
|
|
86
|
+
cacheWritePerMillion: 1875, // $18.75 (cache_creation 1.25×)
|
|
87
|
+
outputPerMillion: 7500, // $75
|
|
88
|
+
currency: 'claude_usd_cents',
|
|
89
|
+
},
|
|
90
|
+
'claude-sonnet-4-6': {
|
|
91
|
+
newInputPerMillion: 300,
|
|
92
|
+
cachedPerMillion: 30,
|
|
93
|
+
cacheWritePerMillion: 375,
|
|
94
|
+
outputPerMillion: 1500,
|
|
95
|
+
currency: 'claude_usd_cents',
|
|
96
|
+
},
|
|
97
|
+
'claude-haiku-4-5-20251001': {
|
|
98
|
+
newInputPerMillion: 100,
|
|
99
|
+
cachedPerMillion: 10,
|
|
100
|
+
cacheWritePerMillion: 125,
|
|
101
|
+
outputPerMillion: 500,
|
|
102
|
+
currency: 'claude_usd_cents',
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
/**
|
|
106
|
+
* Resolve the rate-card entry for a model. Returns `ZERO_RATES` when the
|
|
107
|
+
* model is not registered, so callers always get a defined value.
|
|
108
|
+
*/
|
|
109
|
+
export function resolveRates(model, card = DEFAULT_RATE_CARD) {
|
|
110
|
+
if (!model)
|
|
111
|
+
return ZERO_RATES;
|
|
112
|
+
if (card[model])
|
|
113
|
+
return card[model];
|
|
114
|
+
// alias resolution: prefix match (`claude-opus-4-7-thinking` → `claude-opus-4-7`)
|
|
115
|
+
// and `claude-haiku-X` family fallback.
|
|
116
|
+
for (const key of Object.keys(card)) {
|
|
117
|
+
if (model.startsWith(key))
|
|
118
|
+
return card[key];
|
|
119
|
+
}
|
|
120
|
+
// common families
|
|
121
|
+
if (model.startsWith('claude-haiku'))
|
|
122
|
+
return card['claude-haiku-4-5-20251001'];
|
|
123
|
+
if (model.startsWith('claude-sonnet'))
|
|
124
|
+
return card['claude-sonnet-4-6'];
|
|
125
|
+
if (model.startsWith('claude-opus'))
|
|
126
|
+
return card['claude-opus-4-7'];
|
|
127
|
+
return ZERO_RATES;
|
|
128
|
+
}
|
|
129
|
+
/** Compute the cost of a single turn's usage given the model. */
|
|
130
|
+
export function estimateCost(usage, rates) {
|
|
131
|
+
const amount = (usage.newInputTokens * rates.newInputPerMillion +
|
|
132
|
+
usage.cachedInputTokens * rates.cachedPerMillion +
|
|
133
|
+
usage.cacheWriteTokens * rates.cacheWritePerMillion +
|
|
134
|
+
usage.outputTokens * rates.outputPerMillion) /
|
|
135
|
+
1_000_000;
|
|
136
|
+
return { amount, currency: rates.currency };
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=rate-card.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-card.js","sourceRoot":"","sources":["../src/rate-card.ts"],"names":[],"mappings":"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"}
|
package/dist/schema.d.ts
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Common schema for events extracted from agentic CLI sessions
|
|
3
|
+
* (Claude Code, Codex CLI). Parsers produce streams of `SessionEvent`s;
|
|
4
|
+
* aggregations consume that normalized shape.
|
|
5
|
+
*
|
|
6
|
+
* Design choices:
|
|
7
|
+
* - `Usage` is unified across providers. New/cached/cache-write are split
|
|
8
|
+
* so callers can apply the right rate. Reasoning is a sub-count of
|
|
9
|
+
* output_tokens (consistent with Codex server-side behaviour).
|
|
10
|
+
* - All timestamps are ISO 8601 UTC. Parsers MUST normalize.
|
|
11
|
+
* - `kind` is the discriminant; the union is exhaustive (use `assertNever`).
|
|
12
|
+
*/
|
|
13
|
+
export type Tool = 'claude' | 'codex';
|
|
14
|
+
/**
|
|
15
|
+
* Token usage breakdown for a single turn.
|
|
16
|
+
* Pricing semantics (typical providers, May 2026):
|
|
17
|
+
* newInputTokens = full price input
|
|
18
|
+
* cachedInputTokens = read from cache, ~10% of full price
|
|
19
|
+
* cacheWriteTokens = written to cache (Anthropic only), ~125% of full price
|
|
20
|
+
* outputTokens = generated tokens, full output price
|
|
21
|
+
* reasoningTokens = subset of outputTokens, charged at output rate
|
|
22
|
+
*/
|
|
23
|
+
export interface Usage {
|
|
24
|
+
newInputTokens: number;
|
|
25
|
+
cachedInputTokens: number;
|
|
26
|
+
cacheWriteTokens: number;
|
|
27
|
+
outputTokens: number;
|
|
28
|
+
reasoningTokens: number;
|
|
29
|
+
}
|
|
30
|
+
export declare const ZERO_USAGE: Usage;
|
|
31
|
+
export declare function addUsage(a: Usage, b: Usage): Usage;
|
|
32
|
+
/** Total input tokens processed (regardless of pricing). */
|
|
33
|
+
export declare function totalInputTokens(u: Usage): number;
|
|
34
|
+
/** Shared fields on every `SessionEvent`. */
|
|
35
|
+
export interface EventBase {
|
|
36
|
+
ts: string;
|
|
37
|
+
tool: Tool;
|
|
38
|
+
sessionId: string;
|
|
39
|
+
projectCwd: string;
|
|
40
|
+
}
|
|
41
|
+
/** Emitted once at the start of a session. */
|
|
42
|
+
export interface SessionStartEvent extends EventBase {
|
|
43
|
+
kind: 'session_start';
|
|
44
|
+
model?: string;
|
|
45
|
+
/** Codex: parent thread id when this session is a subagent fork. */
|
|
46
|
+
forkedFromId?: string;
|
|
47
|
+
/** Codex: depth in the subagent tree (0 = top-level). */
|
|
48
|
+
subagentDepth?: number;
|
|
49
|
+
/** Codex: nickname auto-assigned to subagents (philosopher names). */
|
|
50
|
+
agentNickname?: string;
|
|
51
|
+
cliVersion?: string;
|
|
52
|
+
/** True if originated from a parent thread (Codex fork or Claude Task). */
|
|
53
|
+
isSubagent: boolean;
|
|
54
|
+
}
|
|
55
|
+
/** Emitted once at the end of a session. */
|
|
56
|
+
export interface SessionEndEvent extends EventBase {
|
|
57
|
+
kind: 'session_end';
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* An assistant turn that produced token usage.
|
|
61
|
+
* Emitted once per assistant API response.
|
|
62
|
+
*/
|
|
63
|
+
export interface TurnEvent extends EventBase {
|
|
64
|
+
kind: 'turn';
|
|
65
|
+
model: string;
|
|
66
|
+
usage: Usage;
|
|
67
|
+
/** Codex `total_token_usage` if present (running total at this point). */
|
|
68
|
+
cumulative?: Usage;
|
|
69
|
+
/** Codex rate-limit reading at this turn (general window). */
|
|
70
|
+
rateLimit?: {
|
|
71
|
+
primaryPercent: number;
|
|
72
|
+
secondaryPercent: number;
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
/** A user prompt or message. */
|
|
76
|
+
export interface UserPromptEvent extends EventBase {
|
|
77
|
+
kind: 'user_prompt';
|
|
78
|
+
textLength: number;
|
|
79
|
+
/** Short hash for dedup; never the raw text. */
|
|
80
|
+
textHash: string;
|
|
81
|
+
}
|
|
82
|
+
/** A tool invocation (Bash, MCP, native file ops, etc.). */
|
|
83
|
+
export interface ToolCallEvent extends EventBase {
|
|
84
|
+
kind: 'tool_call';
|
|
85
|
+
name: string;
|
|
86
|
+
category: 'bash' | 'mcp' | 'native' | 'function' | 'unknown';
|
|
87
|
+
durationMs?: number;
|
|
88
|
+
inputBytes?: number;
|
|
89
|
+
outputBytes?: number;
|
|
90
|
+
error?: boolean;
|
|
91
|
+
}
|
|
92
|
+
/** A skill (slash-skill) invocation. */
|
|
93
|
+
export interface SkillInvokeEvent extends EventBase {
|
|
94
|
+
kind: 'skill_invoke';
|
|
95
|
+
name: string;
|
|
96
|
+
}
|
|
97
|
+
/** Auto-compaction (context window full). */
|
|
98
|
+
export interface CompactionEvent extends EventBase {
|
|
99
|
+
kind: 'compaction';
|
|
100
|
+
}
|
|
101
|
+
/** Discriminated union of every event type. */
|
|
102
|
+
export type SessionEvent = SessionStartEvent | SessionEndEvent | TurnEvent | UserPromptEvent | ToolCallEvent | SkillInvokeEvent | CompactionEvent;
|
|
103
|
+
/**
|
|
104
|
+
* Aggregated metadata for a session, computed by `collect()` from the
|
|
105
|
+
* stream of events.
|
|
106
|
+
*/
|
|
107
|
+
export interface SessionMeta {
|
|
108
|
+
sessionId: string;
|
|
109
|
+
tool: Tool;
|
|
110
|
+
projectCwd: string;
|
|
111
|
+
model?: string;
|
|
112
|
+
startTs: string;
|
|
113
|
+
endTs: string;
|
|
114
|
+
durationMs: number;
|
|
115
|
+
turns: number;
|
|
116
|
+
totalUsage: Usage;
|
|
117
|
+
isSubagent: boolean;
|
|
118
|
+
forkedFromId?: string;
|
|
119
|
+
agentNickname?: string;
|
|
120
|
+
toolCalls: number;
|
|
121
|
+
compactions: number;
|
|
122
|
+
/** Max rate-limit % seen in the session (Codex). */
|
|
123
|
+
rateLimitMax?: {
|
|
124
|
+
primaryPercent: number;
|
|
125
|
+
secondaryPercent: number;
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
/** Project-level info, derived from cwd. */
|
|
129
|
+
export interface ProjectInfo {
|
|
130
|
+
cwd: string;
|
|
131
|
+
/** Short label derived from cwd basename. */
|
|
132
|
+
name: string;
|
|
133
|
+
/** Sibling repos under the same parent dir (for cross-repo storage). */
|
|
134
|
+
siblings?: Record<string, string>;
|
|
135
|
+
}
|
|
136
|
+
/** Used in switch/case exhaustiveness. */
|
|
137
|
+
export declare function assertNever(x: never): never;
|
|
138
|
+
//# sourceMappingURL=schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"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"}
|
package/dist/schema.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Common schema for events extracted from agentic CLI sessions
|
|
3
|
+
* (Claude Code, Codex CLI). Parsers produce streams of `SessionEvent`s;
|
|
4
|
+
* aggregations consume that normalized shape.
|
|
5
|
+
*
|
|
6
|
+
* Design choices:
|
|
7
|
+
* - `Usage` is unified across providers. New/cached/cache-write are split
|
|
8
|
+
* so callers can apply the right rate. Reasoning is a sub-count of
|
|
9
|
+
* output_tokens (consistent with Codex server-side behaviour).
|
|
10
|
+
* - All timestamps are ISO 8601 UTC. Parsers MUST normalize.
|
|
11
|
+
* - `kind` is the discriminant; the union is exhaustive (use `assertNever`).
|
|
12
|
+
*/
|
|
13
|
+
export const ZERO_USAGE = {
|
|
14
|
+
newInputTokens: 0,
|
|
15
|
+
cachedInputTokens: 0,
|
|
16
|
+
cacheWriteTokens: 0,
|
|
17
|
+
outputTokens: 0,
|
|
18
|
+
reasoningTokens: 0,
|
|
19
|
+
};
|
|
20
|
+
export function addUsage(a, b) {
|
|
21
|
+
return {
|
|
22
|
+
newInputTokens: a.newInputTokens + b.newInputTokens,
|
|
23
|
+
cachedInputTokens: a.cachedInputTokens + b.cachedInputTokens,
|
|
24
|
+
cacheWriteTokens: a.cacheWriteTokens + b.cacheWriteTokens,
|
|
25
|
+
outputTokens: a.outputTokens + b.outputTokens,
|
|
26
|
+
reasoningTokens: a.reasoningTokens + b.reasoningTokens,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/** Total input tokens processed (regardless of pricing). */
|
|
30
|
+
export function totalInputTokens(u) {
|
|
31
|
+
return u.newInputTokens + u.cachedInputTokens + u.cacheWriteTokens;
|
|
32
|
+
}
|
|
33
|
+
/** Used in switch/case exhaustiveness. */
|
|
34
|
+
export function assertNever(x) {
|
|
35
|
+
throw new Error(`unhandled case: ${JSON.stringify(x)}`);
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAqBH,MAAM,CAAC,MAAM,UAAU,GAAU;IAC/B,cAAc,EAAE,CAAC;IACjB,iBAAiB,EAAE,CAAC;IACpB,gBAAgB,EAAE,CAAC;IACnB,YAAY,EAAE,CAAC;IACf,eAAe,EAAE,CAAC;CACnB,CAAC;AAEF,MAAM,UAAU,QAAQ,CAAC,CAAQ,EAAE,CAAQ;IACzC,OAAO;QACL,cAAc,EAAE,CAAC,CAAC,cAAc,GAAG,CAAC,CAAC,cAAc;QACnD,iBAAiB,EAAE,CAAC,CAAC,iBAAiB,GAAG,CAAC,CAAC,iBAAiB;QAC5D,gBAAgB,EAAE,CAAC,CAAC,gBAAgB,GAAG,CAAC,CAAC,gBAAgB;QACzD,YAAY,EAAE,CAAC,CAAC,YAAY,GAAG,CAAC,CAAC,YAAY;QAC7C,eAAe,EAAE,CAAC,CAAC,eAAe,GAAG,CAAC,CAAC,eAAe;KACvD,CAAC;AACJ,CAAC;AAED,4DAA4D;AAC5D,MAAM,UAAU,gBAAgB,CAAC,CAAQ;IACvC,OAAO,CAAC,CAAC,cAAc,GAAG,CAAC,CAAC,iBAAiB,GAAG,CAAC,CAAC,gBAAgB,CAAC;AACrE,CAAC;AA0HD,0CAA0C;AAC1C,MAAM,UAAU,WAAW,CAAC,CAAQ;IAClC,MAAM,IAAI,KAAK,CAAC,mBAAmB,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AAC1D,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thin wrapper over secretlint to scan ad-hoc strings.
|
|
3
|
+
*
|
|
4
|
+
* Uses the preset-recommend bundle as the default rule set. The function
|
|
5
|
+
* returns the list of match ranges so callers can either redact in place
|
|
6
|
+
* (cleanser) or report them (anomalies / audit).
|
|
7
|
+
*/
|
|
8
|
+
export interface SecretMatch {
|
|
9
|
+
/** UTF-16 code unit offset where the secret starts in the source string. */
|
|
10
|
+
start: number;
|
|
11
|
+
/** Exclusive end offset. */
|
|
12
|
+
end: number;
|
|
13
|
+
/** Rule id reporting the match (e.g. `@secretlint/secretlint-rule-aws`). */
|
|
14
|
+
ruleId: string;
|
|
15
|
+
/** Human-readable message. */
|
|
16
|
+
message: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Scan a single string for secrets. Returns an empty array if nothing
|
|
20
|
+
* looks suspicious. Safe to call on small or empty strings — secretlint
|
|
21
|
+
* short-circuits.
|
|
22
|
+
*/
|
|
23
|
+
export declare function scanString(text: string, filePath?: string): Promise<SecretMatch[]>;
|
|
24
|
+
//# sourceMappingURL=secrets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secrets.d.ts","sourceRoot":"","sources":["../src/secrets.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,MAAM,WAAW,WAAW;IAC1B,4EAA4E;IAC5E,KAAK,EAAE,MAAM,CAAC;IACd,4BAA4B;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,4EAA4E;IAC5E,MAAM,EAAE,MAAM,CAAC;IACf,8BAA8B;IAC9B,OAAO,EAAE,MAAM,CAAC;CACjB;AAWD;;;;GAIG;AACH,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,SAAe,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAoB9F"}
|
package/dist/secrets.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thin wrapper over secretlint to scan ad-hoc strings.
|
|
3
|
+
*
|
|
4
|
+
* Uses the preset-recommend bundle as the default rule set. The function
|
|
5
|
+
* returns the list of match ranges so callers can either redact in place
|
|
6
|
+
* (cleanser) or report them (anomalies / audit).
|
|
7
|
+
*/
|
|
8
|
+
import { lintSource } from '@secretlint/core';
|
|
9
|
+
import { creator as presetRecommend } from '@secretlint/secretlint-rule-preset-recommend';
|
|
10
|
+
const DEFAULT_CONFIG = {
|
|
11
|
+
rules: [
|
|
12
|
+
{
|
|
13
|
+
id: '@secretlint/secretlint-rule-preset-recommend',
|
|
14
|
+
rule: presetRecommend,
|
|
15
|
+
},
|
|
16
|
+
],
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Scan a single string for secrets. Returns an empty array if nothing
|
|
20
|
+
* looks suspicious. Safe to call on small or empty strings — secretlint
|
|
21
|
+
* short-circuits.
|
|
22
|
+
*/
|
|
23
|
+
export async function scanString(text, filePath = 'inline.txt') {
|
|
24
|
+
if (!text)
|
|
25
|
+
return [];
|
|
26
|
+
const result = await lintSource({
|
|
27
|
+
source: {
|
|
28
|
+
filePath,
|
|
29
|
+
content: text,
|
|
30
|
+
contentType: 'text',
|
|
31
|
+
},
|
|
32
|
+
options: {
|
|
33
|
+
config: DEFAULT_CONFIG,
|
|
34
|
+
maskSecrets: false,
|
|
35
|
+
noPhysicFilePath: true,
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
return (result.messages ?? []).map((m) => ({
|
|
39
|
+
start: m.range[0],
|
|
40
|
+
end: m.range[1],
|
|
41
|
+
ruleId: m.ruleId,
|
|
42
|
+
message: m.message,
|
|
43
|
+
}));
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=secrets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secrets.js","sourceRoot":"","sources":["../src/secrets.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,8CAA8C,CAAC;AAc1F,MAAM,cAAc,GAAyB;IAC3C,KAAK,EAAE;QACL;YACE,EAAE,EAAE,8CAA8C;YAClD,IAAI,EAAE,eAAe;SACtB;KACF;CACF,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,IAAY,EAAE,QAAQ,GAAG,YAAY;IACpE,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,CAAC;IACrB,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC;QAC9B,MAAM,EAAE;YACN,QAAQ;YACR,OAAO,EAAE,IAAI;YACb,WAAW,EAAE,MAAM;SACpB;QACD,OAAO,EAAE;YACP,MAAM,EAAE,cAAc;YACtB,WAAW,EAAE,KAAK;YAClB,gBAAgB,EAAE,IAAI;SACvB;KACF,CAAC,CAAC;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACzC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;QACjB,GAAG,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;QACf,MAAM,EAAE,CAAC,CAAC,MAAM;QAChB,OAAO,EAAE,CAAC,CAAC,OAAO;KACnB,CAAC,CAAC,CAAC;AACN,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Storage adapter for persisting `WeeklyAggregation` rows.
|
|
3
|
+
*
|
|
4
|
+
* The default `JsonStorage` writes one JSON file per (week × tool) under
|
|
5
|
+
* `<rootDir>/aggregations/<weekStart>/<tool>.json`. This keeps the layout
|
|
6
|
+
* grep-friendly and diffable in Git when the user opts in.
|
|
7
|
+
*
|
|
8
|
+
* The `StorageAdapter` interface is intentionally minimal so we can later
|
|
9
|
+
* swap to `surch` or `opendb` (sibling repos) without touching callers.
|
|
10
|
+
*/
|
|
11
|
+
import type { WeeklyAggregation } from './aggregations.js';
|
|
12
|
+
import type { Tool } from './schema.js';
|
|
13
|
+
export interface StorageFilter {
|
|
14
|
+
weekStart?: string;
|
|
15
|
+
projectCwd?: string;
|
|
16
|
+
tool?: Tool;
|
|
17
|
+
}
|
|
18
|
+
export interface StorageAdapter {
|
|
19
|
+
save(rows: WeeklyAggregation[]): Promise<void>;
|
|
20
|
+
load(filter?: StorageFilter): Promise<WeeklyAggregation[]>;
|
|
21
|
+
}
|
|
22
|
+
export interface JsonStorageOptions {
|
|
23
|
+
/** Root dir; defaults to ~/.agent-stats. */
|
|
24
|
+
rootDir?: string;
|
|
25
|
+
}
|
|
26
|
+
export declare class JsonStorage implements StorageAdapter {
|
|
27
|
+
private readonly rootDir;
|
|
28
|
+
constructor(opts?: JsonStorageOptions);
|
|
29
|
+
private aggDir;
|
|
30
|
+
save(rows: WeeklyAggregation[]): Promise<void>;
|
|
31
|
+
load(filter?: StorageFilter): Promise<WeeklyAggregation[]>;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=storage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAExC,MAAM,WAAW,aAAa;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,IAAI,CAAC;CACb;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,IAAI,EAAE,iBAAiB,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/C,IAAI,CAAC,MAAM,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAAC;CAC5D;AAED,MAAM,WAAW,kBAAkB;IACjC,4CAA4C;IAC5C,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAID,qBAAa,WAAY,YAAW,cAAc;IAChD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAErB,IAAI,GAAE,kBAAuB;IAIzC,OAAO,CAAC,MAAM;IAIR,IAAI,CAAC,IAAI,EAAE,iBAAiB,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAuC9C,IAAI,CAAC,MAAM,GAAE,aAAkB,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC;CAwCrE"}
|
package/dist/storage.js
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Storage adapter for persisting `WeeklyAggregation` rows.
|
|
3
|
+
*
|
|
4
|
+
* The default `JsonStorage` writes one JSON file per (week × tool) under
|
|
5
|
+
* `<rootDir>/aggregations/<weekStart>/<tool>.json`. This keeps the layout
|
|
6
|
+
* grep-friendly and diffable in Git when the user opts in.
|
|
7
|
+
*
|
|
8
|
+
* The `StorageAdapter` interface is intentionally minimal so we can later
|
|
9
|
+
* swap to `surch` or `opendb` (sibling repos) without touching callers.
|
|
10
|
+
*/
|
|
11
|
+
import { mkdir, readFile, writeFile, readdir } from 'node:fs/promises';
|
|
12
|
+
import path from 'node:path';
|
|
13
|
+
const DEFAULT_HOME = () => process.env['HOME'] ?? '';
|
|
14
|
+
export class JsonStorage {
|
|
15
|
+
rootDir;
|
|
16
|
+
constructor(opts = {}) {
|
|
17
|
+
this.rootDir = opts.rootDir ?? path.join(DEFAULT_HOME(), '.agent-stats');
|
|
18
|
+
}
|
|
19
|
+
aggDir() {
|
|
20
|
+
return path.join(this.rootDir, 'aggregations');
|
|
21
|
+
}
|
|
22
|
+
async save(rows) {
|
|
23
|
+
if (rows.length === 0)
|
|
24
|
+
return;
|
|
25
|
+
const byBucket = new Map();
|
|
26
|
+
for (const r of rows) {
|
|
27
|
+
const key = `${r.weekStart}/${r.tool}`;
|
|
28
|
+
let arr = byBucket.get(key);
|
|
29
|
+
if (!arr) {
|
|
30
|
+
arr = [];
|
|
31
|
+
byBucket.set(key, arr);
|
|
32
|
+
}
|
|
33
|
+
arr.push(r);
|
|
34
|
+
}
|
|
35
|
+
for (const [key, list] of byBucket) {
|
|
36
|
+
const [week, tool] = key.split('/');
|
|
37
|
+
if (!week || !tool)
|
|
38
|
+
continue;
|
|
39
|
+
const dir = path.join(this.aggDir(), week);
|
|
40
|
+
await mkdir(dir, { recursive: true });
|
|
41
|
+
const file = path.join(dir, `${tool}.json`);
|
|
42
|
+
// merge with existing rows in the same file: replace on same key
|
|
43
|
+
// (weekStart, projectCwd, tool, model).
|
|
44
|
+
let existing = [];
|
|
45
|
+
try {
|
|
46
|
+
const raw = await readFile(file, 'utf8');
|
|
47
|
+
existing = JSON.parse(raw);
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
existing = [];
|
|
51
|
+
}
|
|
52
|
+
const keyOf = (r) => `${r.weekStart}|${r.projectCwd}|${r.tool}|${r.model}`;
|
|
53
|
+
const merged = new Map();
|
|
54
|
+
for (const r of existing)
|
|
55
|
+
merged.set(keyOf(r), r);
|
|
56
|
+
for (const r of list)
|
|
57
|
+
merged.set(keyOf(r), r);
|
|
58
|
+
const out = [...merged.values()].sort((a, b) => a.projectCwd.localeCompare(b.projectCwd) || a.model.localeCompare(b.model));
|
|
59
|
+
await writeFile(file, `${JSON.stringify(out, null, 2)}\n`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
async load(filter = {}) {
|
|
63
|
+
let weeks;
|
|
64
|
+
try {
|
|
65
|
+
weeks = await readdir(this.aggDir());
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
return [];
|
|
69
|
+
}
|
|
70
|
+
if (filter.weekStart)
|
|
71
|
+
weeks = weeks.filter((w) => w === filter.weekStart);
|
|
72
|
+
const out = [];
|
|
73
|
+
for (const w of weeks) {
|
|
74
|
+
const dir = path.join(this.aggDir(), w);
|
|
75
|
+
let files;
|
|
76
|
+
try {
|
|
77
|
+
files = await readdir(dir);
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
for (const f of files) {
|
|
83
|
+
if (!f.endsWith('.json'))
|
|
84
|
+
continue;
|
|
85
|
+
const tool = f.replace(/\.json$/, '');
|
|
86
|
+
if (filter.tool && filter.tool !== tool)
|
|
87
|
+
continue;
|
|
88
|
+
const file = path.join(dir, f);
|
|
89
|
+
try {
|
|
90
|
+
const raw = await readFile(file, 'utf8');
|
|
91
|
+
const rows = JSON.parse(raw);
|
|
92
|
+
for (const r of rows) {
|
|
93
|
+
if (filter.projectCwd) {
|
|
94
|
+
if (filter.projectCwd.endsWith('/')) {
|
|
95
|
+
if (!r.projectCwd.startsWith(filter.projectCwd))
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
else if (r.projectCwd !== filter.projectCwd)
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
out.push(r);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return out;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.js","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@sentropic/agent-stats-core",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Parsers, aggregations and schema for agent-stats (Claude Code + Codex CLI session analyzer).",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./parsers/claude": {
|
|
14
|
+
"types": "./dist/parsers/claude.d.ts",
|
|
15
|
+
"import": "./dist/parsers/claude.js"
|
|
16
|
+
},
|
|
17
|
+
"./parsers/codex": {
|
|
18
|
+
"types": "./dist/parsers/codex.d.ts",
|
|
19
|
+
"import": "./dist/parsers/codex.js"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"dist",
|
|
24
|
+
"README.md"
|
|
25
|
+
],
|
|
26
|
+
"sideEffects": false,
|
|
27
|
+
"scripts": {
|
|
28
|
+
"build": "tsc -p tsconfig.json",
|
|
29
|
+
"typecheck": "tsc --noEmit -p tsconfig.json"
|
|
30
|
+
},
|
|
31
|
+
"engines": {
|
|
32
|
+
"node": ">=20"
|
|
33
|
+
},
|
|
34
|
+
"publishConfig": {
|
|
35
|
+
"access": "public"
|
|
36
|
+
},
|
|
37
|
+
"repository": {
|
|
38
|
+
"type": "git",
|
|
39
|
+
"url": "git+https://github.com/rhanka/agent-stats.git",
|
|
40
|
+
"directory": "packages/core"
|
|
41
|
+
},
|
|
42
|
+
"license": "MIT",
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"@secretlint/secretlint-rule-preset-recommend": "^13.0.2",
|
|
45
|
+
"@secretlint/types": "^13.0.2",
|
|
46
|
+
"@types/better-sqlite3": "^7.6.13",
|
|
47
|
+
"better-sqlite3": "^12.10.0",
|
|
48
|
+
"secretlint": "^13.0.2"
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"@vitest/coverage-v8": "^4.1.7"
|
|
52
|
+
}
|
|
53
|
+
}
|