codetime-cli 0.6.0 → 0.7.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/bin/codetime.mjs +59 -7
- package/package.json +1 -1
package/bin/codetime.mjs
CHANGED
|
@@ -160,7 +160,7 @@ import { fileURLToPath } from "node:url";
|
|
|
160
160
|
// ../shared/src/index.ts
|
|
161
161
|
import { createHash } from "node:crypto";
|
|
162
162
|
var AGENT_TIME_SCHEMA_VERSION = "2026-04-29";
|
|
163
|
-
var AGENT_ROLLUP_SCHEMA_VERSION =
|
|
163
|
+
var AGENT_ROLLUP_SCHEMA_VERSION = 3;
|
|
164
164
|
var TELEMETRY_EVENT_TYPES = [
|
|
165
165
|
"session.started",
|
|
166
166
|
"session.ended",
|
|
@@ -974,7 +974,7 @@ import { readFile as readFile2, stat as stat2 } from "node:fs/promises";
|
|
|
974
974
|
import path2 from "node:path";
|
|
975
975
|
|
|
976
976
|
// src/lib/constants.ts
|
|
977
|
-
var PACKAGE_VERSION = true ? "0.
|
|
977
|
+
var PACKAGE_VERSION = true ? "0.7.0" : "0.1.1";
|
|
978
978
|
var DEFAULT_API_URL = "https://codetime.dev";
|
|
979
979
|
var DEFAULT_BACKFILL_BATCH_SIZE = 50;
|
|
980
980
|
var DEFAULT_BACKFILL_BATCH_BYTES = 800 * 1024;
|
|
@@ -1932,16 +1932,29 @@ function claudeUsageFromMessage(message) {
|
|
|
1932
1932
|
const outputTokens = numberField(usage, "output_tokens") || 0;
|
|
1933
1933
|
const cachedInputTokens = cacheCreationInputTokens + cacheReadInputTokens;
|
|
1934
1934
|
const totalInputTokens = inputTokens + cachedInputTokens;
|
|
1935
|
+
const cacheCreationSplit = claudeCacheCreationSplit(usage);
|
|
1935
1936
|
return {
|
|
1936
1937
|
tokensInput: totalInputTokens || void 0,
|
|
1937
1938
|
tokensCachedInput: cachedInputTokens || void 0,
|
|
1938
1939
|
tokensCacheCreationInput: cacheCreationInputTokens || void 0,
|
|
1940
|
+
tokensCacheCreation5mInput: cacheCreationSplit?.fiveMinute,
|
|
1941
|
+
tokensCacheCreation1hInput: cacheCreationSplit?.oneHour,
|
|
1939
1942
|
tokensCacheReadInput: cacheReadInputTokens || void 0,
|
|
1940
1943
|
tokensOutput: outputTokens || void 0,
|
|
1941
1944
|
tokensTotal: totalInputTokens + outputTokens || void 0,
|
|
1942
1945
|
modelCalls: 1
|
|
1943
1946
|
};
|
|
1944
1947
|
}
|
|
1948
|
+
function claudeCacheCreationSplit(usage) {
|
|
1949
|
+
const breakdown = usage.cache_creation;
|
|
1950
|
+
if (!isPlainObject(breakdown)) {
|
|
1951
|
+
return void 0;
|
|
1952
|
+
}
|
|
1953
|
+
return {
|
|
1954
|
+
fiveMinute: numberField(breakdown, "ephemeral_5m_input_tokens") || 0,
|
|
1955
|
+
oneHour: numberField(breakdown, "ephemeral_1h_input_tokens") || 0
|
|
1956
|
+
};
|
|
1957
|
+
}
|
|
1945
1958
|
function claudeSubagentMetrics(toolResult, fallbackDurationMs) {
|
|
1946
1959
|
const usage = objectField(toolResult, "usage");
|
|
1947
1960
|
const inputTokens = numberField(usage, "input_tokens") || 0;
|
|
@@ -1950,6 +1963,7 @@ function claudeSubagentMetrics(toolResult, fallbackDurationMs) {
|
|
|
1950
1963
|
const outputTokens = numberField(usage, "output_tokens") || 0;
|
|
1951
1964
|
const cachedInputTokens = cacheCreationInputTokens + cacheReadInputTokens;
|
|
1952
1965
|
const totalInputTokens = inputTokens + cachedInputTokens;
|
|
1966
|
+
const cacheCreationSplit = claudeCacheCreationSplit(usage);
|
|
1953
1967
|
const durationMs = numberField(toolResult, "totalDurationMs") || fallbackDurationMs;
|
|
1954
1968
|
return {
|
|
1955
1969
|
durationMs,
|
|
@@ -1958,6 +1972,8 @@ function claudeSubagentMetrics(toolResult, fallbackDurationMs) {
|
|
|
1958
1972
|
tokensInput: totalInputTokens || void 0,
|
|
1959
1973
|
tokensCachedInput: cachedInputTokens || void 0,
|
|
1960
1974
|
tokensCacheCreationInput: cacheCreationInputTokens || void 0,
|
|
1975
|
+
tokensCacheCreation5mInput: cacheCreationSplit?.fiveMinute,
|
|
1976
|
+
tokensCacheCreation1hInput: cacheCreationSplit?.oneHour,
|
|
1961
1977
|
tokensCacheReadInput: cacheReadInputTokens || void 0,
|
|
1962
1978
|
tokensOutput: outputTokens || void 0,
|
|
1963
1979
|
tokensTotal: numberField(toolResult, "totalTokens") || totalInputTokens + outputTokens || void 0
|
|
@@ -4137,6 +4153,7 @@ function buildSessionRollup(rollupKey, events) {
|
|
|
4137
4153
|
const lastEventAt = ordered.at(-1)?.ts || startedAt;
|
|
4138
4154
|
const timeBuckets = /* @__PURE__ */ new Map();
|
|
4139
4155
|
const modelRollups = /* @__PURE__ */ new Map();
|
|
4156
|
+
const modelBuckets = /* @__PURE__ */ new Map();
|
|
4140
4157
|
const toolRollups = /* @__PURE__ */ new Map();
|
|
4141
4158
|
const fileRollups = /* @__PURE__ */ new Map();
|
|
4142
4159
|
const turnRollups = /* @__PURE__ */ new Map();
|
|
@@ -4158,6 +4175,8 @@ function buildSessionRollup(rollupKey, events) {
|
|
|
4158
4175
|
const eventInputTokens = Math.max(0, event.metrics?.tokensInput || 0);
|
|
4159
4176
|
const eventCachedInputTokens = Math.max(0, event.metrics?.tokensCachedInput || 0);
|
|
4160
4177
|
const eventCacheCreationInputTokens = Math.max(0, event.metrics?.tokensCacheCreationInput || 0);
|
|
4178
|
+
const eventCacheCreation5mInputTokens = Math.max(0, event.metrics?.tokensCacheCreation5mInput || 0);
|
|
4179
|
+
const eventCacheCreation1hInputTokens = Math.max(0, event.metrics?.tokensCacheCreation1hInput || 0);
|
|
4161
4180
|
const eventCacheReadInputTokens = Math.max(0, event.metrics?.tokensCacheReadInput || 0);
|
|
4162
4181
|
const eventOutputTokens = Math.max(0, event.metrics?.tokensOutput || 0);
|
|
4163
4182
|
const eventReasoningOutputTokens = Math.max(0, event.metrics?.tokensReasoningOutput || 0);
|
|
@@ -4278,6 +4297,8 @@ function buildSessionRollup(rollupKey, events) {
|
|
|
4278
4297
|
inputTokens: 0,
|
|
4279
4298
|
cachedInputTokens: 0,
|
|
4280
4299
|
cacheCreationInputTokens: 0,
|
|
4300
|
+
cacheCreation5mInputTokens: 0,
|
|
4301
|
+
cacheCreation1hInputTokens: 0,
|
|
4281
4302
|
cacheReadInputTokens: 0,
|
|
4282
4303
|
outputTokens: 0,
|
|
4283
4304
|
reasoningOutputTokens: 0,
|
|
@@ -4288,12 +4309,40 @@ function buildSessionRollup(rollupKey, events) {
|
|
|
4288
4309
|
modelRollup.inputTokens += eventInputTokens;
|
|
4289
4310
|
modelRollup.cachedInputTokens += eventCachedInputTokens;
|
|
4290
4311
|
modelRollup.cacheCreationInputTokens += eventCacheCreationInputTokens;
|
|
4312
|
+
modelRollup.cacheCreation5mInputTokens += eventCacheCreation5mInputTokens;
|
|
4313
|
+
modelRollup.cacheCreation1hInputTokens += eventCacheCreation1hInputTokens;
|
|
4291
4314
|
modelRollup.cacheReadInputTokens += eventCacheReadInputTokens;
|
|
4292
4315
|
modelRollup.outputTokens += eventOutputTokens;
|
|
4293
4316
|
modelRollup.reasoningOutputTokens += eventReasoningOutputTokens;
|
|
4294
4317
|
modelRollup.totalTokens += eventTotalTokens;
|
|
4295
4318
|
modelRollup.estimatedCostUsd += eventCostUsd;
|
|
4296
4319
|
modelRollups.set(modelKey, modelRollup);
|
|
4320
|
+
const modelBucketKey = `${bucketTs}\0${modelKey}`;
|
|
4321
|
+
const modelBucket = modelBuckets.get(modelBucketKey) || {
|
|
4322
|
+
ts: bucketTs,
|
|
4323
|
+
model: modelKey,
|
|
4324
|
+
callCount: 0,
|
|
4325
|
+
inputTokens: 0,
|
|
4326
|
+
cachedInputTokens: 0,
|
|
4327
|
+
cacheCreationInputTokens: 0,
|
|
4328
|
+
cacheCreation5mInputTokens: 0,
|
|
4329
|
+
cacheCreation1hInputTokens: 0,
|
|
4330
|
+
cacheReadInputTokens: 0,
|
|
4331
|
+
outputTokens: 0,
|
|
4332
|
+
reasoningOutputTokens: 0,
|
|
4333
|
+
totalTokens: 0
|
|
4334
|
+
};
|
|
4335
|
+
modelBucket.callCount += 1;
|
|
4336
|
+
modelBucket.inputTokens += eventInputTokens;
|
|
4337
|
+
modelBucket.cachedInputTokens += eventCachedInputTokens;
|
|
4338
|
+
modelBucket.cacheCreationInputTokens += eventCacheCreationInputTokens;
|
|
4339
|
+
modelBucket.cacheCreation5mInputTokens += eventCacheCreation5mInputTokens;
|
|
4340
|
+
modelBucket.cacheCreation1hInputTokens += eventCacheCreation1hInputTokens;
|
|
4341
|
+
modelBucket.cacheReadInputTokens += eventCacheReadInputTokens;
|
|
4342
|
+
modelBucket.outputTokens += eventOutputTokens;
|
|
4343
|
+
modelBucket.reasoningOutputTokens += eventReasoningOutputTokens;
|
|
4344
|
+
modelBucket.totalTokens += eventTotalTokens;
|
|
4345
|
+
modelBuckets.set(modelBucketKey, modelBucket);
|
|
4297
4346
|
}
|
|
4298
4347
|
if (event.type === "tool.started") {
|
|
4299
4348
|
bucket.toolCalls += 1;
|
|
@@ -4361,11 +4410,12 @@ function buildSessionRollup(rollupKey, events) {
|
|
|
4361
4410
|
const baseRollup = {
|
|
4362
4411
|
rollupKey,
|
|
4363
4412
|
payloadHash: "",
|
|
4364
|
-
//
|
|
4365
|
-
// convention
|
|
4366
|
-
//
|
|
4367
|
-
//
|
|
4368
|
-
//
|
|
4413
|
+
// v3 schema: v2 (gap-clamped turn durations + billable-output token
|
|
4414
|
+
// convention) plus per-model cache-creation TTL split and modelBuckets. Set on
|
|
4415
|
+
// baseRollup (not after) so it participates in payloadHash: every historical
|
|
4416
|
+
// rollup's hash changes, and a re-backfill (uploaded with replace=true by
|
|
4417
|
+
// default) cleanly refreshes all data onto the new convention. This
|
|
4418
|
+
// full-refresh churn is intentional.
|
|
4369
4419
|
schemaVersion: AGENT_ROLLUP_SCHEMA_VERSION,
|
|
4370
4420
|
source: first.source,
|
|
4371
4421
|
project,
|
|
@@ -4390,6 +4440,8 @@ function buildSessionRollup(rollupKey, events) {
|
|
|
4390
4440
|
durationMs: Math.max(0, Date.parse(lastEventAt) - Date.parse(startedAt)),
|
|
4391
4441
|
timeBuckets: [...timeBuckets.values()].sort((a, b) => a.ts.localeCompare(b.ts)),
|
|
4392
4442
|
modelRollups: [...modelRollups.values()].sort((a, b) => b.callCount - a.callCount || a.model.localeCompare(b.model)),
|
|
4443
|
+
// Sorted ts ascending, then model lexicographically (wire contract).
|
|
4444
|
+
modelBuckets: [...modelBuckets.values()].sort((a, b) => a.ts.localeCompare(b.ts) || a.model.localeCompare(b.model)),
|
|
4393
4445
|
toolRollups: [...toolRollups.values()].sort((a, b) => b.callCount - a.callCount || a.tool.localeCompare(b.tool)),
|
|
4394
4446
|
fileRollups: [...fileRollups.values()].sort((a, b) => b.writes - a.writes || b.reads - a.reads || a.displayPath.localeCompare(b.displayPath)),
|
|
4395
4447
|
turnRollups: [...turnRollups.values()].map((rollup) => ({
|
package/package.json
CHANGED