Replace Date.now() with performance.now() for duration measurements (#258)

* Replace Date.now() with performance.now() for duration measurements

- Import performance from node:perf_hooks in all affected files
- Update Timer and ThinkingTimer classes to use performance.now()
- Update activity tracking (markActivity, getIdleMs) to use performance.now()
- Update cache duration measurements to use performance.now()
- Update agent execution timing (cursor, opencode) to use performance.now()
- Update subprocess execution timing to use performance.now()
- Update API performance monitoring to use performance.now()
- Update prep phase timing to use performance.now()
- Update timer.test.ts to mock performance.now() instead of Date.now()

Benefits:
- Monotonic clock immune to system clock adjustments
- Higher precision (microsecond vs millisecond resolution)
- Purpose-built for performance measurement

Fixes #245

* fix lint.

* Round float durations to integers in logging

Preserve original behavior by rounding performance.now() float values
to integers when displaying/logging millisecond durations.

* fix lint.

---------

Co-authored-by: pullfrog[bot] <226033991+pullfrog[bot]@users.noreply.github.com>
Co-authored-by: Robin Tail <robin_tail@me.com>
This commit is contained in:
pullfrog[bot]
2026-02-12 15:26:28 +00:00
committed by pullfrog[bot]
parent a442f766aa
commit b6e6a8976c
8 changed files with 125 additions and 111 deletions
+4 -3
View File
@@ -5,6 +5,7 @@ import { spawn } from "node:child_process";
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
import { homedir } from "node:os";
import { join } from "node:path";
import { performance } from "node:perf_hooks";
import type { Effort } from "../external.ts";
import { ghPullfrogMcpName } from "../external.ts";
import { markActivity } from "../utils/activity.ts";
@@ -249,7 +250,7 @@ export const cursor = agent({
log.info("» running Cursor CLI...");
const startTime = Date.now();
const startTime = performance.now();
// create env without XDG_CONFIG_HOME so CLI uses $HOME/.cursor/ where we wrote config
const cliEnv = Object.fromEntries(
@@ -307,7 +308,7 @@ export const cursor = agent({
log.warning(`Cursor CLI terminated by signal: ${signal}`);
}
const duration = ((Date.now() - startTime) / 1000).toFixed(1);
const duration = ((performance.now() - startTime) / 1000).toFixed(1);
if (code === 0) {
log.success(`Cursor CLI completed successfully in ${duration}s`);
@@ -327,7 +328,7 @@ export const cursor = agent({
});
child.on("error", (error) => {
const duration = ((Date.now() - startTime) / 1000).toFixed(1);
const duration = ((performance.now() - startTime) / 1000).toFixed(1);
const errorMessage = error.message || String(error);
log.error(`Cursor CLI execution failed after ${duration}s: ${errorMessage}`);
resolve({