Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 8 additions & 0 deletions src/constant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
68 changes: 67 additions & 1 deletion src/syncManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();

Comment on lines +105 to +107
// 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);
Expand Down Expand Up @@ -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<void> {
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;
Comment on lines +1241 to +1258
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...');

Expand Down
23 changes: 23 additions & 0 deletions src/utils/notifications.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<void> {
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');
}
}
Comment on lines +165 to +187
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for the command registration to ensure it exists
rg -n "promptitude-prompts" --type=ts -C2

Repository: nventive/Promptitude

Length of output: 476


🏁 Script executed:

rg -n "registerCommand.*promptitude-prompts" --type=ts

Repository: nventive/Promptitude

Length of output: 46


🏁 Script executed:

fd -name "extension.ts" -o -name "activate.ts" -o -name "*command*" --type=f | head -20

Repository: nventive/Promptitude

Length of output: 294


🏁 Script executed:

rg "promptitude-prompts" --type=ts --type=json

Repository: nventive/Promptitude

Length of output: 163


🏁 Script executed:

cat -n package.json | grep -A 20 -B 5 "commands"

Repository: nventive/Promptitude

Length of output: 911


🏁 Script executed:

rg -n "promptitude-prompts" package.json -C3

Repository: nventive/Promptitude

Length of output: 46


🏁 Script executed:

cat -n package.json | grep -A 50 '"views"'

Repository: nventive/Promptitude

Length of output: 1781


🏁 Script executed:

rg "\.focus" --type=ts src/

Repository: nventive/Promptitude

Length of output: 163


🏁 Script executed:

git log --oneline -20 -- package.json src/

Repository: nventive/Promptitude

Length of output: 138


🏁 Script executed:

git show ac3c8a4 --stat

Repository: nventive/Promptitude

Length of output: 2421


🏁 Script executed:

rg "promptitude\.cards\.focus|promptitude\.details\.focus" --type=ts

Repository: nventive/Promptitude

Length of output: 46


The command ID promptitude-prompts.focus does not exist and will fail at runtime.

The package.json defines views with IDs promptitude.cards (Prompts) and promptitude.details (Prompt Details). The code attempts to call a non-existent command; it should likely be promptitude.cards.focus to focus the Prompts view, or use an alternative approach if that's not the intended behavior.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/utils/notifications.ts` around lines 165 - 187, In showPromptSizeWarning,
the invoked command ID 'promptitude-prompts.focus' doesn't exist and will throw
at runtime; replace it with the correct view-focus command matching the view ID
in package.json (likely 'promptitude.cards.focus') when calling
vscode.commands.executeCommand('promptitude-prompts.focus'), or if the intent
was to focus the Prompt Details view use 'promptitude.details.focus' instead;
update the executeCommand invocation(s) in showPromptSizeWarning to use the
exact view ID(s) (promptitude.cards.focus or promptitude.details.focus) so the
command resolves successfully.

}
Loading