@ai-dossier/cli 0.49.2 → 0.53.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 +46 -3
- package/dist/batch-suite-runner.d.ts +30 -6
- package/dist/batch-suite-runner.d.ts.map +1 -1
- package/dist/batch-suite-runner.js +86 -25
- package/dist/batch-suite-runner.js.map +1 -1
- package/dist/capability.d.ts +8 -0
- package/dist/capability.d.ts.map +1 -1
- package/dist/capability.js +16 -1
- package/dist/capability.js.map +1 -1
- package/dist/cli.js +2 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/run.d.ts.map +1 -1
- package/dist/commands/run.js +10 -1
- package/dist/commands/run.js.map +1 -1
- package/dist/commands/sched.d.ts.map +1 -1
- package/dist/commands/sched.js +78 -3
- package/dist/commands/sched.js.map +1 -1
- package/dist/commands/usage.d.ts +84 -0
- package/dist/commands/usage.d.ts.map +1 -0
- package/dist/commands/usage.js +395 -0
- package/dist/commands/usage.js.map +1 -0
- package/dist/usage/collect-claude.d.ts +47 -0
- package/dist/usage/collect-claude.d.ts.map +1 -0
- package/dist/usage/collect-claude.js +237 -0
- package/dist/usage/collect-claude.js.map +1 -0
- package/dist/usage/collect-dispatch.d.ts +73 -0
- package/dist/usage/collect-dispatch.d.ts.map +1 -0
- package/dist/usage/collect-dispatch.js +297 -0
- package/dist/usage/collect-dispatch.js.map +1 -0
- package/dist/usage/collect-opencode.d.ts +74 -0
- package/dist/usage/collect-opencode.d.ts.map +1 -0
- package/dist/usage/collect-opencode.js +198 -0
- package/dist/usage/collect-opencode.js.map +1 -0
- package/dist/usage/host-session.d.ts +63 -0
- package/dist/usage/host-session.d.ts.map +1 -0
- package/dist/usage/host-session.js +325 -0
- package/dist/usage/host-session.js.map +1 -0
- package/dist/usage/ledger.d.ts +87 -0
- package/dist/usage/ledger.d.ts.map +1 -0
- package/dist/usage/ledger.js +268 -0
- package/dist/usage/ledger.js.map +1 -0
- package/dist/usage/types.d.ts +80 -0
- package/dist/usage/types.d.ts.map +1 -0
- package/dist/usage/types.js +11 -0
- package/dist/usage/types.js.map +1 -0
- package/dist/usage/util.d.ts +36 -0
- package/dist/usage/util.d.ts.map +1 -0
- package/dist/usage/util.js +158 -0
- package/dist/usage/util.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Resolve the agent host an `ai-dossier run` was invoked from — session id
|
|
4
|
+
* and the model it is running — so `runs.jsonl` records a concrete model
|
|
5
|
+
* instead of null (#769, "fix at the source").
|
|
6
|
+
*
|
|
7
|
+
* ~99% of `runs.jsonl` rows are `llm: auto` invocations made BY a host agent
|
|
8
|
+
* (Claude Code, opencode) that then follows the printed dossier itself; no
|
|
9
|
+
* agent is spawned, so nothing reported a model. The host's own store knows
|
|
10
|
+
* it:
|
|
11
|
+
*
|
|
12
|
+
* - Claude Code exports `CLAUDE_CODE_SESSION_ID`; its transcript
|
|
13
|
+
* (`~/.claude/projects/<slug>/<id>.jsonl`, or a subagent's under
|
|
14
|
+
* `<id>/subagents/`) records each assistant message's resolved `model`.
|
|
15
|
+
* Subagents share the parent's id, so the caller is the transcript whose
|
|
16
|
+
* newest tool call is a still-pending `ai-dossier run` (else the recently
|
|
17
|
+
* active transcripts' model when they all agree; null when they don't).
|
|
18
|
+
* - Both markers are inherited by child processes, so the NEAREST host
|
|
19
|
+
* ancestor (`CLAUDE_PID` / `OPENCODE_PID` via /proc) wins.
|
|
20
|
+
* - opencode exports `OPENCODE=1` but no session id; the newest session for
|
|
21
|
+
* this working directory in opencode.db (updated in the last few minutes)
|
|
22
|
+
* is the caller.
|
|
23
|
+
*
|
|
24
|
+
* Best effort and bounded: every failure yields nulls, never an exception.
|
|
25
|
+
*/
|
|
26
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
27
|
+
if (k2 === undefined) k2 = k;
|
|
28
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
29
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
30
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
31
|
+
}
|
|
32
|
+
Object.defineProperty(o, k2, desc);
|
|
33
|
+
}) : (function(o, m, k, k2) {
|
|
34
|
+
if (k2 === undefined) k2 = k;
|
|
35
|
+
o[k2] = m[k];
|
|
36
|
+
}));
|
|
37
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
38
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
39
|
+
}) : function(o, v) {
|
|
40
|
+
o["default"] = v;
|
|
41
|
+
});
|
|
42
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
43
|
+
var ownKeys = function(o) {
|
|
44
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
45
|
+
var ar = [];
|
|
46
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
47
|
+
return ar;
|
|
48
|
+
};
|
|
49
|
+
return ownKeys(o);
|
|
50
|
+
};
|
|
51
|
+
return function (mod) {
|
|
52
|
+
if (mod && mod.__esModule) return mod;
|
|
53
|
+
var result = {};
|
|
54
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
55
|
+
__setModuleDefault(result, mod);
|
|
56
|
+
return result;
|
|
57
|
+
};
|
|
58
|
+
})();
|
|
59
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
60
|
+
exports.lastAssistantModel = lastAssistantModel;
|
|
61
|
+
exports.findClaudeTranscript = findClaudeTranscript;
|
|
62
|
+
exports.hasPendingDossierRun = hasPendingDossierRun;
|
|
63
|
+
exports.claudeHostModel = claudeHostModel;
|
|
64
|
+
exports.ancestorDepth = ancestorDepth;
|
|
65
|
+
exports.detectHostSession = detectHostSession;
|
|
66
|
+
const fs = __importStar(require("node:fs"));
|
|
67
|
+
const path = __importStar(require("node:path"));
|
|
68
|
+
const collect_claude_1 = require("./collect-claude");
|
|
69
|
+
const collect_opencode_1 = require("./collect-opencode");
|
|
70
|
+
const util_1 = require("./util");
|
|
71
|
+
const NONE = { agent: null, session_id: null, model: null };
|
|
72
|
+
/** Bytes read from a transcript's tail when looking for the latest model. */
|
|
73
|
+
const TAIL_BYTES = 256 * 1024;
|
|
74
|
+
/** An opencode session older than this is not the one invoking us. */
|
|
75
|
+
const OPENCODE_RECENT_MS = 10 * 60 * 1000;
|
|
76
|
+
const CLAUDE_SESSION_RE = /^[0-9a-f-]{36}$/i;
|
|
77
|
+
function tail(file, bytes) {
|
|
78
|
+
let fd = null;
|
|
79
|
+
try {
|
|
80
|
+
const size = fs.statSync(file).size;
|
|
81
|
+
const start = Math.max(0, size - bytes);
|
|
82
|
+
const buffer = Buffer.allocUnsafe(size - start);
|
|
83
|
+
fd = fs.openSync(file, 'r');
|
|
84
|
+
const read = fs.readSync(fd, buffer, 0, buffer.length, start);
|
|
85
|
+
return buffer.subarray(0, read).toString('utf-8');
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
return '';
|
|
89
|
+
}
|
|
90
|
+
finally {
|
|
91
|
+
if (fd !== null)
|
|
92
|
+
fs.closeSync(fd);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/** The last real (non-synthetic) assistant `message.model` in a transcript's tail. */
|
|
96
|
+
function lastAssistantModel(transcript) {
|
|
97
|
+
const lines = tail(transcript, TAIL_BYTES).split('\n');
|
|
98
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
99
|
+
const line = lines[i];
|
|
100
|
+
if (!line.includes('"assistant"') || !line.includes('"model"'))
|
|
101
|
+
continue;
|
|
102
|
+
try {
|
|
103
|
+
const record = JSON.parse(line);
|
|
104
|
+
const model = record?.message?.model;
|
|
105
|
+
if (record?.type === 'assistant' &&
|
|
106
|
+
typeof model === 'string' &&
|
|
107
|
+
model &&
|
|
108
|
+
model !== '<synthetic>') {
|
|
109
|
+
return model;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
// partial first line of the tail window, or a malformed line
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
/** Newest transcript file (main or subagent) belonging to `sessionId`, or null. */
|
|
119
|
+
function findClaudeTranscript(projectsDir, sessionId) {
|
|
120
|
+
let best = null;
|
|
121
|
+
const consider = (file) => {
|
|
122
|
+
const mtime = (0, util_1.mtimeMs)(file);
|
|
123
|
+
if (mtime !== null && (!best || mtime > best.mtime))
|
|
124
|
+
best = { file, mtime };
|
|
125
|
+
};
|
|
126
|
+
for (const project of (0, util_1.safeReaddir)(projectsDir)) {
|
|
127
|
+
if (!project.isDirectory())
|
|
128
|
+
continue;
|
|
129
|
+
const dir = path.join(projectsDir, project.name);
|
|
130
|
+
consider(path.join(dir, `${sessionId}.jsonl`));
|
|
131
|
+
const subDir = path.join(dir, sessionId, 'subagents');
|
|
132
|
+
for (const sub of (0, util_1.safeReaddir)(subDir)) {
|
|
133
|
+
if (sub.isFile() && sub.name.endsWith('.jsonl'))
|
|
134
|
+
consider(path.join(subDir, sub.name));
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return best?.file ?? null;
|
|
138
|
+
}
|
|
139
|
+
/** Transcripts written within this long of the newest one are "concurrently active" candidates. */
|
|
140
|
+
const ACTIVE_WINDOW_MS = 2 * 60 * 1000;
|
|
141
|
+
const DOSSIER_RUN_RE = /\b(?:ai-)?dossier\s+run\b/;
|
|
142
|
+
/** Every transcript (main + subagents) of `sessionId`, with mtimes. */
|
|
143
|
+
function claudeTranscripts(projectsDir, sessionId) {
|
|
144
|
+
const out = [];
|
|
145
|
+
const consider = (file) => {
|
|
146
|
+
const mtime = (0, util_1.mtimeMs)(file);
|
|
147
|
+
if (mtime !== null)
|
|
148
|
+
out.push({ file, mtime });
|
|
149
|
+
};
|
|
150
|
+
for (const project of (0, util_1.safeReaddir)(projectsDir)) {
|
|
151
|
+
if (!project.isDirectory())
|
|
152
|
+
continue;
|
|
153
|
+
const dir = path.join(projectsDir, project.name);
|
|
154
|
+
consider(path.join(dir, `${sessionId}.jsonl`));
|
|
155
|
+
const subDir = path.join(dir, sessionId, 'subagents');
|
|
156
|
+
for (const sub of (0, util_1.safeReaddir)(subDir)) {
|
|
157
|
+
if (sub.isFile() && sub.name.endsWith('.jsonl'))
|
|
158
|
+
consider(path.join(subDir, sub.name));
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return out;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Whether a transcript's newest tool call is a still-pending `ai-dossier run`
|
|
165
|
+
* — i.e. this transcript's agent is the one executing us right now: the
|
|
166
|
+
* command is in a `tool_use` block whose `tool_result` has not been written.
|
|
167
|
+
*/
|
|
168
|
+
function hasPendingDossierRun(transcript) {
|
|
169
|
+
const lines = tail(transcript, TAIL_BYTES).split('\n');
|
|
170
|
+
const answered = new Set();
|
|
171
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
172
|
+
const line = lines[i];
|
|
173
|
+
if (!line.includes('tool_'))
|
|
174
|
+
continue;
|
|
175
|
+
let record;
|
|
176
|
+
try {
|
|
177
|
+
record = JSON.parse(line);
|
|
178
|
+
}
|
|
179
|
+
catch {
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
const content = Array.isArray(record.message?.content) ? record.message.content : [];
|
|
183
|
+
for (const block of content) {
|
|
184
|
+
if (block?.type === 'tool_result' && typeof block.tool_use_id === 'string') {
|
|
185
|
+
answered.add(block.tool_use_id);
|
|
186
|
+
}
|
|
187
|
+
if (block?.type === 'tool_use' && typeof block.id === 'string' && !answered.has(block.id)) {
|
|
188
|
+
const command = block.input?.command;
|
|
189
|
+
if (typeof command === 'string' && DOSSIER_RUN_RE.test(command))
|
|
190
|
+
return true;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
if (record.type === 'assistant' &&
|
|
194
|
+
content.some((b) => b?.type === 'tool_use')) {
|
|
195
|
+
// Only the newest tool-calling turn can be the one invoking us.
|
|
196
|
+
return false;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return false;
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* The model of the Claude Code agent invoking us. Subagents share their
|
|
203
|
+
* parent's `CLAUDE_CODE_SESSION_ID`, so "newest transcript" alone can pick a
|
|
204
|
+
* concurrent sibling: prefer the one transcript with a pending `ai-dossier
|
|
205
|
+
* run` call; otherwise accept the recently-active candidates' model only when
|
|
206
|
+
* they all agree — a guess between different models records null.
|
|
207
|
+
*/
|
|
208
|
+
function claudeHostModel(projectsDir, sessionId) {
|
|
209
|
+
const all = claudeTranscripts(projectsDir, sessionId);
|
|
210
|
+
if (all.length === 0)
|
|
211
|
+
return null;
|
|
212
|
+
const newest = Math.max(...all.map((t) => t.mtime));
|
|
213
|
+
const active = all.filter((t) => t.mtime >= newest - ACTIVE_WINDOW_MS);
|
|
214
|
+
const pending = active.filter((t) => hasPendingDossierRun(t.file));
|
|
215
|
+
if (pending.length === 1)
|
|
216
|
+
return lastAssistantModel(pending[0].file);
|
|
217
|
+
const pool = pending.length > 1 ? pending : active;
|
|
218
|
+
const models = new Set(pool.map((t) => lastAssistantModel(t.file)));
|
|
219
|
+
if (models.size !== 1)
|
|
220
|
+
return null;
|
|
221
|
+
return [...models][0];
|
|
222
|
+
}
|
|
223
|
+
/** `/proc/<pid>/stat` parent pid, or null (non-Linux, gone, unreadable). */
|
|
224
|
+
function parentPid(pid) {
|
|
225
|
+
try {
|
|
226
|
+
const stat = fs.readFileSync(`/proc/${pid}/stat`, 'utf-8');
|
|
227
|
+
// comm (field 2) may contain spaces/parens — parse after the LAST ')'.
|
|
228
|
+
const fields = stat.slice(stat.lastIndexOf(')') + 2).split(' ');
|
|
229
|
+
const ppid = Number.parseInt(fields[1], 10);
|
|
230
|
+
return Number.isFinite(ppid) ? ppid : null;
|
|
231
|
+
}
|
|
232
|
+
catch {
|
|
233
|
+
return null;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
/** Sentinel depth for "cannot tell" (no pid given, or no /proc): trusted, but loses to a proven ancestor. */
|
|
237
|
+
const UNKNOWN_DEPTH = Number.MAX_SAFE_INTEGER;
|
|
238
|
+
/**
|
|
239
|
+
* How many generations up `pid` is from this process: a number when it is a
|
|
240
|
+
* proven ancestor, null when it provably is not (an inherited env marker from
|
|
241
|
+
* an unrelated outer host), UNKNOWN_DEPTH when it cannot be told.
|
|
242
|
+
*/
|
|
243
|
+
function ancestorDepth(pidText, self = process.pid) {
|
|
244
|
+
const pid = pidText ? Number.parseInt(pidText, 10) : Number.NaN;
|
|
245
|
+
if (!Number.isFinite(pid) || !fs.existsSync(`/proc/${self}/stat`))
|
|
246
|
+
return UNKNOWN_DEPTH;
|
|
247
|
+
let current = self;
|
|
248
|
+
for (let depth = 0; depth < 64 && current !== null && current > 1; depth++) {
|
|
249
|
+
if (current === pid)
|
|
250
|
+
return depth;
|
|
251
|
+
current = parentPid(current);
|
|
252
|
+
}
|
|
253
|
+
return null;
|
|
254
|
+
}
|
|
255
|
+
function openCodeSession(dbFile, cwd, nowMs) {
|
|
256
|
+
const base = { agent: 'opencode', session_id: null, model: null };
|
|
257
|
+
const sqlite = (0, collect_opencode_1.loadNodeSqlite)();
|
|
258
|
+
if (!sqlite || !fs.existsSync(dbFile))
|
|
259
|
+
return base;
|
|
260
|
+
try {
|
|
261
|
+
const db = new sqlite.DatabaseSync(dbFile, { readOnly: true });
|
|
262
|
+
try {
|
|
263
|
+
const session = db
|
|
264
|
+
.prepare('SELECT id FROM session WHERE directory = ? AND time_updated >= ? ORDER BY time_updated DESC LIMIT 1')
|
|
265
|
+
.all(cwd, nowMs - OPENCODE_RECENT_MS)[0];
|
|
266
|
+
if (!session?.id)
|
|
267
|
+
return base;
|
|
268
|
+
const message = db
|
|
269
|
+
.prepare('SELECT data FROM message WHERE session_id = ? ORDER BY time_created DESC LIMIT 20')
|
|
270
|
+
.all(session.id);
|
|
271
|
+
for (const { data } of message) {
|
|
272
|
+
try {
|
|
273
|
+
const parsed = JSON.parse(data);
|
|
274
|
+
if (parsed?.role === 'assistant' && typeof parsed.modelID === 'string') {
|
|
275
|
+
const model = typeof parsed.providerID === 'string'
|
|
276
|
+
? `${parsed.providerID}/${parsed.modelID}`
|
|
277
|
+
: parsed.modelID;
|
|
278
|
+
return { ...base, session_id: session.id, model };
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
catch {
|
|
282
|
+
// skip malformed payloads
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
return { ...base, session_id: session.id };
|
|
286
|
+
}
|
|
287
|
+
finally {
|
|
288
|
+
db.close();
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
catch {
|
|
292
|
+
return base;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
/** Identify the invoking agent host, its session, and its current model. Never throws. */
|
|
296
|
+
function detectHostSession(opts = {}) {
|
|
297
|
+
const env = opts.env ?? process.env;
|
|
298
|
+
try {
|
|
299
|
+
// Child processes inherit BOTH hosts' markers (e.g. an opencode agent
|
|
300
|
+
// dispatched by a sched daemon started from a Claude Code shell), so pick
|
|
301
|
+
// the NEAREST host ancestor, not whichever marker is checked first.
|
|
302
|
+
const claudeDepth = env.CLAUDECODE === '1' || env.CLAUDE_CODE === '1' ? ancestorDepth(env.CLAUDE_PID) : null;
|
|
303
|
+
const opencodeDepth = env.OPENCODE === '1' ? ancestorDepth(env.OPENCODE_PID) : null;
|
|
304
|
+
const useClaude = claudeDepth !== null && (opencodeDepth === null || claudeDepth <= opencodeDepth);
|
|
305
|
+
if (useClaude) {
|
|
306
|
+
const id = env.CLAUDE_CODE_SESSION_ID;
|
|
307
|
+
if (!id || !CLAUDE_SESSION_RE.test(id)) {
|
|
308
|
+
return { agent: 'claude-code', session_id: null, model: null };
|
|
309
|
+
}
|
|
310
|
+
return {
|
|
311
|
+
agent: 'claude-code',
|
|
312
|
+
session_id: id,
|
|
313
|
+
model: claudeHostModel(opts.claudeProjectsDir ?? (0, collect_claude_1.defaultClaudeProjectsDir)(env), id),
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
if (opencodeDepth !== null) {
|
|
317
|
+
return openCodeSession(opts.opencodeDb ?? (0, collect_opencode_1.defaultOpenCodeDbPath)(env), opts.cwd ?? process.cwd(), opts.nowMs ?? Date.now());
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
catch {
|
|
321
|
+
// fall through
|
|
322
|
+
}
|
|
323
|
+
return NONE;
|
|
324
|
+
}
|
|
325
|
+
//# sourceMappingURL=host-session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host-session.js","sourceRoot":"","sources":["../../src/usage/host-session.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ledger assembly + aggregation for `ai-dossier usage` (#769).
|
|
3
|
+
*
|
|
4
|
+
* `collectLedger` runs every collector for a time range and joins the
|
|
5
|
+
* attribution sources; the pure functions below turn rows into the views'
|
|
6
|
+
* numbers (so they are unit-testable without any store on disk).
|
|
7
|
+
*/
|
|
8
|
+
import { type OpenCodeOpenResult } from './collect-opencode';
|
|
9
|
+
import type { Ledger, LimitEvent, UsageRow } from './types';
|
|
10
|
+
/** Where each store lives — defaults resolve from the environment; tests point them at fixtures. */
|
|
11
|
+
export interface LedgerPaths {
|
|
12
|
+
claudeProjectsDir: string;
|
|
13
|
+
opencodeDb: string;
|
|
14
|
+
schedRoot: string;
|
|
15
|
+
runsLog: string;
|
|
16
|
+
}
|
|
17
|
+
export declare function defaultLedgerPaths(env?: NodeJS.ProcessEnv): LedgerPaths;
|
|
18
|
+
export interface CollectOptions {
|
|
19
|
+
sinceMs: number;
|
|
20
|
+
untilMs: number;
|
|
21
|
+
paths: LedgerPaths;
|
|
22
|
+
host?: string;
|
|
23
|
+
/** Override how opencode.db is opened (tests). */
|
|
24
|
+
openOpenCode?: (dbFile: string) => OpenCodeOpenResult;
|
|
25
|
+
}
|
|
26
|
+
/** Run every collector for `[sinceMs, untilMs)` and join attribution. Read-only; never throws for a missing store. */
|
|
27
|
+
export declare function collectLedger(opts: CollectOptions): Ledger;
|
|
28
|
+
export interface TokenTotals {
|
|
29
|
+
input: number;
|
|
30
|
+
output: number;
|
|
31
|
+
reasoning: number;
|
|
32
|
+
cache_read: number;
|
|
33
|
+
cache_write: number;
|
|
34
|
+
/** Sum of every token class. */
|
|
35
|
+
total: number;
|
|
36
|
+
/** Sum of recorded costs; null when no row recorded one. */
|
|
37
|
+
cost_usd: number | null;
|
|
38
|
+
messages: number;
|
|
39
|
+
}
|
|
40
|
+
export declare function rowTotal(row: UsageRow): number;
|
|
41
|
+
export declare function totalsOf(rows: readonly UsageRow[]): TokenTotals;
|
|
42
|
+
export interface GroupTotals extends TokenTotals {
|
|
43
|
+
key: string;
|
|
44
|
+
}
|
|
45
|
+
/** Group rows by `keyOf`, largest total first. */
|
|
46
|
+
export declare function groupRows(rows: readonly UsageRow[], keyOf: (row: UsageRow) => string): GroupTotals[];
|
|
47
|
+
/** Share of tokens (0..1) attributed to a concrete model id; 1 for an empty set. */
|
|
48
|
+
export declare function modelCoverage(rows: readonly UsageRow[]): number;
|
|
49
|
+
export interface SessionSummary extends TokenTotals {
|
|
50
|
+
session_id: string;
|
|
51
|
+
parent_session_id: string | null;
|
|
52
|
+
source: string;
|
|
53
|
+
models: string[];
|
|
54
|
+
project: string | null;
|
|
55
|
+
issue: number | null;
|
|
56
|
+
batch: string | null;
|
|
57
|
+
unit: string | null;
|
|
58
|
+
title: string | null;
|
|
59
|
+
first_ts: string;
|
|
60
|
+
last_ts: string;
|
|
61
|
+
}
|
|
62
|
+
/** Per-session totals, largest first. */
|
|
63
|
+
export declare function summarizeSessions(rows: readonly UsageRow[]): SessionSummary[];
|
|
64
|
+
/** Tokens per clock hour across `[sinceMs, untilMs)`, oldest first — the burn-rate series. */
|
|
65
|
+
export declare function hourlyBurn(rows: readonly UsageRow[], sinceMs: number, untilMs: number): {
|
|
66
|
+
hour: string;
|
|
67
|
+
total: number;
|
|
68
|
+
messages: number;
|
|
69
|
+
}[];
|
|
70
|
+
/** Repeats closer than this fold into one limit event (agents/cron retry a wall every few minutes). */
|
|
71
|
+
export declare const LIMIT_REPEAT_GAP_MS: number;
|
|
72
|
+
/**
|
|
73
|
+
* Fold repeats of the same wall (same source, unit and message) into their
|
|
74
|
+
* first occurrence — `count`/`last_ts` record what was folded. A wall hit by a
|
|
75
|
+
* cron every 15 minutes is one event, not twenty; its onset is what needs
|
|
76
|
+
* explaining. Input must be sorted by `ts`.
|
|
77
|
+
*/
|
|
78
|
+
export declare function collapseLimitEvents(events: readonly LimitEvent[], gapMs?: number): LimitEvent[];
|
|
79
|
+
export interface LimitContext {
|
|
80
|
+
event: LimitEvent;
|
|
81
|
+
/** Top consumers (by session) in the window that ended at the event. */
|
|
82
|
+
top: SessionSummary[];
|
|
83
|
+
window_ms: number;
|
|
84
|
+
}
|
|
85
|
+
/** For each limit event, the top `n` sessions by tokens in the `windowMs` before it. */
|
|
86
|
+
export declare function limitContexts(limits: readonly LimitEvent[], rows: readonly UsageRow[], windowMs: number, n?: number): LimitContext[];
|
|
87
|
+
//# sourceMappingURL=ledger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ledger.d.ts","sourceRoot":"","sources":["../../src/usage/ledger.ts"],"names":[],"mappings":"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"}
|