feat(agents): add thinking time logging between tool calls (#244)

* feat(agents): add thinking time logging between tool calls

Adds a ThinkingTimer utility that tracks the gap between tool results and
the next tool call. When the gap exceeds 3 seconds, it logs the duration
with a stopwatch emoji (⏱️ 4.2s).

Uses performance.now() for high-resolution timing and Intl.NumberFormat
for rendering duration in seconds with optional fraction digits.

Integrated across all 5 agents: Claude, Codex, Cursor, Gemini, OpenCode.

Closes #127

* fix: adjusting tests for mocking performance.now.

* fix: reducing diff for claude.

* fix: rm unused args for claude.

* rm unused args for codex.

* fix: rm unused args for gemini.

* fix: rm unused args for opencode.

* mv THINKING_THRESHOLD.

* rev: I decided to pospone node:perf_hooks integration since it requires more comprehensive refactoring.

* fix: using Intl unit formatting.

* tests for ThinkingTimer.

* fix: narrow unit.

* fix: making durationFormatter a class instance property since using one agent per run.

* fix: inverting condition in markToolCall.

* thinking timer improvements and fix actions/checkout v6 auth

- thinking timer: use » chevron and "thought for X seconds" format
- thinking timer: add debug timestamps for sanity checking
- demote PID namespace isolation logs to debug
- remove redundant "setting up git authentication" log
- fix duplicate Authorization header with actions/checkout v6: clean up
  includeIf credential entries that v6 persists via external config files

Co-authored-by: Cursor <cursoragent@cursor.com>

* standardize tool call log prefix to » double chevron

Co-authored-by: Cursor <cursoragent@cursor.com>

* update timer tests for new thinking log format

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: pullfrog[bot] <226033991+pullfrog[bot]@users.noreply.github.com>
Co-authored-by: Robin Tail <robin_tail@me.com>
Co-authored-by: Colin McDonnell <colinmcd94@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
pullfrog[bot]
2026-02-10 06:17:43 +00:00
committed by pullfrog[bot]
parent f67cc25f74
commit fb80343ffd
13 changed files with 294 additions and 54 deletions
+23 -2
View File
@@ -120,8 +120,6 @@ export async function setupGit(params: SetupGitParams): Promise<void> {
}
// 2. setup authentication
log.info("» setting up git authentication...");
// remove existing git auth headers that actions/checkout might have set
try {
execSync("git config --local --unset-all http.https://github.com/.extraheader", {
@@ -133,6 +131,29 @@ export async function setupGit(params: SetupGitParams): Promise<void> {
log.debug("» no existing authentication headers to remove");
}
// remove includeIf entries that actions/checkout@v6 uses for credential persistence.
// v6 stores credentials in an external file loaded via includeIf.gitdir, which our
// --unset-all above doesn't catch. without this, $git() would produce duplicate
// Authorization headers (one from includeIf, one from GIT_CONFIG_PARAMETERS).
try {
const configOutput = execSync("git config --local --get-regexp ^includeif\\.", {
cwd: repoDir,
encoding: "utf-8",
stdio: "pipe",
});
for (const line of configOutput.trim().split("\n")) {
const key = line.split(" ")[0];
if (!key) continue;
execSync(`git config --local --unset "${key}"`, {
cwd: repoDir,
stdio: "pipe",
});
}
log.info("» removed includeIf credential entries");
} catch {
log.debug("» no includeIf credential entries to remove");
}
// SECURITY: set origin URL without token - auth is injected via GIT_CONFIG_PARAMETERS
// in $git() calls. this prevents token leakage to git hooks and subprocesses.
const originUrl = `https://github.com/${params.owner}/${params.name}.git`;