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:
Alfred 2026-04-07 12:22:21 -04:00
parent d32f46dc59
commit 553487a020
2 changed files with 157 additions and 1 deletions

View File

@ -218,6 +218,41 @@ function buildFullContext() {
return ctx; 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. // 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 - Check the IDE diagnostics panel for current errors
- Suggest targeted fixes, not wholesale rewrites - Suggest targeted fixes, not wholesale rewrites
- Explain WHY something broke, not just HOW to fix it - Explain WHY something broke, not just HOW to fix it
- Diagnose failures before switching tactics don't abandon after one failure
5. ARCHITECTURE & DESIGN: 5. ARCHITECTURE & DESIGN:
- Choose simple solutions over clever ones - 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 - For commands: provide the exact terminal command to run
- Be concise but complete no fluff, no filler - 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) { if (projectTypes.length > 0) {
prompt += `PROJECT CONTEXT: This is a ${projectTypes.join(' + ')} project.\n`; 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 += '\n';
} }
prompt += buildToolAwareness();
return prompt; return prompt;
} }
@ -755,6 +825,92 @@ class AlfredCommanderProvider {
// Return full workspace context to webview // Return full workspace context to webview
const ctx = buildFullContext(); const ctx = buildFullContext();
webviewView.webview.postMessage({ type: 'workspace-context', context: ctx, id: msg.id }); 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 });
} }
}); });

View File

@ -2,7 +2,7 @@
"name": "alfred-commander", "name": "alfred-commander",
"displayName": "Alfred IDE Assistant — Full IDE Chat & Voice", "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.", "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", "publisher": "gositeme",
"repository": { "repository": {
"type": "git", "type": "git",