botmux 2.67.0 → 2.68.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/adapters/backend/tmux-pipe-backend.d.ts +7 -2
- package/dist/adapters/backend/tmux-pipe-backend.d.ts.map +1 -1
- package/dist/adapters/backend/tmux-pipe-backend.js +12 -5
- package/dist/adapters/backend/tmux-pipe-backend.js.map +1 -1
- package/dist/adapters/cli/codex-app.d.ts.map +1 -1
- package/dist/adapters/cli/codex-app.js +5 -17
- package/dist/adapters/cli/codex-app.js.map +1 -1
- package/dist/adapters/cli/mira.d.ts.map +1 -1
- package/dist/adapters/cli/mira.js +4 -17
- package/dist/adapters/cli/mira.js.map +1 -1
- package/dist/adapters/cli/pi.d.ts.map +1 -1
- package/dist/adapters/cli/pi.js +0 -1
- package/dist/adapters/cli/pi.js.map +1 -1
- package/dist/adapters/cli/runner-input.d.ts +66 -0
- package/dist/adapters/cli/runner-input.d.ts.map +1 -0
- package/dist/adapters/cli/runner-input.js +125 -0
- package/dist/adapters/cli/runner-input.js.map +1 -0
- package/dist/adapters/cli/types.d.ts +8 -4
- package/dist/adapters/cli/types.d.ts.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +79 -17
- package/dist/cli.js.map +1 -1
- package/dist/core/auto-start.d.ts +23 -0
- package/dist/core/auto-start.d.ts.map +1 -1
- package/dist/core/auto-start.js +30 -0
- package/dist/core/auto-start.js.map +1 -1
- package/dist/core/command-handler.d.ts +9 -9
- package/dist/core/command-handler.d.ts.map +1 -1
- package/dist/core/command-handler.js +23 -16
- package/dist/core/command-handler.js.map +1 -1
- package/dist/core/cost-calculator.d.ts +27 -0
- package/dist/core/cost-calculator.d.ts.map +1 -1
- package/dist/core/cost-calculator.js +483 -27
- package/dist/core/cost-calculator.js.map +1 -1
- package/dist/core/dashboard-rows.d.ts +3 -0
- package/dist/core/dashboard-rows.d.ts.map +1 -1
- package/dist/core/dashboard-rows.js +11 -0
- package/dist/core/dashboard-rows.js.map +1 -1
- package/dist/core/worker-pool.d.ts.map +1 -1
- package/dist/core/worker-pool.js +22 -1
- package/dist/core/worker-pool.js.map +1 -1
- package/dist/daemon.d.ts.map +1 -1
- package/dist/daemon.js +15 -6
- package/dist/daemon.js.map +1 -1
- package/dist/dashboard/web/i18n.d.ts.map +1 -1
- package/dist/dashboard/web/i18n.js +4 -0
- package/dist/dashboard/web/i18n.js.map +1 -1
- package/dist/dashboard/web/sessions.d.ts.map +1 -1
- package/dist/dashboard/web/sessions.js +16 -1
- package/dist/dashboard/web/sessions.js.map +1 -1
- package/dist/dashboard-web/app.js +120 -116
- package/dist/dashboard-web/style.css +4 -0
- package/dist/dashboard.js +41 -13
- package/dist/dashboard.js.map +1 -1
- package/dist/i18n/en.js +2 -2
- package/dist/i18n/en.js.map +1 -1
- package/dist/i18n/zh.js +2 -2
- package/dist/i18n/zh.js.map +1 -1
- package/dist/services/aiden-checkpoints.d.ts +5 -0
- package/dist/services/aiden-checkpoints.d.ts.map +1 -0
- package/dist/services/aiden-checkpoints.js +91 -0
- package/dist/services/aiden-checkpoints.js.map +1 -0
- package/dist/services/codex-transcript.d.ts +7 -0
- package/dist/services/codex-transcript.d.ts.map +1 -1
- package/dist/services/codex-transcript.js +60 -1
- package/dist/services/codex-transcript.js.map +1 -1
- package/dist/services/usage-ledger.d.ts +81 -0
- package/dist/services/usage-ledger.d.ts.map +1 -0
- package/dist/services/usage-ledger.js +353 -0
- package/dist/services/usage-ledger.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Usage ledger — durable per-turn token usage records.
|
|
3
|
+
*
|
|
4
|
+
* On every turn boundary (working→idle edge, session close) the daemon takes
|
|
5
|
+
* a cumulative token snapshot of the session's transcript (via the cached
|
|
6
|
+
* reader in cost-calculator) and appends the positive delta as one
|
|
7
|
+
* self-describing JSON line to a daily ledger file.
|
|
8
|
+
*
|
|
9
|
+
* The ledger is the stable contract for external usage trackers (kaboo-cli
|
|
10
|
+
* reads it the same way it reads HappyClaw's usage_records table):
|
|
11
|
+
* ~/.botmux/usage/usage-YYYY-MM-DD.jsonl (UTC date, append-only)
|
|
12
|
+
* ~/.botmux/usage/state.json (per-session baselines)
|
|
13
|
+
*
|
|
14
|
+
* Records intentionally carry redundant context (larkAppId, chatId, title,
|
|
15
|
+
* callerOpenId, cumulative totals) so a single excerpted line self-validates
|
|
16
|
+
* without joining back to sessions.json.
|
|
17
|
+
*/
|
|
18
|
+
import { appendFileSync, mkdirSync, readdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
|
|
19
|
+
import { homedir } from 'node:os';
|
|
20
|
+
import { join } from 'node:path';
|
|
21
|
+
import { createHash } from 'node:crypto';
|
|
22
|
+
import { logger } from '../utils/logger.js';
|
|
23
|
+
import { getSessionTokenUsage } from '../core/cost-calculator.js';
|
|
24
|
+
/** Last authoritative baseline per session, kept in memory: the hot path
|
|
25
|
+
* never rescans the ledger, and a lost/stale state file inside one process
|
|
26
|
+
* lifetime cannot regress the baseline. */
|
|
27
|
+
const sessionBaselineMemory = new Map();
|
|
28
|
+
export function __resetUsageLedgerMemoryForTest() {
|
|
29
|
+
sessionBaselineMemory.clear();
|
|
30
|
+
}
|
|
31
|
+
function baselineMemoryKey(larkAppId, sessionId) {
|
|
32
|
+
return `${larkAppId ?? ''}\u0000${sessionId}`;
|
|
33
|
+
}
|
|
34
|
+
function finiteNum(v) {
|
|
35
|
+
return typeof v === 'number' && Number.isFinite(v) ? v : 0;
|
|
36
|
+
}
|
|
37
|
+
/** Reconstruct the newest baseline for a session from the ledger files
|
|
38
|
+
* themselves (newest file first; last matching line in a file is newest).
|
|
39
|
+
* This is the crash-recovery source of truth: a record that reached the
|
|
40
|
+
* ledger but whose state advance was lost is still binding. */
|
|
41
|
+
function baselineFromLedger(dir, sessionId) {
|
|
42
|
+
let files;
|
|
43
|
+
try {
|
|
44
|
+
files = readdirSync(dir)
|
|
45
|
+
.filter((f) => /^usage-\d{4}-\d{2}-\d{2}\.jsonl$/.test(f))
|
|
46
|
+
.sort()
|
|
47
|
+
.reverse();
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
for (const name of files) {
|
|
53
|
+
let content;
|
|
54
|
+
try {
|
|
55
|
+
content = readFileSync(join(dir, name), 'utf8');
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
let latest = null;
|
|
61
|
+
for (const line of content.split('\n')) {
|
|
62
|
+
if (!line.includes(sessionId))
|
|
63
|
+
continue;
|
|
64
|
+
try {
|
|
65
|
+
const rec = JSON.parse(line);
|
|
66
|
+
if (rec?.sessionId === sessionId)
|
|
67
|
+
latest = rec;
|
|
68
|
+
}
|
|
69
|
+
catch { /* skip malformed lines */ }
|
|
70
|
+
}
|
|
71
|
+
if (latest) {
|
|
72
|
+
return {
|
|
73
|
+
inputTokens: finiteNum(latest.totalInputTokens),
|
|
74
|
+
outputTokens: finiteNum(latest.totalOutputTokens),
|
|
75
|
+
cacheReadTokens: finiteNum(latest.totalCacheReadTokens),
|
|
76
|
+
cacheCreateTokens: finiteNum(latest.totalCacheCreateTokens),
|
|
77
|
+
recordedAt: typeof latest.ts === 'string' ? latest.ts : new Date(0).toISOString(),
|
|
78
|
+
epoch: finiteNum(latest.epoch),
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
/** Of two baseline candidates, pick the newer: higher epoch wins; within an
|
|
85
|
+
* epoch totals are monotonic, so the larger sum wins. */
|
|
86
|
+
function newerBaseline(a, b) {
|
|
87
|
+
if (!a)
|
|
88
|
+
return b ?? undefined;
|
|
89
|
+
if (!b)
|
|
90
|
+
return a;
|
|
91
|
+
const ea = a.epoch ?? 0;
|
|
92
|
+
const eb = b.epoch ?? 0;
|
|
93
|
+
if (ea !== eb)
|
|
94
|
+
return ea > eb ? a : b;
|
|
95
|
+
const sum = (x) => x.inputTokens + x.outputTokens + x.cacheReadTokens + x.cacheCreateTokens;
|
|
96
|
+
return sum(a) >= sum(b) ? a : b;
|
|
97
|
+
}
|
|
98
|
+
/** Effective baseline = newest of (state file, in-memory latest, ledger scan).
|
|
99
|
+
* The ledger scan runs at most once per session per process lifetime. */
|
|
100
|
+
function resolveBaseline(dir, larkAppId, sessionId, stateBaseline) {
|
|
101
|
+
const key = baselineMemoryKey(larkAppId, sessionId);
|
|
102
|
+
let remembered = sessionBaselineMemory.get(key);
|
|
103
|
+
if (remembered === undefined) {
|
|
104
|
+
remembered = baselineFromLedger(dir, sessionId);
|
|
105
|
+
sessionBaselineMemory.set(key, remembered);
|
|
106
|
+
}
|
|
107
|
+
return newerBaseline(stateBaseline, remembered);
|
|
108
|
+
}
|
|
109
|
+
/** Baselines for sessions idle longer than this are pruned from state.json. */
|
|
110
|
+
const BASELINE_RETENTION_MS = 30 * 24 * 60 * 60 * 1000;
|
|
111
|
+
export function defaultLedgerDir() {
|
|
112
|
+
return process.env.BOTMUX_USAGE_DIR || join(homedir(), '.botmux', 'usage');
|
|
113
|
+
}
|
|
114
|
+
// Baselines are partitioned per bot (larkAppId): botmux can run one daemon
|
|
115
|
+
// per bot, and a shared read-modify-write state file would let one daemon's
|
|
116
|
+
// rename clobber another's freshly advanced baselines.
|
|
117
|
+
function statePath(dir, larkAppId) {
|
|
118
|
+
const id = (larkAppId ?? '').replace(/[^A-Za-z0-9_-]/g, '') || 'default';
|
|
119
|
+
return join(dir, `state-${id}.json`);
|
|
120
|
+
}
|
|
121
|
+
function loadState(dir, larkAppId) {
|
|
122
|
+
try {
|
|
123
|
+
const parsed = JSON.parse(readFileSync(statePath(dir, larkAppId), 'utf8'));
|
|
124
|
+
if (parsed && typeof parsed === 'object' && parsed.sessions && typeof parsed.sessions === 'object') {
|
|
125
|
+
return { v: 1, sessions: parsed.sessions };
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
catch { /* first run or corrupt state — start fresh */ }
|
|
129
|
+
return { v: 1, sessions: {} };
|
|
130
|
+
}
|
|
131
|
+
function saveState(dir, larkAppId, state, now) {
|
|
132
|
+
for (const [sessionId, baseline] of Object.entries(state.sessions)) {
|
|
133
|
+
const recordedAt = Date.parse(baseline.recordedAt);
|
|
134
|
+
if (Number.isFinite(recordedAt) && now.getTime() - recordedAt > BASELINE_RETENTION_MS) {
|
|
135
|
+
delete state.sessions[sessionId];
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
// temp+rename keeps a crash from truncating state; the pid suffix keeps
|
|
139
|
+
// concurrent daemons from stomping each other's tmp file.
|
|
140
|
+
const target = statePath(dir, larkAppId);
|
|
141
|
+
const tmp = `${target}.${process.pid}.tmp`;
|
|
142
|
+
writeFileSync(tmp, JSON.stringify(state));
|
|
143
|
+
renameSync(tmp, target);
|
|
144
|
+
}
|
|
145
|
+
/** Deterministic id for one baseline→snapshot transition: a crash-replay of
|
|
146
|
+
* the same transition regenerates the SAME id, so the consumer's DedupKey
|
|
147
|
+
* collapses the duplicated ledger line instead of double counting it. */
|
|
148
|
+
function deterministicRecordId(sessionId, epoch, prev, cur) {
|
|
149
|
+
const h = createHash('sha256');
|
|
150
|
+
h.update([
|
|
151
|
+
sessionId,
|
|
152
|
+
epoch,
|
|
153
|
+
prev?.inputTokens ?? 0,
|
|
154
|
+
prev?.outputTokens ?? 0,
|
|
155
|
+
prev?.cacheReadTokens ?? 0,
|
|
156
|
+
prev?.cacheCreateTokens ?? 0,
|
|
157
|
+
cur.inputTokens,
|
|
158
|
+
cur.outputTokens,
|
|
159
|
+
cur.cacheReadTokens,
|
|
160
|
+
cur.cacheCreateTokens,
|
|
161
|
+
].join('|'));
|
|
162
|
+
return h.digest('hex').slice(0, 32);
|
|
163
|
+
}
|
|
164
|
+
function ledgerFilePath(dir, now) {
|
|
165
|
+
const date = now.toISOString().slice(0, 10);
|
|
166
|
+
return join(dir, `usage-${date}.jsonl`);
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Diff the cumulative usage snapshot against the session's stored baseline
|
|
170
|
+
* and append a record when the delta is positive. Returns the record, or
|
|
171
|
+
* null when there is nothing to write (no growth, or a shrink — transcript
|
|
172
|
+
* rotation / clear — which just resets the baseline).
|
|
173
|
+
*/
|
|
174
|
+
export function recordSessionUsage(args) {
|
|
175
|
+
try {
|
|
176
|
+
const now = args.now ?? new Date();
|
|
177
|
+
const dir = args.ledgerDir ?? defaultLedgerDir();
|
|
178
|
+
mkdirSync(dir, { recursive: true });
|
|
179
|
+
const state = loadState(dir, args.larkAppId);
|
|
180
|
+
const prev = resolveBaseline(dir, args.larkAppId, args.sessionId, state.sessions[args.sessionId]);
|
|
181
|
+
const cur = args.usage;
|
|
182
|
+
const prevEpoch = prev?.epoch ?? 0;
|
|
183
|
+
const deltaInput = cur.inputTokens - (prev?.inputTokens ?? 0);
|
|
184
|
+
const deltaOutput = cur.outputTokens - (prev?.outputTokens ?? 0);
|
|
185
|
+
const deltaCacheRead = cur.cacheReadTokens - (prev?.cacheReadTokens ?? 0);
|
|
186
|
+
const deltaCacheCreate = cur.cacheCreateTokens - (prev?.cacheCreateTokens ?? 0);
|
|
187
|
+
const baseline = {
|
|
188
|
+
inputTokens: cur.inputTokens,
|
|
189
|
+
outputTokens: cur.outputTokens,
|
|
190
|
+
cacheReadTokens: cur.cacheReadTokens,
|
|
191
|
+
cacheCreateTokens: cur.cacheCreateTokens,
|
|
192
|
+
recordedAt: now.toISOString(),
|
|
193
|
+
epoch: prevEpoch,
|
|
194
|
+
};
|
|
195
|
+
if (deltaInput < 0 || deltaOutput < 0 || deltaCacheRead < 0 || deltaCacheCreate < 0) {
|
|
196
|
+
// Cumulative shrank (/clear, rotation): re-anchor, never write negatives.
|
|
197
|
+
// The epoch bump keeps a later identical totals transition from reusing
|
|
198
|
+
// a pre-reset recordId.
|
|
199
|
+
baseline.epoch = prevEpoch + 1;
|
|
200
|
+
sessionBaselineMemory.set(baselineMemoryKey(args.larkAppId, args.sessionId), baseline);
|
|
201
|
+
state.sessions[args.sessionId] = baseline;
|
|
202
|
+
saveState(dir, args.larkAppId, state, now);
|
|
203
|
+
return null;
|
|
204
|
+
}
|
|
205
|
+
if (deltaInput === 0 && deltaOutput === 0 && deltaCacheRead === 0 && deltaCacheCreate === 0) {
|
|
206
|
+
return null;
|
|
207
|
+
}
|
|
208
|
+
const record = {
|
|
209
|
+
v: 1,
|
|
210
|
+
recordId: deterministicRecordId(args.sessionId, prevEpoch, prev, cur),
|
|
211
|
+
ts: now.toISOString(),
|
|
212
|
+
epoch: prevEpoch,
|
|
213
|
+
...(args.larkAppId ? { larkAppId: args.larkAppId } : {}),
|
|
214
|
+
sessionId: args.sessionId,
|
|
215
|
+
...(args.cliId ? { cliId: args.cliId } : {}),
|
|
216
|
+
...(args.cliSessionId ? { cliSessionId: args.cliSessionId } : {}),
|
|
217
|
+
...(args.chatId ? { chatId: args.chatId } : {}),
|
|
218
|
+
...(args.title ? { title: args.title } : {}),
|
|
219
|
+
...(args.workingDir ? { workingDir: args.workingDir } : {}),
|
|
220
|
+
...(args.callerOpenId ? { callerOpenId: args.callerOpenId } : {}),
|
|
221
|
+
model: cur.model,
|
|
222
|
+
inputTokens: deltaInput,
|
|
223
|
+
outputTokens: deltaOutput,
|
|
224
|
+
cacheReadTokens: deltaCacheRead,
|
|
225
|
+
cacheCreateTokens: deltaCacheCreate,
|
|
226
|
+
totalInputTokens: cur.inputTokens,
|
|
227
|
+
totalOutputTokens: cur.outputTokens,
|
|
228
|
+
totalCacheReadTokens: cur.cacheReadTokens,
|
|
229
|
+
totalCacheCreateTokens: cur.cacheCreateTokens,
|
|
230
|
+
};
|
|
231
|
+
// Append first, then advance the baseline: a crash in between replays the
|
|
232
|
+
// same transition with the SAME recordId, which the consumer dedupes.
|
|
233
|
+
appendFileSync(ledgerFilePath(dir, now), JSON.stringify(record) + '\n');
|
|
234
|
+
// Memory advances immediately after the append: even if saveState throws
|
|
235
|
+
// without killing the process, this process will not re-bill the interval.
|
|
236
|
+
sessionBaselineMemory.set(baselineMemoryKey(args.larkAppId, args.sessionId), baseline);
|
|
237
|
+
state.sessions[args.sessionId] = baseline;
|
|
238
|
+
saveState(dir, args.larkAppId, state, now);
|
|
239
|
+
return record;
|
|
240
|
+
}
|
|
241
|
+
catch (err) {
|
|
242
|
+
// The ledger must never take the daemon down with it.
|
|
243
|
+
logger.error(`usage-ledger: failed to record session usage: ${err?.message ?? err}`);
|
|
244
|
+
return null;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Re-anchor a session's baseline to the current cumulative snapshot WITHOUT
|
|
249
|
+
* writing a record. Called at worker spawn: anything already in the
|
|
250
|
+
* transcript at that point (resumed history, direct-tmux use while the
|
|
251
|
+
* daemon was down) stays out of the ledger — only growth that happens while
|
|
252
|
+
* botmux drives the session is recorded.
|
|
253
|
+
*/
|
|
254
|
+
export function anchorSessionUsage(args) {
|
|
255
|
+
try {
|
|
256
|
+
const now = args.now ?? new Date();
|
|
257
|
+
const dir = args.ledgerDir ?? defaultLedgerDir();
|
|
258
|
+
mkdirSync(dir, { recursive: true });
|
|
259
|
+
const state = loadState(dir, args.larkAppId);
|
|
260
|
+
const prev = resolveBaseline(dir, args.larkAppId, args.sessionId, state.sessions[args.sessionId]);
|
|
261
|
+
const baseline = {
|
|
262
|
+
inputTokens: args.usage.inputTokens,
|
|
263
|
+
outputTokens: args.usage.outputTokens,
|
|
264
|
+
cacheReadTokens: args.usage.cacheReadTokens,
|
|
265
|
+
cacheCreateTokens: args.usage.cacheCreateTokens,
|
|
266
|
+
recordedAt: now.toISOString(),
|
|
267
|
+
// Anchors start a new epoch: transitions after a re-anchor must never
|
|
268
|
+
// collide with recordIds from before it.
|
|
269
|
+
epoch: (prev?.epoch ?? 0) + 1,
|
|
270
|
+
};
|
|
271
|
+
sessionBaselineMemory.set(baselineMemoryKey(args.larkAppId, args.sessionId), baseline);
|
|
272
|
+
state.sessions[args.sessionId] = baseline;
|
|
273
|
+
saveState(dir, args.larkAppId, state, now);
|
|
274
|
+
}
|
|
275
|
+
catch (err) {
|
|
276
|
+
logger.error(`usage-ledger: failed to anchor session baseline: ${err?.message ?? err}`);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
function ledgerArgsForDaemonSession(ds) {
|
|
280
|
+
const s = ds.session;
|
|
281
|
+
const workingDir = ds.workingDir ?? s.workingDir;
|
|
282
|
+
// fresh: ledger snapshots are turn-boundary exact — bypass the dashboard
|
|
283
|
+
// read throttle (incremental folding keeps this cheap).
|
|
284
|
+
const usage = getSessionTokenUsage({
|
|
285
|
+
cliId: s.cliId ?? 'unknown',
|
|
286
|
+
sessionId: s.sessionId,
|
|
287
|
+
cliSessionId: s.cliSessionId,
|
|
288
|
+
cwd: workingDir,
|
|
289
|
+
fresh: true,
|
|
290
|
+
});
|
|
291
|
+
return {
|
|
292
|
+
sessionId: s.sessionId,
|
|
293
|
+
usage,
|
|
294
|
+
larkAppId: ds.larkAppId ?? s.larkAppId,
|
|
295
|
+
cliId: s.cliId,
|
|
296
|
+
cliSessionId: s.cliSessionId,
|
|
297
|
+
chatId: s.chatId,
|
|
298
|
+
title: s.title,
|
|
299
|
+
workingDir,
|
|
300
|
+
callerOpenId: s.lastCallerOpenId ?? s.creatorOpenId ?? s.ownerOpenId,
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
/** Turn boundary (idle/limited edge, session close): append the delta. */
|
|
304
|
+
export function recordUsageForDaemonSession(ds, opts) {
|
|
305
|
+
try {
|
|
306
|
+
const args = ledgerArgsForDaemonSession(ds);
|
|
307
|
+
if (!args.usage)
|
|
308
|
+
return null;
|
|
309
|
+
return recordSessionUsage({ ...args, usage: args.usage, ...opts });
|
|
310
|
+
}
|
|
311
|
+
catch (err) {
|
|
312
|
+
logger.error(`usage-ledger: failed to record daemon session usage: ${err?.message ?? err}`);
|
|
313
|
+
return null;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Daemon-restart restore: a turn that was in flight when the daemon died may
|
|
318
|
+
* have finished inside tmux while we were away — that work was submitted by
|
|
319
|
+
* botmux and belongs in the ledger. If the session already has a baseline,
|
|
320
|
+
* record the catch-up delta; only sessions the ledger has never seen are
|
|
321
|
+
* anchored (their transcript history predates botmux bookkeeping).
|
|
322
|
+
*/
|
|
323
|
+
export function reconcileUsageForDaemonSession(ds, opts) {
|
|
324
|
+
try {
|
|
325
|
+
const args = ledgerArgsForDaemonSession(ds);
|
|
326
|
+
if (!args.usage)
|
|
327
|
+
return null;
|
|
328
|
+
const dir = opts?.ledgerDir ?? defaultLedgerDir();
|
|
329
|
+
const state = loadState(dir, args.larkAppId);
|
|
330
|
+
if (resolveBaseline(dir, args.larkAppId, args.sessionId, state.sessions[args.sessionId])) {
|
|
331
|
+
return recordSessionUsage({ ...args, usage: args.usage, ...opts });
|
|
332
|
+
}
|
|
333
|
+
anchorSessionUsage({ ...args, usage: args.usage, ...opts });
|
|
334
|
+
return null;
|
|
335
|
+
}
|
|
336
|
+
catch (err) {
|
|
337
|
+
logger.error(`usage-ledger: failed to reconcile daemon session usage: ${err?.message ?? err}`);
|
|
338
|
+
return null;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
/** Worker spawn: re-anchor so pre-existing transcript history is not billed. */
|
|
342
|
+
export function anchorUsageForDaemonSession(ds, opts) {
|
|
343
|
+
try {
|
|
344
|
+
const args = ledgerArgsForDaemonSession(ds);
|
|
345
|
+
if (!args.usage)
|
|
346
|
+
return;
|
|
347
|
+
anchorSessionUsage({ ...args, usage: args.usage, ...opts });
|
|
348
|
+
}
|
|
349
|
+
catch (err) {
|
|
350
|
+
logger.error(`usage-ledger: failed to anchor daemon session usage: ${err?.message ?? err}`);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
//# sourceMappingURL=usage-ledger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usage-ledger.js","sourceRoot":"","sources":["../../src/services/usage-ledger.ts"],"names":[],"mappings":"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"}
|