Skip to content

Commit 33b285f

Browse files
authored
Fix: include workspace metadata in prompts (#58) (#60)
* fix: include workspace metadata in prompts (#58) * chore: build tests with promptGenerator entry
1 parent 09c4c16 commit 33b285f

File tree

6 files changed

+71
-69
lines changed

6 files changed

+71
-69
lines changed

packages/cli/docs/VSCODE-NO-REGRESSION-PROOF.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
1. VS Code extension has NO preset creation functionality
88
2. VS Code extension does NOT use the pattern optimization utilities we modified
99
3. All changes are isolated to the CLI package
10-
4. Core utilities used by VS Code remain completely unchanged
10+
4. VS Code uses only token utilities from @promptcode/core and its own prompt generator
1111

1212
## Detailed Analysis
1313

@@ -37,7 +37,7 @@ The VS Code extension's `package.json` shows NO preset-related commands:
3737

3838
### 3. Clean Import Separation
3939

40-
**VS Code Extension imports from @promptcode/core:**
40+
**VS Code Extension imports token utilities from @promptcode/core and uses its own prompt generator:**
4141
```typescript
4242
// src/extension.ts
4343
import {
@@ -47,16 +47,17 @@ import {
4747
clearTokenCache,
4848
initializeTokenCounter,
4949
tokenCache,
50-
countTokens,
51-
buildPrompt
50+
countTokens
5251
} from '@promptcode/core';
52+
import { generatePrompt } from './promptGenerator';
5353
```
5454

5555
**VS Code Extension does NOT import:**
5656
-`optimizeSelection`
5757
-`generatePatternsFromSelection`
5858
-`patternOptimizer`
5959
- ❌ Any pattern-related utilities
60+
-`buildPrompt` directly (prompt generation runs through `promptGenerator`)
6061

6162
### 4. CLI-Only Changes
6263

@@ -147,4 +148,4 @@ While regression is impossible due to architectural separation, you can verify b
147148
2. Testing file selection in VS Code: Open extension, select files, generate prompt
148149
3. Verifying no preset commands appear in Command Palette
149150

150-
All functionality will work exactly as before because we haven't touched any code the VS Code extension uses.
151+
All functionality will work exactly as before because we haven't touched any code the VS Code extension uses.

packages/cli/test/verify-vscode-no-regression.test.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,13 @@ describe('VS Code Extension Regression Verification', () => {
3333
// VS Code extension should import these utilities from @promptcode/core
3434
expect(extensionContent).toContain('countTokensInFile');
3535
expect(extensionContent).toContain('countTokensWithCache');
36-
expect(extensionContent).toContain('buildPrompt');
36+
expect(extensionContent).toContain('countTokensWithCacheDetailed');
37+
expect(extensionContent).toContain('countTokens');
38+
39+
// VS Code extension should not import prompt builder directly anymore
40+
expect(extensionContent).not.toContain('buildPrompt');
41+
// It should rely on promptGenerator for prompt construction
42+
expect(extensionContent).toContain("from './promptGenerator'");
3743

3844
// VS Code extension should NOT import pattern-related utilities
3945
expect(extensionContent).not.toContain('generatePatternsFromSelection');
@@ -146,4 +152,4 @@ describe('VS Code Extension Regression Verification', () => {
146152
* 5. **Testing Coverage**:
147153
* - This test file verifies the separation
148154
* - Existing VS Code tests would catch any regression
149-
*/
155+
*/

scripts/build-tests.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ const testEntryPoints = [
1313
'src/test/smoke.test.ts',
1414
'src/test/migration.test.ts',
1515
'src/test/promptContract.test.ts',
16+
'src/test/promptWorkspaceMetadata.test.ts',
1617
'src/test/ignorePatterns.test.ts',
1718
'src/test/extensionActivation.test.ts',
1819
'src/test/tokenCounter.test.ts',
@@ -24,6 +25,8 @@ const testEntryPoints = [
2425
// Also compile the utils that tests depend on
2526
'src/utils/filePattern.ts',
2627
'src/utils/generatePatternsFromSelection.ts',
28+
'src/promptcodeDataFetcher.ts',
29+
'src/promptGenerator.ts',
2730
// Compile modules that tests import directly
2831
'src/fileExplorer.ts',
2932
'src/ignoreHelper.ts',
@@ -58,4 +61,4 @@ esbuild.build({
5861
}).catch((error) => {
5962
console.error('Error building test files:', error);
6063
process.exit(1);
61-
});
64+
});

src/extension.ts

Lines changed: 3 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44
// Import the module and reference it with the alias vscode in your code below
55
import * as vscode from 'vscode';
66
import { FileExplorerProvider, checkedItems as checkedItemsMap, FileItem } from './fileExplorer';
7-
import { generatePrompt as generatePromptFromGenerator, copyToClipboard } from './promptGenerator';
7+
import { generatePrompt, copyToClipboard } from './promptGenerator';
88
import { PromptCodeWebViewProvider } from './webviewProvider';
9-
import { countTokensInFile, countTokensWithCache, countTokensWithCacheDetailed, clearTokenCache, initializeTokenCounter, tokenCache, countTokens, buildPrompt } from '@promptcode/core';
9+
import { countTokensInFile, countTokensWithCache, countTokensWithCacheDetailed, clearTokenCache, initializeTokenCounter, tokenCache, countTokens } from '@promptcode/core';
1010
import * as path from 'path';
1111
import * as fs from 'fs';
1212
import * as os from 'os';
@@ -1677,59 +1677,6 @@ function isValidIncludeOptions(options: any): options is { files: boolean; instr
16771677
typeof options.instructions === 'boolean';
16781678
}
16791679

1680-
// Helper function to generate prompt using core's buildPrompt
1681-
async function generatePrompt(
1682-
selectedFiles: {
1683-
path: string;
1684-
tokenCount: number;
1685-
workspaceFolderRootPath?: string;
1686-
absolutePath?: string;
1687-
workspaceFolderName?: string;
1688-
}[],
1689-
instructions: string,
1690-
includeOptions: { files: boolean; instructions: boolean }
1691-
): Promise<string> {
1692-
const startTime = performance.now();
1693-
1694-
// Early returns for edge cases (per O3-pro recommendation)
1695-
if (!includeOptions.files && (!instructions || !includeOptions.instructions)) {
1696-
const endTime = performance.now();
1697-
console.log(`Prompt generation took ${endTime - startTime}ms for ${selectedFiles.length} files`);
1698-
return '';
1699-
}
1700-
1701-
// Early return if no files selected but files are required
1702-
if (selectedFiles.length === 0 && includeOptions.files) {
1703-
const endTime = performance.now();
1704-
console.log(`Prompt generation took ${endTime - startTime}ms - no files selected`);
1705-
return includeOptions.instructions ? instructions : '';
1706-
}
1707-
1708-
// Convert to SelectedFile format expected by core
1709-
const coreSelectedFiles: SelectedFile[] = selectedFiles.map(file => ({
1710-
path: file.path,
1711-
absolutePath: file.absolutePath || path.join(file.workspaceFolderRootPath || '', file.path),
1712-
tokenCount: file.tokenCount,
1713-
workspaceFolderRootPath: file.workspaceFolderRootPath || '',
1714-
workspaceFolderName: file.workspaceFolderName || ''
1715-
}));
1716-
1717-
// Use core's buildPrompt
1718-
const result = await buildPrompt(coreSelectedFiles, instructions, {
1719-
includeFiles: includeOptions.files,
1720-
includeInstructions: includeOptions.instructions,
1721-
includeFileContents: includeOptions.files
1722-
});
1723-
1724-
// No transformation needed - core now uses standard tags
1725-
const prompt = result.prompt;
1726-
1727-
const endTime = performance.now();
1728-
console.log(`Prompt generation took ${endTime - startTime}ms for ${selectedFiles.length} files`);
1729-
1730-
return prompt;
1731-
}
1732-
17331680
// Helper function to get selected files with content
17341681
async function getSelectedFilesWithContent(): Promise<SelectedFile[]> {
17351682
if (!vscode.workspace.workspaceFolders || vscode.workspace.workspaceFolders.length === 0) {
@@ -1857,4 +1804,4 @@ export async function savePromptToFile(prompt: string, context?: vscode.Extensio
18571804
// ... error telemetry code ...
18581805
}
18591806
}
1860-
// --- End Save to file feature ---
1807+
// --- End Save to file feature ---

src/promptGenerator.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -217,12 +217,17 @@ export async function generatePrompt(
217217
): Promise<string> {
218218
log('--- Starting generatePrompt ---');
219219
const workspaceFolders = vscode.workspace.workspaceFolders;
220-
if (!workspaceFolders || workspaceFolders.length === 0) {
221-
log('No workspace folders found. Aborting prompt generation.');
220+
const hasWorkspace = !!workspaceFolders && workspaceFolders.length > 0;
221+
222+
// If files are requested but no workspace is open, we cannot proceed safely.
223+
if (!hasWorkspace && includeOptions.files) {
224+
log('No workspace folders found. Aborting prompt generation that requires files.');
222225
return 'No workspace folders available.';
223226
}
224-
const workspaceRoot = workspaceFolders[0].uri.fsPath;
225-
log('Workspace root:', { workspaceRoot });
227+
228+
// Instructions-only scenarios can proceed without a workspace.
229+
const workspaceRoot = hasWorkspace ? workspaceFolders[0].uri.fsPath : '';
230+
log('Workspace root:', { workspaceRoot: workspaceRoot || 'N/A (instructions-only mode)' });
226231

227232
let finalPromptText = '';
228233
let processedInstructions = '';
@@ -337,4 +342,4 @@ export async function generatePrompt(
337342
export async function copyToClipboard(text: string): Promise<void> {
338343
await vscode.env.clipboard.writeText(text);
339344
log('Prompt copied to clipboard.');
340-
}
345+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import * as assert from 'assert';
2+
import * as path from 'path';
3+
import * as vscode from 'vscode';
4+
import { generatePrompt } from '../promptGenerator';
5+
import type { SelectedFile } from '@promptcode/core';
6+
7+
suite('Prompt workspace metadata', () => {
8+
test('generatePrompt includes workspace name and root for each file', async () => {
9+
const workspace = vscode.workspace.workspaceFolders?.[0];
10+
if (!workspace) {
11+
console.log('Skipping test - no workspace folder available');
12+
return;
13+
}
14+
15+
const workspaceRoot = workspace.uri.fsPath;
16+
const workspaceName = workspace.name;
17+
const absolutePath = path.join(workspaceRoot, 'src', 'a.ts');
18+
19+
const selectedFiles: SelectedFile[] = [
20+
{
21+
path: 'src/a.ts',
22+
absolutePath,
23+
tokenCount: 1, // Value is informational only for this assertion
24+
workspaceFolderRootPath: workspaceRoot,
25+
workspaceFolderName: workspaceName
26+
}
27+
];
28+
29+
const prompt = await generatePrompt(selectedFiles, 'Test instructions', {
30+
files: true,
31+
instructions: true
32+
});
33+
34+
const escapedRoot = workspaceRoot.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
35+
const workspaceLine = new RegExp(`Workspace:\\s*${workspaceName}\\s*\\(${escapedRoot}\\)`);
36+
37+
assert.match(prompt, workspaceLine, 'prompt should include workspace name and root');
38+
assert.match(prompt, /File:\s*src\/a\.ts/i, 'prompt should include the relative file path');
39+
});
40+
});

0 commit comments

Comments
 (0)