diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c6527e..8a5f944 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ All notable changes to the "promptitude" extension will be documented in this fi ## [Unreleased] +### Added + +- Prompt size safeguard: warns when active prompts may overwhelm GitHub Copilot's context window. Checks total file size (>500 KB), active prompt count (>50), and repository count (>10) after each sync. Shows actionable warning with "Manage Prompts" and "Open Settings" buttons. +- Disabled (inactive) prompts are now cleaned up from the active prompts directory during sync, preventing them from being loaded by Copilot. + ## [1.5.4] - 2026-01-12 ### Fixed diff --git a/src/constant.ts b/src/constant.ts index b5f9830..e750bb5 100644 --- a/src/constant.ts +++ b/src/constant.ts @@ -4,3 +4,11 @@ export const REPO_SYNC_CHAT_MODE_LEGACY_PATH = `chatmodes/`; export const REPO_SYNC_CHAT_MODE_LEGACY_SINGULAR_PATH = `chatmode/`; export const REPO_SYNC_INSTRUCTIONS_PATH = `instructions/`; export const REPO_SYNC_PROMPT_PATH = `prompts/`; + +// Prompt size safeguard thresholds +/** Maximum total size (in bytes) of all active prompts before warning the user */ +export const PROMPT_SIZE_WARNING_THRESHOLD_BYTES = 500 * 1024; // 500 KB +/** Maximum number of active prompts before warning the user */ +export const PROMPT_COUNT_WARNING_THRESHOLD = 50; +/** Maximum number of configured repositories before warning the user */ +export const REPO_COUNT_WARNING_THRESHOLD = 10; diff --git a/src/syncManager.ts b/src/syncManager.ts index 0231894..0e90730 100644 --- a/src/syncManager.ts +++ b/src/syncManager.ts @@ -10,7 +10,7 @@ import { GitProviderFactory } from './utils/gitProviderFactory'; import { FileSystemManager } from './utils/fileSystem'; import { AzureDevOpsApiManager } from './utils/azureDevOps'; import { PromptTreeDataProvider } from './ui/promptTreeProvider'; -import { REPO_SYNC_CHAT_MODE_PATH, REPO_SYNC_CHAT_MODE_LEGACY_PATH, REPO_SYNC_CHAT_MODE_LEGACY_SINGULAR_PATH, REPO_SYNC_INSTRUCTIONS_PATH, REPO_SYNC_PROMPT_PATH, } from './constant'; +import { REPO_SYNC_CHAT_MODE_PATH, REPO_SYNC_CHAT_MODE_LEGACY_PATH, REPO_SYNC_CHAT_MODE_LEGACY_SINGULAR_PATH, REPO_SYNC_INSTRUCTIONS_PATH, REPO_SYNC_PROMPT_PATH, PROMPT_SIZE_WARNING_THRESHOLD_BYTES, PROMPT_COUNT_WARNING_THRESHOLD, REPO_COUNT_WARNING_THRESHOLD, } from './constant'; export interface SyncResult { success: boolean; itemsUpdated: number; @@ -102,12 +102,18 @@ export class SyncManager { // Recreate symlinks for active prompts (in case they were manually deleted) await this.recreateActivePromptSymlinks(); + // Remove disabled prompts from the active prompts directory + await this.cleanupInactivePrompts(); + // Clean up orphaned regular files in prompts directory const cleanup = await this.cleanupOrphanedPrompts(); if (cleanup.removed > 0) { this.logger.info(`Cleaned up ${cleanup.removed} orphaned prompt files`); } + // Validate total prompt size to prevent Copilot context overflow + await this.validatePromptSize(); + // Update status based on overall result if (result.overallSuccess) { this.statusBar.setStatus(SyncStatus.Success); @@ -1226,6 +1232,66 @@ export class SyncManager { } } + /** + * Validate total prompt size and count, warning the user if thresholds are exceeded. + * This prevents GitHub Copilot's context window from being overwhelmed. + */ + private async validatePromptSize(): Promise { + try { + const fs = require('fs').promises; + const promptsDir = this.config.getPromptsDirectory(); + + // Ensure the prompts directory exists + await this.fileSystem.ensureDirectoryExists(promptsDir); + + const entries = await this.fileSystem.readDirectory(promptsDir); + const promptFiles = entries.filter(f => this.isPromptFile(f)); + + // Calculate total size of active prompt files + let totalSize = 0; + let activeCount = 0; + + for (const file of promptFiles) { + try { + const filePath = this.fileSystem.joinPath(promptsDir, file); + const stats = await fs.stat(filePath); + totalSize += stats.size; + activeCount++; + } catch { + // Skip files that can't be stat'd + } + } + + const repoCount = this.config.repositories.length; + const totalSizeKB = totalSize / 1024; + const reasons: string[] = []; + + if (totalSize > PROMPT_SIZE_WARNING_THRESHOLD_BYTES) { + reasons.push(`total size (${totalSizeKB.toFixed(0)} KB) exceeds ${(PROMPT_SIZE_WARNING_THRESHOLD_BYTES / 1024).toFixed(0)} KB`); + } + if (activeCount > PROMPT_COUNT_WARNING_THRESHOLD) { + reasons.push(`${activeCount} active prompts exceeds limit of ${PROMPT_COUNT_WARNING_THRESHOLD}`); + } + if (repoCount > REPO_COUNT_WARNING_THRESHOLD) { + reasons.push(`${repoCount} repositories exceeds limit of ${REPO_COUNT_WARNING_THRESHOLD}`); + } + + if (reasons.length > 0) { + this.logger.warn(`Prompt size safeguard triggered: ${reasons.join('; ')}`); + await this.notifications.showPromptSizeWarning({ + totalSizeKB, + activeCount, + repoCount, + reasons + }); + } else { + this.logger.debug(`Prompt size check passed: ${activeCount} prompts, ${totalSizeKB.toFixed(1)} KB, ${repoCount} repos`); + } + } catch (error) { + this.logger.error('Failed to validate prompt size', error instanceof Error ? error : undefined); + } + } + dispose(): void { this.logger.info('Disposing SyncManager...'); diff --git a/src/utils/notifications.ts b/src/utils/notifications.ts index 2340c07..2180a59 100644 --- a/src/utils/notifications.ts +++ b/src/utils/notifications.ts @@ -162,4 +162,27 @@ export class NotificationManager { await this.showError(`Failed to setup Azure DevOps authentication: ${errorMessage}`); } } + + /** + * Show a warning when the total prompt size or count exceeds safe thresholds. + * Always shown regardless of showNotifications setting to prevent Copilot context overflow. + */ + async showPromptSizeWarning(details: { totalSizeKB: number; activeCount: number; repoCount: number; reasons: string[] }): Promise { + const reasonText = details.reasons.join('; '); + const message = `⚠️ Promptitude: Your active prompts may be too large for GitHub Copilot (${details.totalSizeKB.toFixed(0)} KB across ${details.activeCount} prompts from ${details.repoCount} repos). ${reasonText}. Consider disabling unused prompts, reducing synced repositories, or switching to manual sync.`; + + // Always show this warning regardless of notification settings — it's a safeguard + const result = await vscode.window.showWarningMessage( + message, + 'Manage Prompts', + 'Open Settings', + 'Dismiss' + ); + + if (result === 'Manage Prompts') { + vscode.commands.executeCommand('promptitude-prompts.focus'); + } else if (result === 'Open Settings') { + vscode.commands.executeCommand('workbench.action.openSettings', 'promptitude'); + } + } }