@@ -36,6 +36,8 @@ import {
3636 checkSafeTarget ,
3737 executeFileOps ,
3838 executeUninstallOps ,
39+ listExtensionBundleManifests ,
40+ listJsonFiles ,
3941 readExistingFiles ,
4042} from "../util/install-fs.ts" ;
4143import { claudeDesktopConfigPath } from "../detect/claude-desktop.ts" ;
@@ -351,6 +353,11 @@ export async function runInstall(argv: string[] = []): Promise<void> {
351353 uninstallPaths . push ( resolve ( join ( dir , "settings.json" ) ) ) ;
352354 } else if ( id === "claude-desktop" ) {
353355 uninstallPaths . push ( resolve ( join ( dir , "claude_desktop_config.json" ) ) ) ;
356+ // Bundle manifests live one dir over and are the actual launch
357+ // source for Desktop Extensions — the daemon needs each to
358+ // unwind the wrap on uninstall.
359+ const bundlesDir = resolve ( join ( dir , "Claude Extensions" ) ) ;
360+ uninstallPaths . push ( ...( await listExtensionBundleManifests ( bundlesDir ) ) ) ;
354361 } else if ( id === "codex" || id === "cursor" ) {
355362 uninstallPaths . push ( resolve ( join ( dir , "hooks.json" ) ) ) ;
356363 } else if ( id === "gemini" ) {
@@ -411,13 +418,31 @@ export async function runInstall(argv: string[] = []): Promise<void> {
411418 const geminiSettings = resolve (
412419 join ( hostConfigDirs [ "gemini" ] , "settings.json" ) ,
413420 ) ;
421+ // Per-extension bundle manifests are THE launch source for Desktop
422+ // Extensions installed via Settings → Extensions UI — claudeDesktopPlan
423+ // wraps each one in place using the schema-blessed _meta.agentlock
424+ // slot (MCPB v0.3+). The Claude Extensions Settings sidecar JSONs
425+ // tell us which extensions are isEnabled so disabled ones get
426+ // unwound rather than re-wrapped.
427+ const claudeDesktopBundlesDir = resolve (
428+ join ( hostConfigDirs [ "claude-desktop" ] , "Claude Extensions" ) ,
429+ ) ;
430+ const claudeDesktopExtSettingsDir = resolve (
431+ join ( hostConfigDirs [ "claude-desktop" ] , "Claude Extensions Settings" ) ,
432+ ) ;
433+ const bundleManifests = await listExtensionBundleManifests (
434+ claudeDesktopBundlesDir ,
435+ ) ;
436+ const extSettingsFiles = await listJsonFiles ( claudeDesktopExtSettingsDir ) ;
414437 const existingFiles = await readExistingFiles ( [
415438 claudeSettings ,
416439 claudeDesktopConfig ,
417440 codexHooks ,
418441 codexConfig ,
419442 cursorHooks ,
420443 geminiSettings ,
444+ ...bundleManifests ,
445+ ...extSettingsFiles ,
421446 ] ) ;
422447
423448 // Write the status-line script alongside the binary wrapper. Daemon
0 commit comments