@agent-finops/core 0.7.1 → 0.7.2
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/activitySnapshot.d.ts +11 -28
- package/dist/activitySnapshot.js +19 -10
- package/dist/contextHealth.js +3 -1
- package/dist/glance.js +16 -16
- package/dist/index.d.ts +4 -1
- package/dist/index.js +2 -1
- package/dist/localAgentFormats/registry.d.ts +8 -0
- package/dist/localAgentFormats/registry.js +219 -0
- package/dist/localAgentFormats/runtimeRegistry.d.ts +4 -0
- package/dist/localAgentFormats/runtimeRegistry.js +55 -0
- package/dist/localAgentFormats/types.d.ts +84 -0
- package/dist/localAgentFormats/types.js +2 -0
- package/dist/localAgentLogs.d.ts +19 -2
- package/dist/localAgentLogs.js +234 -172
- package/dist/sourceStatus.d.ts +2 -1
- package/dist/sourceStatus.js +7 -13
- package/package.json +1 -1
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { type LocalAgentCall, type LocalAgentSourceScan } from "./localAgentLogs.js";
|
|
3
|
+
import type { LocalAgentFormatId } from "./localAgentFormats/types.js";
|
|
3
4
|
import type { DetectedPlan } from "./planDetection.js";
|
|
4
5
|
import { type UsageRecord } from "./schema.js";
|
|
5
6
|
import { type SourceValidationCoverage } from "./sourceStatus.js";
|
|
6
|
-
export declare const activitySnapshotAgentValues: readonly [
|
|
7
|
-
export type ActivitySnapshotAgent =
|
|
7
|
+
export declare const activitySnapshotAgentValues: readonly LocalAgentFormatId[];
|
|
8
|
+
export type ActivitySnapshotAgent = LocalAgentFormatId;
|
|
8
9
|
export declare const activitySnapshotPlanIdValues: readonly ["claude-pro", "claude-max-5x", "claude-max-20x", "chatgpt-plus", "chatgpt-pro"];
|
|
9
10
|
export type ActivitySnapshotPlanId = typeof activitySnapshotPlanIdValues[number];
|
|
10
11
|
export declare const activitySnapshotProviderValues: readonly ["openai", "anthropic", "cursor", "github-copilot", "other"];
|
|
@@ -177,10 +178,7 @@ export declare const activitySnapshotLimitSchema: z.ZodObject<{
|
|
|
177
178
|
}, z.core.$strict>;
|
|
178
179
|
export type ActivitySnapshotLimit = z.infer<typeof activitySnapshotLimitSchema>;
|
|
179
180
|
export declare const activitySnapshotSubscriptionAgentSchema: z.ZodObject<{
|
|
180
|
-
agent: z.
|
|
181
|
-
"claude-code": "claude-code";
|
|
182
|
-
codex: "codex";
|
|
183
|
-
}>;
|
|
181
|
+
agent: z.ZodString & z.ZodType<LocalAgentFormatId, string, z.core.$ZodTypeInternals<LocalAgentFormatId, string>>;
|
|
184
182
|
billing: z.ZodLiteral<"subscription">;
|
|
185
183
|
planId: z.ZodNullable<z.ZodEnum<{
|
|
186
184
|
"claude-max-20x": "claude-max-20x";
|
|
@@ -260,10 +258,7 @@ export declare const activitySnapshotOverageSchema: z.ZodObject<{
|
|
|
260
258
|
export type ActivitySnapshotOverage = z.infer<typeof activitySnapshotOverageSchema>;
|
|
261
259
|
export declare const activitySnapshotCoverageSchema: z.ZodObject<{
|
|
262
260
|
agents: z.ZodArray<z.ZodObject<{
|
|
263
|
-
agent: z.
|
|
264
|
-
"claude-code": "claude-code";
|
|
265
|
-
codex: "codex";
|
|
266
|
-
}>;
|
|
261
|
+
agent: z.ZodString & z.ZodType<LocalAgentFormatId, string, z.core.$ZodTypeInternals<LocalAgentFormatId, string>>;
|
|
267
262
|
directoryStatus: z.ZodEnum<{
|
|
268
263
|
missing: "missing";
|
|
269
264
|
readable: "readable";
|
|
@@ -314,8 +309,8 @@ export declare const activitySnapshotCoverageSchema: z.ZodObject<{
|
|
|
314
309
|
recordsPriced: z.ZodNumber;
|
|
315
310
|
recordsUnpriced: z.ZodNumber;
|
|
316
311
|
validationStatus: z.ZodEnum<{
|
|
317
|
-
complete: "complete";
|
|
318
312
|
failed: "failed";
|
|
313
|
+
complete: "complete";
|
|
319
314
|
not_checked: "not_checked";
|
|
320
315
|
partial: "partial";
|
|
321
316
|
}>;
|
|
@@ -354,10 +349,7 @@ export declare const activitySnapshotSchema: z.ZodObject<{
|
|
|
354
349
|
}>;
|
|
355
350
|
subscription: z.ZodNullable<z.ZodObject<{
|
|
356
351
|
agents: z.ZodArray<z.ZodObject<{
|
|
357
|
-
agent: z.
|
|
358
|
-
"claude-code": "claude-code";
|
|
359
|
-
codex: "codex";
|
|
360
|
-
}>;
|
|
352
|
+
agent: z.ZodString & z.ZodType<LocalAgentFormatId, string, z.core.$ZodTypeInternals<LocalAgentFormatId, string>>;
|
|
361
353
|
billing: z.ZodLiteral<"subscription">;
|
|
362
354
|
planId: z.ZodNullable<z.ZodEnum<{
|
|
363
355
|
"claude-max-20x": "claude-max-20x";
|
|
@@ -428,10 +420,7 @@ export declare const activitySnapshotSchema: z.ZodObject<{
|
|
|
428
420
|
}, z.core.$strict>>;
|
|
429
421
|
metered: z.ZodNullable<z.ZodObject<{
|
|
430
422
|
agents: z.ZodArray<z.ZodObject<{
|
|
431
|
-
agent: z.
|
|
432
|
-
"claude-code": "claude-code";
|
|
433
|
-
codex: "codex";
|
|
434
|
-
}>;
|
|
423
|
+
agent: z.ZodString & z.ZodType<LocalAgentFormatId, string, z.core.$ZodTypeInternals<LocalAgentFormatId, string>>;
|
|
435
424
|
billing: z.ZodLiteral<"api_key">;
|
|
436
425
|
planId: z.ZodNullable<z.ZodEnum<{
|
|
437
426
|
"claude-max-20x": "claude-max-20x";
|
|
@@ -532,10 +521,7 @@ export declare const activitySnapshotSchema: z.ZodObject<{
|
|
|
532
521
|
}, z.core.$strict>>;
|
|
533
522
|
unresolved: z.ZodNullable<z.ZodObject<{
|
|
534
523
|
agents: z.ZodArray<z.ZodObject<{
|
|
535
|
-
agent: z.
|
|
536
|
-
"claude-code": "claude-code";
|
|
537
|
-
codex: "codex";
|
|
538
|
-
}>;
|
|
524
|
+
agent: z.ZodString & z.ZodType<LocalAgentFormatId, string, z.core.$ZodTypeInternals<LocalAgentFormatId, string>>;
|
|
539
525
|
billing: z.ZodLiteral<"unknown">;
|
|
540
526
|
planId: z.ZodNullable<z.ZodEnum<{
|
|
541
527
|
"claude-max-20x": "claude-max-20x";
|
|
@@ -600,10 +586,7 @@ export declare const activitySnapshotSchema: z.ZodObject<{
|
|
|
600
586
|
}, z.core.$strict>>;
|
|
601
587
|
coverage: z.ZodObject<{
|
|
602
588
|
agents: z.ZodArray<z.ZodObject<{
|
|
603
|
-
agent: z.
|
|
604
|
-
"claude-code": "claude-code";
|
|
605
|
-
codex: "codex";
|
|
606
|
-
}>;
|
|
589
|
+
agent: z.ZodString & z.ZodType<LocalAgentFormatId, string, z.core.$ZodTypeInternals<LocalAgentFormatId, string>>;
|
|
607
590
|
directoryStatus: z.ZodEnum<{
|
|
608
591
|
missing: "missing";
|
|
609
592
|
readable: "readable";
|
|
@@ -654,8 +637,8 @@ export declare const activitySnapshotSchema: z.ZodObject<{
|
|
|
654
637
|
recordsPriced: z.ZodNumber;
|
|
655
638
|
recordsUnpriced: z.ZodNumber;
|
|
656
639
|
validationStatus: z.ZodEnum<{
|
|
657
|
-
complete: "complete";
|
|
658
640
|
failed: "failed";
|
|
641
|
+
complete: "complete";
|
|
659
642
|
not_checked: "not_checked";
|
|
660
643
|
partial: "partial";
|
|
661
644
|
}>;
|
package/dist/activitySnapshot.js
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { aggregateCalls, dedupeCumulativeSessionCalls } from "./localAgentLogs.js";
|
|
3
|
+
import { localAgentFormatDescriptors } from "./localAgentFormats/registry.js";
|
|
3
4
|
import { estimateTokenCostUsd, PRICING_TABLE_AS_OF } from "./modelPricing.js";
|
|
4
5
|
import { isBundledSampleUsage } from "./schema.js";
|
|
5
6
|
import { sourceValidationCoverageValues } from "./sourceStatus.js";
|
|
6
7
|
const DAY_MS = 24 * 60 * 60 * 1_000;
|
|
7
|
-
export const activitySnapshotAgentValues =
|
|
8
|
+
export const activitySnapshotAgentValues = Object.freeze(localAgentFormatDescriptors.map((descriptor) => descriptor.id));
|
|
9
|
+
const activitySnapshotAgentValueSet = new Set(activitySnapshotAgentValues);
|
|
10
|
+
const activitySnapshotAgentLimit = activitySnapshotAgentValues.length;
|
|
8
11
|
export const activitySnapshotPlanIdValues = [
|
|
9
12
|
"claude-pro",
|
|
10
13
|
"claude-max-5x",
|
|
@@ -45,7 +48,9 @@ const isoTimestampSchema = z.string().datetime({ offset: true });
|
|
|
45
48
|
const usdSchema = z.number().finite().nonnegative();
|
|
46
49
|
const countSchema = z.number().int().nonnegative();
|
|
47
50
|
const windowCoverageSchema = z.enum(["complete", "partial", "missing"]);
|
|
48
|
-
const agentSchema = z.
|
|
51
|
+
const agentSchema = z.string().refine(isSnapshotAgent, {
|
|
52
|
+
message: "Agent must be registered as a local-agent format."
|
|
53
|
+
});
|
|
49
54
|
const planIdSchema = z.enum(activitySnapshotPlanIdValues).nullable();
|
|
50
55
|
export const activitySnapshotApiEquivalentWindowSchema = z.object({
|
|
51
56
|
amountUsd: usdSchema.nullable(),
|
|
@@ -169,14 +174,14 @@ export const activitySnapshotSubscriptionAgentSchema = z.object({
|
|
|
169
174
|
}
|
|
170
175
|
});
|
|
171
176
|
const activitySnapshotSubscriptionSchema = z.object({
|
|
172
|
-
agents: z.array(activitySnapshotSubscriptionAgentSchema).min(1).max(
|
|
177
|
+
agents: z.array(activitySnapshotSubscriptionAgentSchema).min(1).max(activitySnapshotAgentLimit)
|
|
173
178
|
}).strict().superRefine(uniqueAgentEntries);
|
|
174
179
|
const activitySnapshotMeteredSchema = z.object({
|
|
175
180
|
agents: z.array(z.object({
|
|
176
181
|
agent: agentSchema,
|
|
177
182
|
billing: z.literal("api_key"),
|
|
178
183
|
planId: planIdSchema
|
|
179
|
-
}).strict()).max(
|
|
184
|
+
}).strict()).max(activitySnapshotAgentLimit),
|
|
180
185
|
apiEquivalent: activitySnapshotApiEquivalentWindowsSchema,
|
|
181
186
|
providerBilled: activitySnapshotBilledWindowsSchema
|
|
182
187
|
}).strict().superRefine((value, context) => {
|
|
@@ -196,7 +201,7 @@ const activitySnapshotUnresolvedSchema = z.object({
|
|
|
196
201
|
agent: agentSchema,
|
|
197
202
|
billing: z.literal("unknown"),
|
|
198
203
|
planId: planIdSchema
|
|
199
|
-
}).strict()).max(
|
|
204
|
+
}).strict()).max(activitySnapshotAgentLimit),
|
|
200
205
|
apiEquivalent: activitySnapshotApiEquivalentWindowsSchema
|
|
201
206
|
}).strict().superRefine((value, context) => {
|
|
202
207
|
uniqueAgentEntries(value, context);
|
|
@@ -290,7 +295,7 @@ const activitySnapshotProviderCoverageSchema = z.object({
|
|
|
290
295
|
}
|
|
291
296
|
});
|
|
292
297
|
export const activitySnapshotCoverageSchema = z.object({
|
|
293
|
-
agents: z.array(activitySnapshotAgentCoverageSchema).max(
|
|
298
|
+
agents: z.array(activitySnapshotAgentCoverageSchema).max(activitySnapshotAgentLimit),
|
|
294
299
|
providers: z.array(activitySnapshotProviderCoverageSchema).max(5),
|
|
295
300
|
recordsParsed: countSchema,
|
|
296
301
|
recordsPriced: countSchema,
|
|
@@ -483,8 +488,10 @@ export function buildActivitySnapshot(input) {
|
|
|
483
488
|
if (isSnapshotAgent(entry.record.agentId))
|
|
484
489
|
activeAgents.add(entry.record.agentId);
|
|
485
490
|
}
|
|
486
|
-
for (const call of calls)
|
|
487
|
-
|
|
491
|
+
for (const call of calls) {
|
|
492
|
+
if (isSnapshotAgent(call.agent))
|
|
493
|
+
activeAgents.add(call.agent);
|
|
494
|
+
}
|
|
488
495
|
const meteredAgents = [...activeAgents]
|
|
489
496
|
.filter((agent) => plans.get(agent)?.billing === "api_key")
|
|
490
497
|
.sort()
|
|
@@ -529,7 +536,7 @@ export function buildActivitySnapshot(input) {
|
|
|
529
536
|
const subscription = hasSubscriptionActivity ? { agents: subscriptionAgents } : null;
|
|
530
537
|
const metered = hasMeteredActivity ? {
|
|
531
538
|
agents: meteredAgents,
|
|
532
|
-
apiEquivalent: buildApiWindows(meteredApiRecords, allCalls.filter((call) => plans.get(call.agent)?.billing === "api_key"), trustedIds, asOfMs, localCoverageForRecords(meteredApiRecords, scans, [...plans.entries()]
|
|
539
|
+
apiEquivalent: buildApiWindows(meteredApiRecords, allCalls.filter((call) => (isSnapshotAgent(call.agent) && plans.get(call.agent)?.billing === "api_key")), trustedIds, asOfMs, localCoverageForRecords(meteredApiRecords, scans, [...plans.entries()]
|
|
533
540
|
.filter(([, plan]) => plan.billing === "api_key")
|
|
534
541
|
.map(([agent]) => agent))),
|
|
535
542
|
providerBilled: buildBilledWindows(meteredBilledRecords, asOfMs, providers)
|
|
@@ -537,6 +544,8 @@ export function buildActivitySnapshot(input) {
|
|
|
537
544
|
const unresolved = hasUnresolvedActivity ? {
|
|
538
545
|
agents: unresolvedAgents,
|
|
539
546
|
apiEquivalent: buildApiWindows(unresolvedRecords, allCalls.filter((call) => {
|
|
547
|
+
if (!isSnapshotAgent(call.agent))
|
|
548
|
+
return false;
|
|
540
549
|
const billing = plans.get(call.agent)?.billing;
|
|
541
550
|
return billing !== "subscription" && billing !== "api_key";
|
|
542
551
|
}), trustedIds, asOfMs, unresolvedCoverageForRecords(unresolvedRecords, scans, providers))
|
|
@@ -1200,7 +1209,7 @@ function inRollingWindow(timestamp, asOfMs, days) {
|
|
|
1200
1209
|
return Number.isFinite(value) && value >= asOfMs - days * DAY_MS && value <= asOfMs;
|
|
1201
1210
|
}
|
|
1202
1211
|
function isSnapshotAgent(value) {
|
|
1203
|
-
return typeof value === "string" &&
|
|
1212
|
+
return typeof value === "string" && activitySnapshotAgentValueSet.has(value);
|
|
1204
1213
|
}
|
|
1205
1214
|
function isKnownPlanId(value) {
|
|
1206
1215
|
return typeof value === "string" && activitySnapshotPlanIdValues.includes(value);
|
package/dist/contextHealth.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { loadAgentInventory } from "./agentInventory.js";
|
|
2
2
|
import { computeDeadContext } from "./deadContext.js";
|
|
3
|
+
import { localAgentFormatSupports } from "./localAgentFormats/registry.js";
|
|
3
4
|
import { loadToolInvocations } from "./toolInvocations.js";
|
|
4
5
|
const DAY_MS = 24 * 60 * 60 * 1_000;
|
|
5
6
|
const DEFAULT_WINDOW_DAYS = 30;
|
|
@@ -30,7 +31,8 @@ export async function loadContextHealth(calls, options = {}) {
|
|
|
30
31
|
/** Pure Context Health contract builder for deterministic tests and adapters. */
|
|
31
32
|
export function buildContextHealth(input = {}) {
|
|
32
33
|
const now = input.now ?? new Date();
|
|
33
|
-
const calls = input.calls ?? []
|
|
34
|
+
const calls = (input.calls ?? [])
|
|
35
|
+
.filter((call) => localAgentFormatSupports(call.agent, "contextHealth"));
|
|
34
36
|
const items = input.inventory?.items ?? [];
|
|
35
37
|
const invocations = input.invocations ?? emptyInvocations();
|
|
36
38
|
const windowDays = input.windowDays ?? input.deadContext?.windowDays ?? DEFAULT_WINDOW_DAYS;
|
package/dist/glance.js
CHANGED
|
@@ -2,6 +2,7 @@ import { dedupeCumulativeSessionCalls, sanitizeLocalActivityText } from "./local
|
|
|
2
2
|
import { estimateTokenCostUsd, PRICING_TABLE_AS_OF } from "./modelPricing.js";
|
|
3
3
|
import { subscriptionPlans } from "./planMath.js";
|
|
4
4
|
import { buildContextHealth } from "./contextHealth.js";
|
|
5
|
+
import { localAgentFormatDescriptors, localAgentFormatSupports } from "./localAgentFormats/registry.js";
|
|
5
6
|
const HOUR_MS = 60 * 60 * 1_000;
|
|
6
7
|
const DAY_MS = 24 * HOUR_MS;
|
|
7
8
|
/**
|
|
@@ -16,7 +17,9 @@ export function buildUsageGlance(calls, options = {}) {
|
|
|
16
17
|
// defense-in-depth to every string-bearing transcript/context field before
|
|
17
18
|
// any calculation so secrets cannot survive in a nested session-health or
|
|
18
19
|
// provenance field even if an upstream parser missed them.
|
|
19
|
-
const
|
|
20
|
+
const supportedFormats = localAgentFormatDescriptors.filter((descriptor) => (descriptor.capabilities.glance));
|
|
21
|
+
const safeCalls = dedupeCumulativeSessionCalls(sanitizeStringMetadata(calls))
|
|
22
|
+
.filter((call) => localAgentFormatSupports(call.agent, "glance"));
|
|
20
23
|
const suppliedContextHealth = options.contextHealth
|
|
21
24
|
? sanitizeStringMetadata(options.contextHealth)
|
|
22
25
|
: undefined;
|
|
@@ -40,7 +43,8 @@ export function buildUsageGlance(calls, options = {}) {
|
|
|
40
43
|
const plan = currentSession
|
|
41
44
|
? toGlancePlan(currentSession.agent, safeDetectedPlans)
|
|
42
45
|
: null;
|
|
43
|
-
const limitCalls = sanitizeStringMetadata(options.limitCalls ?? safeCalls)
|
|
46
|
+
const limitCalls = sanitizeStringMetadata(options.limitCalls ?? safeCalls)
|
|
47
|
+
.filter((call) => localAgentFormatSupports(call.agent, "rateLimits"));
|
|
44
48
|
const limits = latestLimits(limitCalls, now).map(({ agent, window, observedAt }) => toGlanceLimit(agent, window, observedAt));
|
|
45
49
|
const windowStart = now.getTime() - focusWindowDays * DAY_MS;
|
|
46
50
|
const windowCalls = safeCalls.filter((call) => Date.parse(call.timestamp) >= windowStart);
|
|
@@ -62,7 +66,8 @@ export function buildUsageGlance(calls, options = {}) {
|
|
|
62
66
|
generatedAt: now.toISOString(),
|
|
63
67
|
filesParsed: options.filesParsed ?? 0
|
|
64
68
|
});
|
|
65
|
-
const detectedAgents = options.detectedAgents ?? uniqueAgents(safeCalls)
|
|
69
|
+
const detectedAgents = (options.detectedAgents ?? uniqueAgents(safeCalls))
|
|
70
|
+
.filter((agent) => localAgentFormatSupports(agent, "glance"));
|
|
66
71
|
const agentsWithLimits = new Set(limits.map((limit) => limit.agent));
|
|
67
72
|
const limitAgents = uniqueAgents(limitCalls.filter((call) => call.rateLimits));
|
|
68
73
|
const reportedWindows = (agent) => ([...new Set(limits
|
|
@@ -82,20 +87,15 @@ export function buildUsageGlance(calls, options = {}) {
|
|
|
82
87
|
generatedAt: now.toISOString(),
|
|
83
88
|
coverage: {
|
|
84
89
|
filesParsed: options.filesParsed ?? 0,
|
|
85
|
-
supportedTranscriptAgents:
|
|
90
|
+
supportedTranscriptAgents: supportedFormats.map((descriptor) => descriptor.id),
|
|
86
91
|
detectedAgents,
|
|
87
|
-
rateLimitMetadata:
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
agent: "codex",
|
|
95
|
-
status: agentsWithLimits.has("codex") ? "reported" : "not_seen",
|
|
96
|
-
windowsReported: reportedWindows("codex")
|
|
97
|
-
}
|
|
98
|
-
],
|
|
92
|
+
rateLimitMetadata: supportedFormats.map((descriptor) => ({
|
|
93
|
+
agent: descriptor.id,
|
|
94
|
+
status: descriptor.capabilities.rateLimits
|
|
95
|
+
? agentsWithLimits.has(descriptor.id) ? "reported" : "not_seen"
|
|
96
|
+
: "not_reported_by_transcript",
|
|
97
|
+
windowsReported: reportedWindows(descriptor.id)
|
|
98
|
+
})),
|
|
99
99
|
providerConnectionRequired: ["cursor", "github-copilot"]
|
|
100
100
|
},
|
|
101
101
|
provenance: {
|
package/dist/index.d.ts
CHANGED
|
@@ -12,7 +12,10 @@ export * from "./discovery.js";
|
|
|
12
12
|
export * from "./glance.js";
|
|
13
13
|
export * from "./toolInvocations.js";
|
|
14
14
|
export * from "./insights.js";
|
|
15
|
-
export
|
|
15
|
+
export { aggregateCalls, dedupeCumulativeSessionCalls, latestObservedWorkingDirectory, loadLocalAgentFinancialUsage, loadLocalAgentUsage, parseClaudeCodeTranscript, parseCodexRollout, sanitizeLocalActivityText } from "./localAgentLogs.js";
|
|
16
|
+
export type { LocalAgentActivity, LocalAgentCall, LocalAgentFinancialLogOptions, LocalAgentLogDiagnostic, LocalAgentLogDiagnosticCode, LocalAgentLogOptions, LocalAgentLogResult, LocalAgentRateLimitSnapshot, LocalAgentRateLimitWindow, LocalAgentSourceScan, LocalAgentTurnUsage } from "./localAgentLogs.js";
|
|
17
|
+
export * from "./localAgentFormats/registry.js";
|
|
18
|
+
export type * from "./localAgentFormats/types.js";
|
|
16
19
|
export * from "./modelPricing.js";
|
|
17
20
|
export * from "./planDetection.js";
|
|
18
21
|
export * from "./planMath.js";
|
package/dist/index.js
CHANGED
|
@@ -12,7 +12,8 @@ export * from "./discovery.js";
|
|
|
12
12
|
export * from "./glance.js";
|
|
13
13
|
export * from "./toolInvocations.js";
|
|
14
14
|
export * from "./insights.js";
|
|
15
|
-
export
|
|
15
|
+
export { aggregateCalls, dedupeCumulativeSessionCalls, latestObservedWorkingDirectory, loadLocalAgentFinancialUsage, loadLocalAgentUsage, parseClaudeCodeTranscript, parseCodexRollout, sanitizeLocalActivityText } from "./localAgentLogs.js";
|
|
16
|
+
export * from "./localAgentFormats/registry.js";
|
|
16
17
|
export * from "./modelPricing.js";
|
|
17
18
|
export * from "./planDetection.js";
|
|
18
19
|
export * from "./planMath.js";
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { LocalAgentFormatDescriptor, LocalAgentFormatId } from "./types.js";
|
|
2
|
+
export declare const localAgentFormatDescriptors: readonly LocalAgentFormatDescriptor[];
|
|
3
|
+
export declare function localAgentFormatDescriptor(id: LocalAgentFormatId): LocalAgentFormatDescriptor | undefined;
|
|
4
|
+
export declare function localAgentFormatLabel(id: LocalAgentFormatId): string;
|
|
5
|
+
export declare function localAgentFormatSupports(id: LocalAgentFormatId, capability: keyof LocalAgentFormatDescriptor["capabilities"]): boolean;
|
|
6
|
+
export declare function matchesLocalAgentFormatFile(descriptor: LocalAgentFormatDescriptor, filePath: string): boolean;
|
|
7
|
+
export declare function validateLocalAgentFormatDescriptors(registry?: readonly LocalAgentFormatDescriptor[]): void;
|
|
8
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import { basename } from "node:path";
|
|
2
|
+
const descriptors = [
|
|
3
|
+
{
|
|
4
|
+
schemaVersion: 1,
|
|
5
|
+
id: "claude-code",
|
|
6
|
+
order: 10,
|
|
7
|
+
label: "Claude Code",
|
|
8
|
+
provider: "anthropic",
|
|
9
|
+
defaultHomeRelative: [".claude", "projects"],
|
|
10
|
+
legacyDirectoryOption: "claudeProjectsDir",
|
|
11
|
+
discovery: { extension: ".jsonl" },
|
|
12
|
+
confidenceDefaults: {
|
|
13
|
+
validationCoverage: "live_verified",
|
|
14
|
+
pricedFinancialEvidence: "estimated",
|
|
15
|
+
unpricedFinancialEvidence: "missing",
|
|
16
|
+
sourceConfidence: "estimated"
|
|
17
|
+
},
|
|
18
|
+
sourceRecord: {
|
|
19
|
+
id: "local-agent-logs",
|
|
20
|
+
name: "Local agent session logs",
|
|
21
|
+
observedFrom: "claude-code transcript JSONL (this machine)",
|
|
22
|
+
providerCostType: "local_agent_logs",
|
|
23
|
+
usageGranularity: "daily_aggregate",
|
|
24
|
+
operation: "claude-code sessions"
|
|
25
|
+
},
|
|
26
|
+
capabilities: {
|
|
27
|
+
activity: true,
|
|
28
|
+
contextHealth: true,
|
|
29
|
+
financialFastPath: true,
|
|
30
|
+
glance: true,
|
|
31
|
+
invocationEvidence: false,
|
|
32
|
+
planContext: true,
|
|
33
|
+
rateLimits: false
|
|
34
|
+
},
|
|
35
|
+
financialRead: "full_jsonl",
|
|
36
|
+
validationNote: "Local transcript parsing is exercised against live logs; dollar values remain API-rate estimates.",
|
|
37
|
+
docs: {
|
|
38
|
+
format: "JSON Lines under ~/.claude/projects/**/*.jsonl",
|
|
39
|
+
howRead: [
|
|
40
|
+
"Read one JSON object per line and keep assistant records with message.usage.",
|
|
41
|
+
"Ignore <synthetic> placeholder models and deduplicate streaming/retry rewrites by message and request identity.",
|
|
42
|
+
"Treat each retained assistant usage record as turn-scoped evidence."
|
|
43
|
+
],
|
|
44
|
+
fieldsRead: [
|
|
45
|
+
"timestamp, model, and token-usage components",
|
|
46
|
+
"session and working-directory metadata for local deduplication and attribution",
|
|
47
|
+
"human-prompt and tool metadata for privacy-reduced local activity summaries"
|
|
48
|
+
],
|
|
49
|
+
verified: [
|
|
50
|
+
"The reader and its failure paths have been exercised against live local Claude Code logs.",
|
|
51
|
+
"Synthetic recorded fixtures lock the supported JSONL shapes and normalized output."
|
|
52
|
+
],
|
|
53
|
+
estimated: [
|
|
54
|
+
"Supported token components are priced at published API rates as API-equivalent value."
|
|
55
|
+
],
|
|
56
|
+
notVerified: [
|
|
57
|
+
"API-equivalent value is not billed spend, subscription cost, savings, or ROI.",
|
|
58
|
+
"Claude Code transcripts do not provide account-plan headroom; missing limits are not inferred."
|
|
59
|
+
],
|
|
60
|
+
privacy: [
|
|
61
|
+
"Parsing and aggregation run locally; raw prompts and responses are not returned by the parser registry.",
|
|
62
|
+
"aibill never sits in the inference path and never stores, prints, or proxies provider credentials."
|
|
63
|
+
],
|
|
64
|
+
limitations: [
|
|
65
|
+
"Malformed lines are skipped and reported.",
|
|
66
|
+
"Incomplete token shapes remain unpriced with missing financial evidence instead of becoming $0."
|
|
67
|
+
]
|
|
68
|
+
},
|
|
69
|
+
fixtures: ["claude-code-v1"]
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
schemaVersion: 1,
|
|
73
|
+
id: "codex",
|
|
74
|
+
order: 20,
|
|
75
|
+
label: "Codex",
|
|
76
|
+
provider: "openai",
|
|
77
|
+
defaultHomeRelative: [".codex", "sessions"],
|
|
78
|
+
legacyDirectoryOption: "codexSessionsDir",
|
|
79
|
+
discovery: { extension: ".jsonl", basenamePrefix: "rollout-" },
|
|
80
|
+
confidenceDefaults: {
|
|
81
|
+
validationCoverage: "live_verified",
|
|
82
|
+
pricedFinancialEvidence: "estimated",
|
|
83
|
+
unpricedFinancialEvidence: "missing",
|
|
84
|
+
sourceConfidence: "estimated"
|
|
85
|
+
},
|
|
86
|
+
sourceRecord: {
|
|
87
|
+
id: "local-agent-logs",
|
|
88
|
+
name: "Local agent session logs",
|
|
89
|
+
observedFrom: "codex transcript JSONL (this machine)",
|
|
90
|
+
providerCostType: "local_agent_logs",
|
|
91
|
+
usageGranularity: "daily_aggregate",
|
|
92
|
+
operation: "codex sessions"
|
|
93
|
+
},
|
|
94
|
+
capabilities: {
|
|
95
|
+
activity: true,
|
|
96
|
+
contextHealth: true,
|
|
97
|
+
financialFastPath: true,
|
|
98
|
+
glance: true,
|
|
99
|
+
invocationEvidence: true,
|
|
100
|
+
planContext: true,
|
|
101
|
+
rateLimits: true
|
|
102
|
+
},
|
|
103
|
+
financialRead: "bounded_event_jsonl",
|
|
104
|
+
validationNote: "Local parsing was replayed against live logs; total-only token shapes and unknown aliases remain missing rather than becoming estimated $0.",
|
|
105
|
+
docs: {
|
|
106
|
+
format: "JSON Lines under ~/.codex/sessions/YYYY/MM/DD/rollout-*.jsonl",
|
|
107
|
+
howRead: [
|
|
108
|
+
"Read the Codex event stream and retain the root session identity, model, and latest cumulative event_msg/token_count evidence.",
|
|
109
|
+
"Never sum earlier running token counters; forked sessions subtract a supported inherited cumulative baseline.",
|
|
110
|
+
"Use a bounded proof-based financial reader for init/cache while the full reader retains privacy-reduced activity and optional invocation evidence."
|
|
111
|
+
],
|
|
112
|
+
fieldsRead: [
|
|
113
|
+
"session metadata, timestamps, model, and cumulative/last-turn token usage",
|
|
114
|
+
"transcript-reported rate-limit windows when present",
|
|
115
|
+
"tool-call metadata for local attribution and optional privacy-safe invocation counts"
|
|
116
|
+
],
|
|
117
|
+
verified: [
|
|
118
|
+
"The full and optimized financial readers have been replayed against live local Codex logs.",
|
|
119
|
+
"Synthetic recorded fixtures lock cumulative, last-turn, and rate-limit normalization."
|
|
120
|
+
],
|
|
121
|
+
estimated: [
|
|
122
|
+
"Supported token components are priced at published API rates as API-equivalent value."
|
|
123
|
+
],
|
|
124
|
+
notVerified: [
|
|
125
|
+
"API-equivalent value is not billed spend, subscription cost, savings, or ROI.",
|
|
126
|
+
"A transcript-reported limit is plan-capacity evidence, not a provider invoice."
|
|
127
|
+
],
|
|
128
|
+
privacy: [
|
|
129
|
+
"Parsing and aggregation run locally; raw prompts and responses are not returned by the parser registry.",
|
|
130
|
+
"aibill never sits in the inference path and never stores, prints, or proxies provider credentials."
|
|
131
|
+
],
|
|
132
|
+
limitations: [
|
|
133
|
+
"Only rollout-*.jsonl files are parsed as Codex sessions.",
|
|
134
|
+
"Incomplete, regressing, or total-only token shapes remain unpriced with missing financial evidence."
|
|
135
|
+
]
|
|
136
|
+
},
|
|
137
|
+
fixtures: ["codex-v1"]
|
|
138
|
+
}
|
|
139
|
+
];
|
|
140
|
+
export const localAgentFormatDescriptors = Object.freeze([...descriptors]
|
|
141
|
+
.sort((left, right) => left.order - right.order)
|
|
142
|
+
.map(freezeDescriptor));
|
|
143
|
+
export function localAgentFormatDescriptor(id) {
|
|
144
|
+
return localAgentFormatDescriptors.find((descriptor) => descriptor.id === id);
|
|
145
|
+
}
|
|
146
|
+
export function localAgentFormatLabel(id) {
|
|
147
|
+
return localAgentFormatDescriptor(id)?.label ?? id;
|
|
148
|
+
}
|
|
149
|
+
export function localAgentFormatSupports(id, capability) {
|
|
150
|
+
return localAgentFormatDescriptor(id)?.capabilities[capability] === true;
|
|
151
|
+
}
|
|
152
|
+
export function matchesLocalAgentFormatFile(descriptor, filePath) {
|
|
153
|
+
const name = basename(filePath);
|
|
154
|
+
if (descriptor.discovery.extension && !name.endsWith(descriptor.discovery.extension))
|
|
155
|
+
return false;
|
|
156
|
+
if (descriptor.discovery.basename && name !== descriptor.discovery.basename)
|
|
157
|
+
return false;
|
|
158
|
+
if (descriptor.discovery.basenamePrefix && !name.startsWith(descriptor.discovery.basenamePrefix))
|
|
159
|
+
return false;
|
|
160
|
+
return true;
|
|
161
|
+
}
|
|
162
|
+
export function validateLocalAgentFormatDescriptors(registry = localAgentFormatDescriptors) {
|
|
163
|
+
const ids = new Set();
|
|
164
|
+
const orders = new Set();
|
|
165
|
+
for (const descriptor of registry) {
|
|
166
|
+
if (descriptor.schemaVersion !== 1)
|
|
167
|
+
throw new Error(`Unsupported local-agent format schema for ${descriptor.id}.`);
|
|
168
|
+
if (!descriptor.id || !descriptor.label || !descriptor.provider)
|
|
169
|
+
throw new Error("Local-agent format identity is incomplete.");
|
|
170
|
+
if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(descriptor.id) ||
|
|
171
|
+
!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(descriptor.provider)) {
|
|
172
|
+
throw new Error(`Unsafe local-agent format identity for ${descriptor.id}.`);
|
|
173
|
+
}
|
|
174
|
+
if (ids.has(descriptor.id))
|
|
175
|
+
throw new Error(`Duplicate local-agent format id: ${descriptor.id}.`);
|
|
176
|
+
if (orders.has(descriptor.order))
|
|
177
|
+
throw new Error(`Duplicate local-agent format order: ${descriptor.order}.`);
|
|
178
|
+
if (descriptor.defaultHomeRelative.length === 0 || descriptor.defaultHomeRelative.some((part) => (!part || part === "." || part === ".." || /[\\/\u0000]/.test(part)))) {
|
|
179
|
+
throw new Error(`Unsafe default local-agent root for ${descriptor.id}.`);
|
|
180
|
+
}
|
|
181
|
+
const discovery = descriptor.discovery;
|
|
182
|
+
if (!discovery.extension && !discovery.basename && !discovery.basenamePrefix) {
|
|
183
|
+
throw new Error(`Local-agent format ${descriptor.id} must declare a bounded file rule.`);
|
|
184
|
+
}
|
|
185
|
+
if (discovery.extension && !/^\.[A-Za-z0-9]+$/.test(discovery.extension)) {
|
|
186
|
+
throw new Error(`Unsafe discovery extension for ${descriptor.id}.`);
|
|
187
|
+
}
|
|
188
|
+
for (const value of [discovery.basename, discovery.basenamePrefix]) {
|
|
189
|
+
if (value && (!/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(value) || /[\\/\u0000]/.test(value))) {
|
|
190
|
+
throw new Error(`Unsafe discovery filename rule for ${descriptor.id}.`);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
if (descriptor.confidenceDefaults.pricedFinancialEvidence !== "estimated" ||
|
|
194
|
+
descriptor.confidenceDefaults.unpricedFinancialEvidence !== "missing" ||
|
|
195
|
+
descriptor.confidenceDefaults.sourceConfidence !== "estimated") {
|
|
196
|
+
throw new Error(`Local transcript format ${descriptor.id} must default to estimated/missing financial evidence.`);
|
|
197
|
+
}
|
|
198
|
+
if (descriptor.fixtures.length === 0 || descriptor.fixtures.some((fixture) => (!/^[a-z0-9]+(?:-[a-z0-9]+)*-v[1-9][0-9]*$/.test(fixture)))) {
|
|
199
|
+
throw new Error(`Local-agent format ${descriptor.id} has an unsafe or missing recorded fixture.`);
|
|
200
|
+
}
|
|
201
|
+
ids.add(descriptor.id);
|
|
202
|
+
orders.add(descriptor.order);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
function freezeDescriptor(descriptor) {
|
|
206
|
+
Object.freeze(descriptor.defaultHomeRelative);
|
|
207
|
+
Object.freeze(descriptor.discovery);
|
|
208
|
+
Object.freeze(descriptor.confidenceDefaults);
|
|
209
|
+
Object.freeze(descriptor.sourceRecord);
|
|
210
|
+
Object.freeze(descriptor.capabilities);
|
|
211
|
+
for (const values of Object.values(descriptor.docs)) {
|
|
212
|
+
if (Array.isArray(values))
|
|
213
|
+
Object.freeze(values);
|
|
214
|
+
}
|
|
215
|
+
Object.freeze(descriptor.docs);
|
|
216
|
+
Object.freeze(descriptor.fixtures);
|
|
217
|
+
return Object.freeze(descriptor);
|
|
218
|
+
}
|
|
219
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { LocalAgentFormatRuntime } from "./types.js";
|
|
2
|
+
export declare const localAgentFormatRuntimeRegistry: readonly LocalAgentFormatRuntime[];
|
|
3
|
+
export declare function validateLocalAgentFormatRuntimeRegistry(registry?: readonly LocalAgentFormatRuntime[], descriptors?: readonly import("./types.js").LocalAgentFormatDescriptor[]): void;
|
|
4
|
+
//# sourceMappingURL=runtimeRegistry.d.ts.map
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { parseClaudeCodeTranscript, parseCodexRollout, readClaudeCodeFinancialFileForRegistry, readCodexFinancialFileForRegistry } from "../localAgentLogs.js";
|
|
2
|
+
import { createCodexInvocationCollector } from "../toolInvocations.js";
|
|
3
|
+
import { localAgentFormatDescriptors, validateLocalAgentFormatDescriptors } from "./registry.js";
|
|
4
|
+
const byId = new Map(localAgentFormatDescriptors.map((descriptor) => [descriptor.id, descriptor]));
|
|
5
|
+
const claudeCode = byId.get("claude-code");
|
|
6
|
+
const codex = byId.get("codex");
|
|
7
|
+
if (!claudeCode || !codex) {
|
|
8
|
+
throw new Error("Built-in local-agent format descriptors are incomplete.");
|
|
9
|
+
}
|
|
10
|
+
validateLocalAgentFormatDescriptors();
|
|
11
|
+
const runtimes = [
|
|
12
|
+
{
|
|
13
|
+
descriptor: claudeCode,
|
|
14
|
+
parseFull: ({ content, filePath, sinceMs, onDiagnostic }) => ({
|
|
15
|
+
calls: parseClaudeCodeTranscript(content, filePath, sinceMs, onDiagnostic)
|
|
16
|
+
}),
|
|
17
|
+
parseFinancialFile: readClaudeCodeFinancialFileForRegistry
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
descriptor: codex,
|
|
21
|
+
parseFull: ({ content, sinceMs, collectInvocationEvidence, onDiagnostic }) => {
|
|
22
|
+
const collector = collectInvocationEvidence
|
|
23
|
+
? createCodexInvocationCollector(sinceMs)
|
|
24
|
+
: undefined;
|
|
25
|
+
return {
|
|
26
|
+
calls: parseCodexRollout(content, collector?.consume, onDiagnostic),
|
|
27
|
+
...(collector ? { invocationFile: collector.finish() } : {})
|
|
28
|
+
};
|
|
29
|
+
},
|
|
30
|
+
parseFinancialFile: readCodexFinancialFileForRegistry
|
|
31
|
+
}
|
|
32
|
+
];
|
|
33
|
+
export const localAgentFormatRuntimeRegistry = Object.freeze(runtimes.map((runtime) => Object.freeze(runtime)));
|
|
34
|
+
export function validateLocalAgentFormatRuntimeRegistry(registry = localAgentFormatRuntimeRegistry, descriptors = localAgentFormatDescriptors) {
|
|
35
|
+
validateLocalAgentFormatDescriptors(registry.map((entry) => entry.descriptor));
|
|
36
|
+
const expected = [...registry].sort((left, right) => (left.descriptor.order - right.descriptor.order));
|
|
37
|
+
if (expected.some((entry, index) => entry !== registry[index])) {
|
|
38
|
+
throw new Error("Local-agent runtime registry must be ordered by descriptor order.");
|
|
39
|
+
}
|
|
40
|
+
for (const entry of registry) {
|
|
41
|
+
if (typeof entry.parseFull !== "function" || typeof entry.parseFinancialFile !== "function") {
|
|
42
|
+
throw new Error(`Local-agent format ${entry.descriptor.id} is missing a runtime parser.`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
const runtimeIds = registry.map((entry) => entry.descriptor.id);
|
|
46
|
+
const descriptorIds = descriptors.map((descriptor) => descriptor.id);
|
|
47
|
+
if (JSON.stringify(runtimeIds) !== JSON.stringify(descriptorIds)) {
|
|
48
|
+
throw new Error(`Local-agent runtime registry must exactly match descriptor order: ${descriptorIds.join(", ")}.`);
|
|
49
|
+
}
|
|
50
|
+
if (registry.some((entry, index) => entry.descriptor !== descriptors[index])) {
|
|
51
|
+
throw new Error("Local-agent runtime entries must use the canonical descriptor objects.");
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
validateLocalAgentFormatRuntimeRegistry();
|
|
55
|
+
//# sourceMappingURL=runtimeRegistry.js.map
|