crewly 1.20.73 → 1.20.75

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.
Files changed (51) hide show
  1. package/dist/backend/backend/src/constants.d.ts +64 -0
  2. package/dist/backend/backend/src/constants.d.ts.map +1 -1
  3. package/dist/backend/backend/src/constants.js +64 -0
  4. package/dist/backend/backend/src/constants.js.map +1 -1
  5. package/dist/backend/backend/src/controllers/browser/browser.controller.d.ts +49 -0
  6. package/dist/backend/backend/src/controllers/browser/browser.controller.d.ts.map +1 -1
  7. package/dist/backend/backend/src/controllers/browser/browser.controller.js +119 -0
  8. package/dist/backend/backend/src/controllers/browser/browser.controller.js.map +1 -1
  9. package/dist/backend/backend/src/controllers/browser/browser.routes.d.ts.map +1 -1
  10. package/dist/backend/backend/src/controllers/browser/browser.routes.js +8 -1
  11. package/dist/backend/backend/src/controllers/browser/browser.routes.js.map +1 -1
  12. package/dist/backend/backend/src/index.d.ts.map +1 -1
  13. package/dist/backend/backend/src/index.js +55 -5
  14. package/dist/backend/backend/src/index.js.map +1 -1
  15. package/dist/backend/backend/src/services/agent/context-window-monitor.service.d.ts +61 -0
  16. package/dist/backend/backend/src/services/agent/context-window-monitor.service.d.ts.map +1 -1
  17. package/dist/backend/backend/src/services/agent/context-window-monitor.service.js +111 -2
  18. package/dist/backend/backend/src/services/agent/context-window-monitor.service.js.map +1 -1
  19. package/dist/backend/backend/src/services/browser/browser-session.service.d.ts +261 -0
  20. package/dist/backend/backend/src/services/browser/browser-session.service.d.ts.map +1 -0
  21. package/dist/backend/backend/src/services/browser/browser-session.service.js +432 -0
  22. package/dist/backend/backend/src/services/browser/browser-session.service.js.map +1 -0
  23. package/dist/backend/backend/src/services/monitoring/claude-transcript-sync.service.d.ts +221 -0
  24. package/dist/backend/backend/src/services/monitoring/claude-transcript-sync.service.d.ts.map +1 -0
  25. package/dist/backend/backend/src/services/monitoring/claude-transcript-sync.service.js +484 -0
  26. package/dist/backend/backend/src/services/monitoring/claude-transcript-sync.service.js.map +1 -0
  27. package/dist/backend/backend/src/services/monitoring/model-pricing.d.ts +97 -0
  28. package/dist/backend/backend/src/services/monitoring/model-pricing.d.ts.map +1 -0
  29. package/dist/backend/backend/src/services/monitoring/model-pricing.js +120 -0
  30. package/dist/backend/backend/src/services/monitoring/model-pricing.js.map +1 -0
  31. package/dist/backend/backend/src/services/monitoring/token-usage.service.d.ts +8 -0
  32. package/dist/backend/backend/src/services/monitoring/token-usage.service.d.ts.map +1 -1
  33. package/dist/backend/backend/src/services/monitoring/token-usage.service.js +1 -1
  34. package/dist/backend/backend/src/services/monitoring/token-usage.service.js.map +1 -1
  35. package/dist/backend/build-info.json +2 -2
  36. package/dist/cli/backend/src/constants.d.ts +64 -0
  37. package/dist/cli/backend/src/constants.d.ts.map +1 -1
  38. package/dist/cli/backend/src/constants.js +64 -0
  39. package/dist/cli/backend/src/constants.js.map +1 -1
  40. package/dist/cli/backend/src/services/agent/context-window-monitor.service.d.ts +61 -0
  41. package/dist/cli/backend/src/services/agent/context-window-monitor.service.d.ts.map +1 -1
  42. package/dist/cli/backend/src/services/agent/context-window-monitor.service.js +111 -2
  43. package/dist/cli/backend/src/services/agent/context-window-monitor.service.js.map +1 -1
  44. package/dist/cli/backend/src/services/monitoring/token-usage.service.d.ts +8 -0
  45. package/dist/cli/backend/src/services/monitoring/token-usage.service.d.ts.map +1 -1
  46. package/dist/cli/backend/src/services/monitoring/token-usage.service.js +1 -1
  47. package/dist/cli/backend/src/services/monitoring/token-usage.service.js.map +1 -1
  48. package/frontend/dist/assets/{index-26a16b91.css → index-a6480a0f.css} +1 -1
  49. package/frontend/dist/assets/{index-320b73bf.js → index-cc910352.js} +259 -259
  50. package/frontend/dist/index.html +2 -2
  51. package/package.json +1 -1
@@ -0,0 +1,484 @@
1
+ /**
2
+ * Claude Transcript Sync Service
3
+ *
4
+ * Keeps the Usage dashboard honest for `claude-code` agents by reading the
5
+ * exact per-turn `usage` block that Claude Code writes into its own session
6
+ * transcript, and feeding it into {@link TokenUsageService}.
7
+ *
8
+ * This replaces a boot-time sync that never recorded anything. That version
9
+ * had four defects, each of which this module exists to avoid:
10
+ *
11
+ * 1. It derived the transcript directory from `CREWLY_HOME`, but agents run
12
+ * with their project as the working directory, so it always read an empty
13
+ * or absent folder. We take each session's real `cwd` from
14
+ * {@link SessionStatePersistence} instead.
15
+ * 2. It ran once at startup, so nothing an agent did afterwards was counted.
16
+ * We poll on an interval and read only the bytes appended since last time.
17
+ * 3. It keyed records on the Claude conversation UUID and re-added the whole
18
+ * running total on every call, so a restart double-counted the entire
19
+ * history. We key on the Crewly session name and keep a byte cursor plus a
20
+ * recent-message-id set so a turn is counted exactly once.
21
+ * 4. Its price table stopped at an older model generation, so current models
22
+ * silently fell through to the sonnet default. Pricing now lives in
23
+ * {@link module:services/monitoring/model-pricing} and reports whether a
24
+ * rate was an exact match.
25
+ *
26
+ * As a side effect the sync knows each agent's true context size — the sum of
27
+ * fresh, cached and cache-written input on its most recent turn — which is the
28
+ * only reliable source for it, since Claude Code's TUI context readout is not
29
+ * capturable from PTY scrollback. That number is handed to an observer so the
30
+ * context-window monitor can act on real figures.
31
+ *
32
+ * @module services/monitoring/claude-transcript-sync
33
+ */
34
+ import { promises as fs } from 'fs';
35
+ import * as path from 'path';
36
+ import * as os from 'os';
37
+ import { LoggerService } from '../core/logger.service.js';
38
+ import { getSessionStatePersistence } from '../session/session-state-persistence.js';
39
+ import { TokenUsageService } from './token-usage.service.js';
40
+ import { calculateCost } from './model-pricing.js';
41
+ import { CLAUDE_TRANSCRIPT_SYNC_CONSTANTS } from '../../constants.js';
42
+ import { encodeProjectSlug } from './claude-session-tokens.service.js';
43
+ /**
44
+ * Reads Claude Code transcripts on an interval and records exact token usage.
45
+ *
46
+ * @example
47
+ * ```typescript
48
+ * const sync = ClaudeTranscriptSyncService.getInstance();
49
+ * sync.onContextReading((r) => monitor.updateContextTokens(r.sessionName, r.contextTokens));
50
+ * await sync.start();
51
+ * ```
52
+ */
53
+ export class ClaudeTranscriptSyncService {
54
+ static instance = null;
55
+ logger;
56
+ cursorFile;
57
+ /**
58
+ * Home directory that `~/.claude/projects` is resolved against.
59
+ *
60
+ * Injectable because `os.homedir()` does not reliably follow a `$HOME`
61
+ * override once the process has already resolved it, which makes it
62
+ * untestable against a temp tree.
63
+ */
64
+ homeDir;
65
+ cursors = new Map();
66
+ timer = null;
67
+ observers = [];
68
+ loaded = false;
69
+ /** Guards against a slow pass overlapping the next tick. */
70
+ running = false;
71
+ /**
72
+ * @param cursorFile - Override the cursor persistence path (tests)
73
+ * @param homeDir - Override the home directory transcripts live under (tests)
74
+ */
75
+ constructor(cursorFile, homeDir) {
76
+ this.logger = LoggerService.getInstance().createComponentLogger('ClaudeTranscriptSync');
77
+ this.homeDir = homeDir ?? os.homedir();
78
+ this.cursorFile =
79
+ cursorFile ?? path.join(this.homeDir, '.crewly', CLAUDE_TRANSCRIPT_SYNC_CONSTANTS.CURSOR_FILE);
80
+ }
81
+ /**
82
+ * Get the shared instance.
83
+ *
84
+ * @returns The singleton service
85
+ */
86
+ static getInstance() {
87
+ if (!ClaudeTranscriptSyncService.instance) {
88
+ ClaudeTranscriptSyncService.instance = new ClaudeTranscriptSyncService();
89
+ }
90
+ return ClaudeTranscriptSyncService.instance;
91
+ }
92
+ /** Drops the singleton and stops its timer (tests). */
93
+ static resetInstance() {
94
+ ClaudeTranscriptSyncService.instance?.stop();
95
+ ClaudeTranscriptSyncService.instance = null;
96
+ }
97
+ /**
98
+ * Register a callback to receive each session's context size per pass.
99
+ *
100
+ * @param observer - Invoked once per session that produced a new turn
101
+ */
102
+ onContextReading(observer) {
103
+ this.observers.push(observer);
104
+ }
105
+ /**
106
+ * Load cursors, run one pass immediately, then poll.
107
+ *
108
+ * Safe to call twice; the second call is a no-op.
109
+ */
110
+ async start() {
111
+ if (this.timer)
112
+ return;
113
+ await this.loadCursors();
114
+ await this.sync();
115
+ this.timer = setInterval(() => {
116
+ void this.sync();
117
+ }, CLAUDE_TRANSCRIPT_SYNC_CONSTANTS.SYNC_INTERVAL_MS);
118
+ // Never hold the event loop open for a metrics poll.
119
+ this.timer.unref?.();
120
+ this.logger.info('Claude transcript sync started', {
121
+ intervalMs: CLAUDE_TRANSCRIPT_SYNC_CONSTANTS.SYNC_INTERVAL_MS,
122
+ cursorFile: this.cursorFile,
123
+ });
124
+ }
125
+ /** Stops polling. Cursors already on disk are left alone. */
126
+ stop() {
127
+ if (this.timer) {
128
+ clearInterval(this.timer);
129
+ this.timer = null;
130
+ }
131
+ }
132
+ /**
133
+ * Run one sync pass across every registered claude-code session.
134
+ *
135
+ * Overlapping calls are dropped rather than queued — a pass that outruns
136
+ * the interval means the machine is busy, and piling up reads of
137
+ * multi-megabyte transcripts would make that worse.
138
+ *
139
+ * @returns What the pass counted
140
+ */
141
+ async sync() {
142
+ const result = {
143
+ sessionsUpdated: 0,
144
+ turnsCounted: 0,
145
+ costAdded: 0,
146
+ sessionsWithoutTranscript: 0,
147
+ };
148
+ if (this.running)
149
+ return result;
150
+ this.running = true;
151
+ try {
152
+ if (!this.loaded)
153
+ await this.loadCursors();
154
+ const sessions = getSessionStatePersistence().getRegisteredSessionsMap();
155
+ // Several agents commonly work in one repo. Count them up front so
156
+ // transcript resolution knows when a directory cannot identify a
157
+ // single agent.
158
+ const perCwd = new Map();
159
+ for (const info of sessions.values()) {
160
+ if (info.runtimeType !== 'claude-code' || !info.cwd)
161
+ continue;
162
+ perCwd.set(info.cwd, (perCwd.get(info.cwd) ?? 0) + 1);
163
+ }
164
+ for (const [sessionName, info] of sessions) {
165
+ // Only Claude Code writes the transcripts this service reads.
166
+ if (info.runtimeType !== 'claude-code')
167
+ continue;
168
+ if (!info.cwd)
169
+ continue;
170
+ const filePath = await this.resolveTranscript(info.cwd, info.claudeSessionId, (perCwd.get(info.cwd) ?? 0) > 1);
171
+ if (!filePath) {
172
+ result.sessionsWithoutTranscript += 1;
173
+ continue;
174
+ }
175
+ const counted = await this.syncOne(sessionName, filePath);
176
+ if (counted.turns > 0) {
177
+ result.sessionsUpdated += 1;
178
+ result.turnsCounted += counted.turns;
179
+ result.costAdded += counted.cost;
180
+ }
181
+ else {
182
+ // No new turns, but the agent is still carrying whatever it
183
+ // was carrying. Re-announce it so a monitor that started
184
+ // after the first reading still learns the figure.
185
+ const known = this.cursors.get(sessionName)?.lastContextTokens;
186
+ if (known !== undefined) {
187
+ this.emitContext({ sessionName, contextTokens: known, model: '' });
188
+ }
189
+ }
190
+ }
191
+ if (result.sessionsUpdated > 0) {
192
+ await this.saveCursors();
193
+ this.logger.info('Synced Claude transcripts', result);
194
+ }
195
+ }
196
+ catch (err) {
197
+ // A metrics poll must never take the server down.
198
+ this.logger.warn('Claude transcript sync pass failed', {
199
+ error: err instanceof Error ? err.message : String(err),
200
+ });
201
+ }
202
+ finally {
203
+ this.running = false;
204
+ }
205
+ return result;
206
+ }
207
+ /**
208
+ * Locate a session's transcript file.
209
+ *
210
+ * Prefers the conversation id Crewly recorded when it launched the agent.
211
+ * Falls back to the newest transcript in the project's slug directory,
212
+ * which covers an agent whose id has not been captured yet.
213
+ *
214
+ * @param cwd - The agent's working directory
215
+ * @param claudeSessionId - Conversation id, when known
216
+ * @param cwdIsShared - Whether another registered session works in the
217
+ * same directory, which makes newest-wins unsafe
218
+ * @returns Absolute path, or null when nothing readable exists
219
+ */
220
+ async resolveTranscript(cwd, claudeSessionId, cwdIsShared) {
221
+ const dir = path.join(this.homeDir, '.claude', 'projects', encodeProjectSlug(cwd));
222
+ if (claudeSessionId) {
223
+ const direct = path.join(dir, `${claudeSessionId}.jsonl`);
224
+ try {
225
+ await fs.access(direct);
226
+ return direct;
227
+ }
228
+ catch {
229
+ // Recorded id has no file — fall through to newest-wins.
230
+ }
231
+ }
232
+ // Newest transcript in the project directory. Covers an agent whose
233
+ // conversation id Crewly has not captured yet.
234
+ //
235
+ // Only safe when this agent is the sole one working in this directory.
236
+ // Several agents in one repo share a slug directory, so newest-wins
237
+ // would hand all of them the same transcript and attribute one busy
238
+ // agent's turns — and its context size — to every one of its
239
+ // colleagues. Observed exactly that: four agents each reported the
240
+ // same 726,475 tokens, which was one agent's figure. Waiting for the
241
+ // conversation id costs a little early data; guessing costs the
242
+ // dashboard its meaning.
243
+ if (cwdIsShared)
244
+ return null;
245
+ let files;
246
+ try {
247
+ files = await fs.readdir(dir);
248
+ }
249
+ catch {
250
+ return null;
251
+ }
252
+ let newest = '';
253
+ let newestMtime = -1;
254
+ for (const file of files) {
255
+ if (!file.endsWith('.jsonl'))
256
+ continue;
257
+ try {
258
+ const { mtimeMs } = await fs.stat(path.join(dir, file));
259
+ if (mtimeMs > newestMtime) {
260
+ newestMtime = mtimeMs;
261
+ newest = file;
262
+ }
263
+ }
264
+ catch {
265
+ continue;
266
+ }
267
+ }
268
+ return newest ? path.join(dir, newest) : null;
269
+ }
270
+ /**
271
+ * Consume the unread tail of one transcript and record what it holds.
272
+ *
273
+ * @param sessionName - Crewly session name, used as the usage key
274
+ * @param filePath - Transcript to read
275
+ * @returns Turns counted and cost added for this session
276
+ */
277
+ async syncOne(sessionName, filePath) {
278
+ let cursor = this.cursors.get(sessionName);
279
+ // A different transcript means the agent was given a new conversation
280
+ // (a fresh session id, not a resume). Start its cursor over, but keep
281
+ // the cost so the dashboard shows the agent's lifetime spend.
282
+ if (!cursor || cursor.filePath !== filePath) {
283
+ cursor = { filePath, offset: 0, seenMessageIds: [], cost: cursor?.cost ?? 0 };
284
+ this.cursors.set(sessionName, cursor);
285
+ }
286
+ let size;
287
+ try {
288
+ size = (await fs.stat(filePath)).size;
289
+ }
290
+ catch {
291
+ return { turns: 0, cost: 0 };
292
+ }
293
+ // Truncated or rotated underneath us — re-read from the top rather
294
+ // than seeking past the end and silently counting nothing forever.
295
+ if (size < cursor.offset) {
296
+ cursor.offset = 0;
297
+ cursor.seenMessageIds = [];
298
+ }
299
+ if (size === cursor.offset)
300
+ return { turns: 0, cost: 0 };
301
+ const tail = await this.readFrom(filePath, cursor.offset, size);
302
+ // Only advance past whole lines; a partial trailing line is re-read next pass.
303
+ const lastNewline = tail.lastIndexOf('\n');
304
+ if (lastNewline < 0)
305
+ return { turns: 0, cost: 0 };
306
+ const complete = tail.slice(0, lastNewline);
307
+ const consumedBytes = Buffer.byteLength(complete, 'utf-8') + 1;
308
+ const seen = new Set(cursor.seenMessageIds);
309
+ const turns = this.parseTurns(complete, seen);
310
+ cursor.offset += consumedBytes;
311
+ if (turns.length === 0)
312
+ return { turns: 0, cost: 0 };
313
+ const tokenSvc = TokenUsageService.getInstance();
314
+ let costAdded = 0;
315
+ let latest = null;
316
+ for (const turn of turns) {
317
+ const { cost } = calculateCost({ input: turn.input, output: turn.output, cacheRead: turn.cacheRead, cacheWrite: turn.cacheWrite }, turn.model);
318
+ costAdded += cost;
319
+ // `input` stays the fresh-token count so the dashboard's input
320
+ // column means what it says; cached tokens ride along in `detail`
321
+ // and are what make the cost figure meaningful.
322
+ tokenSvc.recordUsage(sessionName, sessionName, turn.input, turn.output, turn.model, undefined, {
323
+ cachedInput: turn.cacheRead + turn.cacheWrite,
324
+ timestamp: turn.timestamp,
325
+ });
326
+ seen.add(turn.messageId);
327
+ latest = turn;
328
+ }
329
+ cursor.cost += costAdded;
330
+ tokenSvc.overrideSessionCost(sessionName, cursor.cost);
331
+ // Keep the dedupe set bounded — only the newest ids can collide with
332
+ // a line Claude Code rewrites.
333
+ cursor.seenMessageIds = Array.from(seen).slice(-CLAUDE_TRANSCRIPT_SYNC_CONSTANTS.MAX_DEDUPE_IDS);
334
+ if (latest) {
335
+ const contextTokens = latest.input + latest.cacheRead + latest.cacheWrite;
336
+ cursor.lastContextTokens = contextTokens;
337
+ this.emitContext({ sessionName, contextTokens, model: latest.model });
338
+ }
339
+ return { turns: turns.length, cost: costAdded };
340
+ }
341
+ /**
342
+ * Read a byte range of a file as UTF-8.
343
+ *
344
+ * Reads only the new tail; these transcripts reach tens of megabytes and
345
+ * loading one whole on every poll is what makes a naive version of this
346
+ * service more expensive than the usage it measures.
347
+ *
348
+ * @param filePath - File to read
349
+ * @param start - First byte to read
350
+ * @param end - Exclusive end byte
351
+ * @returns The decoded slice
352
+ */
353
+ async readFrom(filePath, start, end) {
354
+ const handle = await fs.open(filePath, 'r');
355
+ try {
356
+ const length = end - start;
357
+ const buf = Buffer.alloc(length);
358
+ await handle.read(buf, 0, length, start);
359
+ return buf.toString('utf-8');
360
+ }
361
+ finally {
362
+ await handle.close();
363
+ }
364
+ }
365
+ /**
366
+ * Extract the assistant turns from a slice of transcript.
367
+ *
368
+ * @param text - Whole lines of JSONL
369
+ * @param seen - Message ids already counted; matches are skipped
370
+ * @returns Turns in file order
371
+ */
372
+ parseTurns(text, seen) {
373
+ const turns = [];
374
+ for (const line of text.split('\n')) {
375
+ if (!line.trim())
376
+ continue;
377
+ let entry;
378
+ try {
379
+ entry = JSON.parse(line);
380
+ }
381
+ catch {
382
+ continue;
383
+ }
384
+ if (entry.type !== 'assistant')
385
+ continue;
386
+ const msg = entry.message;
387
+ const usage = msg?.usage;
388
+ if (!msg || !usage)
389
+ continue;
390
+ const input = usage.input_tokens || 0;
391
+ const output = usage.output_tokens || 0;
392
+ const cacheRead = usage.cache_read_input_tokens || 0;
393
+ const cacheWrite = usage.cache_creation_input_tokens || 0;
394
+ // Claude Code writes `<synthetic>` entries — cancellations, tool
395
+ // bookkeeping — with an all-zero usage block. They are not model
396
+ // round-trips. Counting them inflates the turn count, and worse,
397
+ // one landing last makes the agent look like it is carrying no
398
+ // context at all: Atlas sat behind three of them reporting 0
399
+ // while actually holding 726k tokens.
400
+ if (input === 0 && output === 0 && cacheRead === 0 && cacheWrite === 0)
401
+ continue;
402
+ const messageId = msg.id || `${entry.timestamp}`;
403
+ if (seen.has(messageId))
404
+ continue;
405
+ seen.add(messageId);
406
+ turns.push({
407
+ messageId,
408
+ timestamp: entry.timestamp || new Date().toISOString(),
409
+ model: msg.model || '',
410
+ input,
411
+ output,
412
+ cacheRead,
413
+ cacheWrite,
414
+ });
415
+ }
416
+ return turns;
417
+ }
418
+ /**
419
+ * Hand a context reading to every observer, isolating their failures.
420
+ *
421
+ * @param reading - The measurement to publish
422
+ */
423
+ emitContext(reading) {
424
+ for (const observer of this.observers) {
425
+ try {
426
+ observer(reading);
427
+ }
428
+ catch (err) {
429
+ this.logger.warn('Context observer threw', {
430
+ sessionName: reading.sessionName,
431
+ error: err instanceof Error ? err.message : String(err),
432
+ });
433
+ }
434
+ }
435
+ }
436
+ /** Reads persisted cursors; a missing or corrupt file starts fresh. */
437
+ async loadCursors() {
438
+ this.loaded = true;
439
+ try {
440
+ const raw = await fs.readFile(this.cursorFile, 'utf-8');
441
+ const parsed = JSON.parse(raw);
442
+ this.cursors = new Map(Object.entries(parsed));
443
+ this.logger.debug('Loaded transcript cursors', { sessions: this.cursors.size });
444
+ }
445
+ catch {
446
+ this.cursors = new Map();
447
+ }
448
+ }
449
+ /** Writes cursors atomically so a crash mid-write cannot corrupt them. */
450
+ async saveCursors() {
451
+ const obj = {};
452
+ for (const [k, v] of this.cursors)
453
+ obj[k] = v;
454
+ const tmp = `${this.cursorFile}.tmp`;
455
+ try {
456
+ await fs.mkdir(path.dirname(this.cursorFile), { recursive: true });
457
+ await fs.writeFile(tmp, JSON.stringify(obj, null, 2), 'utf-8');
458
+ await fs.rename(tmp, this.cursorFile);
459
+ }
460
+ catch (err) {
461
+ this.logger.warn('Failed to persist transcript cursors', {
462
+ error: err instanceof Error ? err.message : String(err),
463
+ });
464
+ }
465
+ }
466
+ /**
467
+ * Current cursor for a session (tests and diagnostics).
468
+ *
469
+ * @param sessionName - Crewly session name
470
+ * @returns The cursor, or undefined if the session has never synced
471
+ */
472
+ getCursor(sessionName) {
473
+ return this.cursors.get(sessionName);
474
+ }
475
+ }
476
+ /**
477
+ * Convenience accessor for the shared sync service.
478
+ *
479
+ * @returns The singleton instance
480
+ */
481
+ export function getClaudeTranscriptSync() {
482
+ return ClaudeTranscriptSyncService.getInstance();
483
+ }
484
+ //# sourceMappingURL=claude-transcript-sync.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-transcript-sync.service.js","sourceRoot":"","sources":["../../../../../../backend/src/services/monitoring/claude-transcript-sync.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,IAAI,CAAC;AACpC,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,EAAE,aAAa,EAAmB,MAAM,2BAA2B,CAAC;AAC3E,OAAO,EAAE,0BAA0B,EAAE,MAAM,yCAAyC,CAAC;AACrF,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,gCAAgC,EAAE,MAAM,oBAAoB,CAAC;AACtE,OAAO,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AAwEvE;;;;;;;;;GASG;AACH,MAAM,OAAO,2BAA2B;IAC/B,MAAM,CAAC,QAAQ,GAAuC,IAAI,CAAC;IAElD,MAAM,CAAkB;IACxB,UAAU,CAAS;IACpC;;;;;;OAMG;IACc,OAAO,CAAS;IACzB,OAAO,GAAkC,IAAI,GAAG,EAAE,CAAC;IACnD,KAAK,GAA0C,IAAI,CAAC;IACpD,SAAS,GAAsB,EAAE,CAAC;IAClC,MAAM,GAAG,KAAK,CAAC;IACvB,4DAA4D;IACpD,OAAO,GAAG,KAAK,CAAC;IAExB;;;OAGG;IACH,YAAY,UAAmB,EAAE,OAAgB;QAChD,IAAI,CAAC,MAAM,GAAG,aAAa,CAAC,WAAW,EAAE,CAAC,qBAAqB,CAAC,sBAAsB,CAAC,CAAC;QACxF,IAAI,CAAC,OAAO,GAAG,OAAO,IAAI,EAAE,CAAC,OAAO,EAAE,CAAC;QACvC,IAAI,CAAC,UAAU;YACd,UAAU,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,EAAE,gCAAgC,CAAC,WAAW,CAAC,CAAC;IACjG,CAAC;IAED;;;;OAIG;IACH,MAAM,CAAC,WAAW;QACjB,IAAI,CAAC,2BAA2B,CAAC,QAAQ,EAAE,CAAC;YAC3C,2BAA2B,CAAC,QAAQ,GAAG,IAAI,2BAA2B,EAAE,CAAC;QAC1E,CAAC;QACD,OAAO,2BAA2B,CAAC,QAAQ,CAAC;IAC7C,CAAC;IAED,uDAAuD;IACvD,MAAM,CAAC,aAAa;QACnB,2BAA2B,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC;QAC7C,2BAA2B,CAAC,QAAQ,GAAG,IAAI,CAAC;IAC7C,CAAC;IAED;;;;OAIG;IACH,gBAAgB,CAAC,QAAyB;QACzC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC/B,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,KAAK;QACV,IAAI,IAAI,CAAC,KAAK;YAAE,OAAO;QACvB,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;QACzB,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;QAClB,IAAI,CAAC,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE;YAC7B,KAAK,IAAI,CAAC,IAAI,EAAE,CAAC;QAClB,CAAC,EAAE,gCAAgC,CAAC,gBAAgB,CAAC,CAAC;QACtD,qDAAqD;QACrD,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC;QACrB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,gCAAgC,EAAE;YAClD,UAAU,EAAE,gCAAgC,CAAC,gBAAgB;YAC7D,UAAU,EAAE,IAAI,CAAC,UAAU;SAC3B,CAAC,CAAC;IACJ,CAAC;IAED,6DAA6D;IAC7D,IAAI;QACH,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YAChB,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC1B,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QACnB,CAAC;IACF,CAAC;IAED;;;;;;;;OAQG;IACH,KAAK,CAAC,IAAI;QACT,MAAM,MAAM,GAAe;YAC1B,eAAe,EAAE,CAAC;YAClB,YAAY,EAAE,CAAC;YACf,SAAS,EAAE,CAAC;YACZ,yBAAyB,EAAE,CAAC;SAC5B,CAAC;QACF,IAAI,IAAI,CAAC,OAAO;YAAE,OAAO,MAAM,CAAC;QAChC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QAEpB,IAAI,CAAC;YACJ,IAAI,CAAC,IAAI,CAAC,MAAM;gBAAE,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;YAE3C,MAAM,QAAQ,GAAG,0BAA0B,EAAE,CAAC,wBAAwB,EAAE,CAAC;YAEzE,mEAAmE;YACnE,iEAAiE;YACjE,gBAAgB;YAChB,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;YACzC,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC;gBACtC,IAAI,IAAI,CAAC,WAAW,KAAK,aAAa,IAAI,CAAC,IAAI,CAAC,GAAG;oBAAE,SAAS;gBAC9D,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YACvD,CAAC;YAED,KAAK,MAAM,CAAC,WAAW,EAAE,IAAI,CAAC,IAAI,QAAQ,EAAE,CAAC;gBAC5C,8DAA8D;gBAC9D,IAAI,IAAI,CAAC,WAAW,KAAK,aAAa;oBAAE,SAAS;gBACjD,IAAI,CAAC,IAAI,CAAC,GAAG;oBAAE,SAAS;gBAExB,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAC5C,IAAI,CAAC,GAAG,EACR,IAAI,CAAC,eAAe,EACpB,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAC/B,CAAC;gBACF,IAAI,CAAC,QAAQ,EAAE,CAAC;oBACf,MAAM,CAAC,yBAAyB,IAAI,CAAC,CAAC;oBACtC,SAAS;gBACV,CAAC;gBAED,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;gBAC1D,IAAI,OAAO,CAAC,KAAK,GAAG,CAAC,EAAE,CAAC;oBACvB,MAAM,CAAC,eAAe,IAAI,CAAC,CAAC;oBAC5B,MAAM,CAAC,YAAY,IAAI,OAAO,CAAC,KAAK,CAAC;oBACrC,MAAM,CAAC,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;gBAClC,CAAC;qBAAM,CAAC;oBACP,4DAA4D;oBAC5D,yDAAyD;oBACzD,mDAAmD;oBACnD,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,iBAAiB,CAAC;oBAC/D,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;wBACzB,IAAI,CAAC,WAAW,CAAC,EAAE,WAAW,EAAE,aAAa,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;oBACpE,CAAC;gBACF,CAAC;YACF,CAAC;YAED,IAAI,MAAM,CAAC,eAAe,GAAG,CAAC,EAAE,CAAC;gBAChC,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;gBACzB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,2BAA2B,EAAE,MAAM,CAAC,CAAC;YACvD,CAAC;QACF,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,kDAAkD;YAClD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,oCAAoC,EAAE;gBACtD,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;aACvD,CAAC,CAAC;QACJ,CAAC;gBAAS,CAAC;YACV,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;QACtB,CAAC;QAED,OAAO,MAAM,CAAC;IACf,CAAC;IAED;;;;;;;;;;;;OAYG;IACK,KAAK,CAAC,iBAAiB,CAC9B,GAAW,EACX,eAAmC,EACnC,WAAoB;QAEpB,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC;QAEnF,IAAI,eAAe,EAAE,CAAC;YACrB,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,eAAe,QAAQ,CAAC,CAAC;YAC1D,IAAI,CAAC;gBACJ,MAAM,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;gBACxB,OAAO,MAAM,CAAC;YACf,CAAC;YAAC,MAAM,CAAC;gBACR,yDAAyD;YAC1D,CAAC;QACF,CAAC;QAED,oEAAoE;QACpE,+CAA+C;QAC/C,EAAE;QACF,uEAAuE;QACvE,oEAAoE;QACpE,oEAAoE;QACpE,6DAA6D;QAC7D,mEAAmE;QACnE,qEAAqE;QACrE,gEAAgE;QAChE,yBAAyB;QACzB,IAAI,WAAW;YAAE,OAAO,IAAI,CAAC;QAE7B,IAAI,KAAe,CAAC;QACpB,IAAI,CAAC;YACJ,KAAK,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC/B,CAAC;QAAC,MAAM,CAAC;YACR,OAAO,IAAI,CAAC;QACb,CAAC;QAED,IAAI,MAAM,GAAG,EAAE,CAAC;QAChB,IAAI,WAAW,GAAG,CAAC,CAAC,CAAC;QACrB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YAC1B,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC;gBAAE,SAAS;YACvC,IAAI,CAAC;gBACJ,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC;gBACxD,IAAI,OAAO,GAAG,WAAW,EAAE,CAAC;oBAC3B,WAAW,GAAG,OAAO,CAAC;oBACtB,MAAM,GAAG,IAAI,CAAC;gBACf,CAAC;YACF,CAAC;YAAC,MAAM,CAAC;gBACR,SAAS;YACV,CAAC;QACF,CAAC;QAED,OAAO,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC/C,CAAC;IAED;;;;;;OAMG;IACK,KAAK,CAAC,OAAO,CAAC,WAAmB,EAAE,QAAgB;QAC1D,IAAI,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QAE3C,sEAAsE;QACtE,sEAAsE;QACtE,8DAA8D;QAC9D,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;YAC7C,MAAM,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,EAAE,cAAc,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,IAAI,CAAC,EAAE,CAAC;YAC9E,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;QACvC,CAAC;QAED,IAAI,IAAY,CAAC;QACjB,IAAI,CAAC;YACJ,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC;QACvC,CAAC;QAAC,MAAM,CAAC;YACR,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;QAC9B,CAAC;QAED,mEAAmE;QACnE,mEAAmE;QACnE,IAAI,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC;YAC1B,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;YAClB,MAAM,CAAC,cAAc,GAAG,EAAE,CAAC;QAC5B,CAAC;QACD,IAAI,IAAI,KAAK,MAAM,CAAC,MAAM;YAAE,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;QAEzD,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAChE,+EAA+E;QAC/E,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;QAC3C,IAAI,WAAW,GAAG,CAAC;YAAE,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;QAClD,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC;QAC5C,MAAM,aAAa,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;QAE/D,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;QAC5C,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QAE9C,MAAM,CAAC,MAAM,IAAI,aAAa,CAAC;QAE/B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;QAErD,MAAM,QAAQ,GAAG,iBAAiB,CAAC,WAAW,EAAE,CAAC;QACjD,IAAI,SAAS,GAAG,CAAC,CAAC;QAClB,IAAI,MAAM,GAAyB,IAAI,CAAC;QAExC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YAC1B,MAAM,EAAE,IAAI,EAAE,GAAG,aAAa,CAC7B,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,EAClG,IAAI,CAAC,KAAK,CACV,CAAC;YACF,SAAS,IAAI,IAAI,CAAC;YAElB,+DAA+D;YAC/D,kEAAkE;YAClE,gDAAgD;YAChD,QAAQ,CAAC,WAAW,CAAC,WAAW,EAAE,WAAW,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,EAAE,SAAS,EAAE;gBAC9F,WAAW,EAAE,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,UAAU;gBAC7C,SAAS,EAAE,IAAI,CAAC,SAAS;aACzB,CAAC,CAAC;YAEH,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACzB,MAAM,GAAG,IAAI,CAAC;QACf,CAAC;QAED,MAAM,CAAC,IAAI,IAAI,SAAS,CAAC;QACzB,QAAQ,CAAC,mBAAmB,CAAC,WAAW,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;QAEvD,qEAAqE;QACrE,+BAA+B;QAC/B,MAAM,CAAC,cAAc,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,gCAAgC,CAAC,cAAc,CAAC,CAAC;QAEjG,IAAI,MAAM,EAAE,CAAC;YACZ,MAAM,aAAa,GAAG,MAAM,CAAC,KAAK,GAAG,MAAM,CAAC,SAAS,GAAG,MAAM,CAAC,UAAU,CAAC;YAC1E,MAAM,CAAC,iBAAiB,GAAG,aAAa,CAAC;YACzC,IAAI,CAAC,WAAW,CAAC,EAAE,WAAW,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;QACvE,CAAC;QAED,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;IACjD,CAAC;IAED;;;;;;;;;;;OAWG;IACK,KAAK,CAAC,QAAQ,CAAC,QAAgB,EAAE,KAAa,EAAE,GAAW;QAClE,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;QAC5C,IAAI,CAAC;YACJ,MAAM,MAAM,GAAG,GAAG,GAAG,KAAK,CAAC;YAC3B,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YACjC,MAAM,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;YACzC,OAAO,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAC9B,CAAC;gBAAS,CAAC;YACV,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;QACtB,CAAC;IACF,CAAC;IAED;;;;;;OAMG;IACK,UAAU,CAAC,IAAY,EAAE,IAAiB;QACjD,MAAM,KAAK,GAAoB,EAAE,CAAC;QAElC,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YACrC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;gBAAE,SAAS;YAE3B,IAAI,KAA8B,CAAC;YACnC,IAAI,CAAC;gBACJ,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAC1B,CAAC;YAAC,MAAM,CAAC;gBACR,SAAS;YACV,CAAC;YACD,IAAI,KAAK,CAAC,IAAI,KAAK,WAAW;gBAAE,SAAS;YAEzC,MAAM,GAAG,GAAG,KAAK,CAAC,OAA8C,CAAC;YACjE,MAAM,KAAK,GAAG,GAAG,EAAE,KAA2C,CAAC;YAC/D,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK;gBAAE,SAAS;YAE7B,MAAM,KAAK,GAAG,KAAK,CAAC,YAAY,IAAI,CAAC,CAAC;YACtC,MAAM,MAAM,GAAG,KAAK,CAAC,aAAa,IAAI,CAAC,CAAC;YACxC,MAAM,SAAS,GAAG,KAAK,CAAC,uBAAuB,IAAI,CAAC,CAAC;YACrD,MAAM,UAAU,GAAG,KAAK,CAAC,2BAA2B,IAAI,CAAC,CAAC;YAE1D,iEAAiE;YACjE,iEAAiE;YACjE,iEAAiE;YACjE,+DAA+D;YAC/D,6DAA6D;YAC7D,sCAAsC;YACtC,IAAI,KAAK,KAAK,CAAC,IAAI,MAAM,KAAK,CAAC,IAAI,SAAS,KAAK,CAAC,IAAI,UAAU,KAAK,CAAC;gBAAE,SAAS;YAEjF,MAAM,SAAS,GAAI,GAAG,CAAC,EAAa,IAAI,GAAG,KAAK,CAAC,SAAmB,EAAE,CAAC;YACvE,IAAI,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC;gBAAE,SAAS;YAClC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;YAEpB,KAAK,CAAC,IAAI,CAAC;gBACV,SAAS;gBACT,SAAS,EAAG,KAAK,CAAC,SAAoB,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;gBAClE,KAAK,EAAG,GAAG,CAAC,KAAgB,IAAI,EAAE;gBAClC,KAAK;gBACL,MAAM;gBACN,SAAS;gBACT,UAAU;aACV,CAAC,CAAC;QACJ,CAAC;QAED,OAAO,KAAK,CAAC;IACd,CAAC;IAED;;;;OAIG;IACK,WAAW,CAAC,OAAuB;QAC1C,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACvC,IAAI,CAAC;gBACJ,QAAQ,CAAC,OAAO,CAAC,CAAC;YACnB,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACd,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,wBAAwB,EAAE;oBAC1C,WAAW,EAAE,OAAO,CAAC,WAAW;oBAChC,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;iBACvD,CAAC,CAAC;YACJ,CAAC;QACF,CAAC;IACF,CAAC;IAED,uEAAuE;IAC/D,KAAK,CAAC,WAAW;QACxB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACnB,IAAI,CAAC;YACJ,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;YACxD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAqC,CAAC;YACnE,IAAI,CAAC,OAAO,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;YAC/C,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,2BAA2B,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;QACjF,CAAC;QAAC,MAAM,CAAC;YACR,IAAI,CAAC,OAAO,GAAG,IAAI,GAAG,EAAE,CAAC;QAC1B,CAAC;IACF,CAAC;IAED,0EAA0E;IAClE,KAAK,CAAC,WAAW;QACxB,MAAM,GAAG,GAAqC,EAAE,CAAC;QACjD,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,OAAO;YAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QAC9C,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,UAAU,MAAM,CAAC;QACrC,IAAI,CAAC;YACJ,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACnE,MAAM,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;YAC/D,MAAM,EAAE,CAAC,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;QACvC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,sCAAsC,EAAE;gBACxD,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;aACvD,CAAC,CAAC;QACJ,CAAC;IACF,CAAC;IAED;;;;;OAKG;IACH,SAAS,CAAC,WAAmB;QAC5B,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IACtC,CAAC;;AAGF;;;;GAIG;AACH,MAAM,UAAU,uBAAuB;IACtC,OAAO,2BAA2B,CAAC,WAAW,EAAE,CAAC;AAClD,CAAC"}
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Model Pricing Table
3
+ *
4
+ * List prices for the runtimes Crewly drives, used to turn raw token counts
5
+ * into a cost figure for the Usage dashboard.
6
+ *
7
+ * Two things to keep in mind when reading a cost produced from this table:
8
+ *
9
+ * 1. These are pay-as-you-go API list prices. An agent running under a Max
10
+ * subscription does not generate a bill at these rates — the number is an
11
+ * API-equivalent, useful for comparing agents against each other and for
12
+ * spotting runaway context, not for reconciling an invoice.
13
+ * 2. Cache reads are far cheaper than fresh input and cache writes are dearer,
14
+ * so a cost computed without splitting them out is wrong by an order of
15
+ * magnitude for a long-lived agent. Every rate here is cache-aware and
16
+ * {@link calculateCost} requires the split.
17
+ *
18
+ * When a model is not listed by name we fall back to its family (the `opus` /
19
+ * `sonnet` / `haiku` substring) and finally to the sonnet tier. The resolved
20
+ * rate carries a `source` so callers can mark an estimated cost as estimated
21
+ * rather than presenting a guess as a measurement.
22
+ *
23
+ * @module services/monitoring/model-pricing
24
+ */
25
+ /** Per-token USD rates for one model, split by how the tokens were billed. */
26
+ export interface ModelRate {
27
+ /** USD per fresh (uncached) input token */
28
+ input: number;
29
+ /** USD per output token */
30
+ output: number;
31
+ /** USD per token read from the prompt cache */
32
+ cacheRead: number;
33
+ /** USD per token written to the prompt cache */
34
+ cacheWrite: number;
35
+ }
36
+ /** A {@link ModelRate} plus how confidently it was matched to the model. */
37
+ export interface ResolvedModelRate extends ModelRate {
38
+ /**
39
+ * `exact` — the model id is listed by name.
40
+ * `family` — matched on an `opus`/`sonnet`/`haiku`/`fable` substring.
41
+ * `default` — nothing matched; the sonnet tier was assumed.
42
+ *
43
+ * Anything other than `exact` means the cost is an estimate.
44
+ */
45
+ source: 'exact' | 'family' | 'default';
46
+ }
47
+ /** Opus-class list price (USD per 1M tokens). */
48
+ export declare const OPUS_TIER: ModelRate;
49
+ /** Sonnet-class list price (USD per 1M tokens). */
50
+ export declare const SONNET_TIER: ModelRate;
51
+ /** Haiku-class list price (USD per 1M tokens), 4.5 generation. */
52
+ export declare const HAIKU_TIER: ModelRate;
53
+ /**
54
+ * Resolves the billing rate for a model id.
55
+ *
56
+ * @param model - Model id as the runtime reported it (e.g. `claude-opus-5`)
57
+ * @returns The rate plus how it was matched; never throws, never returns null
58
+ *
59
+ * @example
60
+ * ```typescript
61
+ * const rate = resolveRate('claude-opus-5'); // source: 'exact'
62
+ * const guess = resolveRate('claude-fable-5-1'); // source: 'family'
63
+ * ```
64
+ */
65
+ export declare function resolveRate(model: string): ResolvedModelRate;
66
+ /** The four token counts that make up one model round-trip. */
67
+ export interface TokenSplit {
68
+ /** Fresh input tokens (not served from cache) */
69
+ input: number;
70
+ /** Output tokens */
71
+ output: number;
72
+ /** Input tokens served from the prompt cache */
73
+ cacheRead: number;
74
+ /** Input tokens written into the prompt cache */
75
+ cacheWrite: number;
76
+ }
77
+ /**
78
+ * Computes the cache-aware cost of one or more model round-trips.
79
+ *
80
+ * @param split - The four token counts; pass 0 for any the runtime omits
81
+ * @param model - Model id as the runtime reported it
82
+ * @returns Cost in USD, and whether the rate was an exact match
83
+ *
84
+ * @example
85
+ * ```typescript
86
+ * const { cost, estimated } = calculateCost(
87
+ * { input: 500, output: 200, cacheRead: 690_000, cacheWrite: 0 },
88
+ * 'claude-opus-5',
89
+ * );
90
+ * ```
91
+ */
92
+ export declare function calculateCost(split: TokenSplit, model: string): {
93
+ cost: number;
94
+ estimated: boolean;
95
+ rateSource: ResolvedModelRate['source'];
96
+ };
97
+ //# sourceMappingURL=model-pricing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-pricing.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/monitoring/model-pricing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,8EAA8E;AAC9E,MAAM,WAAW,SAAS;IACzB,2CAA2C;IAC3C,KAAK,EAAE,MAAM,CAAC;IACd,2BAA2B;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,+CAA+C;IAC/C,SAAS,EAAE,MAAM,CAAC;IAClB,gDAAgD;IAChD,UAAU,EAAE,MAAM,CAAC;CACnB;AAED,4EAA4E;AAC5E,MAAM,WAAW,iBAAkB,SAAQ,SAAS;IACnD;;;;;;OAMG;IACH,MAAM,EAAE,OAAO,GAAG,QAAQ,GAAG,SAAS,CAAC;CACvC;AAYD,iDAAiD;AACjD,eAAO,MAAM,SAAS,WAAiC,CAAC;AACxD,mDAAmD;AACnD,eAAO,MAAM,WAAW,WAA+B,CAAC;AACxD,kEAAkE;AAClE,eAAO,MAAM,UAAU,WAA8B,CAAC;AAsCtD;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,iBAAiB,CAW5D;AAED,+DAA+D;AAC/D,MAAM,WAAW,UAAU;IAC1B,iDAAiD;IACjD,KAAK,EAAE,MAAM,CAAC;IACd,oBAAoB;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,gDAAgD;IAChD,SAAS,EAAE,MAAM,CAAC;IAClB,iDAAiD;IACjD,UAAU,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,aAAa,CAC5B,KAAK,EAAE,UAAU,EACjB,KAAK,EAAE,MAAM,GACX;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,OAAO,CAAC;IAAC,UAAU,EAAE,iBAAiB,CAAC,QAAQ,CAAC,CAAA;CAAE,CAQ/E"}