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.
Files changed (2) hide show
  1. package/bin/codetime.mjs +59 -7
  2. 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 = 2;
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.6.0" : "0.1.1";
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
- // v2 schema: trustworthy gap-clamped turn durations + billable-output token
4365
- // convention. Set on baseRollup (not after) so it participates in payloadHash:
4366
- // every historical rollup's hash changes, and a re-backfill (uploaded with
4367
- // replace=true by default) cleanly refreshes all data onto the new convention.
4368
- // This full-refresh churn is intentional.
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
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "codetime-cli",
3
3
  "type": "module",
4
- "version": "0.6.0",
4
+ "version": "0.7.0",
5
5
  "description": "codetime CLI — install AI-agent hooks (Claude Code, Codex, OpenCode, Pi) and report activity to codetime.dev.",
6
6
  "license": "MIT",
7
7
  "publishConfig": {