@newrelic/preflight 1.49.0 → 1.50.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 (57) hide show
  1. package/dist/dashboard/routes/api-handler.d.ts +14 -0
  2. package/dist/dashboard/routes/api-handler.d.ts.map +1 -1
  3. package/dist/dashboard/routes/api-handler.js +31 -32
  4. package/dist/dashboard/routes/api-handler.js.map +1 -1
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +15 -0
  7. package/dist/index.js.map +1 -1
  8. package/dist/metrics/git-activity-recorder.d.ts +51 -0
  9. package/dist/metrics/git-activity-recorder.d.ts.map +1 -0
  10. package/dist/metrics/git-activity-recorder.js +178 -0
  11. package/dist/metrics/git-activity-recorder.js.map +1 -0
  12. package/dist/metrics/git-activity-store.d.ts +63 -0
  13. package/dist/metrics/git-activity-store.d.ts.map +1 -0
  14. package/dist/metrics/git-activity-store.js +115 -0
  15. package/dist/metrics/git-activity-store.js.map +1 -0
  16. package/dist/metrics/git-efficiency-tracker.d.ts +2 -15
  17. package/dist/metrics/git-efficiency-tracker.d.ts.map +1 -1
  18. package/dist/metrics/git-efficiency-tracker.js +12 -118
  19. package/dist/metrics/git-efficiency-tracker.js.map +1 -1
  20. package/dist/metrics/git-event-classifier.d.ts +36 -0
  21. package/dist/metrics/git-event-classifier.d.ts.map +1 -0
  22. package/dist/metrics/git-event-classifier.js +138 -0
  23. package/dist/metrics/git-event-classifier.js.map +1 -0
  24. package/dist/metrics/git-window-params.d.ts +22 -0
  25. package/dist/metrics/git-window-params.d.ts.map +1 -0
  26. package/dist/metrics/git-window-params.js +65 -0
  27. package/dist/metrics/git-window-params.js.map +1 -0
  28. package/dist/metrics/git-workspace-identity.d.ts +38 -0
  29. package/dist/metrics/git-workspace-identity.d.ts.map +1 -0
  30. package/dist/metrics/git-workspace-identity.js +136 -0
  31. package/dist/metrics/git-workspace-identity.js.map +1 -0
  32. package/dist/metrics/git-workspace-report.d.ts +114 -0
  33. package/dist/metrics/git-workspace-report.d.ts.map +1 -0
  34. package/dist/metrics/git-workspace-report.js +1187 -0
  35. package/dist/metrics/git-workspace-report.js.map +1 -0
  36. package/dist/metrics/git-workspace-reporter.d.ts +138 -0
  37. package/dist/metrics/git-workspace-reporter.d.ts.map +1 -0
  38. package/dist/metrics/git-workspace-reporter.js +326 -0
  39. package/dist/metrics/git-workspace-reporter.js.map +1 -0
  40. package/dist/metrics/local-session-aggregator.d.ts.map +1 -1
  41. package/dist/metrics/local-session-aggregator.js +1 -0
  42. package/dist/metrics/local-session-aggregator.js.map +1 -1
  43. package/dist/storage/session-store.d.ts.map +1 -1
  44. package/dist/storage/session-store.js +2 -0
  45. package/dist/storage/session-store.js.map +1 -1
  46. package/dist/storage/types.d.ts +1 -0
  47. package/dist/storage/types.d.ts.map +1 -1
  48. package/dist/tools/session-stats.d.ts +27 -0
  49. package/dist/tools/session-stats.d.ts.map +1 -1
  50. package/dist/tools/session-stats.js +29 -7
  51. package/dist/tools/session-stats.js.map +1 -1
  52. package/dist/web/assets/index-4h4AORA2.js +64 -0
  53. package/dist/web/assets/index-qULXLTB2.css +2 -0
  54. package/dist/web/index.html +2 -2
  55. package/package.json +1 -1
  56. package/dist/web/assets/index-C14Y4BRS.js +0 -64
  57. package/dist/web/assets/index-CQvdP3BR.css +0 -2
@@ -0,0 +1,178 @@
1
+ import { classifyGitCommand } from './git-event-classifier.js';
2
+ import { stripHeredocBodies } from './local-session-aggregator.js';
3
+ // GitHub CLI patterns for PR detection
4
+ const GH_PR_CREATE_RE = /\bgh\s+pr\s+create\b/;
5
+ const GH_PR_MERGE_RE = /\bgh\s+pr\s+merge\b/;
6
+ const GH_PR_VIEW_RE = /\bgh\s+pr\s+view\b/;
7
+ const GH_PR_EDIT_RE = /\bgh\s+pr\s+edit\b/;
8
+ const GH_PR_READY_RE = /\bgh\s+pr\s+ready\b/;
9
+ const GH_PR_CHECKS_RE = /\bgh\s+pr\s+checks\b/;
10
+ const GH_COMMAND_RE = /\bgh\s+/;
11
+ const GH_PR_NUMBER_RE = /\bgh\s+pr\s+\w+\s+(\d+)/;
12
+ /** Detected PR action from gh CLI or MCP tools. */
13
+ const MCP_PR_TOOL_ACTION = {
14
+ create_pull_request: 'create',
15
+ update_pull_request: 'edit',
16
+ };
17
+ /**
18
+ * Extract and return a PrEvent from a gh CLI command, or null if the command
19
+ * doesn't match a recognized PR action.
20
+ */
21
+ export function processGhCommand(command, timestamp) {
22
+ const numberMatch = GH_PR_NUMBER_RE.exec(command);
23
+ const prNumber = numberMatch ? numberMatch[1] : null;
24
+ if (GH_PR_CREATE_RE.test(command)) {
25
+ return { timestamp, action: 'create', prNumber };
26
+ }
27
+ else if (GH_PR_MERGE_RE.test(command)) {
28
+ return { timestamp, action: 'merge', prNumber };
29
+ }
30
+ else if (GH_PR_CHECKS_RE.test(command)) {
31
+ return { timestamp, action: 'checks', prNumber };
32
+ }
33
+ else if (GH_PR_READY_RE.test(command)) {
34
+ return { timestamp, action: 'ready', prNumber };
35
+ }
36
+ else if (GH_PR_EDIT_RE.test(command)) {
37
+ return { timestamp, action: 'edit', prNumber };
38
+ }
39
+ else if (GH_PR_VIEW_RE.test(command)) {
40
+ return { timestamp, action: 'view', prNumber };
41
+ }
42
+ return null;
43
+ }
44
+ export class GitActivityRecorder {
45
+ store;
46
+ identityResolver;
47
+ constructor(store, identityResolver) {
48
+ this.store = store;
49
+ this.identityResolver = identityResolver;
50
+ }
51
+ /** Mirrors GitEfficiencyTracker.recordToolCall's existing dispatch logic —
52
+ * ingest file edits, build/test commands, MCP/gh-CLI PR actions, and
53
+ * classified git commands, turning each into zero or more GitActivityRecord(s)
54
+ * and pushing them into the store.
55
+ */
56
+ recordToolCall(record) {
57
+ const cwd = record.cwd;
58
+ // Track file edits (non-git tool calls that modify files)
59
+ if (record.toolName === 'Edit' || record.toolName === 'Write') {
60
+ const filePath = record.filePath;
61
+ if (filePath) {
62
+ this.ingestActivity({
63
+ sessionId: record.sessionId ?? 'unknown',
64
+ kind: 'edit',
65
+ filePath,
66
+ timestamp: record.timestamp,
67
+ recordId: this.makeRecordId(record, 'edit'),
68
+ workspaceKey: this.resolveWorkspaceKey(cwd),
69
+ });
70
+ }
71
+ }
72
+ // Track build/test commands for "verify before push" metric
73
+ if (record.isTestCommand) {
74
+ this.ingestActivity({
75
+ sessionId: record.sessionId ?? 'unknown',
76
+ kind: 'verify',
77
+ verify: 'test',
78
+ timestamp: record.timestamp,
79
+ recordId: this.makeRecordId(record, 'verify-test'),
80
+ workspaceKey: this.resolveWorkspaceKey(cwd),
81
+ });
82
+ }
83
+ if (record.isBuildCommand) {
84
+ this.ingestActivity({
85
+ sessionId: record.sessionId ?? 'unknown',
86
+ kind: 'verify',
87
+ verify: 'build',
88
+ timestamp: record.timestamp,
89
+ recordId: this.makeRecordId(record, 'verify-build'),
90
+ workspaceKey: this.resolveWorkspaceKey(cwd),
91
+ });
92
+ }
93
+ // MCP tool calls (e.g. the GitHub MCP server's create_pull_request /
94
+ // update_pull_request)
95
+ const mcpPrAction = MCP_PR_TOOL_ACTION[record.toolName];
96
+ if (mcpPrAction) {
97
+ this.ingestActivity({
98
+ sessionId: record.sessionId ?? 'unknown',
99
+ kind: 'pr',
100
+ prEvent: { timestamp: record.timestamp, action: mcpPrAction, prNumber: null },
101
+ timestamp: record.timestamp,
102
+ recordId: this.makeRecordId(record, 'pr-mcp'),
103
+ workspaceKey: this.resolveWorkspaceKey(cwd),
104
+ });
105
+ }
106
+ const rawCommand = record.command;
107
+ if (!rawCommand)
108
+ return;
109
+ // Classify on the command *minus* any inline script bodies: a heredoc
110
+ // that merely mentions git/gh words is not a git or PR operation.
111
+ const command = stripHeredocBodies(rawCommand);
112
+ // Track GitHub CLI PR commands. Split on shell separators first so a
113
+ // `gh` invocation chained after a `git` command is still detected.
114
+ const segments = command.split(/&&|;|\|/);
115
+ for (let i = 0; i < segments.length; i++) {
116
+ const trimmedSegment = segments[i].trim();
117
+ if (GH_COMMAND_RE.test(trimmedSegment) && !trimmedSegment.startsWith('git ')) {
118
+ const prEvent = processGhCommand(trimmedSegment, record.timestamp);
119
+ if (prEvent) {
120
+ this.ingestActivity({
121
+ sessionId: record.sessionId ?? 'unknown',
122
+ kind: 'pr',
123
+ prEvent,
124
+ timestamp: record.timestamp,
125
+ // Indexed so a compound command chaining two `gh pr` calls (rare,
126
+ // but possible) doesn't collide on the same recordId.
127
+ recordId: this.makeRecordId(record, `pr-gh-${i}`),
128
+ workspaceKey: this.resolveWorkspaceKey(cwd),
129
+ });
130
+ }
131
+ }
132
+ }
133
+ // Test for git command
134
+ if (!/\bgit\s+/.test(command)) {
135
+ // Not a git command, return early
136
+ return;
137
+ }
138
+ // Classify and ingest git command
139
+ const gitEvent = classifyGitCommand(command, record, (dir) => this.identityResolver.resolve(dir)?.repoName ?? null);
140
+ this.ingestActivity({
141
+ sessionId: record.sessionId ?? 'unknown',
142
+ kind: 'git',
143
+ gitEvent,
144
+ timestamp: record.timestamp,
145
+ recordId: this.makeRecordId(record, 'git'),
146
+ workspaceKey: this.resolveWorkspaceKey(cwd),
147
+ });
148
+ }
149
+ ingestActivity(activity) {
150
+ this.store.ingest(activity);
151
+ }
152
+ resolveWorkspaceKey(cwd) {
153
+ const identity = this.identityResolver.resolve(cwd);
154
+ if (identity === null) {
155
+ return 'unattributed';
156
+ }
157
+ // Use repoKey for repo-level identity and worktreeKey for worktree-level
158
+ // tracking. For now, use worktreeKey so each worktree is tracked separately.
159
+ return identity.worktreeKey;
160
+ }
161
+ // `discriminator` is part of the id, not just a label: one ToolCallRecord
162
+ // can legitimately produce several distinct activities (e.g. `npm run
163
+ // build && git commit` is both a 'verify' and a 'git' activity from the
164
+ // SAME record, and a record can even be both isTestCommand AND
165
+ // isBuildCommand at once). Without a discriminator in the id, two such
166
+ // activities would share the same (workspaceKey, recordId) pair and the
167
+ // store's insert-or-ignore dedup would silently drop the second one as a
168
+ // "duplicate" of the first — so this takes a string specific enough to
169
+ // distinguish every activity kind AND sub-kind a single record can
170
+ // produce, not just `GitActivityRecord['kind']`.
171
+ makeRecordId(record, discriminator) {
172
+ const base = record.toolUseId && record.toolUseId.length > 0
173
+ ? record.toolUseId
174
+ : `${record.sessionId ?? 'unknown'}:${record.timestamp}:${record.toolName}`;
175
+ return `${base}:${discriminator}`;
176
+ }
177
+ }
178
+ //# sourceMappingURL=git-activity-recorder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-activity-recorder.js","sourceRoot":"","sources":["../../src/metrics/git-activity-recorder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,63 @@
1
+ /** Minimum shape any record needs to be stored: a stable dedup id, a
2
+ * timestamp, and which "workspace" (an opaque grouping key defined by the
3
+ * caller — this store doesn't know or care what it means) it belongs to. */
4
+ export interface KeyedRecord {
5
+ readonly recordId: string;
6
+ readonly timestamp: number;
7
+ readonly workspaceKey: string;
8
+ }
9
+ export interface ActivityQuery {
10
+ readonly since: number;
11
+ readonly until: number;
12
+ /** Omit or pass an empty array to match every known key. */
13
+ readonly keys?: readonly string[];
14
+ }
15
+ /**
16
+ * Generic in-memory activity store, keyed by an opaque workspaceKey.
17
+ *
18
+ * Concurrency note: two different workspaceKeys' records never interact —
19
+ * each key's records live in their own bucket, so nothing about inserting
20
+ * for key A can corrupt or reorder key B's bucket, regardless of call order.
21
+ * This matters because a caller may be feeding records from several
22
+ * concurrent sources (e.g. several git worktrees producing activity "at the
23
+ * same time") — per-key isolation is what makes that safe without a lock.
24
+ */
25
+ export declare class ActivityStore<T extends KeyedRecord> {
26
+ private buckets;
27
+ private dedup;
28
+ /**
29
+ * Insert-or-ignore, keyed on `record.recordId` WITHIN that record's own
30
+ * workspaceKey bucket (the same recordId string appearing under two
31
+ * different workspaceKeys is not a duplicate — that would be a caller
32
+ * bug, but this store doesn't need to detect it, just not misbehave: treat
33
+ * each (workspaceKey, recordId) pair as the true dedup key). Ingesting a
34
+ * record whose (workspaceKey, recordId) pair has already been seen is a
35
+ * silent no-op — same call twice, e.g. from replaying the same session
36
+ * summary at startup twice, or a retried write, must not double-count.
37
+ */
38
+ ingest(record: T): void;
39
+ /**
40
+ * Every stored record whose timestamp falls in [since, until), across the
41
+ * given keys (or every known key if `keys` is omitted/empty), returned
42
+ * SORTED ASCENDING by timestamp regardless of insertion order (insertion
43
+ * order across different workspaceKeys is never meaningful — each key's
44
+ * own records happen to already be insertion-ordered since ingest is
45
+ * append-only per key, but don't rely on that; sort explicitly so this
46
+ * stays correct even if that internal detail ever changes).
47
+ */
48
+ query(opts: ActivityQuery): readonly T[];
49
+ /** Every workspaceKey with at least one record whose timestamp is >= since. */
50
+ knownKeys(since: number): readonly string[];
51
+ /**
52
+ * Housekeeping only — bounds memory for a long-lived process. Deletes
53
+ * every record with timestamp < cutoffMs, across every key. This is NOT a
54
+ * correctness dependency for any caller: nothing about `query()`'s
55
+ * correctness for an in-range window relies on this having been called at
56
+ * any particular time, unlike a "reset" that a caller might depend on for
57
+ * a number to be right. If a key's bucket becomes empty as a result,
58
+ * remove the empty bucket too (so `knownKeys()` doesn't report a key with
59
+ * zero records).
60
+ */
61
+ evictBefore(cutoffMs: number): void;
62
+ }
63
+ //# sourceMappingURL=git-activity-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-activity-store.d.ts","sourceRoot":"","sources":["../../src/metrics/git-activity-store.ts"],"names":[],"mappings":"AAAA;;6EAE6E;AAC7E,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,4DAA4D;IAC5D,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACnC;AAED;;;;;;;;;GASG;AACH,qBAAa,aAAa,CAAC,CAAC,SAAS,WAAW;IAC9C,OAAO,CAAC,OAAO,CAA+B;IAC9C,OAAO,CAAC,KAAK,CAAuC;IAEpD;;;;;;;;;OASG;IACH,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,IAAI;IAyBvB;;;;;;;;OAQG;IACH,KAAK,CAAC,IAAI,EAAE,aAAa,GAAG,SAAS,CAAC,EAAE;IAuBxC,+EAA+E;IAC/E,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE;IAe3C;;;;;;;;;OASG;IACH,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;CAyBpC"}
@@ -0,0 +1,115 @@
1
+ /**
2
+ * Generic in-memory activity store, keyed by an opaque workspaceKey.
3
+ *
4
+ * Concurrency note: two different workspaceKeys' records never interact —
5
+ * each key's records live in their own bucket, so nothing about inserting
6
+ * for key A can corrupt or reorder key B's bucket, regardless of call order.
7
+ * This matters because a caller may be feeding records from several
8
+ * concurrent sources (e.g. several git worktrees producing activity "at the
9
+ * same time") — per-key isolation is what makes that safe without a lock.
10
+ */
11
+ export class ActivityStore {
12
+ buckets = new Map();
13
+ dedup = new Map();
14
+ /**
15
+ * Insert-or-ignore, keyed on `record.recordId` WITHIN that record's own
16
+ * workspaceKey bucket (the same recordId string appearing under two
17
+ * different workspaceKeys is not a duplicate — that would be a caller
18
+ * bug, but this store doesn't need to detect it, just not misbehave: treat
19
+ * each (workspaceKey, recordId) pair as the true dedup key). Ingesting a
20
+ * record whose (workspaceKey, recordId) pair has already been seen is a
21
+ * silent no-op — same call twice, e.g. from replaying the same session
22
+ * summary at startup twice, or a retried write, must not double-count.
23
+ */
24
+ ingest(record) {
25
+ const key = record.workspaceKey;
26
+ const recordId = record.recordId;
27
+ let dedupSet = this.dedup.get(key);
28
+ if (!dedupSet) {
29
+ dedupSet = new Set();
30
+ this.dedup.set(key, dedupSet);
31
+ }
32
+ if (dedupSet.has(recordId)) {
33
+ return;
34
+ }
35
+ dedupSet.add(recordId);
36
+ let bucket = this.buckets.get(key);
37
+ if (!bucket) {
38
+ bucket = [];
39
+ this.buckets.set(key, bucket);
40
+ }
41
+ bucket.push(record);
42
+ }
43
+ /**
44
+ * Every stored record whose timestamp falls in [since, until), across the
45
+ * given keys (or every known key if `keys` is omitted/empty), returned
46
+ * SORTED ASCENDING by timestamp regardless of insertion order (insertion
47
+ * order across different workspaceKeys is never meaningful — each key's
48
+ * own records happen to already be insertion-ordered since ingest is
49
+ * append-only per key, but don't rely on that; sort explicitly so this
50
+ * stays correct even if that internal detail ever changes).
51
+ */
52
+ query(opts) {
53
+ const { since, until, keys } = opts;
54
+ const keysToQuery = !keys || keys.length === 0 ? Array.from(this.buckets.keys()) : keys;
55
+ const results = [];
56
+ for (const key of keysToQuery) {
57
+ const bucket = this.buckets.get(key);
58
+ if (!bucket) {
59
+ continue;
60
+ }
61
+ for (const record of bucket) {
62
+ if (record.timestamp >= since && record.timestamp < until) {
63
+ results.push(record);
64
+ }
65
+ }
66
+ }
67
+ results.sort((a, b) => a.timestamp - b.timestamp);
68
+ return results;
69
+ }
70
+ /** Every workspaceKey with at least one record whose timestamp is >= since. */
71
+ knownKeys(since) {
72
+ const result = [];
73
+ for (const [key, bucket] of this.buckets) {
74
+ for (const record of bucket) {
75
+ if (record.timestamp >= since) {
76
+ result.push(key);
77
+ break;
78
+ }
79
+ }
80
+ }
81
+ return result;
82
+ }
83
+ /**
84
+ * Housekeeping only — bounds memory for a long-lived process. Deletes
85
+ * every record with timestamp < cutoffMs, across every key. This is NOT a
86
+ * correctness dependency for any caller: nothing about `query()`'s
87
+ * correctness for an in-range window relies on this having been called at
88
+ * any particular time, unlike a "reset" that a caller might depend on for
89
+ * a number to be right. If a key's bucket becomes empty as a result,
90
+ * remove the empty bucket too (so `knownKeys()` doesn't report a key with
91
+ * zero records).
92
+ */
93
+ evictBefore(cutoffMs) {
94
+ const keysToRemove = [];
95
+ for (const [key, bucket] of this.buckets) {
96
+ const filteredBucket = bucket.filter((record) => record.timestamp >= cutoffMs);
97
+ if (filteredBucket.length === 0) {
98
+ keysToRemove.push(key);
99
+ continue;
100
+ }
101
+ this.buckets.set(key, filteredBucket);
102
+ // A partial eviction still needs to drop the evicted records' ids from
103
+ // the dedup set — otherwise they leak forever, and evictBefore stops
104
+ // bounding memory for exactly the callers that use it as intended
105
+ // (continuous rolling eviction rather than one final cleanup).
106
+ const survivingIds = new Set(filteredBucket.map((record) => record.recordId));
107
+ this.dedup.set(key, survivingIds);
108
+ }
109
+ for (const key of keysToRemove) {
110
+ this.buckets.delete(key);
111
+ this.dedup.delete(key);
112
+ }
113
+ }
114
+ }
115
+ //# sourceMappingURL=git-activity-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-activity-store.js","sourceRoot":"","sources":["../../src/metrics/git-activity-store.ts"],"names":[],"mappings":"AAgBA;;;;;;;;;GASG;AACH,MAAM,OAAO,aAAa;IAChB,OAAO,GAAqB,IAAI,GAAG,EAAE,CAAC;IACtC,KAAK,GAA6B,IAAI,GAAG,EAAE,CAAC;IAEpD;;;;;;;;;OASG;IACH,MAAM,CAAC,MAAS;QACd,MAAM,GAAG,GAAG,MAAM,CAAC,YAAY,CAAC;QAChC,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;QAEjC,IAAI,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACnC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,QAAQ,GAAG,IAAI,GAAG,EAAE,CAAC;YACrB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;QAChC,CAAC;QAED,IAAI,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC3B,OAAO;QACT,CAAC;QAED,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAEvB,IAAI,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACnC,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,GAAG,EAAE,CAAC;YACZ,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QAChC,CAAC;QAED,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACtB,CAAC;IAED;;;;;;;;OAQG;IACH,KAAK,CAAC,IAAmB;QACvB,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC;QACpC,MAAM,WAAW,GAAG,CAAC,IAAI,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAExF,MAAM,OAAO,GAAQ,EAAE,CAAC;QAExB,KAAK,MAAM,GAAG,IAAI,WAAW,EAAE,CAAC;YAC9B,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YACrC,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,SAAS;YACX,CAAC;YAED,KAAK,MAAM,MAAM,IAAI,MAAM,EAAE,CAAC;gBAC5B,IAAI,MAAM,CAAC,SAAS,IAAI,KAAK,IAAI,MAAM,CAAC,SAAS,GAAG,KAAK,EAAE,CAAC;oBAC1D,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBACvB,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC;QAClD,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,+EAA+E;IAC/E,SAAS,CAAC,KAAa;QACrB,MAAM,MAAM,GAAa,EAAE,CAAC;QAE5B,KAAK,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACzC,KAAK,MAAM,MAAM,IAAI,MAAM,EAAE,CAAC;gBAC5B,IAAI,MAAM,CAAC,SAAS,IAAI,KAAK,EAAE,CAAC;oBAC9B,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;oBACjB,MAAM;gBACR,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAED;;;;;;;;;OASG;IACH,WAAW,CAAC,QAAgB;QAC1B,MAAM,YAAY,GAAa,EAAE,CAAC;QAElC,KAAK,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACzC,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,SAAS,IAAI,QAAQ,CAAC,CAAC;YAE/E,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAChC,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBACvB,SAAS;YACX,CAAC;YAED,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;YACtC,uEAAuE;YACvE,qEAAqE;YACrE,kEAAkE;YAClE,+DAA+D;YAC/D,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;YAC9E,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;QACpC,CAAC;QAED,KAAK,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;YAC/B,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACzB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACzB,CAAC;IACH,CAAC;CACF"}
@@ -1,5 +1,6 @@
1
1
  import type { MetricAggregator } from '../shared/index.js';
2
2
  import type { ReplayTimelineEntry, ToolCallRecord } from '../storage/types.js';
3
+ import { type GitEvent } from './git-event-classifier.js';
3
4
  /**
4
5
  * Parse `git symbolic-ref --short refs/remotes/<remoteName>/HEAD`'s stdout
5
6
  * (e.g. "origin/main") into just the branch name. Falls back to 'main' if
@@ -8,20 +9,7 @@ import type { ReplayTimelineEntry, ToolCallRecord } from '../storage/types.js';
8
9
  * expected remote prefix).
9
10
  */
10
11
  export declare function parseDefaultBranchFromSymbolicRef(output: string, remoteName: string): string;
11
- export interface GitEvent {
12
- readonly timestamp: number;
13
- readonly type: GitEventType;
14
- readonly command?: string;
15
- readonly success: boolean;
16
- readonly durationMs: number | null;
17
- /** `owner/name` of the repo this event belongs to, when known. */
18
- readonly repo?: string | null;
19
- /** Commit subject line, for events hydrated from `git log`. */
20
- readonly subject?: string | null;
21
- /** Browsable URL for the commit, when the remote could be mapped. */
22
- readonly url?: string | null;
23
- }
24
- export type GitEventType = 'merge_conflict' | 'rebase_conflict' | 'merge_abort' | 'rebase_abort' | 'cherry_pick_abort' | 'force_push' | 'force_push_lease' | 'reset_hard' | 'discard_changes' | 'pull' | 'fetch' | 'push' | 'push_rejected' | 'merge' | 'rebase' | 'stash' | 'branch' | 'commit' | 'status' | 'diff' | 'log' | 'worktree' | 'other_git';
12
+ export type { GitEvent, GitEventType } from './git-event-classifier.js';
25
13
  export interface MergeConflictRecord {
26
14
  readonly timestamp: number;
27
15
  readonly resolution: 'resolved' | 'aborted' | 'pending';
@@ -193,7 +181,6 @@ export declare class GitEfficiencyTracker {
193
181
  getMetrics(): GitEfficiencyMetrics;
194
182
  emitMetrics(aggregator: MetricAggregator): void;
195
183
  reset(_sessionId: string): void;
196
- private classifyGitCommand;
197
184
  private processEvent;
198
185
  private countStaleBranchPulls;
199
186
  private computeRiskIndicators;
@@ -1 +1 @@
1
- {"version":3,"file":"git-efficiency-tracker.d.ts","sourceRoot":"","sources":["../../src/metrics/git-efficiency-tracker.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"git-efficiency-tracker.d.ts","sourceRoot":"","sources":["../../src/metrics/git-efficiency-tracker.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,6 @@
1
- import { redactSensitive } from '../config.js';
2
- import { gitCommandTargetDir, RepoNameResolver, stripHeredocBodies, } from './local-session-aggregator.js';
1
+ import { stripHeredocBodies } from './local-session-aggregator.js';
2
+ import { classifyGitCommand } from './git-event-classifier.js';
3
+ import { RepoNameResolver } from './local-session-aggregator.js';
3
4
  /**
4
5
  * Parse `git symbolic-ref --short refs/remotes/<remoteName>/HEAD`'s stdout
5
6
  * (e.g. "origin/main") into just the branch name. Falls back to 'main' if
@@ -15,49 +16,16 @@ export function parseDefaultBranchFromSymbolicRef(output, remoteName) {
15
16
  }
16
17
  return 'main';
17
18
  }
18
- // ---------------------------------------------------------------------------
19
- // Git command classification patterns
20
- // ---------------------------------------------------------------------------
21
- const GIT_COMMAND_RE = /\bgit\s+/;
22
- const MERGE_CONFLICT_INDICATORS = [
23
- /CONFLICT\s*\(/i,
24
- /Automatic merge failed/i,
25
- /fix conflicts and then commit/i,
26
- /Merge conflict in/i,
27
- /both modified:/i,
28
- ];
29
- const REBASE_CONFLICT_RE = /\brebase\b.*(?:conflict|could not apply|patch does not apply)/i;
30
- const MERGE_ABORT_RE = /\bgit\s+merge\s+--abort\b/;
31
- const REBASE_ABORT_RE = /\bgit\s+rebase\s+--abort\b/;
32
- const CHERRY_PICK_ABORT_RE = /\bgit\s+cherry-pick\s+--abort\b/;
33
- const GIT_PULL_RE = /\bgit\s+pull\b/;
34
- const GIT_FETCH_RE = /\bgit\s+fetch\b/;
35
- const GIT_PUSH_RE = /\bgit\s+push\b/;
36
- // `(?!-)` excludes `--force-with-lease` — without it, a lease-protected force
37
- // push would also match this plain "unsafe force push" pattern, since
38
- // "--force-with-lease" starts with the literal text "--force".
39
- const GIT_PUSH_FORCE_RE = /\bgit\s+push\s+.*--force(?!-)|\bgit\s+push\s+-f\b/;
40
- const GIT_PUSH_FORCE_LEASE_RE = /--force-with-lease\b/;
41
- const GIT_MERGE_RE = /\bgit\s+merge\b/;
42
- const GIT_REBASE_RE = /\bgit\s+rebase\b/;
43
- const GIT_STASH_RE = /\bgit\s+stash\b/;
44
- const GIT_RESET_HARD_RE = /\bgit\s+reset\s+--hard\b/;
45
- const GIT_CHECKOUT_DASH_RE = /\bgit\s+checkout\s+--\s/;
46
- const GIT_RESTORE_RE = /\bgit\s+restore\b/;
47
- const GIT_BRANCH_RE = /\bgit\s+(?:branch|checkout\s+-b|switch\s+-c)\b/;
48
- const GIT_STATUS_RE = /\bgit\s+status\b/;
49
- const GIT_DIFF_RE = /\bgit\s+diff\b/;
50
- const GIT_LOG_RE = /\bgit\s+log\b/;
51
- const GIT_COMMIT_RE = /\bgit\s+commit\b/;
52
- const GIT_WORKTREE_RE = /\bgit\s+worktree\b/;
53
- // Only `add`/`remove` create or tear down real isolation — `list`/`prune`/
54
- // `lock`/etc. are read-only inspection and shouldn't inflate the "worktree
55
- // ops" count with commands that don't reflect any parallel-isolation work.
56
- const GIT_WORKTREE_ADD_REMOVE_RE = /\bgit\s+worktree\s+(?:add|remove)\b/;
19
+ // Regex patterns needed by processEvent (others moved to git-event-classifier.ts)
57
20
  const GIT_CHECKOUT_OURS_RE = /\bgit\s+checkout\s+--ours\b/;
58
21
  const GIT_CHECKOUT_THEIRS_RE = /\bgit\s+checkout\s+--theirs\b/;
59
22
  const GIT_CHERRY_PICK_RE = /\bgit\s+cherry-pick\b/;
60
- // GitHub CLI patterns
23
+ const CHERRY_PICK_ABORT_RE = /\bgit\s+cherry-pick\s+--abort\b/;
24
+ const GIT_WORKTREE_ADD_REMOVE_RE = /\bgit\s+worktree\s+(?:add|remove)\b/;
25
+ const GIT_PULL_RE = /\bgit\s+pull\b/;
26
+ // Conflict file path extraction: "CONFLICT (content): Merge conflict in <path>"
27
+ const CONFLICT_FILE_RE = /Merge conflict in (.+)/g;
28
+ // GitHub CLI patterns (used by processGhCommand)
61
29
  const GH_PR_CREATE_RE = /\bgh\s+pr\s+create\b/;
62
30
  const GH_PR_MERGE_RE = /\bgh\s+pr\s+merge\b/;
63
31
  const GH_PR_VIEW_RE = /\bgh\s+pr\s+view\b/;
@@ -101,14 +69,6 @@ const COMMIT_DEDUP_WINDOW_MS = 5_000;
101
69
  // (see below), letting isDuplicate() tell a hydrated event apart from a
102
70
  // hook-observed one and recover its hash.
103
71
  const HYDRATED_COMMIT_HASH_RE = /^git commit \((.+)\)$/;
104
- const REJECT_INDICATORS = [
105
- /\[rejected\]/i,
106
- /non-fast-forward/i,
107
- /failed to push/i,
108
- /Updates were rejected/i,
109
- ];
110
- // Conflict file path extraction: "CONFLICT (content): Merge conflict in <path>"
111
- const CONFLICT_FILE_RE = /Merge conflict in (.+)/g;
112
72
  // Render order for suggestions/best-practices — most severe first — rather
113
73
  // than fixed source-code push order, which could put a critical item below
114
74
  // a milder one.
@@ -239,9 +199,9 @@ export class GitEfficiencyTracker {
239
199
  this.processGhCommand(trimmedSegment, record.timestamp);
240
200
  }
241
201
  }
242
- if (!GIT_COMMAND_RE.test(command))
202
+ if (!/\bgit\s+/.test(command))
243
203
  return;
244
- const event = this.classifyGitCommand(command, record);
204
+ const event = classifyGitCommand(command, record, (dir) => this.repoResolver.resolve(dir));
245
205
  // A hook-observed commit whose timestamp `hydrateGitLog()` already saw
246
206
  // (via `git log`) is the same commit, not a new one — hydrateGitLog()
247
207
  // can't dedupe this itself since a live event's `command` is the raw
@@ -571,72 +531,6 @@ export class GitEfficiencyTracker {
571
531
  // -------------------------------------------------------------------------
572
532
  // Internals
573
533
  // -------------------------------------------------------------------------
574
- // Order matters: several patterns overlap (e.g. a force-push-with-lease
575
- // command also matches the plain push/force-push patterns), so more
576
- // specific checks must run before the more general ones they'd otherwise
577
- // be shadowed by.
578
- classifyGitCommand(command, record) {
579
- const base = {
580
- timestamp: record.timestamp,
581
- // The command is now surfaced in the dashboard's Detail column, so
582
- // redact it: a git remote URL can carry an embedded access token.
583
- command: redactSensitive(command),
584
- success: record.success,
585
- durationMs: record.durationMs,
586
- // Live git events previously carried no repo at all, so the dashboard
587
- // showed "—" for everything except commits hydrated from git log.
588
- repo: this.repoResolver.resolve(gitCommandTargetDir(command, record.cwd)),
589
- };
590
- const output = record.error ?? '';
591
- const hasConflict = MERGE_CONFLICT_INDICATORS.some((re) => re.test(output));
592
- const hasRebaseConflict = REBASE_CONFLICT_RE.test(output);
593
- const hasRejection = REJECT_INDICATORS.some((re) => re.test(output));
594
- if (hasConflict && !hasRebaseConflict)
595
- return { ...base, type: 'merge_conflict' };
596
- if (hasRebaseConflict)
597
- return { ...base, type: 'rebase_conflict' };
598
- if (MERGE_ABORT_RE.test(command))
599
- return { ...base, type: 'merge_abort' };
600
- if (REBASE_ABORT_RE.test(command))
601
- return { ...base, type: 'rebase_abort' };
602
- if (CHERRY_PICK_ABORT_RE.test(command))
603
- return { ...base, type: 'cherry_pick_abort' };
604
- if (GIT_PUSH_FORCE_LEASE_RE.test(command))
605
- return { ...base, type: 'force_push_lease' };
606
- if (GIT_PUSH_FORCE_RE.test(command))
607
- return { ...base, type: 'force_push' };
608
- if (GIT_RESET_HARD_RE.test(command))
609
- return { ...base, type: 'reset_hard' };
610
- if (GIT_CHECKOUT_DASH_RE.test(command) || GIT_RESTORE_RE.test(command))
611
- return { ...base, type: 'discard_changes' };
612
- if (GIT_WORKTREE_RE.test(command))
613
- return { ...base, type: 'worktree' };
614
- if (GIT_PULL_RE.test(command))
615
- return { ...base, type: 'pull' };
616
- if (GIT_FETCH_RE.test(command))
617
- return { ...base, type: 'fetch' };
618
- if (GIT_PUSH_RE.test(command) && hasRejection)
619
- return { ...base, type: 'push_rejected' };
620
- if (GIT_PUSH_RE.test(command))
621
- return { ...base, type: 'push' };
622
- if (GIT_REBASE_RE.test(command))
623
- return { ...base, type: 'rebase' };
624
- if (GIT_MERGE_RE.test(command))
625
- return { ...base, type: 'merge' };
626
- if (GIT_STASH_RE.test(command))
627
- return { ...base, type: 'stash' };
628
- if (GIT_BRANCH_RE.test(command))
629
- return { ...base, type: 'branch' };
630
- if (GIT_COMMIT_RE.test(command))
631
- return { ...base, type: 'commit' };
632
- if (GIT_STATUS_RE.test(command))
633
- return { ...base, type: 'status' };
634
- if (GIT_DIFF_RE.test(command))
635
- return { ...base, type: 'diff' };
636
- if (GIT_LOG_RE.test(command))
637
- return { ...base, type: 'log' };
638
- return { ...base, type: 'other_git' };
639
- }
640
534
  processEvent(event, command, record) {
641
535
  // Attribute ours/theirs/cherry-pick resolution strategy to the oldest
642
536
  // still-open conflict, not to every matching command — a multi-file