Skip to content

Commit d466859

Browse files
author
wangchen01
committed
fix(session-analysis): recognize lowercase edit tool names from Pi sessions
Pi's coding agent emits lowercase tool names (edit, write), while the edit-event detection in episode-contract and insights matched Claude Code's capitalized names (Edit, Write) with a case-sensitive Set lookup. Every Pi edit event was therefore missed, which surfaced as withChanges: 0 in session facts for any workspace with real commits. Store the edit tool names lowercase and compare against the lowercased tool name, matching the existing case-insensitive check used for PATHLESS_EDIT_TOOL_NAMES in the same function. Validation: reran session-analysis facts --platform pi over a 254-session workspace; populationCoverage.withChanges moved 0 -> 29, candidate classes gained change-gap 11, and read-only-work dropped 44 -> 21 as editing episodes were no longer misclassified. The existing episode contract and lifecycle signal tests (28 tests, all using capitalized Claude tool names) pass unchanged, confirming backward compatibility.
1 parent 1eea73a commit d466859

2 files changed

Lines changed: 13 additions & 9 deletions

File tree

‎scripts/session-analysis/episode-contract.mjs‎

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,16 @@ export const EVENT_SCHEMA_VERSION = 2;
1111
export const TASK_EPISODE_SCHEMA_VERSION = 3;
1212
export const DEFAULT_EPISODE_GAP_MS = 30 * 60 * 1000;
1313

14+
// Tool-name matching is case-insensitive: providers differ in casing
15+
// (Claude Code emits "Edit"/"Write", pi emits "edit"/"write"), so entries
16+
// are stored lowercase and compared against the lowercased tool name.
1417
const EDIT_TOOL_NAMES = new Set([
15-
"Edit",
16-
"MultiEdit",
17-
"NotebookEdit",
18-
"NotebookWrite",
19-
"SearchReplace",
20-
"Write",
18+
"edit",
19+
"multiedit",
20+
"notebookedit",
21+
"notebookwrite",
22+
"searchreplace",
23+
"write",
2124
]);
2225
const PATHLESS_EDIT_TOOL_NAMES = new Set(["apply_patch"]);
2326
const LIFECYCLE_USER_EVENT_TYPES = new Set(["user", "last-prompt", "UserPromptSubmit"]);
@@ -131,7 +134,7 @@ export function isEditEvent(event) {
131134
if (event?.type === "event.patch_apply_end") return true;
132135
if (PATHLESS_EDIT_TOOL_NAMES.has(String(event?.toolName ?? event?.functionCallName ?? "").toLowerCase())) return true;
133136
if (/^\s*apply_patch(?:\s|$)/u.test(String(event?.commandText ?? ""))) return true;
134-
return targetPaths.length > 0 && EDIT_TOOL_NAMES.has(event?.toolName);
137+
return targetPaths.length > 0 && EDIT_TOOL_NAMES.has(String(event?.toolName ?? "").toLowerCase());
135138
}
136139

137140
export function validationCategory(event) {

‎scripts/session-analysis/insights.mjs‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ const FRICTION_TYPE_PATTERNS = Object.freeze([
3131
{ name: "aborted-event", pattern: /\b(?:abort|aborted|cancel|cancelled|interrupted)\b/i },
3232
]);
3333

34-
const EDIT_TOOL_NAMES = new Set(["Edit", "MultiEdit", "NotebookEdit", "Write"]);
34+
// Case-insensitive: providers differ in casing (Claude Code "Edit", pi "edit").
35+
const EDIT_TOOL_NAMES = new Set(["edit", "multiedit", "notebookedit", "write"]);
3536

3637
const EDIT_COMMAND_PATTERNS = Object.freeze([
3738
{ name: "apply_patch", pattern: /\bapply_patch\b|\*\*\*\s+Begin Patch/i },
@@ -724,7 +725,7 @@ function longSessionRows(rows = []) {
724725
}
725726

726727
function isEditEvent(event) {
727-
if (EDIT_TOOL_NAMES.has(event.toolName)) {
728+
if (EDIT_TOOL_NAMES.has(String(event?.toolName ?? "").toLowerCase())) {
728729
return true;
729730
}
730731
const commandText = event.commandText ?? "";

0 commit comments

Comments
 (0)