Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save mikegwhit/3f469c2a8a80b78bb4f052ec694f5ba2 to your computer and use it in GitHub Desktop.

Select an option

Save mikegwhit/3f469c2a8a80b78bb4f052ec694f5ba2 to your computer and use it in GitHub Desktop.
claude-code-vscode-add-file-or-folder-to-context-menu.js
const vscode = require('vscode');
const path = require('path');
const fs = require('fs');
/**
* Resolves the Claude Code insertAtMention command name,
* or null if Claude Code isn't installed.
* @return {Promise<string|null>}
*/
async function findClaudeCommand() {
const all = await vscode.commands.getCommands(true);
if (all.includes('claude-vscode.insertAtMention')) {
return 'claude-vscode.insertAtMention';
}
if (all.includes('claude-code.insertAtMentioned')) {
return 'claude-code.insertAtMentioned';
}
return null;
}
/**
* Returns a workspace-relative @mention string for a URI.
* @param {vscode.Uri} u
* @return {string}
*/
function toMention(u) {
const folders = vscode.workspace.workspaceFolders;
const wsRoot = folders && folders.length > 0
? folders[0].uri.fsPath
: (process.env.HOME || '/tmp');
const rel = path.relative(wsRoot, u.fsPath);
return '@' + (rel.startsWith('..') ? u.fsPath : rel);
}
/**
* Returns true if the given URI points to a directory.
* @param {vscode.Uri} u
* @return {boolean}
*/
function isDirectory(u) {
try {
return fs.statSync(u.fsPath).isDirectory();
} catch (_) {
return false;
}
}
/**
* Injects a single file @mention into the Claude Code
* sidebar input using the insertAtMention command (same
* mechanism as Alt+K). Opens the file as the active
* editor so the command can read it.
* @param {vscode.Uri} u
* @param {string} claudeCmd
*/
async function injectFileToClaudeInput(u, claudeCmd) {
await vscode.window.showTextDocument(u, {
preview: true,
preserveFocus: false,
});
await vscode.commands.executeCommand(claudeCmd);
}
/**
* Injects a folder @mention into the Claude Code sidebar
* input using the same insertAtMention mechanism as files.
*
* Trick: open an untitled document whose URI path equals
* the folder's fsPath. insertAtMention reads
* document.fileName → workspace.asRelativePath() → fires
* @relativeFolder into Claude Code. We close the scratch
* document immediately after.
*
* Falls back to clipboard + sidebar focus if that fails.
*
* @param {vscode.Uri} u
* @param {string} claudeCmd
*/
async function injectFolderToClaudeInput(u, claudeCmd) {
try {
const scratchUri = vscode.Uri.parse(
'untitled:' + u.fsPath);
const doc = await vscode.workspace
.openTextDocument(scratchUri);
await vscode.window.showTextDocument(doc, {
preview: true,
preserveFocus: false,
});
await vscode.commands.executeCommand(claudeCmd);
await vscode.commands.executeCommand(
'workbench.action.closeActiveEditor');
return;
} catch (_) {}
// Fallback: clipboard + focus sidebar.
const mention = toMention(u);
await vscode.env.clipboard.writeText(mention);
for (const cmd of [
'claudeVSCodeSidebarSecondary.focus',
'claudeVSCodeSidebar.focus',
]) {
try {
await vscode.commands.executeCommand(cmd);
break;
} catch (_) {}
}
vscode.window.showInformationMessage(
`${mention} copied — press Ctrl+V to add to Claude`);
}
/**
* "Add to Claude Context" command handler.
*
* - Files → opens as active editor + fires insertAtMention
* (identical to Alt+K, injects into sidebar input)
* - Folders → sends @folderPath to Claude terminal, or clipboard
* - Multi-select in Explorer passes all URIs as second arg.
*
* @param {vscode.Uri|undefined} uri
* @param {vscode.Uri[]|undefined} uris
*/
async function addToClaudeContext(uri, uris) {
let targets = [];
if (uris && uris.length > 0) {
targets = uris;
} else if (uri) {
targets = [uri];
} else {
const editor = vscode.window.activeTextEditor;
if (editor) targets = [editor.document.uri];
}
if (targets.length === 0) {
vscode.window.showWarningMessage(
'Claude Context: no file or folder selected.');
return;
}
const claudeCmd = await findClaudeCommand();
if (!claudeCmd) {
// Claude Code not installed — clipboard fallback for all.
const text = targets.map(toMention).join(' ');
await vscode.env.clipboard.writeText(text);
vscode.window.showInformationMessage(
`Claude Code not found — copied to clipboard: ${text}`);
return;
}
for (const u of targets) {
if (isDirectory(u)) {
await injectFolderToClaudeInput(u, claudeCmd);
} else {
await injectFileToClaudeInput(u, claudeCmd);
}
}
}
module.exports = {addToClaudeContext};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment