@newrelic/preflight 1.14.35 → 1.14.37
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/dashboard/routes/api-handler.d.ts +3 -3
- package/dist/dashboard/routes/api-handler.d.ts.map +1 -1
- package/dist/dashboard/routes/api-handler.js +170 -39
- package/dist/dashboard/routes/api-handler.js.map +1 -1
- package/dist/dashboard/workflow-store.d.ts +20 -0
- package/dist/dashboard/workflow-store.d.ts.map +1 -1
- package/dist/dashboard/workflow-store.js +8 -0
- package/dist/dashboard/workflow-store.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +126 -42
- package/dist/index.js.map +1 -1
- package/dist/metrics/cost-tracker.d.ts +17 -0
- package/dist/metrics/cost-tracker.d.ts.map +1 -1
- package/dist/metrics/cost-tracker.js +19 -0
- package/dist/metrics/cost-tracker.js.map +1 -1
- package/dist/metrics/decision-tracker.d.ts +18 -1
- package/dist/metrics/decision-tracker.d.ts.map +1 -1
- package/dist/metrics/decision-tracker.js +28 -11
- package/dist/metrics/decision-tracker.js.map +1 -1
- package/dist/metrics/git-efficiency-tracker.d.ts +18 -5
- package/dist/metrics/git-efficiency-tracker.d.ts.map +1 -1
- package/dist/metrics/git-efficiency-tracker.js +335 -137
- package/dist/metrics/git-efficiency-tracker.js.map +1 -1
- package/dist/metrics/turn-cost-attributor.d.ts +37 -7
- package/dist/metrics/turn-cost-attributor.d.ts.map +1 -1
- package/dist/metrics/turn-cost-attributor.js +140 -45
- package/dist/metrics/turn-cost-attributor.js.map +1 -1
- package/dist/security/audit-trail.d.ts +32 -1
- package/dist/security/audit-trail.d.ts.map +1 -1
- package/dist/security/audit-trail.js +142 -4
- package/dist/security/audit-trail.js.map +1 -1
- package/dist/storage/local-store.d.ts +29 -0
- package/dist/storage/local-store.d.ts.map +1 -1
- package/dist/storage/local-store.js +93 -0
- package/dist/storage/local-store.js.map +1 -1
- package/dist/web/assets/{index-DI6sTfcj.js → index-ndsRsiKh.js} +3 -3
- package/dist/web/index.html +1 -1
- package/package.json +1 -1
|
@@ -157,13 +157,13 @@ export interface ApiHandlerDeps {
|
|
|
157
157
|
getMetrics: () => InstructionDriftMetrics;
|
|
158
158
|
};
|
|
159
159
|
readonly decisionTracker?: {
|
|
160
|
-
getMetrics: () => DecisionTreeMetrics;
|
|
160
|
+
getMetrics: (sessionId?: string) => DecisionTreeMetrics;
|
|
161
161
|
};
|
|
162
162
|
readonly turnCostAttributor?: {
|
|
163
|
-
getMetrics: () => CostAttributionMetrics;
|
|
163
|
+
getMetrics: (sessionId?: string) => CostAttributionMetrics;
|
|
164
164
|
};
|
|
165
165
|
readonly auditTrailManager?: {
|
|
166
|
-
getAuditLog: () => readonly AuditRecord[];
|
|
166
|
+
getAuditLog: (limit?: number) => readonly AuditRecord[];
|
|
167
167
|
};
|
|
168
168
|
readonly weeklySummaryGenerator?: WeeklySummaryGenerator;
|
|
169
169
|
readonly budgetTracker?: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api-handler.d.ts","sourceRoot":"","sources":["../../../src/dashboard/routes/api-handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAc5D,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AAC9E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,EAEL,KAAK,yBAAyB,EAC/B,MAAM,mCAAmC,CAAC;AAS3C,OAAO,KAAK,EAAkC,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC7F,OAAO,KAAK,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAC1F,OAAO,KAAK,EAAE,cAAc,EAAoB,MAAM,sBAAsB,CAAC;AAC7E,OAAO,KAAK,EACV,gBAAgB,EAChB,SAAS,EACT,qBAAqB,EACtB,MAAM,+BAA+B,CAAC;AACvC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAEnE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AACpE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AAC9E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wCAAwC,CAAC;AAC7E,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,yCAAyC,CAAC;AACpF,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"api-handler.d.ts","sourceRoot":"","sources":["../../../src/dashboard/routes/api-handler.ts"],"names":[],"mappings":"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"}
|
|
@@ -46,6 +46,7 @@ function toWorkflowRunDto(row) {
|
|
|
46
46
|
agentCount: r.agent_count,
|
|
47
47
|
totalTokens: r.total_tokens,
|
|
48
48
|
totalUsd: r.total_usd ?? null,
|
|
49
|
+
costUnknown: r.cost_unknown ?? false,
|
|
49
50
|
declaredPhases: r.declared_phases ?? null,
|
|
50
51
|
observedPhases: r.observed_phases,
|
|
51
52
|
declaredParallelWidths: r.declared_parallel_widths ?? [],
|
|
@@ -93,6 +94,11 @@ function toLiveWorkflowDetail(live) {
|
|
|
93
94
|
agentCount: live.agentCount,
|
|
94
95
|
totalTokens: live.totalTokens,
|
|
95
96
|
totalUsd: live.totalUsd,
|
|
97
|
+
// A still-running workflow's cost comes straight from this process's own
|
|
98
|
+
// live SubagentWatcher state, not a cross-process/restart-vulnerable
|
|
99
|
+
// on-disk rollup — so it's never ambiguous the way a completed run's
|
|
100
|
+
// WorkflowStore-read cost can be.
|
|
101
|
+
costUnknown: false,
|
|
96
102
|
declaredPhases: live.topology?.declaredPhases ?? null,
|
|
97
103
|
// No phase-title telemetry exists mid-run (that comes from the rollup's
|
|
98
104
|
// workflowProgress), so observed phases are unknown → 0.
|
|
@@ -319,18 +325,44 @@ function computeTodayPeakConcurrency(sessions) {
|
|
|
319
325
|
}
|
|
320
326
|
return peak;
|
|
321
327
|
}
|
|
328
|
+
// Mirrors QualityProxyTracker's own getRawCounts()/countBySignal() math, but
|
|
329
|
+
// over a caller-filtered event slice — needed so GET /api/quality-proxy can
|
|
330
|
+
// day-filter this process's own live contribution (see the startMs pattern
|
|
331
|
+
// in GET /api/tool-selection-score) without adding a day-bucketed accessor
|
|
332
|
+
// to the tracker itself.
|
|
333
|
+
function rawQualityCountsFromEvents(events) {
|
|
334
|
+
const count = (signal) => events.filter((e) => e.signal === signal).length;
|
|
335
|
+
return {
|
|
336
|
+
totalSignals: events.length,
|
|
337
|
+
diffApplyCleanCount: count('diff_applied_clean'),
|
|
338
|
+
diffFailCount: count('diff_failed'),
|
|
339
|
+
testPassCount: count('test_pass'),
|
|
340
|
+
testFailCount: count('test_fail'),
|
|
341
|
+
backtrackCount: count('backtrack'),
|
|
342
|
+
selfCorrectionCount: count('self_correction'),
|
|
343
|
+
};
|
|
344
|
+
}
|
|
322
345
|
function computeDailyPeakConcurrency(sessions, days) {
|
|
323
|
-
|
|
346
|
+
// Local (not UTC) day boundaries — see localStartOfDay's doc comment. A
|
|
347
|
+
// developer's evening session commonly straddles UTC midnight, which would
|
|
348
|
+
// otherwise land that activity on the wrong calendar day for anyone not in
|
|
349
|
+
// UTC, and disagree with this same file's local-day `aggregateDailyCost`
|
|
350
|
+
// equivalent on the client (History.tsx).
|
|
351
|
+
const todayStart = localStartOfDay();
|
|
324
352
|
const result = [];
|
|
325
353
|
for (let d = days - 1; d >= 0; d--) {
|
|
326
|
-
const dayStart = new Date(
|
|
327
|
-
dayStart.
|
|
328
|
-
dayStart.setUTCHours(0, 0, 0, 0);
|
|
329
|
-
const dayEnd = new Date(dayStart);
|
|
330
|
-
dayEnd.setUTCDate(dayEnd.getUTCDate() + 1);
|
|
354
|
+
const dayStart = new Date(todayStart);
|
|
355
|
+
dayStart.setDate(dayStart.getDate() - d);
|
|
331
356
|
const dayStartMs = dayStart.getTime();
|
|
357
|
+
// `dayEnd` must be derived via the same local-date arithmetic as
|
|
358
|
+
// `dayStart`, not `dayStartMs + 86_400_000` — a local calendar day is
|
|
359
|
+
// 23h or 25h long on the ~2 DST-transition days/year, so the fixed-ms
|
|
360
|
+
// offset lands an hour into (or short of) the next/previous local day,
|
|
361
|
+
// misattributing entries near the boundary on those days.
|
|
362
|
+
const dayEnd = new Date(dayStart);
|
|
363
|
+
dayEnd.setDate(dayEnd.getDate() + 1);
|
|
332
364
|
const dayEndMs = dayEnd.getTime();
|
|
333
|
-
const dateKey =
|
|
365
|
+
const dateKey = localDateKey(dayStartMs);
|
|
334
366
|
// Find sessions that overlap with this day and have timeline data
|
|
335
367
|
const events = [];
|
|
336
368
|
for (const session of sessions) {
|
|
@@ -570,6 +602,12 @@ export function createApiHandler(deps) {
|
|
|
570
602
|
durationMs: live.sessionDurationMs,
|
|
571
603
|
toolCallCount: live.toolCallCount,
|
|
572
604
|
estimatedCostUsd: deps.costTracker?.getMetrics().sessionTotalCostUsd ?? null,
|
|
605
|
+
// costTracker.getMetrics() also exposes the model this live
|
|
606
|
+
// session is actually using; without it, aggregateModelPerformance
|
|
607
|
+
// (History.tsx) buckets this session's real-time cost/count under
|
|
608
|
+
// "unknown" until the session is persisted and rebuilt with a
|
|
609
|
+
// real `model` field.
|
|
610
|
+
model: deps.costTracker?.getMetrics().model ?? null,
|
|
573
611
|
});
|
|
574
612
|
}
|
|
575
613
|
}
|
|
@@ -1143,15 +1181,24 @@ export function createApiHandler(deps) {
|
|
|
1143
1181
|
return unavailable(res, 'instructionDriftTracker');
|
|
1144
1182
|
jsonOk(res, deps.instructionDriftTracker.getMetrics());
|
|
1145
1183
|
});
|
|
1146
|
-
routes.set('GET /api/decision-tree', (
|
|
1184
|
+
routes.set('GET /api/decision-tree', (req, res) => {
|
|
1147
1185
|
if (!deps.decisionTracker)
|
|
1148
1186
|
return unavailable(res, 'decisionTracker');
|
|
1149
|
-
|
|
1187
|
+
// Optional ?sessionId= scopes the result to one session — without
|
|
1188
|
+
// it, this process-global tracker's data can belong to a different
|
|
1189
|
+
// session than the one selected in the dashboard's trace pane (in
|
|
1190
|
+
// `--local` mode, several concurrently-live sessions blended together).
|
|
1191
|
+
const url = new URL(req.url ?? '/', 'http://localhost');
|
|
1192
|
+
const sessionId = url.searchParams.get('sessionId') ?? undefined;
|
|
1193
|
+
jsonOk(res, deps.decisionTracker.getMetrics(sessionId));
|
|
1150
1194
|
});
|
|
1151
|
-
routes.set('GET /api/turn-costs', (
|
|
1195
|
+
routes.set('GET /api/turn-costs', (req, res) => {
|
|
1152
1196
|
if (!deps.turnCostAttributor)
|
|
1153
1197
|
return unavailable(res, 'turnCostAttributor');
|
|
1154
|
-
|
|
1198
|
+
// Same reasoning as /api/decision-tree above.
|
|
1199
|
+
const url = new URL(req.url ?? '/', 'http://localhost');
|
|
1200
|
+
const sessionId = url.searchParams.get('sessionId') ?? undefined;
|
|
1201
|
+
jsonOk(res, deps.turnCostAttributor.getMetrics(sessionId));
|
|
1155
1202
|
});
|
|
1156
1203
|
routes.set('GET /api/compute-waste', (_req, res) => {
|
|
1157
1204
|
if (!deps.retryDetector)
|
|
@@ -1188,10 +1235,21 @@ export function createApiHandler(deps) {
|
|
|
1188
1235
|
status,
|
|
1189
1236
|
});
|
|
1190
1237
|
});
|
|
1191
|
-
routes.set('GET /api/audit', (
|
|
1238
|
+
routes.set('GET /api/audit', (req, res) => {
|
|
1192
1239
|
if (!deps.auditTrailManager)
|
|
1193
1240
|
return unavailable(res, 'auditTrailManager');
|
|
1194
|
-
|
|
1241
|
+
// Cap here too (not just via getAuditLog()'s own default) so a caller
|
|
1242
|
+
// can't force an unbounded read by passing an absurdly large `limit` —
|
|
1243
|
+
// the audit log is unpruned on disk, so a naive pass-through would let
|
|
1244
|
+
// a single request re-read the entire history.
|
|
1245
|
+
const url = new URL(req.url ?? '/', 'http://localhost');
|
|
1246
|
+
const limitStr = url.searchParams.get('limit') ?? '';
|
|
1247
|
+
let limit = 1000;
|
|
1248
|
+
const parsedLimit = parseInt(limitStr, 10);
|
|
1249
|
+
if (!Number.isNaN(parsedLimit)) {
|
|
1250
|
+
limit = Math.min(Math.max(parsedLimit, 1), 2000);
|
|
1251
|
+
}
|
|
1252
|
+
const log = deps.auditTrailManager.getAuditLog(limit);
|
|
1195
1253
|
jsonOk(res, log.map(toAuditEntry));
|
|
1196
1254
|
});
|
|
1197
1255
|
routes.set('GET /api/weekly', (req, res) => {
|
|
@@ -1285,8 +1343,21 @@ export function createApiHandler(deps) {
|
|
|
1285
1343
|
if (!Number.isNaN(parsedDays)) {
|
|
1286
1344
|
days = Math.min(Math.max(parsedDays, 1), 365);
|
|
1287
1345
|
}
|
|
1288
|
-
|
|
1289
|
-
|
|
1346
|
+
// Anchor the window to local midnight `days` ago — matching
|
|
1347
|
+
// aggregateDailyCost's local-day grouping for the sibling "Daily Spend"
|
|
1348
|
+
// chart (History.tsx) — instead of a raw rolling instant, which doesn't
|
|
1349
|
+
// align with any calendar boundary and would draw a different
|
|
1350
|
+
// "last N days" line than that chart. loadAllSessions()'s own
|
|
1351
|
+
// pre-filter still compares against session-store.ts's UTC-derived
|
|
1352
|
+
// filename date, so `since` is widened by one extra day to guarantee it
|
|
1353
|
+
// never excludes a session that actually falls inside the local window;
|
|
1354
|
+
// the startTime check below applies the real, local-day-aligned cutoff.
|
|
1355
|
+
const windowStartMs = localStartOfDay() - (days - 1) * 86_400_000;
|
|
1356
|
+
const since = new Date(windowStartMs - 86_400_000);
|
|
1357
|
+
const sessions = deps.sessionStore.loadAllSessions({ since }).filter((s) => {
|
|
1358
|
+
const startTime = s.startTime;
|
|
1359
|
+
return startTime === undefined || startTime >= windowStartMs;
|
|
1360
|
+
});
|
|
1290
1361
|
jsonOk(res, attributeSessionCosts(sessions));
|
|
1291
1362
|
});
|
|
1292
1363
|
routes.set('GET /api/personal-coach', (_req, res) => {
|
|
@@ -1397,13 +1468,19 @@ export function createApiHandler(deps) {
|
|
|
1397
1468
|
// live tracker only.
|
|
1398
1469
|
const live = deps.qualityProxyTracker.getMetrics();
|
|
1399
1470
|
const ownSessionId = deps.sessionTracker?.getMetrics().sessionId;
|
|
1471
|
+
// Day-filter this process's own live contribution the same way GET
|
|
1472
|
+
// /api/tool-selection-score does just below — QualityProxyTracker has no
|
|
1473
|
+
// concept of "day" internally (events accumulate for the tracker's whole
|
|
1474
|
+
// process lifetime), so a --local dashboard daemon running since before
|
|
1475
|
+
// midnight would otherwise blend yesterday's (or older) signals into
|
|
1476
|
+
// "today's sessions" here, inconsistent with the correctly-scoped Tool
|
|
1477
|
+
// Selection panel right next to it.
|
|
1478
|
+
const startMs = localStartOfDay(Date.now());
|
|
1479
|
+
const liveRawCounts = rawQualityCountsFromEvents(live.events.filter((e) => e.timestamp >= startMs));
|
|
1400
1480
|
const persistedCounts = (deps.sessionStore?.loadTodaySessions() ?? [])
|
|
1401
1481
|
.filter((s) => s.sessionId !== ownSessionId)
|
|
1402
1482
|
.map((s) => s.qualityProxy ?? ZERO_QUALITY_PROXY_COUNTS);
|
|
1403
|
-
const combined = combineQualityProxyRawCounts([
|
|
1404
|
-
deps.qualityProxyTracker.getRawCounts(),
|
|
1405
|
-
...persistedCounts,
|
|
1406
|
-
]);
|
|
1483
|
+
const combined = combineQualityProxyRawCounts([liveRawCounts, ...persistedCounts]);
|
|
1407
1484
|
jsonOk(res, {
|
|
1408
1485
|
...combined,
|
|
1409
1486
|
qualityByTurnBucket: live.qualityByTurnBucket,
|
|
@@ -1541,15 +1618,15 @@ export function createApiHandler(deps) {
|
|
|
1541
1618
|
// Derive the headline "today peak" from the SAME buckets shown in the
|
|
1542
1619
|
// chart — rather than from an independent computation over a
|
|
1543
1620
|
// differently-scoped session set — so the two numbers can never
|
|
1544
|
-
// disagree by construction.
|
|
1545
|
-
//
|
|
1546
|
-
//
|
|
1621
|
+
// disagree by construction. Computing them from two different
|
|
1622
|
+
// concurrency models is exactly how the headline and chart can
|
|
1623
|
+
// silently drift apart.
|
|
1547
1624
|
//
|
|
1548
1625
|
// Deliberately NOT folded with `livePeak` here (unlike allTimePeak
|
|
1549
1626
|
// below): `livePeak` is a synthetic-id-unfiltered, never-reset
|
|
1550
1627
|
// lifetime max from LiveSessionRegistry, so mixing it into today's
|
|
1551
|
-
// headline can reintroduce
|
|
1552
|
-
//
|
|
1628
|
+
// headline can reintroduce that same chart/headline disagreement.
|
|
1629
|
+
// It's unnecessary anyway:
|
|
1553
1630
|
// `windows` already unions each live session's buffered (not-yet-
|
|
1554
1631
|
// persisted) activity into the same buckets, so a currently-live
|
|
1555
1632
|
// session with any tool-call activity is already reflected here.
|
|
@@ -1573,6 +1650,15 @@ export function createApiHandler(deps) {
|
|
|
1573
1650
|
const url = new URL(req.url ?? '/', 'http://localhost');
|
|
1574
1651
|
const view = url.searchParams.get('view') ?? 'today';
|
|
1575
1652
|
if (view === 'today') {
|
|
1653
|
+
// localStartOfDay() draws "today" using this dashboard *server*
|
|
1654
|
+
// process's own OS/Intl timezone. The browser calls the same helper
|
|
1655
|
+
// client-side (src/lib/date.ts) for its own "today" filtering, so
|
|
1656
|
+
// this endpoint is only guaranteed to agree with the client when
|
|
1657
|
+
// server and browser share a timezone — the common single-machine
|
|
1658
|
+
// `--local`/`--stdio` deployment. A cloud-hosted or containerized
|
|
1659
|
+
// dashboard viewed from a different timezone can see this bucket
|
|
1660
|
+
// range anchored to the wrong midnight; neither side is ever
|
|
1661
|
+
// told the other's offset today.
|
|
1576
1662
|
const now = Date.now();
|
|
1577
1663
|
const startMs = localStartOfDay(now);
|
|
1578
1664
|
const bucketSizeMs = 900_000;
|
|
@@ -1616,25 +1702,52 @@ export function createApiHandler(deps) {
|
|
|
1616
1702
|
if (view === 'history') {
|
|
1617
1703
|
const weeksParam = url.searchParams.get('weeks');
|
|
1618
1704
|
const weeks = weeksParam ? Math.min(Math.max(parseInt(weeksParam, 10) || 12, 1), 52) : 12;
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1705
|
+
// Local (not UTC) day boundaries — see localStartOfDay's doc comment
|
|
1706
|
+
// and computeDailyPeakConcurrency's identical handling just above. A
|
|
1707
|
+
// developer's evening session commonly straddles UTC midnight, which
|
|
1708
|
+
// would otherwise land that activity on the wrong calendar day for
|
|
1709
|
+
// anyone not in UTC.
|
|
1710
|
+
const todayStart = localStartOfDay();
|
|
1711
|
+
const startDate = new Date(todayStart);
|
|
1712
|
+
startDate.setDate(startDate.getDate() - weeks * 7);
|
|
1623
1713
|
const sessions = deps.sessionStore?.loadAllSessions?.({ since: startDate }) ?? [];
|
|
1624
1714
|
const dayMap = new Map();
|
|
1625
1715
|
const cursor = new Date(startDate);
|
|
1626
|
-
while (cursor <=
|
|
1627
|
-
dayMap.set(cursor.
|
|
1628
|
-
cursor.
|
|
1716
|
+
while (cursor.getTime() <= todayStart) {
|
|
1717
|
+
dayMap.set(localDateKey(cursor.getTime()), 0);
|
|
1718
|
+
cursor.setDate(cursor.getDate() + 1);
|
|
1629
1719
|
}
|
|
1720
|
+
// Bucket by each timeline entry's own timestamp, mirroring the
|
|
1721
|
+
// `view=today` branch above — not by attributing a session's entire
|
|
1722
|
+
// toolCallCount to the single day it *started* on. A session whose
|
|
1723
|
+
// activity spans a day boundary would otherwise show a false spike
|
|
1724
|
+
// on the start day and a false gap on the day(s) it actually
|
|
1725
|
+
// continued into.
|
|
1726
|
+
//
|
|
1727
|
+
// `timeline` is optional and was only added to persisted sessions
|
|
1728
|
+
// ~2026-06-02 (session-store.ts) — this route's default 12-week
|
|
1729
|
+
// window still reaches sessions saved before that. A session with no
|
|
1730
|
+
// timeline falls back to the old, still local-day-keyed,
|
|
1731
|
+
// start-day/toolCallCount attribution so that older history doesn't
|
|
1732
|
+
// silently drop to zero; only sessions that *do* have a timeline get
|
|
1733
|
+
// the per-entry walk.
|
|
1734
|
+
const startMs = startDate.getTime();
|
|
1630
1735
|
for (const s of sessions) {
|
|
1631
1736
|
const session = s;
|
|
1632
|
-
if (
|
|
1737
|
+
if (session.timeline) {
|
|
1738
|
+
for (const entry of session.timeline) {
|
|
1739
|
+
if (entry.timestamp < startMs)
|
|
1740
|
+
continue;
|
|
1741
|
+
const key = localDateKey(entry.timestamp);
|
|
1742
|
+
if (dayMap.has(key)) {
|
|
1743
|
+
dayMap.set(key, (dayMap.get(key) ?? 0) + 1);
|
|
1744
|
+
}
|
|
1745
|
+
}
|
|
1633
1746
|
continue;
|
|
1634
|
-
|
|
1635
|
-
if (
|
|
1747
|
+
}
|
|
1748
|
+
if (!session.startTime || session.startTime < startMs)
|
|
1636
1749
|
continue;
|
|
1637
|
-
const key =
|
|
1750
|
+
const key = localDateKey(session.startTime);
|
|
1638
1751
|
if (dayMap.has(key)) {
|
|
1639
1752
|
dayMap.set(key, (dayMap.get(key) ?? 0) + (session.toolCallCount ?? 0));
|
|
1640
1753
|
}
|
|
@@ -1655,7 +1768,14 @@ export function createApiHandler(deps) {
|
|
|
1655
1768
|
routes.set('GET /api/git-efficiency/repos', (_req, res) => {
|
|
1656
1769
|
if (!deps.sessionStore)
|
|
1657
1770
|
return unavailable(res, 'sessionStore');
|
|
1658
|
-
|
|
1771
|
+
// Prefer loadSessionsOverlappingToday() so a session that started
|
|
1772
|
+
// yesterday and crossed into today isn't invisible from these pills —
|
|
1773
|
+
// loadTodaySessions() filters by filename date (= start date) and would
|
|
1774
|
+
// otherwise silently drop it, even though its git activity still counts
|
|
1775
|
+
// toward the KPIs shown alongside these pills — same reasoning as the
|
|
1776
|
+
// day-boundary hydration in src/index.ts.
|
|
1777
|
+
const todaySessions = (deps.sessionStore.loadSessionsOverlappingToday?.() ??
|
|
1778
|
+
deps.sessionStore.loadTodaySessions());
|
|
1659
1779
|
const repoSet = new Set();
|
|
1660
1780
|
for (const session of todaySessions) {
|
|
1661
1781
|
if (typeof session.repoName === 'string' && session.repoName) {
|
|
@@ -2027,6 +2147,13 @@ export function createApiHandler(deps) {
|
|
|
2027
2147
|
const responseBody = { ...session };
|
|
2028
2148
|
if (quality.totalSignals > 0)
|
|
2029
2149
|
responseBody.qualityProxy = quality;
|
|
2150
|
+
// `session.timeline` is append-only in processing order, not
|
|
2151
|
+
// timestamp order (parallel tool calls can complete out of
|
|
2152
|
+
// start-order) — sort before returning, mirroring the identical
|
|
2153
|
+
// fix already applied to buildReplayResponse()'s persisted branch.
|
|
2154
|
+
if (Array.isArray(session.timeline)) {
|
|
2155
|
+
responseBody.timeline = [...session.timeline].sort((a, b) => a.timestamp - b.timestamp);
|
|
2156
|
+
}
|
|
2030
2157
|
jsonOk(res, responseBody);
|
|
2031
2158
|
return;
|
|
2032
2159
|
}
|
|
@@ -2066,13 +2193,17 @@ export function createApiHandler(deps) {
|
|
|
2066
2193
|
: undefined,
|
|
2067
2194
|
// Use the same `timeline` shape as persisted sessions so the
|
|
2068
2195
|
// Sessions and Replay views can consume one type. See
|
|
2069
|
-
// src/storage/types.ts ReplayTimelineEntry.
|
|
2070
|
-
|
|
2196
|
+
// src/storage/types.ts ReplayTimelineEntry. `toolCallTimeline`
|
|
2197
|
+
// is append-only in processing order, not timestamp order —
|
|
2198
|
+
// sort before returning, mirroring buildReplayResponse().
|
|
2199
|
+
timeline: live.toolCallTimeline
|
|
2200
|
+
.map((t) => ({
|
|
2071
2201
|
timestamp: t.timestamp,
|
|
2072
2202
|
toolName: t.toolName,
|
|
2073
2203
|
durationMs: t.durationMs,
|
|
2074
2204
|
success: t.success ?? true,
|
|
2075
|
-
}))
|
|
2205
|
+
}))
|
|
2206
|
+
.sort((a, b) => a.timestamp - b.timestamp),
|
|
2076
2207
|
});
|
|
2077
2208
|
return;
|
|
2078
2209
|
}
|