v1.2.0: Integrate Claude Code deep research patterns
System prompt upgrades: - Implementation Discipline: don't over-engineer, read before edit, no premature abstractions - Action Safety: reversibility assessment, confirm destructive ops - Verification Protocol: verify before reporting done, report failures faithfully - Output Excellence: state intent before acting, brief updates, complete context - Code Style: default to NO comments, diagnose before switching tactics New LSP tools (5): - goto-definition: Jump to symbol definition via Language Server - find-references: Find all references to symbol across workspace - document-symbols: List all functions/classes/variables in a file - hover-info: Get type info and documentation for symbol at position - workspace-symbols: Search symbols across entire workspace by name Tool Registry: - Formal TOOL_REGISTRY array with 17 tools defined with schemas - buildToolAwareness() injects tool listing into system prompt - AI now discoverable-aware of all available IDE tools
This commit is contained in:
parent
d32f46dc59
commit
553487a020
156
extension.js
156
extension.js
@ -218,6 +218,41 @@ function buildFullContext() {
|
||||
return ctx;
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
// TOOL REGISTRY — Formal tool definitions for AI agent awareness
|
||||
// Claude Code pattern: tools defined with schemas, discoverable by AI
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
const TOOL_REGISTRY = [
|
||||
{ name: 'read-file', description: 'Read file content from workspace', params: { filePath: 'string (relative or absolute path)', maxChars: 'number (optional, default 50000)' } },
|
||||
{ name: 'search-files', description: 'Search for files by name pattern in workspace', params: { pattern: 'string (filename pattern)' } },
|
||||
{ name: 'grep-search', description: 'Search file contents with text/regex pattern', params: { text: 'string (search text)', filePattern: 'string (optional glob, e.g. "*.php")' } },
|
||||
{ name: 'open-file', description: 'Open a file in the editor at optional line number', params: { filePath: 'string', line: 'number (optional)' } },
|
||||
{ name: 'apply-edit', description: 'Apply a code edit: find-and-replace or insert-at-line', params: { filePath: 'string', oldText: 'string (text to find)', newText: 'string (replacement)', line: 'number (for insert mode)', text: 'string (for insert mode)' } },
|
||||
{ name: 'create-file', description: 'Create a new file with content (creates directories as needed)', params: { filePath: 'string', content: 'string' } },
|
||||
{ name: 'get-context', description: 'Get full workspace context (project type, git, diagnostics, active file)', params: {} },
|
||||
{ name: 'get-git-info', description: 'Get git branch, status, last commit, remote URL', params: {} },
|
||||
{ name: 'get-diagnostics', description: 'Get error/warning counts and affected files', params: {} },
|
||||
{ name: 'get-project-structure', description: 'Get project file tree (3 levels deep, excluding .git/node_modules)', params: {} },
|
||||
{ name: 'goto-definition', description: 'LSP: Jump to the definition of a symbol at a given position', params: { filePath: 'string', line: 'number (1-based)', character: 'number (0-based column)' } },
|
||||
{ name: 'find-references', description: 'LSP: Find all references to a symbol across the workspace', params: { filePath: 'string', line: 'number (1-based)', character: 'number (0-based column)' } },
|
||||
{ name: 'document-symbols', description: 'LSP: List all symbols (functions, classes, variables) in a file', params: { filePath: 'string' } },
|
||||
{ name: 'hover-info', description: 'LSP: Get type info and documentation for symbol at position', params: { filePath: 'string', line: 'number (1-based)', character: 'number (0-based column)' } },
|
||||
{ name: 'workspace-symbols', description: 'LSP: Search for symbols by name across entire workspace', params: { query: 'string (symbol name or pattern)' } },
|
||||
{ name: 'run-terminal', description: 'Execute a command in a new terminal', params: { command: 'string' } },
|
||||
{ name: 'insert-code', description: 'Insert code at cursor position in active editor', params: { code: 'string' } },
|
||||
];
|
||||
|
||||
function buildToolAwareness() {
|
||||
let section = '\nAVAILABLE IDE TOOLS (you can request these via the IDE):\n';
|
||||
for (const tool of TOOL_REGISTRY) {
|
||||
section += `- ${tool.name}: ${tool.description}\n`;
|
||||
}
|
||||
section += '\nYou have direct access to the workspace file system, LSP (Language Server Protocol) for code intelligence,\n';
|
||||
section += 'git operations, diagnostics, and terminal execution through these tools.\n';
|
||||
return section;
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
// COMMANDER SYSTEM PROMPT — The soul of Alfred. Knows who Danny is.
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
@ -307,6 +342,7 @@ You are assisting ${name}. Be helpful, precise, and technically thorough.
|
||||
- Check the IDE diagnostics panel for current errors
|
||||
- Suggest targeted fixes, not wholesale rewrites
|
||||
- Explain WHY something broke, not just HOW to fix it
|
||||
- Diagnose failures before switching tactics — don't abandon after one failure
|
||||
|
||||
5. ARCHITECTURE & DESIGN:
|
||||
- Choose simple solutions over clever ones
|
||||
@ -328,8 +364,40 @@ You are assisting ${name}. Be helpful, precise, and technically thorough.
|
||||
- For commands: provide the exact terminal command to run
|
||||
- Be concise but complete — no fluff, no filler
|
||||
|
||||
IMPLEMENTATION DISCIPLINE:
|
||||
- Only make changes that are directly requested or clearly necessary
|
||||
- Don't add features, refactor code, or make "improvements" beyond what was asked
|
||||
- A bug fix doesn't need surrounding code cleaned up; a simple feature doesn't need extra configurability
|
||||
- Default to writing NO comments — only add one when the WHY is non-obvious (well-named code explains itself)
|
||||
- Don't add error handling, fallbacks, or validation for scenarios that can't happen
|
||||
- Don't create helpers, utilities, or abstractions for one-time operations — 3 similar lines are better than a premature abstraction
|
||||
- Read files before proposing changes — NEVER suggest edits to code you haven't seen
|
||||
- Don't create new files unless absolutely necessary — prefer editing existing files
|
||||
|
||||
EXECUTING ACTIONS WITH CARE:
|
||||
- Consider the reversibility and potential impact of every action
|
||||
- Take local, reversible actions freely (edits, tests) but confirm destructive or shared-system operations first
|
||||
- Destructive operations (deleting files/branches, dropping tables, rm -rf): ALWAYS confirm
|
||||
- Hard to reverse operations (force push, reset --hard, amending published commits): ALWAYS confirm
|
||||
- Operations visible to others (pushing code, commenting on PRs, sending messages): confirm first
|
||||
- When encountering unexpected state, investigate before deleting — don't bypass safety checks as a shortcut
|
||||
|
||||
VERIFICATION PROTOCOL:
|
||||
- Before reporting a task complete, verify it actually works: run the test, execute the script, check the output
|
||||
- Report outcomes faithfully — if tests fail, say so. If something wasn't verified, state that clearly
|
||||
- For non-trivial changes (3+ file edits, backend/API changes, infrastructure): independently verify by reviewing the changes
|
||||
- Never suppress failures or gloss over errors to appear successful
|
||||
|
||||
OUTPUT EXCELLENCE:
|
||||
- State what you're about to do before the first action — give the user orientation
|
||||
- Provide brief updates at key moments: found a bug, changing direction, hit a blocker
|
||||
- Assume the user may have stepped away — give complete context, not fragments
|
||||
- Avoid time estimates or predictions for how long tasks will take — focus on what needs to be done
|
||||
- Only use tables for factual data (filenames, line numbers, pass/fail) or quantitative comparisons
|
||||
|
||||
`;
|
||||
|
||||
|
||||
if (projectTypes.length > 0) {
|
||||
prompt += `PROJECT CONTEXT: This is a ${projectTypes.join(' + ')} project.\n`;
|
||||
}
|
||||
@ -339,6 +407,8 @@ You are assisting ${name}. Be helpful, precise, and technically thorough.
|
||||
prompt += '\n';
|
||||
}
|
||||
|
||||
prompt += buildToolAwareness();
|
||||
|
||||
return prompt;
|
||||
}
|
||||
|
||||
@ -755,6 +825,92 @@ class AlfredCommanderProvider {
|
||||
// Return full workspace context to webview
|
||||
const ctx = buildFullContext();
|
||||
webviewView.webview.postMessage({ type: 'workspace-context', context: ctx, id: msg.id });
|
||||
} else if (msg.type === 'goto-definition') {
|
||||
// LSP: Go to definition of symbol at position
|
||||
try {
|
||||
const root = getWorkspaceRoot();
|
||||
const fullPath = path.isAbsolute(msg.filePath) ? msg.filePath : path.join(root, msg.filePath);
|
||||
const uri = vscode.Uri.file(fullPath);
|
||||
const doc = await vscode.workspace.openTextDocument(uri);
|
||||
const pos = new vscode.Position((msg.line || 1) - 1, msg.character || 0);
|
||||
const locations = await vscode.commands.executeCommand('vscode.executeDefinitionProvider', uri, pos);
|
||||
const results = (locations || []).map(loc => ({
|
||||
file: vscode.workspace.asRelativePath(loc.uri || loc.targetUri, false),
|
||||
line: ((loc.range || loc.targetRange || {}).start || {}).line + 1,
|
||||
character: ((loc.range || loc.targetRange || {}).start || {}).character
|
||||
}));
|
||||
webviewView.webview.postMessage({ type: 'definition-result', results, id: msg.id });
|
||||
} catch (e) {
|
||||
webviewView.webview.postMessage({ type: 'definition-result', results: [], error: e.message, id: msg.id });
|
||||
}
|
||||
} else if (msg.type === 'find-references') {
|
||||
// LSP: Find all references to symbol
|
||||
try {
|
||||
const root = getWorkspaceRoot();
|
||||
const fullPath = path.isAbsolute(msg.filePath) ? msg.filePath : path.join(root, msg.filePath);
|
||||
const uri = vscode.Uri.file(fullPath);
|
||||
const doc = await vscode.workspace.openTextDocument(uri);
|
||||
const pos = new vscode.Position((msg.line || 1) - 1, msg.character || 0);
|
||||
const locations = await vscode.commands.executeCommand('vscode.executeReferenceProvider', uri, pos);
|
||||
const results = (locations || []).slice(0, 50).map(loc => ({
|
||||
file: vscode.workspace.asRelativePath(loc.uri, false),
|
||||
line: (loc.range.start.line || 0) + 1,
|
||||
preview: ''
|
||||
}));
|
||||
webviewView.webview.postMessage({ type: 'references-result', results, id: msg.id });
|
||||
} catch (e) {
|
||||
webviewView.webview.postMessage({ type: 'references-result', results: [], error: e.message, id: msg.id });
|
||||
}
|
||||
} else if (msg.type === 'document-symbols') {
|
||||
// LSP: Get all symbols in a document (functions, classes, variables)
|
||||
try {
|
||||
const root = getWorkspaceRoot();
|
||||
const fullPath = path.isAbsolute(msg.filePath) ? msg.filePath : path.join(root, msg.filePath);
|
||||
const uri = vscode.Uri.file(fullPath);
|
||||
const doc = await vscode.workspace.openTextDocument(uri);
|
||||
const symbols = await vscode.commands.executeCommand('vscode.executeDocumentSymbolProvider', uri);
|
||||
const flatten = (syms, depth) => {
|
||||
const out = [];
|
||||
for (const s of (syms || [])) {
|
||||
out.push({ name: s.name, kind: vscode.SymbolKind[s.kind] || s.kind, line: (s.range || s.location?.range)?.start?.line + 1, detail: s.detail || '' });
|
||||
if (s.children) out.push(...flatten(s.children, depth + 1));
|
||||
}
|
||||
return out;
|
||||
};
|
||||
webviewView.webview.postMessage({ type: 'symbols-result', symbols: flatten(symbols, 0).slice(0, 200), id: msg.id });
|
||||
} catch (e) {
|
||||
webviewView.webview.postMessage({ type: 'symbols-result', symbols: [], error: e.message, id: msg.id });
|
||||
}
|
||||
} else if (msg.type === 'hover-info') {
|
||||
// LSP: Get hover info (type info, docs) for symbol at position
|
||||
try {
|
||||
const root = getWorkspaceRoot();
|
||||
const fullPath = path.isAbsolute(msg.filePath) ? msg.filePath : path.join(root, msg.filePath);
|
||||
const uri = vscode.Uri.file(fullPath);
|
||||
const doc = await vscode.workspace.openTextDocument(uri);
|
||||
const pos = new vscode.Position((msg.line || 1) - 1, msg.character || 0);
|
||||
const hovers = await vscode.commands.executeCommand('vscode.executeHoverProvider', uri, pos);
|
||||
const contents = (hovers || []).map(h => (h.contents || []).map(c => typeof c === 'string' ? c : c.value || '').join('\\n')).join('\\n');
|
||||
webviewView.webview.postMessage({ type: 'hover-result', info: contents, id: msg.id });
|
||||
} catch (e) {
|
||||
webviewView.webview.postMessage({ type: 'hover-result', info: '', error: e.message, id: msg.id });
|
||||
}
|
||||
} else if (msg.type === 'workspace-symbols') {
|
||||
// LSP: Search symbols across workspace by query
|
||||
try {
|
||||
const symbols = await vscode.commands.executeCommand('vscode.executeWorkspaceSymbolProvider', msg.query || '');
|
||||
const results = (symbols || []).slice(0, 50).map(s => ({
|
||||
name: s.name, kind: vscode.SymbolKind[s.kind] || s.kind,
|
||||
file: vscode.workspace.asRelativePath(s.location.uri, false),
|
||||
line: (s.location.range?.start?.line || 0) + 1
|
||||
}));
|
||||
webviewView.webview.postMessage({ type: 'workspace-symbols-result', symbols: results, id: msg.id });
|
||||
} catch (e) {
|
||||
webviewView.webview.postMessage({ type: 'workspace-symbols-result', symbols: [], error: e.message, id: msg.id });
|
||||
}
|
||||
} else if (msg.type === 'get-tool-registry') {
|
||||
// Return formal tool definitions for AI tool-use awareness
|
||||
webviewView.webview.postMessage({ type: 'tool-registry', tools: TOOL_REGISTRY, id: msg.id });
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
"name": "alfred-commander",
|
||||
"displayName": "Alfred IDE Assistant — Full IDE Chat & Voice",
|
||||
"description": "Fresh Alfred panel: all agents & models, voice STT/TTS, attachments, hands-free. IDE shortcuts are explicit buttons — chat text always goes to AI.",
|
||||
"version": "1.0.1",
|
||||
"version": "1.2.0",
|
||||
"publisher": "gositeme",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
Loading…
Reference in New Issue
Block a user