crewly 1.20.187 → 1.20.188
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/config/skills/agent/core/project-tickets/SKILL.md +3 -2
- package/config/skills/agent/core/project-tickets/execute.sh +4 -4
- package/config/skills/agent/core/project-tickets/execute.test.sh +2 -2
- package/dist/backend/backend/src/constants.d.ts +70 -12
- package/dist/backend/backend/src/constants.d.ts.map +1 -1
- package/dist/backend/backend/src/constants.js +70 -12
- package/dist/backend/backend/src/constants.js.map +1 -1
- package/dist/backend/backend/src/controllers/project-tickets/project-tickets.controller.d.ts +1 -1
- package/dist/backend/backend/src/controllers/project-tickets/project-tickets.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/project-tickets/project-tickets.controller.js +5 -1
- package/dist/backend/backend/src/controllers/project-tickets/project-tickets.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/project-tickets/project-tickets.routes.d.ts +1 -1
- package/dist/backend/backend/src/controllers/project-tickets/project-tickets.routes.js +1 -1
- package/dist/backend/backend/src/controllers/system/usage.controller.d.ts +46 -0
- package/dist/backend/backend/src/controllers/system/usage.controller.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/system/usage.controller.js +181 -0
- package/dist/backend/backend/src/controllers/system/usage.controller.js.map +1 -0
- package/dist/backend/backend/src/index.d.ts +7 -0
- package/dist/backend/backend/src/index.d.ts.map +1 -1
- package/dist/backend/backend/src/index.js +59 -4
- package/dist/backend/backend/src/index.js.map +1 -1
- package/dist/backend/backend/src/routes/modules/system.routes.js +3 -3
- package/dist/backend/backend/src/routes/modules/system.routes.js.map +1 -1
- package/dist/backend/backend/src/services/agent/agent-registration.service.js +7 -7
- package/dist/backend/backend/src/services/agent/agent-registration.service.js.map +1 -1
- package/dist/backend/backend/src/services/messaging/owner-message-watchdog.service.d.ts +4 -2
- package/dist/backend/backend/src/services/messaging/owner-message-watchdog.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/messaging/owner-message-watchdog.service.js +6 -1
- package/dist/backend/backend/src/services/messaging/owner-message-watchdog.service.js.map +1 -1
- package/dist/backend/backend/src/services/messaging/queue-processor.service.js +2 -2
- package/dist/backend/backend/src/services/monitoring/activity-monitor.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/monitoring/activity-monitor.service.js +4 -2
- package/dist/backend/backend/src/services/monitoring/activity-monitor.service.js.map +1 -1
- package/dist/backend/backend/src/services/monitoring/antigravity-usage-sync.service.d.ts +130 -0
- package/dist/backend/backend/src/services/monitoring/antigravity-usage-sync.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/monitoring/antigravity-usage-sync.service.js +274 -0
- package/dist/backend/backend/src/services/monitoring/antigravity-usage-sync.service.js.map +1 -0
- package/dist/backend/backend/src/services/monitoring/codex-rollout-sync.service.d.ts +152 -0
- package/dist/backend/backend/src/services/monitoring/codex-rollout-sync.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/monitoring/codex-rollout-sync.service.js +311 -0
- package/dist/backend/backend/src/services/monitoring/codex-rollout-sync.service.js.map +1 -0
- package/dist/backend/backend/src/services/monitoring/token-usage.service.d.ts +53 -1
- package/dist/backend/backend/src/services/monitoring/token-usage.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/monitoring/token-usage.service.js +51 -3
- package/dist/backend/backend/src/services/monitoring/token-usage.service.js.map +1 -1
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-decision.d.ts +4 -4
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-decision.d.ts.map +1 -1
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-decision.js +1 -1
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-decision.js.map +1 -1
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-messages.d.ts +4 -3
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-messages.d.ts.map +1 -1
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-messages.js +7 -4
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-messages.js.map +1 -1
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot.service.d.ts +40 -9
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot.service.js +68 -20
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot.service.js.map +1 -1
- package/dist/backend/backend/src/services/spend/spend-cap-command.d.ts +48 -18
- package/dist/backend/backend/src/services/spend/spend-cap-command.d.ts.map +1 -1
- package/dist/backend/backend/src/services/spend/spend-cap-command.js +195 -62
- package/dist/backend/backend/src/services/spend/spend-cap-command.js.map +1 -1
- package/dist/backend/backend/src/services/spend/spend-cap.gate.d.ts +11 -15
- package/dist/backend/backend/src/services/spend/spend-cap.gate.d.ts.map +1 -1
- package/dist/backend/backend/src/services/spend/spend-cap.gate.js +8 -13
- package/dist/backend/backend/src/services/spend/spend-cap.gate.js.map +1 -1
- package/dist/backend/backend/src/services/spend/spend-cap.service.d.ts +179 -64
- package/dist/backend/backend/src/services/spend/spend-cap.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/spend/spend-cap.service.js +406 -149
- package/dist/backend/backend/src/services/spend/spend-cap.service.js.map +1 -1
- package/dist/backend/backend/src/services/spend/spend-cap.store.d.ts +52 -11
- package/dist/backend/backend/src/services/spend/spend-cap.store.d.ts.map +1 -1
- package/dist/backend/backend/src/services/spend/spend-cap.store.js +67 -21
- package/dist/backend/backend/src/services/spend/spend-cap.store.js.map +1 -1
- package/dist/backend/backend/src/services/spend/spend-cap.wiring.d.ts +3 -1
- package/dist/backend/backend/src/services/spend/spend-cap.wiring.d.ts.map +1 -1
- package/dist/backend/backend/src/services/spend/spend-cap.wiring.js +21 -7
- package/dist/backend/backend/src/services/spend/spend-cap.wiring.js.map +1 -1
- package/dist/backend/backend/src/services/spend/spend-ledger.service.d.ts +57 -36
- package/dist/backend/backend/src/services/spend/spend-ledger.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/spend/spend-ledger.service.js +80 -55
- package/dist/backend/backend/src/services/spend/spend-ledger.service.js.map +1 -1
- package/dist/backend/backend/src/services/task-pool/work-item-usage.d.ts +10 -1
- package/dist/backend/backend/src/services/task-pool/work-item-usage.d.ts.map +1 -1
- package/dist/backend/backend/src/services/task-pool/work-item-usage.js +2 -0
- package/dist/backend/backend/src/services/task-pool/work-item-usage.js.map +1 -1
- package/dist/backend/backend/src/services/usage/token-format.d.ts +49 -0
- package/dist/backend/backend/src/services/usage/token-format.d.ts.map +1 -0
- package/dist/backend/backend/src/services/usage/token-format.js +81 -0
- package/dist/backend/backend/src/services/usage/token-format.js.map +1 -0
- package/dist/backend/backend/src/services/usage/usage-stats.service.d.ts +132 -0
- package/dist/backend/backend/src/services/usage/usage-stats.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/usage/usage-stats.service.js +226 -0
- package/dist/backend/backend/src/services/usage/usage-stats.service.js.map +1 -0
- package/dist/backend/backend/src/types/decision.types.d.ts +2 -2
- package/dist/backend/backend/src/types/ticket-autopilot.types.d.ts +24 -7
- package/dist/backend/backend/src/types/ticket-autopilot.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/ticket-autopilot.types.js +29 -13
- package/dist/backend/backend/src/types/ticket-autopilot.types.js.map +1 -1
- package/dist/backend/build-info.json +2 -2
- package/dist/cli/backend/src/constants.d.ts +70 -12
- package/dist/cli/backend/src/constants.d.ts.map +1 -1
- package/dist/cli/backend/src/constants.js +70 -12
- package/dist/cli/backend/src/constants.js.map +1 -1
- package/dist/cli/backend/src/services/agent/agent-registration.service.js +7 -7
- package/dist/cli/backend/src/services/agent/agent-registration.service.js.map +1 -1
- package/dist/cli/backend/src/services/messaging/owner-message-watchdog.service.d.ts +4 -2
- package/dist/cli/backend/src/services/messaging/owner-message-watchdog.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/messaging/owner-message-watchdog.service.js +6 -1
- package/dist/cli/backend/src/services/messaging/owner-message-watchdog.service.js.map +1 -1
- package/dist/cli/backend/src/services/messaging/queue-processor.service.js +2 -2
- package/dist/cli/backend/src/services/monitoring/activity-monitor.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/monitoring/activity-monitor.service.js +4 -2
- package/dist/cli/backend/src/services/monitoring/activity-monitor.service.js.map +1 -1
- package/dist/cli/backend/src/services/monitoring/token-usage.service.d.ts +53 -1
- package/dist/cli/backend/src/services/monitoring/token-usage.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/monitoring/token-usage.service.js +51 -3
- package/dist/cli/backend/src/services/monitoring/token-usage.service.js.map +1 -1
- package/dist/cli/backend/src/services/spend/spend-cap.gate.d.ts +11 -15
- package/dist/cli/backend/src/services/spend/spend-cap.gate.d.ts.map +1 -1
- package/dist/cli/backend/src/services/spend/spend-cap.gate.js +8 -13
- package/dist/cli/backend/src/services/spend/spend-cap.gate.js.map +1 -1
- package/dist/cli/backend/src/services/task-pool/work-item-usage.d.ts +10 -1
- package/dist/cli/backend/src/services/task-pool/work-item-usage.d.ts.map +1 -1
- package/dist/cli/backend/src/services/task-pool/work-item-usage.js +2 -0
- package/dist/cli/backend/src/services/task-pool/work-item-usage.js.map +1 -1
- package/dist/cli/backend/src/services/usage/token-format.d.ts +49 -0
- package/dist/cli/backend/src/services/usage/token-format.d.ts.map +1 -0
- package/dist/cli/backend/src/services/usage/token-format.js +81 -0
- package/dist/cli/backend/src/services/usage/token-format.js.map +1 -0
- package/dist/cli/backend/src/types/decision.types.d.ts +2 -2
- package/dist/cli/backend/src/types/ticket-autopilot.types.d.ts +24 -7
- package/dist/cli/backend/src/types/ticket-autopilot.types.d.ts.map +1 -1
- package/dist/cli/backend/src/types/ticket-autopilot.types.js +29 -13
- package/dist/cli/backend/src/types/ticket-autopilot.types.js.map +1 -1
- package/frontend/dist/assets/{index-15c2faf2.js → index-49f50b45.js} +276 -276
- package/frontend/dist/index.html +1 -1
- package/package.json +1 -1
- package/dist/backend/backend/src/controllers/system/spend.controller.d.ts +0 -32
- package/dist/backend/backend/src/controllers/system/spend.controller.d.ts.map +0 -1
- package/dist/backend/backend/src/controllers/system/spend.controller.js +0 -100
- package/dist/backend/backend/src/controllers/system/spend.controller.js.map +0 -1
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Antigravity Usage Sync — records Antigravity CLI (`agy`) token usage in
|
|
3
|
+
* the shared ledger, BEST EFFORT.
|
|
4
|
+
*
|
|
5
|
+
* Where agy keeps usage: one SQLite database per conversation,
|
|
6
|
+
* `~/.gemini/antigravity-cli/conversations/<conversation id>.db`. Its
|
|
7
|
+
* `steps` table holds one row per step; a model-generation step's
|
|
8
|
+
* `metadata` blob is a protobuf whose field 9 is a usage message with the
|
|
9
|
+
* input tokens in field 2 and the output tokens in field 3 (observed on agy
|
|
10
|
+
* 1.x: a one-word prompt read 12,719 in / 169 out). The schema is not
|
|
11
|
+
* published, so:
|
|
12
|
+
*
|
|
13
|
+
* - only blobs that carry exactly that shape are counted; anything else is
|
|
14
|
+
* skipped, never guessed;
|
|
15
|
+
* - agy does not expose cached input there, so Antigravity events have no
|
|
16
|
+
* `cachedInput` (their total = input + output as recorded);
|
|
17
|
+
* - the model is stored as an enum, so events use the model id
|
|
18
|
+
* `antigravity-cli-default`.
|
|
19
|
+
*
|
|
20
|
+
* `agy --output-format stream-json` is print mode only; Crewly runs agy as an
|
|
21
|
+
* interactive PTY, so the conversation database is the only source.
|
|
22
|
+
*
|
|
23
|
+
* Attribution: Crewly records each agy agent's conversation id in the
|
|
24
|
+
* session state right after launch (runtime-session-recovery). Steps are
|
|
25
|
+
* counted once each (a per-conversation set of counted step indexes,
|
|
26
|
+
* persisted under CREWLY_HOME), so passes and restarts are idempotent; a
|
|
27
|
+
* step whose usage is written later is picked up on a later pass.
|
|
28
|
+
*
|
|
29
|
+
* specs/2026-10-02-spend-cap.md §Sources
|
|
30
|
+
*
|
|
31
|
+
* @module services/monitoring/antigravity-usage-sync
|
|
32
|
+
*/
|
|
33
|
+
import { promises as fs } from 'fs';
|
|
34
|
+
import * as path from 'path';
|
|
35
|
+
import { ANTIGRAVITY_CONSTANTS, ANTIGRAVITY_USAGE_SYNC_CONSTANTS as C, RUNTIME_TYPES } from '../../constants.js';
|
|
36
|
+
/**
|
|
37
|
+
* Decode one level of a protobuf message (no schema).
|
|
38
|
+
*
|
|
39
|
+
* @param buf - Message bytes
|
|
40
|
+
* @returns Fields in order, or null when the bytes are not a valid message
|
|
41
|
+
*/
|
|
42
|
+
export function decodeProtoFields(buf) {
|
|
43
|
+
const out = [];
|
|
44
|
+
let i = 0;
|
|
45
|
+
const varint = () => {
|
|
46
|
+
let result = 0;
|
|
47
|
+
let shift = 0;
|
|
48
|
+
while (i < buf.length) {
|
|
49
|
+
const b = buf[i++];
|
|
50
|
+
result += (b & 0x7f) * 2 ** shift;
|
|
51
|
+
if ((b & 0x80) === 0)
|
|
52
|
+
return result;
|
|
53
|
+
shift += 7;
|
|
54
|
+
if (shift > 63)
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
return null;
|
|
58
|
+
};
|
|
59
|
+
while (i < buf.length) {
|
|
60
|
+
const key = varint();
|
|
61
|
+
if (key === null || key === 0)
|
|
62
|
+
return null;
|
|
63
|
+
const field = Math.floor(key / 8);
|
|
64
|
+
const wireType = key % 8;
|
|
65
|
+
if (wireType === 0) {
|
|
66
|
+
const v = varint();
|
|
67
|
+
if (v === null)
|
|
68
|
+
return null;
|
|
69
|
+
out.push({ field, wireType, int: v });
|
|
70
|
+
}
|
|
71
|
+
else if (wireType === 2) {
|
|
72
|
+
const len = varint();
|
|
73
|
+
if (len === null || i + len > buf.length)
|
|
74
|
+
return null;
|
|
75
|
+
out.push({ field, wireType, bytes: buf.subarray(i, i + len) });
|
|
76
|
+
i += len;
|
|
77
|
+
}
|
|
78
|
+
else if (wireType === 1) {
|
|
79
|
+
if (i + 8 > buf.length)
|
|
80
|
+
return null;
|
|
81
|
+
out.push({ field, wireType, int: Number(buf.readBigUInt64LE(i)) });
|
|
82
|
+
i += 8;
|
|
83
|
+
}
|
|
84
|
+
else if (wireType === 5) {
|
|
85
|
+
if (i + 4 > buf.length)
|
|
86
|
+
return null;
|
|
87
|
+
out.push({ field, wireType, int: buf.readUInt32LE(i) });
|
|
88
|
+
i += 4;
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return out;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* The usage a step's metadata blob records.
|
|
98
|
+
*
|
|
99
|
+
* @param metadata - `steps.metadata` blob
|
|
100
|
+
* @returns Input / output tokens, or null when the blob carries no usage
|
|
101
|
+
*/
|
|
102
|
+
export function antigravityStepUsage(metadata) {
|
|
103
|
+
if (!metadata || metadata.length === 0)
|
|
104
|
+
return null;
|
|
105
|
+
const top = decodeProtoFields(metadata);
|
|
106
|
+
const usageField = top?.find((f) => f.field === C.USAGE_FIELD && f.wireType === 2);
|
|
107
|
+
if (!usageField?.bytes)
|
|
108
|
+
return null;
|
|
109
|
+
const usage = decodeProtoFields(usageField.bytes);
|
|
110
|
+
if (!usage)
|
|
111
|
+
return null;
|
|
112
|
+
const input = usage.find((f) => f.field === C.INPUT_FIELD && f.wireType === 0)?.int;
|
|
113
|
+
const output = usage.find((f) => f.field === C.OUTPUT_FIELD && f.wireType === 0)?.int;
|
|
114
|
+
if (typeof input !== 'number' || typeof output !== 'number' || input + output <= 0)
|
|
115
|
+
return null;
|
|
116
|
+
return { input, output };
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Step timestamp: metadata field 1 is a protobuf Timestamp (seconds, nanos).
|
|
120
|
+
*
|
|
121
|
+
* @param metadata - `steps.metadata` blob
|
|
122
|
+
* @returns ISO time, or null
|
|
123
|
+
*/
|
|
124
|
+
export function antigravityStepTime(metadata) {
|
|
125
|
+
const top = decodeProtoFields(metadata);
|
|
126
|
+
const ts = top?.find((f) => f.field === 1 && f.wireType === 2)?.bytes;
|
|
127
|
+
const fields = ts ? decodeProtoFields(ts) : null;
|
|
128
|
+
const seconds = fields?.find((f) => f.field === 1 && f.wireType === 0)?.int;
|
|
129
|
+
if (typeof seconds !== 'number' || seconds <= 0)
|
|
130
|
+
return null;
|
|
131
|
+
const nanos = fields?.find((f) => f.field === 2 && f.wireType === 0)?.int ?? 0;
|
|
132
|
+
return new Date(seconds * 1000 + Math.floor(nanos / 1e6)).toISOString();
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Read step rows with better-sqlite3, read-only.
|
|
136
|
+
*
|
|
137
|
+
* @param nodeRequire - A require able to load `better-sqlite3`
|
|
138
|
+
* @returns Reader
|
|
139
|
+
*/
|
|
140
|
+
export function sqliteStepReader(nodeRequire) {
|
|
141
|
+
return (dbPath) => {
|
|
142
|
+
let db = null;
|
|
143
|
+
try {
|
|
144
|
+
const Database = nodeRequire('better-sqlite3');
|
|
145
|
+
db = new Database(dbPath, { readonly: true, fileMustExist: true });
|
|
146
|
+
return db.prepare('SELECT idx, metadata FROM steps ORDER BY idx').all();
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
finally {
|
|
152
|
+
try {
|
|
153
|
+
db?.close();
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
/* ignore */
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Polls the conversation databases of Crewly's agy agents.
|
|
163
|
+
*/
|
|
164
|
+
export class AntigravityUsageSyncService {
|
|
165
|
+
deps;
|
|
166
|
+
cursors = new Map();
|
|
167
|
+
loaded = false;
|
|
168
|
+
running = false;
|
|
169
|
+
timer = null;
|
|
170
|
+
/** @param deps - Collaborators */
|
|
171
|
+
constructor(deps) {
|
|
172
|
+
this.deps = deps;
|
|
173
|
+
}
|
|
174
|
+
/** Run a pass now, then poll. */
|
|
175
|
+
async start() {
|
|
176
|
+
if (this.timer)
|
|
177
|
+
return;
|
|
178
|
+
await this.sync();
|
|
179
|
+
this.timer = setInterval(() => void this.sync(), C.SYNC_INTERVAL_MS);
|
|
180
|
+
this.timer.unref?.();
|
|
181
|
+
}
|
|
182
|
+
/** Stop polling. */
|
|
183
|
+
stop() {
|
|
184
|
+
if (this.timer)
|
|
185
|
+
clearInterval(this.timer);
|
|
186
|
+
this.timer = null;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* One pass.
|
|
190
|
+
*
|
|
191
|
+
* @returns Events and tokens recorded
|
|
192
|
+
*/
|
|
193
|
+
async sync() {
|
|
194
|
+
const result = { eventsRecorded: 0, tokensRecorded: 0 };
|
|
195
|
+
if (this.running)
|
|
196
|
+
return result;
|
|
197
|
+
this.running = true;
|
|
198
|
+
let changed = false;
|
|
199
|
+
try {
|
|
200
|
+
if (!this.loaded)
|
|
201
|
+
await this.load();
|
|
202
|
+
for (const [session, info] of this.deps.sessions()) {
|
|
203
|
+
const id = info.claudeSessionId;
|
|
204
|
+
if (info.runtimeType !== RUNTIME_TYPES.ANTIGRAVITY_CLI || !id || this.cursors.has(id))
|
|
205
|
+
continue;
|
|
206
|
+
this.cursors.set(id, { session, counted: [], mtimeMs: 0 });
|
|
207
|
+
changed = true;
|
|
208
|
+
}
|
|
209
|
+
for (const [id, cursor] of this.cursors) {
|
|
210
|
+
const dbPath = path.join(this.deps.configDir, ANTIGRAVITY_CONSTANTS.CONVERSATIONS_DIR, `${id}${ANTIGRAVITY_CONSTANTS.CONVERSATION_FILE_EXT}`);
|
|
211
|
+
let mtimeMs;
|
|
212
|
+
try {
|
|
213
|
+
mtimeMs = (await fs.stat(dbPath)).mtimeMs;
|
|
214
|
+
}
|
|
215
|
+
catch {
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
if (mtimeMs === cursor.mtimeMs)
|
|
219
|
+
continue;
|
|
220
|
+
const rows = this.deps.readSteps(dbPath);
|
|
221
|
+
if (!rows)
|
|
222
|
+
continue;
|
|
223
|
+
cursor.mtimeMs = mtimeMs;
|
|
224
|
+
changed = true;
|
|
225
|
+
const counted = new Set(cursor.counted);
|
|
226
|
+
for (const row of rows) {
|
|
227
|
+
if (counted.has(row.idx))
|
|
228
|
+
continue;
|
|
229
|
+
const usage = antigravityStepUsage(row.metadata);
|
|
230
|
+
if (!usage || !row.metadata)
|
|
231
|
+
continue;
|
|
232
|
+
counted.add(row.idx);
|
|
233
|
+
const timestamp = antigravityStepTime(row.metadata) ?? (this.deps.now?.() ?? new Date()).toISOString();
|
|
234
|
+
this.deps.record(cursor.session, { timestamp, model: C.MODEL, input: usage.input, output: usage.output });
|
|
235
|
+
result.eventsRecorded += 1;
|
|
236
|
+
result.tokensRecorded += usage.input + usage.output;
|
|
237
|
+
}
|
|
238
|
+
cursor.counted = [...counted].sort((a, b) => a - b);
|
|
239
|
+
}
|
|
240
|
+
if (changed)
|
|
241
|
+
await this.save();
|
|
242
|
+
if (result.eventsRecorded > 0)
|
|
243
|
+
this.deps.logger?.info('Synced Antigravity usage', result);
|
|
244
|
+
}
|
|
245
|
+
catch (err) {
|
|
246
|
+
this.deps.logger?.warn('Antigravity usage sync pass failed', { error: err instanceof Error ? err.message : String(err) });
|
|
247
|
+
}
|
|
248
|
+
finally {
|
|
249
|
+
this.running = false;
|
|
250
|
+
}
|
|
251
|
+
return result;
|
|
252
|
+
}
|
|
253
|
+
async load() {
|
|
254
|
+
this.loaded = true;
|
|
255
|
+
try {
|
|
256
|
+
this.cursors = new Map(Object.entries(JSON.parse(await fs.readFile(this.deps.cursorFile, 'utf-8'))));
|
|
257
|
+
}
|
|
258
|
+
catch {
|
|
259
|
+
this.cursors = new Map();
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
async save() {
|
|
263
|
+
const tmp = `${this.deps.cursorFile}.tmp`;
|
|
264
|
+
try {
|
|
265
|
+
await fs.mkdir(path.dirname(this.deps.cursorFile), { recursive: true });
|
|
266
|
+
await fs.writeFile(tmp, JSON.stringify(Object.fromEntries(this.cursors), null, 2), 'utf-8');
|
|
267
|
+
await fs.rename(tmp, this.deps.cursorFile);
|
|
268
|
+
}
|
|
269
|
+
catch (err) {
|
|
270
|
+
this.deps.logger?.warn('Could not save Antigravity usage cursors', { error: err instanceof Error ? err.message : String(err) });
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
//# sourceMappingURL=antigravity-usage-sync.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"antigravity-usage-sync.service.js","sourceRoot":"","sources":["../../../../../../backend/src/services/monitoring/antigravity-usage-sync.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Codex Rollout Sync — records Codex CLI token usage in the shared ledger.
|
|
3
|
+
*
|
|
4
|
+
* Codex writes every conversation to `<codexHome>/sessions/YYYY/MM/DD/
|
|
5
|
+
* rollout-<time>-<conversation id>.jsonl`. After each model call it appends
|
|
6
|
+
* an `event_msg` line of type `token_count` whose `info.total_token_usage`
|
|
7
|
+
* is the conversation's running total (OpenAI convention: `input_tokens`
|
|
8
|
+
* includes `cached_input_tokens`; `output_tokens` includes reasoning) and
|
|
9
|
+
* `info.last_token_usage` is that one call. The model comes from the
|
|
10
|
+
* preceding `turn_context` line.
|
|
11
|
+
*
|
|
12
|
+
* Each pass reads only the bytes appended since the last pass (a byte
|
|
13
|
+
* cursor per file, persisted under CREWLY_HOME like the Claude transcript
|
|
14
|
+
* cursors) and records the DELTA of the running total, so a `token_count`
|
|
15
|
+
* line Codex repeats (it re-emits the same totals) is counted once, and a
|
|
16
|
+
* restart never re-counts a file.
|
|
17
|
+
*
|
|
18
|
+
* Attribution: Crewly persists each Codex agent's conversation id (learned
|
|
19
|
+
* from the rollout right after launch, see runtime-session-recovery) in the
|
|
20
|
+
* session state, so the rollout named `…-<id>.jsonl` belongs to that
|
|
21
|
+
* session. A cursor keeps its session after the agent moves to a fresh
|
|
22
|
+
* conversation, so the old file's last turns are still counted. Rollouts no
|
|
23
|
+
* Crewly agent owns (the owner's own Codex use) are never read.
|
|
24
|
+
*
|
|
25
|
+
* Events are stored in the ledger's "cached on top" shape (`input` = fresh
|
|
26
|
+
* tokens, `cachedInput` beside it, `runtime: 'codex-cli'`), the same as
|
|
27
|
+
* Claude transcript turns. specs/2026-10-02-spend-cap.md §Sources.
|
|
28
|
+
*
|
|
29
|
+
* @module services/monitoring/codex-rollout-sync
|
|
30
|
+
*/
|
|
31
|
+
/** Running token totals as Codex reports them. */
|
|
32
|
+
export interface CodexTotals {
|
|
33
|
+
/** All input tokens, cached included */
|
|
34
|
+
input: number;
|
|
35
|
+
cached: number;
|
|
36
|
+
output: number;
|
|
37
|
+
total: number;
|
|
38
|
+
}
|
|
39
|
+
/** Parse state carried from one chunk of a rollout to the next. */
|
|
40
|
+
export interface CodexParseState {
|
|
41
|
+
/** Model of the current turn */
|
|
42
|
+
model: string;
|
|
43
|
+
/** Last running total counted, null before the first */
|
|
44
|
+
lastTotal: CodexTotals | null;
|
|
45
|
+
}
|
|
46
|
+
/** One model call's usage, ready for the ledger. */
|
|
47
|
+
export interface CodexUsageEvent {
|
|
48
|
+
timestamp: string;
|
|
49
|
+
model: string;
|
|
50
|
+
/** Fresh (non-cached) input tokens */
|
|
51
|
+
input: number;
|
|
52
|
+
/** Cached input tokens (on top of `input`) */
|
|
53
|
+
cachedInput: number;
|
|
54
|
+
output: number;
|
|
55
|
+
}
|
|
56
|
+
/** A rollout file's cursor. */
|
|
57
|
+
export interface CodexRolloutCursor {
|
|
58
|
+
/** Crewly session the conversation belongs to */
|
|
59
|
+
session: string;
|
|
60
|
+
/** Codex conversation id */
|
|
61
|
+
conversationId: string;
|
|
62
|
+
/** Bytes already consumed */
|
|
63
|
+
offset: number;
|
|
64
|
+
model: string;
|
|
65
|
+
lastTotal: CodexTotals | null;
|
|
66
|
+
}
|
|
67
|
+
/** A registered agent session, as the sync needs it. */
|
|
68
|
+
export interface CodexSessionInfo {
|
|
69
|
+
runtimeType: string;
|
|
70
|
+
/** Runtime conversation id (Claude session id / Codex conversation id) */
|
|
71
|
+
claudeSessionId?: string;
|
|
72
|
+
}
|
|
73
|
+
/** What one pass did. */
|
|
74
|
+
export interface CodexSyncResult {
|
|
75
|
+
filesRead: number;
|
|
76
|
+
eventsRecorded: number;
|
|
77
|
+
tokensRecorded: number;
|
|
78
|
+
}
|
|
79
|
+
/** Collaborators. */
|
|
80
|
+
export interface CodexRolloutSyncDeps {
|
|
81
|
+
/** Codex home (`CODEX_HOME` or `~/.codex`) */
|
|
82
|
+
codexHome: string;
|
|
83
|
+
/** Absolute cursor file path */
|
|
84
|
+
cursorFile: string;
|
|
85
|
+
/** Registered agent sessions: name → info */
|
|
86
|
+
sessions: () => Map<string, CodexSessionInfo>;
|
|
87
|
+
/** Record one event in the ledger */
|
|
88
|
+
record: (session: string, event: CodexUsageEvent) => void;
|
|
89
|
+
logger?: {
|
|
90
|
+
info(m: string, meta?: Record<string, unknown>): void;
|
|
91
|
+
warn(m: string, meta?: Record<string, unknown>): void;
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Turn whole JSONL lines of a rollout into usage events. Mutates `state`.
|
|
96
|
+
*
|
|
97
|
+
* - `turn_context` sets the model;
|
|
98
|
+
* - `token_count` with a running total records the delta since the last
|
|
99
|
+
* counted total (0 = a repeated line, skipped);
|
|
100
|
+
* - a running total that went DOWN, or the first total of a file, records
|
|
101
|
+
* only that call's `last_token_usage` (a resumed conversation's file may
|
|
102
|
+
* open with history counted elsewhere).
|
|
103
|
+
*
|
|
104
|
+
* @param text - Whole lines
|
|
105
|
+
* @param state - Parse state (model, last total)
|
|
106
|
+
* @returns Events in file order
|
|
107
|
+
*/
|
|
108
|
+
export declare function parseCodexRolloutLines(text: string, state: CodexParseState): CodexUsageEvent[];
|
|
109
|
+
/**
|
|
110
|
+
* Find a conversation's rollout file by id.
|
|
111
|
+
*
|
|
112
|
+
* @param codexHome - Codex home
|
|
113
|
+
* @param conversationId - Conversation id
|
|
114
|
+
* @returns Absolute path, or null
|
|
115
|
+
*/
|
|
116
|
+
export declare function findCodexRollout(codexHome: string, conversationId: string): Promise<string | null>;
|
|
117
|
+
/**
|
|
118
|
+
* Polls Codex rollouts of Crewly's Codex agents and records their usage.
|
|
119
|
+
*/
|
|
120
|
+
export declare class CodexRolloutSyncService {
|
|
121
|
+
private readonly deps;
|
|
122
|
+
private cursors;
|
|
123
|
+
private loaded;
|
|
124
|
+
private running;
|
|
125
|
+
private timer;
|
|
126
|
+
/** Conversation id → when a lookup last failed (ms), to avoid rescanning every pass */
|
|
127
|
+
private readonly missing;
|
|
128
|
+
/**
|
|
129
|
+
* @param deps - Collaborators
|
|
130
|
+
*/
|
|
131
|
+
constructor(deps: CodexRolloutSyncDeps);
|
|
132
|
+
/** Run a pass now, then poll. */
|
|
133
|
+
start(): Promise<void>;
|
|
134
|
+
/** Stop polling. */
|
|
135
|
+
stop(): void;
|
|
136
|
+
/**
|
|
137
|
+
* @param filePath - Rollout path
|
|
138
|
+
* @returns Its cursor (tests, diagnostics)
|
|
139
|
+
*/
|
|
140
|
+
getCursor(filePath: string): CodexRolloutCursor | undefined;
|
|
141
|
+
/**
|
|
142
|
+
* One pass: adopt rollouts of newly seen Codex conversations, then read
|
|
143
|
+
* the new tail of every known rollout.
|
|
144
|
+
*
|
|
145
|
+
* @returns What the pass recorded
|
|
146
|
+
*/
|
|
147
|
+
sync(): Promise<CodexSyncResult>;
|
|
148
|
+
private syncFile;
|
|
149
|
+
private load;
|
|
150
|
+
private save;
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=codex-rollout-sync.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codex-rollout-sync.service.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/monitoring/codex-rollout-sync.service.ts"],"names":[],"mappings":"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"}
|