@agent-finops/core 0.8.1 → 0.9.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 +5 -3
- package/dist/actionPlanner.d.ts +140 -0
- package/dist/actionPlanner.js +938 -0
- package/dist/actionVerification.d.ts +1240 -0
- package/dist/actionVerification.js +1028 -0
- package/dist/activitySnapshot.d.ts +142 -50
- package/dist/activitySnapshot.js +145 -6
- package/dist/activitySnapshotCache.d.ts +8 -1
- package/dist/activitySnapshotCache.js +103 -7
- package/dist/agentEconomicsReceipt.d.ts +74 -74
- package/dist/glance.d.ts +27 -1
- package/dist/glance.js +151 -12
- package/dist/index.d.ts +11 -2
- package/dist/index.js +10 -1
- package/dist/localAgentFormats/gemini.js +2 -2
- package/dist/localAgentFormats/registry.js +6 -2
- package/dist/localAgentFormats/runtimeRegistry.js +5 -2
- package/dist/localAgentFormats/types.d.ts +2 -1
- package/dist/localAgentLogs.d.ts +362 -3
- package/dist/localAgentLogs.js +1964 -165
- package/dist/modelPricing.d.ts +1 -1
- package/dist/modelPricing.js +1 -1
- package/dist/projectEconomics.d.ts +617 -0
- package/dist/projectEconomics.js +620 -0
- package/dist/projectEconomicsBuilder.d.ts +89 -0
- package/dist/projectEconomicsBuilder.js +473 -0
- package/dist/projectIndexStore.d.ts +545 -0
- package/dist/projectIndexStore.js +606 -0
- package/dist/providerConnectors.d.ts +59 -1
- package/dist/providerConnectors.js +175 -11
- package/dist/qualitativeIndexCache.d.ts +494 -0
- package/dist/qualitativeIndexCache.js +930 -0
- package/dist/resultCard.d.ts +350 -0
- package/dist/resultCard.js +604 -0
- package/dist/runtimeCommands.d.ts +21 -0
- package/dist/runtimeCommands.js +27 -0
- package/dist/scanGuard.d.ts +3 -1
- package/dist/scanGuard.js +164 -4
- package/dist/schema.d.ts +31 -31
- package/dist/sessionVitals.d.ts +145 -0
- package/dist/sessionVitals.js +521 -0
- package/dist/toolInvocations.d.ts +40 -1
- package/dist/toolInvocations.js +101 -20
- package/package.json +1 -1
package/dist/toolInvocations.js
CHANGED
|
@@ -132,27 +132,64 @@ export function parseCodexInvocations(content, sinceMs) {
|
|
|
132
132
|
}
|
|
133
133
|
return collector.finish();
|
|
134
134
|
}
|
|
135
|
+
/** Fail-closed structural check for a restored collector snapshot. */
|
|
136
|
+
export function isCodexInvocationCollectorSnapshot(value) {
|
|
137
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
138
|
+
return false;
|
|
139
|
+
const record = value;
|
|
140
|
+
const stringNumberPairs = (input) => (Array.isArray(input) && input.every((pair) => (Array.isArray(pair) && pair.length === 2 &&
|
|
141
|
+
typeof pair[0] === "string" &&
|
|
142
|
+
Number.isSafeInteger(pair[1]) && Number(pair[1]) >= 0)));
|
|
143
|
+
const stringArray = (input) => (Array.isArray(input) && input.every((item) => typeof item === "string"));
|
|
144
|
+
const optionalString = (input) => (input === undefined || typeof input === "string");
|
|
145
|
+
const optionalFinite = (input) => (input === undefined || typeof input === "number" && Number.isFinite(input));
|
|
146
|
+
return stringNumberPairs(record.counts) &&
|
|
147
|
+
stringArray(record.mcpTools) &&
|
|
148
|
+
stringArray(record.skills) &&
|
|
149
|
+
stringArray(record.subagents) &&
|
|
150
|
+
stringArray(record.commands) &&
|
|
151
|
+
stringNumberPairs(record.fileReads) &&
|
|
152
|
+
Number.isSafeInteger(record.assistantTurns) && Number(record.assistantTurns) >= 0 &&
|
|
153
|
+
optionalString(record.sessionId) &&
|
|
154
|
+
typeof record.rootSessionMetaSeen === "boolean" &&
|
|
155
|
+
optionalFinite(record.rootStartedAtMs) &&
|
|
156
|
+
typeof record.rootTaskStarted === "boolean" &&
|
|
157
|
+
optionalString(record.lastActivityAt) &&
|
|
158
|
+
Number.isSafeInteger(record.compactionEvents) && Number(record.compactionEvents) >= 0 &&
|
|
159
|
+
typeof record.isSubagent === "boolean" &&
|
|
160
|
+
optionalString(record.parentSessionId) &&
|
|
161
|
+
Array.isArray(record.nestedSessions) && record.nestedSessions.every((pair) => (Array.isArray(pair) && pair.length === 2 && typeof pair[0] === "string" &&
|
|
162
|
+
typeof pair[1] === "object" && pair[1] !== null &&
|
|
163
|
+
typeof pair[1].isSubagent === "boolean")) &&
|
|
164
|
+
optionalFinite(record.earliestCountedMs) &&
|
|
165
|
+
typeof record.allCountedEventsTimestamped === "boolean";
|
|
166
|
+
}
|
|
135
167
|
/**
|
|
136
168
|
* Stateful Codex invocation parser used to share localAgentLogs' JSONL pass.
|
|
137
169
|
* One collector is created per rollout file and discarded after `finish()`.
|
|
170
|
+
* A checkpointed stream restores a prior run's snapshot; the window (sinceMs)
|
|
171
|
+
* must be the one the snapshot was created under — the caller pins it in the
|
|
172
|
+
* checkpoint envelope.
|
|
138
173
|
*/
|
|
139
|
-
export function createCodexInvocationCollector(sinceMs) {
|
|
140
|
-
const counts = new Map();
|
|
141
|
-
const mcpTools = new Set();
|
|
142
|
-
const skills = new Set();
|
|
143
|
-
const subagents = new Set();
|
|
144
|
-
const commands = new Set();
|
|
145
|
-
const fileReads = new Map();
|
|
146
|
-
let assistantTurns = 0;
|
|
147
|
-
let sessionId;
|
|
148
|
-
let rootSessionMetaSeen = false;
|
|
149
|
-
let rootStartedAtMs;
|
|
150
|
-
let rootTaskStarted = false;
|
|
151
|
-
let lastActivityAt;
|
|
152
|
-
let compactionEvents = 0;
|
|
153
|
-
let isSubagent = false;
|
|
154
|
-
let parentSessionId;
|
|
155
|
-
const nestedSessions = new Map();
|
|
174
|
+
export function createCodexInvocationCollector(sinceMs, restored) {
|
|
175
|
+
const counts = new Map(restored?.counts ?? []);
|
|
176
|
+
const mcpTools = new Set(restored?.mcpTools ?? []);
|
|
177
|
+
const skills = new Set(restored?.skills ?? []);
|
|
178
|
+
const subagents = new Set(restored?.subagents ?? []);
|
|
179
|
+
const commands = new Set(restored?.commands ?? []);
|
|
180
|
+
const fileReads = new Map(restored?.fileReads ?? []);
|
|
181
|
+
let assistantTurns = restored?.assistantTurns ?? 0;
|
|
182
|
+
let sessionId = restored?.sessionId;
|
|
183
|
+
let rootSessionMetaSeen = restored?.rootSessionMetaSeen ?? false;
|
|
184
|
+
let rootStartedAtMs = restored?.rootStartedAtMs;
|
|
185
|
+
let rootTaskStarted = restored?.rootTaskStarted ?? false;
|
|
186
|
+
let lastActivityAt = restored?.lastActivityAt;
|
|
187
|
+
let compactionEvents = restored?.compactionEvents ?? 0;
|
|
188
|
+
let isSubagent = restored?.isSubagent ?? false;
|
|
189
|
+
let parentSessionId = restored?.parentSessionId;
|
|
190
|
+
const nestedSessions = new Map(restored?.nestedSessions ?? []);
|
|
191
|
+
let earliestCountedMs = restored?.earliestCountedMs;
|
|
192
|
+
let allCountedEventsTimestamped = restored?.allCountedEventsTimestamped ?? true;
|
|
156
193
|
const resetObservedEvidence = () => {
|
|
157
194
|
counts.clear();
|
|
158
195
|
mcpTools.clear();
|
|
@@ -162,6 +199,18 @@ export function createCodexInvocationCollector(sinceMs) {
|
|
|
162
199
|
fileReads.clear();
|
|
163
200
|
assistantTurns = 0;
|
|
164
201
|
compactionEvents = 0;
|
|
202
|
+
earliestCountedMs = undefined;
|
|
203
|
+
allCountedEventsTimestamped = true;
|
|
204
|
+
};
|
|
205
|
+
const recordCountedTimestamp = (entry) => {
|
|
206
|
+
const timestamp = Date.parse(stringOf(entry.timestamp) ?? "");
|
|
207
|
+
if (!Number.isFinite(timestamp)) {
|
|
208
|
+
allCountedEventsTimestamped = false;
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
earliestCountedMs = earliestCountedMs === undefined
|
|
212
|
+
? timestamp
|
|
213
|
+
: Math.min(earliestCountedMs, timestamp);
|
|
165
214
|
};
|
|
166
215
|
const consume = (entry) => {
|
|
167
216
|
const payload = isRecord(entry.payload) ? entry.payload : undefined;
|
|
@@ -211,18 +260,23 @@ export function createCodexInvocationCollector(sinceMs) {
|
|
|
211
260
|
return;
|
|
212
261
|
// Codex writes both a top-level `compacted` entry and a separate
|
|
213
262
|
// `context_compacted` event for one compaction. Count only the former.
|
|
214
|
-
if (entry.type === "compacted")
|
|
263
|
+
if (entry.type === "compacted") {
|
|
215
264
|
compactionEvents += 1;
|
|
265
|
+
recordCountedTimestamp(entry);
|
|
266
|
+
}
|
|
216
267
|
// Codex emits one turn_context per model turn.
|
|
217
268
|
if (entry.type === "turn_context") {
|
|
218
269
|
assistantTurns += 1;
|
|
270
|
+
recordCountedTimestamp(entry);
|
|
219
271
|
return;
|
|
220
272
|
}
|
|
221
273
|
if (payload.type === "message" && payload.role === "user") {
|
|
222
274
|
for (const text of codexTextValues(payload.content)) {
|
|
223
275
|
const command = /^\s*\/([A-Za-z0-9:_-]+)/.exec(text)?.[1];
|
|
224
|
-
if (command)
|
|
276
|
+
if (command) {
|
|
225
277
|
commands.add(command);
|
|
278
|
+
recordCountedTimestamp(entry);
|
|
279
|
+
}
|
|
226
280
|
}
|
|
227
281
|
return;
|
|
228
282
|
}
|
|
@@ -233,6 +287,7 @@ export function createCodexInvocationCollector(sinceMs) {
|
|
|
233
287
|
if (!name)
|
|
234
288
|
return;
|
|
235
289
|
counts.set(name, (counts.get(name) ?? 0) + 1);
|
|
290
|
+
recordCountedTimestamp(entry);
|
|
236
291
|
const input = codexToolInput(payload);
|
|
237
292
|
if (name.startsWith("mcp__")) {
|
|
238
293
|
mcpTools.add(name);
|
|
@@ -280,7 +335,33 @@ export function createCodexInvocationCollector(sinceMs) {
|
|
|
280
335
|
})
|
|
281
336
|
};
|
|
282
337
|
};
|
|
283
|
-
|
|
338
|
+
const windowProof = () => ({
|
|
339
|
+
...(earliestCountedMs === undefined
|
|
340
|
+
? {}
|
|
341
|
+
: { earliestCountedAt: new Date(earliestCountedMs).toISOString() }),
|
|
342
|
+
allCountedEventsTimestamped
|
|
343
|
+
});
|
|
344
|
+
const snapshot = () => ({
|
|
345
|
+
counts: [...counts.entries()],
|
|
346
|
+
mcpTools: [...mcpTools],
|
|
347
|
+
skills: [...skills],
|
|
348
|
+
subagents: [...subagents],
|
|
349
|
+
commands: [...commands],
|
|
350
|
+
fileReads: [...fileReads.entries()],
|
|
351
|
+
assistantTurns,
|
|
352
|
+
...(sessionId !== undefined ? { sessionId } : {}),
|
|
353
|
+
rootSessionMetaSeen,
|
|
354
|
+
...(rootStartedAtMs !== undefined ? { rootStartedAtMs } : {}),
|
|
355
|
+
rootTaskStarted,
|
|
356
|
+
...(lastActivityAt !== undefined ? { lastActivityAt } : {}),
|
|
357
|
+
compactionEvents,
|
|
358
|
+
isSubagent,
|
|
359
|
+
...(parentSessionId !== undefined ? { parentSessionId } : {}),
|
|
360
|
+
nestedSessions: [...nestedSessions.entries()],
|
|
361
|
+
...(earliestCountedMs !== undefined ? { earliestCountedMs } : {}),
|
|
362
|
+
allCountedEventsTimestamped
|
|
363
|
+
});
|
|
364
|
+
return { consume, finish, windowProof, snapshot };
|
|
284
365
|
}
|
|
285
366
|
/** Scan this machine's Claude Code + Codex transcripts and aggregate invocations. */
|
|
286
367
|
export async function loadToolInvocations(options = {}) {
|