Skip to content

Commit 8b8e940

Browse files
committed
Support AI Coding category on web extension
1 parent 5a566f8 commit 8b8e940

File tree

4 files changed

+73
-13
lines changed

4 files changed

+73
-13
lines changed

src/constants.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,6 @@ export enum LogLevel {
1414
WARN,
1515
ERROR,
1616
}
17+
18+
export const AI_RECENT_PASTES_TIME_MS = 500;
19+
export const TIME_BETWEEN_HEARTBEATS_MS = 120000;

src/utils.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import * as vscode from 'vscode';
2+
import { TIME_BETWEEN_HEARTBEATS_MS } from './constants';
23

34
export class Utils {
45
private static appNames = {
@@ -121,6 +122,10 @@ export class Utils {
121122
return url;
122123
}
123124

125+
public static enoughTimePassed(lastHeartbeat: number, now: number): boolean {
126+
return lastHeartbeat + TIME_BETWEEN_HEARTBEATS_MS < now;
127+
}
128+
124129
public static isPullRequest(uri: vscode.Uri): boolean {
125130
if (!uri) return false;
126131
return uri.scheme === 'pr';

src/wakatime.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import * as fs from 'fs';
44
import * as path from 'path';
55
import * as vscode from 'vscode';
66

7-
import { COMMAND_DASHBOARD, LogLevel } from './constants';
7+
import { AI_RECENT_PASTES_TIME_MS, COMMAND_DASHBOARD, LogLevel } from './constants';
88
import { Options, Setting } from './options';
99

1010
import { Dependencies } from './dependencies';
@@ -537,7 +537,7 @@ export class WakaTime {
537537
let time: number = Date.now();
538538
if (
539539
isWrite ||
540-
this.enoughTimePassed(time) ||
540+
Utils.enoughTimePassed(this.lastHeartbeat, time) ||
541541
this.lastFile !== file ||
542542
this.lastDebug !== this.isDebugging ||
543543
this.lastCompile !== this.isCompiling ||
@@ -959,12 +959,8 @@ export class WakaTime {
959959
}
960960
}
961961

962-
private enoughTimePassed(time: number): boolean {
963-
return this.lastHeartbeat + 120000 < time;
964-
}
965-
966962
private recentlyAIPasted(time: number): boolean {
967-
this.AIrecentPastes = this.AIrecentPastes.filter((x) => x + 500 >= time);
963+
this.AIrecentPastes = this.AIrecentPastes.filter((x) => x + AI_RECENT_PASTES_TIME_MS >= time);
968964
return this.AIrecentPastes.length > 3;
969965
}
970966

src/web/wakatime.ts

Lines changed: 62 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as vscode from 'vscode';
22

3-
import { COMMAND_DASHBOARD, LogLevel } from '../constants';
3+
import { AI_RECENT_PASTES_TIME_MS, COMMAND_DASHBOARD, LogLevel } from '../constants';
44

55
import { Logger } from './logger';
66
import { Memento } from 'vscode';
@@ -26,9 +26,14 @@ export class WakaTime {
2626
private lastHeartbeat: number = 0;
2727
private lastDebug: boolean = false;
2828
private lastCompile: boolean = false;
29+
private lastAICodeGenerating: boolean = false;
2930
private dedupe: FileSelectionMap = {};
3031
private debounceTimeoutId: any = null;
3132
private debounceMs = 50;
33+
private AIDebounceTimeoutId: any = null;
34+
private AIdebounceMs = 1000;
35+
private AIdebounceCount = 0;
36+
private AIrecentPastes: number[] = [];
3237
private logger: Logger;
3338
private config: Memento;
3439
private fetchTodayInterval: number = 60000;
@@ -40,6 +45,7 @@ export class WakaTime {
4045
private disabled: boolean = true;
4146
private isCompiling: boolean = false;
4247
private isDebugging: boolean = false;
48+
private isAICodeGenerating: boolean = false;
4349
private currentlyFocusedFile: string;
4450
private teamDevsForFileCache = {};
4551
private lastApiKeyPrompted: number = 0;
@@ -329,9 +335,13 @@ export class WakaTime {
329335
// subscribe to selection change and editor activation events
330336
let subscriptions: vscode.Disposable[] = [];
331337
vscode.window.onDidChangeTextEditorSelection(this.onChangeSelection, this, subscriptions);
338+
vscode.workspace.onDidChangeTextDocument(this.onChangeTextDocument, this, subscriptions);
332339
vscode.window.onDidChangeActiveTextEditor(this.onChangeTab, this, subscriptions);
333340
vscode.workspace.onDidSaveTextDocument(this.onSave, this, subscriptions);
334341

342+
vscode.workspace.onDidChangeNotebookDocument(this.onChangeNotebook, this, subscriptions);
343+
vscode.workspace.onDidSaveNotebookDocument(this.onSaveNotebook, this, subscriptions);
344+
335345
vscode.tasks.onDidStartTask(this.onDidStartTask, this, subscriptions);
336346
vscode.tasks.onDidEndTask(this.onDidEndTask, this, subscriptions);
337347

@@ -375,6 +385,36 @@ export class WakaTime {
375385
this.onEvent(false);
376386
}
377387

388+
private onChangeTextDocument(e: vscode.TextDocumentChangeEvent): void {
389+
if (Utils.isAIChatSidebar(e.document?.uri)) {
390+
this.isAICodeGenerating = true;
391+
this.AIdebounceCount = 0;
392+
} else if (Utils.isPossibleAICodeInsert(e)) {
393+
const now = Date.now();
394+
if (this.recentlyAIPasted(now)) {
395+
this.isAICodeGenerating = true;
396+
this.AIdebounceCount = 0;
397+
}
398+
this.AIrecentPastes.push(now);
399+
} else if (Utils.isPossibleHumanCodeInsert(e)) {
400+
this.AIrecentPastes = [];
401+
if (this.isAICodeGenerating) {
402+
this.AIdebounceCount++;
403+
clearTimeout(this.AIDebounceTimeoutId);
404+
this.AIDebounceTimeoutId = setTimeout(() => {
405+
if (this.AIdebounceCount > 1) {
406+
this.isAICodeGenerating = false;
407+
}
408+
}, this.AIdebounceMs);
409+
}
410+
} else if (this.isAICodeGenerating) {
411+
this.AIdebounceCount = 0;
412+
clearTimeout(this.AIDebounceTimeoutId);
413+
}
414+
if (!this.isAICodeGenerating) return;
415+
this.onEvent(false);
416+
}
417+
378418
private onChangeTab(_e: vscode.TextEditor | undefined): void {
379419
this.onEvent(false);
380420
}
@@ -383,6 +423,14 @@ export class WakaTime {
383423
this.onEvent(true);
384424
}
385425

426+
private onChangeNotebook(_e: vscode.NotebookDocumentChangeEvent): void {
427+
this.onEvent(false);
428+
}
429+
430+
private onSaveNotebook(_e: vscode.NotebookDocument | undefined): void {
431+
this.onEvent(true);
432+
}
433+
386434
private onEvent(isWrite: boolean): void {
387435
clearTimeout(this.debounceTimeoutId);
388436
this.debounceTimeoutId = setTimeout(() => {
@@ -402,10 +450,11 @@ export class WakaTime {
402450
let time: number = Date.now();
403451
if (
404452
isWrite ||
405-
this.enoughTimePassed(time) ||
453+
Utils.enoughTimePassed(this.lastHeartbeat, time) ||
406454
this.lastFile !== file ||
407455
this.lastDebug !== this.isDebugging ||
408-
this.lastCompile !== this.isCompiling
456+
this.lastCompile !== this.isCompiling ||
457+
this.lastAICodeGenerating !== this.isAICodeGenerating
409458
) {
410459
this.sendHeartbeat(
411460
doc,
@@ -414,11 +463,13 @@ export class WakaTime {
414463
isWrite,
415464
this.isCompiling,
416465
this.isDebugging,
466+
this.isAICodeGenerating,
417467
);
418468
this.lastFile = file;
419469
this.lastHeartbeat = time;
420470
this.lastDebug = this.isDebugging;
421471
this.lastCompile = this.isCompiling;
472+
this.lastAICodeGenerating = this.isAICodeGenerating;
422473
}
423474
}
424475
}
@@ -433,10 +484,11 @@ export class WakaTime {
433484
isWrite: boolean,
434485
isCompiling: boolean,
435486
isDebugging: boolean,
487+
isAICoding: boolean,
436488
): void {
437489
this.hasApiKey((hasApiKey) => {
438490
if (hasApiKey) {
439-
this._sendHeartbeat(doc, time, selection, isWrite, isCompiling, isDebugging);
491+
this._sendHeartbeat(doc, time, selection, isWrite, isCompiling, isDebugging, isAICoding);
440492
} else {
441493
this.promptForApiKey();
442494
}
@@ -450,6 +502,7 @@ export class WakaTime {
450502
isWrite: boolean,
451503
isCompiling: boolean,
452504
isDebugging: boolean,
505+
isAICoding: boolean,
453506
) {
454507
let file = doc.fileName;
455508
if (Utils.isRemoteUri(doc.uri)) {
@@ -487,6 +540,8 @@ export class WakaTime {
487540
payload['category'] = 'debugging';
488541
} else if (isCompiling) {
489542
payload['category'] = 'building';
543+
} else if (isAICoding) {
544+
payload['category'] = 'ai coding';
490545
} else if (Utils.isPullRequest(doc.uri)) {
491546
payload['category'] = 'code reviewing';
492547
}
@@ -741,8 +796,9 @@ export class WakaTime {
741796
}
742797
}
743798

744-
private enoughTimePassed(time: number): boolean {
745-
return this.lastHeartbeat + 120000 < time;
799+
private recentlyAIPasted(time: number): boolean {
800+
this.AIrecentPastes = this.AIrecentPastes.filter((x) => x + AI_RECENT_PASTES_TIME_MS >= time);
801+
return this.AIrecentPastes.length > 3;
746802
}
747803

748804
private isDuplicateHeartbeat(file: string, time: number, selection: vscode.Position): boolean {

0 commit comments

Comments
 (0)