@@ -304,6 +304,75 @@ async function installForCopilot(
304304 }
305305}
306306
307+ // ── Status detection ─────────────────────────────────────────────────────────
308+
309+ /**
310+ * Returns the set of skill dirNames already installed for the given IDE target.
311+ * Errors reading individual paths are silently treated as "not installed".
312+ */
313+ async function readInstalledSkillDirNames (
314+ rootUri : vscode . Uri ,
315+ ideTargetLabel : string ,
316+ skills : SkillInfo [ ]
317+ ) : Promise < Set < string > > {
318+ const installed = new Set < string > ( ) ;
319+
320+ if ( ideTargetLabel === "VS Code (Copilot)" ) {
321+ try {
322+ const uri = vscode . Uri . joinPath ( rootUri , ".github/copilot-instructions.md" ) ;
323+ const bytes = await vscode . workspace . fs . readFile ( uri ) ;
324+ const content = Buffer . from ( bytes ) . toString ( "utf-8" ) ;
325+ for ( const skill of skills ) {
326+ if ( content . includes ( `## ${ skill . name } ` ) ) {
327+ installed . add ( skill . dirName ) ;
328+ }
329+ }
330+ } catch {
331+ // file not found — nothing installed
332+ }
333+ return installed ;
334+ }
335+
336+ await Promise . all (
337+ skills . map ( async ( skill ) => {
338+ try {
339+ const checkPath =
340+ ideTargetLabel === "Claude Code"
341+ ? `.claude/skills/${ skill . dirName } /SKILL.md`
342+ : `.cursor/rules/${ skill . dirName } .mdc` ;
343+ await vscode . workspace . fs . stat ( vscode . Uri . joinPath ( rootUri , checkPath ) ) ;
344+ installed . add ( skill . dirName ) ;
345+ } catch {
346+ // not installed
347+ }
348+ } )
349+ ) ;
350+ return installed ;
351+ }
352+
353+ /**
354+ * Returns the set of server keys already present in the MCP config file.
355+ * Returns an empty Set if the file doesn't exist or can't be parsed.
356+ */
357+ async function readConfiguredMcpServerKeys (
358+ rootUri : vscode . Uri ,
359+ mcpFilePath : string ,
360+ rootKey : string
361+ ) : Promise < Set < string > > {
362+ try {
363+ const uri = vscode . Uri . joinPath ( rootUri , mcpFilePath ) ;
364+ const bytes = await vscode . workspace . fs . readFile ( uri ) ;
365+ const config = JSON . parse ( Buffer . from ( bytes ) . toString ( "utf-8" ) ) ;
366+ const servers = config [ rootKey ] ;
367+ if ( servers && typeof servers === "object" ) {
368+ return new Set ( Object . keys ( servers ) ) ;
369+ }
370+ } catch {
371+ // file not found or invalid JSON
372+ }
373+ return new Set ( ) ;
374+ }
375+
307376// ── MCP Server definitions ────────────────────────────────────────────────────
308377
309378const MCP_SERVERS : McpServerDef [ ] = [
0 commit comments