feat(extension): adicionar lembrete inteligente para iniciar tarefa ao codar sem task ativa

This commit is contained in:
Gabriel Menezes 2026-11-05 15:11:53 -04:00
parent c613c71f1e
commit e7703f34e7
4 changed files with 106 additions and 9 deletions

View file

@ -8,6 +8,7 @@ Extensão oficial do **BeeTask** para o Visual Studio Code. Gerencie suas demand
- **⏱️ Cronômetro em Tempo Real:** Acompanhe o tempo trabalhado na tarefa ativa direto na Barra de Status (rodapé do VS Code).
- **🛑 Pausa Automática por Inatividade (10min):** Se você se ausentar do VS Code por mais de 10 minutos com uma tarefa rodando, a extensão pausa o cronômetro automaticamente e pergunta se você ainda está trabalhando nela ao retornar.
- **💡 Lembrete de Início de Tarefa:** Se você começar a editar código sem nenhuma tarefa ativa, a extensão lembra de forma sutil e pergunta qual tarefa você vai trabalhar.
- **📋 Painel de Tarefas na Barra Lateral:** Visualize rapidamente suas tarefas pendentes, em execução e concluídas na aba BeeTask.
- **▶️ Play / ⏸️ Pause com 1 Clique:** Inicie e pause o cronômetro das suas tarefas direto do VS Code.
- **➕ Criação Rápida de Tarefas:** Crie novas tarefas associadas a projetos e categorias sem sair do editor.
@ -81,3 +82,5 @@ Acesse `Configurações` (`Ctrl+,`) e busque por `BeeTask`:
- `beetask.refreshIntervalSeconds`: Intervalo de sincronização automática em segundos (Padrão: `30`).
- `beetask.enableIdleDetection`: Ativar pausa automática da tarefa por inatividade (Padrão: `true`).
- `beetask.idleTimeoutMinutes`: Tempo limite de inatividade em minutos (Padrão: `10`).
- `beetask.enableNoActiveTaskPrompt`: Lembrar de iniciar tarefa ao começar a codar (Padrão: `true`).
- `beetask.noActiveTaskCooldownMinutes`: Intervalo mínimo entre lembretes em minutos (Padrão: `15`).

View file

@ -2,7 +2,7 @@
"name": "beetask-vscode",
"displayName": "BeeTask",
"description": "Gerenciamento e rastreamento de tarefas com cronômetro integrado ao VS Code",
"version": "1.1.0",
"version": "1.2.0",
"publisher": "beetech",
"icon": "media/icon.png",
"repository": {
@ -163,6 +163,16 @@
"type": "number",
"default": 10,
"description": "Tempo limite de inatividade em minutos para pausar a tarefa ativa (padrão: 10 minutos)"
},
"beetask.enableNoActiveTaskPrompt": {
"type": "boolean",
"default": true,
"description": "Lembrar de iniciar uma tarefa ao começar a codar sem nenhuma tarefa ativa"
},
"beetask.noActiveTaskCooldownMinutes": {
"type": "number",
"default": 15,
"description": "Intervalo mínimo em minutos entre lembretes de início de tarefa (padrão: 15 minutos)"
}
}
}

View file

@ -11,6 +11,11 @@ export class IdleDetector implements vscode.Disposable {
private isPrompting: boolean = false;
private disposables: vscode.Disposable[] = [];
// Lembrete de codar sem tarefa ativa
private lastNoActivePromptTime: number = 0;
private isPromptingNoActive: boolean = false;
private pendingActivityTimer: NodeJS.Timeout | null = null;
private api: BeeTaskApiClient;
private authManager: AuthManager;
private statusBar: StatusBarManager;
@ -31,46 +36,121 @@ export class IdleDetector implements vscode.Disposable {
this.startPeriodicCheck();
}
public recordActivity(): void {
public recordActivity(isCodeEdit: boolean = false): void {
this.lastActivityTime = Date.now();
if (isCodeEdit) {
this.scheduleNoActiveTaskCheck();
}
}
private registerActivityListeners(): void {
// 1. Digitação ou alteração de código
// 1. Digitação ou alteração de código (edição real de código)
this.disposables.push(
vscode.workspace.onDidChangeTextDocument(() => this.recordActivity())
vscode.workspace.onDidChangeTextDocument((e) => {
// Ignora alterações em esquemas que não sejam arquivos reais (ex: output, git, etc)
if (e.document.uri.scheme === 'file') {
this.recordActivity(true);
} else {
this.recordActivity(false);
}
})
);
// 2. Movimentação de cursor ou seleção de texto
this.disposables.push(
vscode.window.onDidChangeTextEditorSelection(() => this.recordActivity())
vscode.window.onDidChangeTextEditorSelection(() => this.recordActivity(false))
);
// 3. Troca de arquivo / aba ativa
this.disposables.push(
vscode.window.onDidChangeActiveTextEditor(() => this.recordActivity())
vscode.window.onDidChangeActiveTextEditor(() => this.recordActivity(false))
);
// 4. Rolagem da página (scroll)
this.disposables.push(
vscode.window.onDidChangeTextEditorVisibleRanges(() => this.recordActivity())
vscode.window.onDidChangeTextEditorVisibleRanges(() => this.recordActivity(false))
);
// 5. Salvamento de arquivo
this.disposables.push(
vscode.workspace.onDidSaveTextDocument(() => this.recordActivity())
vscode.workspace.onDidSaveTextDocument((doc) => {
if (doc.uri.scheme === 'file') {
this.recordActivity(true);
} else {
this.recordActivity(false);
}
})
);
// 6. Janela do VS Code ganhou foco
this.disposables.push(
vscode.window.onDidChangeWindowState((state) => {
if (state.focused) {
this.recordActivity();
this.recordActivity(false);
}
})
);
}
private scheduleNoActiveTaskCheck(): void {
if (this.pendingActivityTimer) return;
// Aguarda 3 segundos de digitação contínua para exibir o lembrete de forma suave
this.pendingActivityTimer = setTimeout(async () => {
this.pendingActivityTimer = null;
await this.checkNoActiveTask();
}, 3000);
}
private async checkNoActiveTask(): Promise<void> {
const config = vscode.workspace.getConfiguration('beetask');
const enabled = config.get<boolean>('enableNoActiveTaskPrompt', true);
const cooldownMinutes = config.get<number>('noActiveTaskCooldownMinutes', 15);
if (!enabled || this.isPromptingNoActive || this.isPrompting) {
return;
}
const isAuth = await this.authManager.isAuthenticated();
if (!isAuth) {
return;
}
const activeTask = this.statusBar.getActiveTask();
if (activeTask) {
// Já está com uma tarefa rodando, nada a fazer
return;
}
const now = Date.now();
if (now - this.lastNoActivePromptTime < cooldownMinutes * 60000) {
return; // Ainda dentro do período de cooldown
}
this.isPromptingNoActive = true;
this.lastNoActivePromptTime = now;
try {
const choice = await vscode.window.showInformationMessage(
'🐝 BeeTask: Você começou a mexer no código sem nenhuma tarefa ativa. Qual demanda você está trabalhando?',
'Selecionar Tarefa',
'Criar Nova Tarefa',
'Lembrar mais tarde'
);
if (choice === 'Selecionar Tarefa') {
await vscode.commands.executeCommand('beetask.startTask');
} else if (choice === 'Criar Nova Tarefa') {
await vscode.commands.executeCommand('beetask.createTask');
}
} catch (err: any) {
console.error('[BeeTask] Erro ao exibir lembrete de tarefa ativa:', err);
} finally {
this.isPromptingNoActive = false;
}
}
private startPeriodicCheck(): void {
// Checa a cada 15 segundos
this.checkInterval = setInterval(async () => {
@ -158,6 +238,10 @@ export class IdleDetector implements vscode.Disposable {
}
public dispose(): void {
if (this.pendingActivityTimer) {
clearTimeout(this.pendingActivityTimer);
this.pendingActivityTimer = null;
}
if (this.checkInterval) {
clearInterval(this.checkInterval);
this.checkInterval = null;