openclaw - ✅(Solved) Fix [Bug]: plugins uninstall does not remove extension files for --link or manually installed plugins [3 pull requests, 1 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#66668Fetched 2026-04-15 06:25:06
View on GitHub
Comments
1
Participants
2
Timeline
8
Reactions
0
Timeline (top)
cross-referenced ×3referenced ×2commented ×1mentioned ×1

openclaw plugins uninstall <id> does not remove the extension directory files when the plugin was installed via --link or manually copied to the extensions folder.

Root Cause

The uninstall command only removes files for plugins tracked in plugins.installs (npm-installed plugins). For --link installs or manual copies, the plugin is not in plugins.installs, so the file removal step is skipped.

Fix Action

Workaround

Manual delete required:

rm -rf ~/.openclaw/extensions/<id>/

PR fix notes

PR #66704: fix(plugins): delete files for path-based installs where installPath != sourcePath

Description (problem / solution / changelog)

Summary

plugins uninstall was not deleting files for path-based installs because it treated ALL source === 'path' installs as linked installs (where no files were copied).

Root Cause

The uninstall logic had two places that incorrectly skipped file deletion for ALL path-based installs:

  1. resolveUninstallDirectoryTarget() returned null for source === 'path' unconditionally
  2. uninstallPlugin() set isLinked = true for source === 'path' unconditionally

However, there's a distinction between:

  • Linked installs: source === 'path' AND installPath === sourcePath — no files were copied to extensions, so nothing to delete
  • Normal path installs: source === 'path' AND installPath !== sourcePath — files WERE copied to extensions, so they should be deleted

Fix

  1. In resolveUninstallDirectoryTarget(): Only return null for path-based installs when installPath === sourcePath (linked install)
  2. In uninstallPlugin(): Only set isLinked = true when installPath === sourcePath

Test Plan

  • All 36 tests pass in src/plugins/uninstall.test.ts
  • Added new test case: does NOT return null for path-based installs where installPath !== sourcePath (files were copied)

Fixes #66668

Changed files

  • extensions/feishu/src/monitor.account.ts (modified, +1/-1)
  • extensions/feishu/src/sequential-key.test.ts (modified, +20/-0)
  • extensions/feishu/src/sequential-key.ts (modified, +1/-1)
  • extensions/qqbot/src/gateway.ts (modified, +1/-1)
  • extensions/qqbot/src/utils/text-parsing.test.ts (modified, +4/-0)
  • extensions/qqbot/src/utils/text-parsing.ts (modified, +2/-2)
  • package.json (modified, +2/-7)
  • scripts/openclaw-npm-release-check.ts (modified, +4/-6)
  • src/config/redact-snapshot.test.ts (modified, +9/-4)
  • src/config/redact-snapshot.ts (modified, +4/-4)
  • src/memory-host-sdk/host/embeddings.ts (modified, +1/-1)
  • src/plugins/uninstall.test.ts (modified, +19/-1)
  • src/plugins/uninstall.ts (modified, +13/-2)

PR #9: fix(plugins): delete files for path-based installs where installPath != sourcePath

Description (problem / solution / changelog)

Summary

plugins uninstall was not deleting files for path-based (non-npm) installs because it treated ALL source === 'path' installs as linked installs.

Root Cause

The uninstall logic had two places that incorrectly skipped file deletion for ALL path-based installs:

  1. resolveUninstallDirectoryTarget() returned null for source === 'path' unconditionally
  2. uninstallPlugin() set isLinked = true for source === 'path' unconditionally

However, there's a distinction between:

  • Linked installs: source === 'path' AND installPath === sourcePath — no files were copied, so nothing to delete
  • Normal path installs: source === 'path' AND installPath !== sourcePath — files WERE copied to extensions, so they should be deleted

Fix

  1. In resolveUninstallDirectoryTarget(): Only return null for path-based installs when installPath === sourcePath (linked install)
  2. In uninstallPlugin(): Only set isLinked = true when installPath === sourcePath

Test Plan

  • All 36 tests pass in src/plugins/uninstall.test.ts
  • Added new test case: does NOT return null for path-based installs where installPath !== sourcePath (files were copied)

Fixes #66668

Changed files

  • .agent/workflows/update_clawdbot.md (removed, +0/-380)
  • .agents/skills/openclaw-parallels-smoke/SKILL.md (modified, +50/-6)
  • .agents/skills/openclaw-qa-testing/SKILL.md (added, +148/-0)
  • .agents/skills/openclaw-qa-testing/agents/openai.yaml (added, +4/-0)
  • .agents/skills/openclaw-release-maintainer/SKILL.md (modified, +79/-23)
  • .agents/skills/openclaw-secret-scanning-maintainer/SKILL.md (added, +201/-0)
  • .agents/skills/openclaw-secret-scanning-maintainer/scripts/secret-scanning.mjs (added, +538/-0)
  • .agents/skills/openclaw-test-heap-leaks/SKILL.md (modified, +16/-12)
  • .agents/skills/openclaw-test-heap-leaks/scripts/heapsnapshot-delta.mjs (modified, +308/-20)
  • .agents/skills/security-triage/SKILL.md (modified, +3/-0)
  • .codex (renamed, +0/-0)
  • .dockerignore (modified, +2/-0)
  • .env.example (modified, +7/-4)
  • .github/actionlint.yaml (modified, +1/-0)
  • .github/actions/setup-node-env/action.yml (modified, +1/-1)
  • .github/actions/setup-pnpm-store-cache/action.yml (modified, +1/-1)
  • .github/labeler.yml (modified, +40/-0)
  • .github/pr-assets/compaction-checkpoints/sessions-checkpoints-inline.png (added, +0/-0)
  • .github/pr-assets/compaction-checkpoints/sessions-overview-inline.png (added, +0/-0)
  • .github/pull_request_template.md (modified, +3/-5)
  • .github/workflows/auto-response.yml (modified, +6/-2)
  • .github/workflows/ci-bun.yml (removed, +0/-110)
  • .github/workflows/ci.yml (modified, +389/-48)
  • .github/workflows/control-ui-locale-refresh.yml (added, +172/-0)
  • .github/workflows/docs-sync-publish.yml (added, +70/-0)
  • .github/workflows/docs-translate-trigger-release.yml (added, +42/-0)
  • .github/workflows/install-smoke.yml (modified, +18/-9)
  • .github/workflows/macos-release.yml (modified, +6/-5)
  • .github/workflows/openclaw-npm-release.yml (modified, +248/-22)
  • .github/workflows/openclaw-release-checks.yml (added, +120/-0)
  • .github/workflows/parity-gate.yml (added, +93/-0)
  • .github/workflows/plugin-clawhub-release.yml (added, +276/-0)
  • .github/workflows/plugin-npm-release.yml (modified, +4/-1)
  • .gitignore (modified, +11/-1)
  • .markdownlint-cli2.jsonc (modified, +3/-0)
  • .npmignore (modified, +1/-0)
  • .oxfmtrc.jsonc (modified, +3/-2)
  • .oxlintrc.json (modified, +36/-8)
  • .vscode/settings.json (modified, +1/-2)
  • AGENTS.md (modified, +75/-30)
  • CHANGELOG.md (modified, +1516/-380)
  • CONTRIBUTING.md (modified, +19/-1)
  • Dockerfile (modified, +18/-5)
  • INCIDENT_RESPONSE.md (added, +52/-0)
  • Makefile (added, +4/-0)
  • README.md (modified, +55/-5)
  • SECURITY.md (modified, +33/-2)
  • appcast.xml (modified, +240/-201)
  • apps/android/app/build.gradle.kts (modified, +41/-33)
  • apps/android/app/src/main/AndroidManifest.xml (modified, +14/-0)
  • apps/android/app/src/main/java/ai/openclaw/app/AssistantLaunch.kt (added, +43/-0)
  • apps/android/app/src/main/java/ai/openclaw/app/MainActivity.kt (modified, +12/-0)
  • apps/android/app/src/main/java/ai/openclaw/app/MainViewModel.kt (modified, +106/-0)
  • apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt (modified, +256/-54)
  • apps/android/app/src/main/java/ai/openclaw/app/NotificationForwardingPolicy.kt (added, +102/-0)
  • apps/android/app/src/main/java/ai/openclaw/app/PermissionRequester.kt (modified, +10/-1)
  • apps/android/app/src/main/java/ai/openclaw/app/SecurePrefs.kt (modified, +202/-0)
  • apps/android/app/src/main/java/ai/openclaw/app/chat/ChatController.kt (modified, +51/-37)
  • apps/android/app/src/main/java/ai/openclaw/app/gateway/DeviceAuthStore.kt (modified, +67/-7)
  • apps/android/app/src/main/java/ai/openclaw/app/gateway/GatewayHostSecurity.kt (added, +124/-0)
  • apps/android/app/src/main/java/ai/openclaw/app/gateway/GatewaySession.kt (modified, +108/-34)
  • apps/android/app/src/main/java/ai/openclaw/app/gateway/GatewayTls.kt (modified, +33/-7)
  • apps/android/app/src/main/java/ai/openclaw/app/node/CanvasActionTrust.kt (modified, +17/-16)
  • apps/android/app/src/main/java/ai/openclaw/app/node/ConnectionManager.kt (modified, +14/-1)
  • apps/android/app/src/main/java/ai/openclaw/app/node/DeviceHandler.kt (modified, +51/-5)
  • apps/android/app/src/main/java/ai/openclaw/app/node/DeviceNotificationListenerService.kt (modified, +120/-24)
  • apps/android/app/src/main/java/ai/openclaw/app/node/InvokeCommandRegistry.kt (modified, +4/-1)
  • apps/android/app/src/main/java/ai/openclaw/app/node/InvokeDispatcher.kt (modified, +47/-9)
  • apps/android/app/src/main/java/ai/openclaw/app/node/SmsHandler.kt (modified, +15/-10)
  • apps/android/app/src/main/java/ai/openclaw/app/node/SmsManager.kt (modified, +649/-135)
  • apps/android/app/src/main/java/ai/openclaw/app/ui/CanvasScreen.kt (modified, +1/-1)
  • apps/android/app/src/main/java/ai/openclaw/app/ui/ConnectTabScreen.kt (modified, +66/-10)
  • apps/android/app/src/main/java/ai/openclaw/app/ui/GatewayConfigResolver.kt (modified, +112/-18)
  • apps/android/app/src/main/java/ai/openclaw/app/ui/GatewayDiagnostics.kt (modified, +1/-0)
  • apps/android/app/src/main/java/ai/openclaw/app/ui/GatewayPairingRetry.kt (added, +45/-0)
  • apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt (modified, +99/-41)
  • apps/android/app/src/main/java/ai/openclaw/app/ui/PostOnboardingTabs.kt (modified, +15/-0)
  • apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsSheet.kt (modified, +517/-12)
  • apps/android/app/src/main/java/ai/openclaw/app/ui/chat/ChatComposer.kt (modified, +44/-0)
  • apps/android/app/src/main/java/ai/openclaw/app/ui/chat/ChatSheetContent.kt (modified, +46/-0)
  • apps/android/app/src/main/java/ai/openclaw/app/voice/MicCaptureManager.kt (modified, +116/-10)
  • apps/android/app/src/main/java/ai/openclaw/app/voice/TalkAudioPlayer.kt (added, +242/-0)
  • apps/android/app/src/main/java/ai/openclaw/app/voice/TalkModeManager.kt (modified, +97/-22)
  • apps/android/app/src/main/java/ai/openclaw/app/voice/TalkSpeakClient.kt (added, +143/-0)
  • apps/android/app/src/main/res/values/assistant.xml (added, +7/-0)
  • apps/android/app/src/main/res/xml/shortcuts.xml (added, +17/-0)
  • apps/android/app/src/test/java/ai/openclaw/app/AssistantLaunchTest.kt (added, +43/-0)
  • apps/android/app/src/test/java/ai/openclaw/app/GatewayBootstrapAuthTest.kt (added, +263/-0)
  • apps/android/app/src/test/java/ai/openclaw/app/NotificationForwardingPolicyTest.kt (added, +189/-0)
  • apps/android/app/src/test/java/ai/openclaw/app/SecurePrefsNotificationForwardingTest.kt (added, +133/-0)
  • apps/android/app/src/test/java/ai/openclaw/app/SecurePrefsTest.kt (modified, +21/-0)
  • apps/android/app/src/test/java/ai/openclaw/app/gateway/DeviceAuthStoreTest.kt (added, +63/-0)
  • apps/android/app/src/test/java/ai/openclaw/app/gateway/GatewaySessionInvokeTest.kt (modified, +155/-6)
  • apps/android/app/src/test/java/ai/openclaw/app/gateway/GatewaySessionInvokeTimeoutTest.kt (modified, +17/-0)
  • apps/android/app/src/test/java/ai/openclaw/app/node/CallLogHandlerTest.kt (modified, +35/-0)
  • apps/android/app/src/test/java/ai/openclaw/app/node/CanvasActionTrustTest.kt (modified, +30/-0)
  • apps/android/app/src/test/java/ai/openclaw/app/node/ConnectionManagerTest.kt (modified, +459/-1)
  • apps/android/app/src/test/java/ai/openclaw/app/node/DeviceHandlerTest.kt (modified, +122/-0)
  • apps/android/app/src/test/java/ai/openclaw/app/node/DeviceNotificationListenerServiceTest.kt (added, +119/-0)
  • apps/android/app/src/test/java/ai/openclaw/app/node/InvokeCommandRegistryTest.kt (modified, +44/-1)

PR #66737: fix(plugins): delete files for path-based installs where installPath != sourcePath

Description (problem / solution / changelog)

Summary

plugins uninstall was not deleting files for path-based (non-npm) installs because it treated ALL source === 'path' installs as linked installs.

Root Cause

The uninstall logic had two places that incorrectly skipped file deletion for ALL path-based installs:

  1. resolveUninstallDirectoryTarget() returned null for source === 'path' unconditionally
  2. uninstallPlugin() set isLinked = true for source === 'path' unconditionally

However, there's a distinction between:

  • Linked installs: source === 'path' AND installPath === sourcePath — no files were copied, so nothing to delete
  • Normal path installs: source === 'path' AND installPath !== sourcePath — files WERE copied to extensions, so they should be deleted

Fix

  1. In resolveUninstallDirectoryTarget(): Only return null for path-based installs when installPath === sourcePath (linked install)
  2. In uninstallPlugin(): Only set isLinked = true when installPath === sourcePath

Test Plan

  • All 36 tests pass in src/plugins/uninstall.test.ts
  • Added new test case: does NOT return null for path-based installs where installPath !== sourcePath (files were copied)

Fixes #66668 Closes #66704 (re-created after automatic closure)

Changed files

  • extensions/qqbot/src/utils/text-parsing.test.ts (modified, +4/-0)
  • extensions/qqbot/src/utils/text-parsing.ts (modified, +2/-2)
  • src/config/redact-snapshot.test.ts (modified, +4/-4)
  • src/config/redact-snapshot.ts (modified, +4/-4)
  • src/plugins/uninstall.test.ts (modified, +19/-0)
  • src/plugins/uninstall.ts (modified, +11/-3)

Code Example

openclaw plugins install /path/to/plugin --link
   # OR manually copy
   cp -r plugin ~/.openclaw/extensions/

---

openclaw plugins uninstall <id> --force

---

ls ~/.openclaw/extensions/<id>/

---

rm -rf ~/.openclaw/extensions/<id>/
RAW_BUFFERClick to expand / collapse

Summary

openclaw plugins uninstall <id> does not remove the extension directory files when the plugin was installed via --link or manually copied to the extensions folder.

Steps to reproduce

  1. Install a plugin using --link or manually copy to ~/.openclaw/extensions/<id>:
    openclaw plugins install /path/to/plugin --link
    # OR manually copy
    cp -r plugin ~/.openclaw/extensions/
  2. Run uninstall:
    openclaw plugins uninstall <id> --force
  3. Check if extension files are removed:
    ls ~/.openclaw/extensions/<id>/

Expected behavior

Per docs: "By default, uninstall also removes the plugin install directory under the active state-dir plugin root."

The files should be deleted.

Actual behavior

The extension directory remains intact with all files (index.ts, node_modules, etc.).

Root cause

The uninstall command only removes files for plugins tracked in plugins.installs (npm-installed plugins). For --link installs or manual copies, the plugin is not in plugins.installs, so the file removal step is skipped.

Environment

  • OpenClaw: 2026.4.10
  • OS: Linux

Workaround

Manual delete required:

rm -rf ~/.openclaw/extensions/<id>/

Suggested fix

Either:

  1. Update uninstall to check plugins.load.paths for linked plugins and also remove those directories
  2. Or document that --keep-files is default behavior for linked installs and require explicit --no-keep-files (which doesn't exist currently)

extent analysis

TL;DR

The openclaw plugins uninstall command does not remove extension directory files for plugins installed via --link or manual copy, requiring a manual delete as a workaround.

Guidance

  • The root cause is that the uninstall command only removes files for plugins tracked in plugins.installs, which does not include --link installs or manual copies.
  • To verify the issue, check if the extension directory remains after running openclaw plugins uninstall <id> --force.
  • A temporary workaround is to manually delete the extension directory using rm -rf ~/.openclaw/extensions/<id>/.
  • To mitigate this issue, consider updating the uninstall command to check plugins.load.paths for linked plugins and remove those directories.

Example

No code snippet is provided as the issue is more related to the behavior of the openclaw command rather than a specific code implementation.

Notes

The suggested fix involves either updating the uninstall command or documenting the current behavior and introducing a new flag to control file removal. However, without further information on the openclaw command's implementation, it's difficult to provide a more detailed solution.

Recommendation

Apply workaround: Manual deletion of the extension directory is currently the safest approach until a fix is implemented, as it allows for control over which files are removed.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

Expected behavior

Per docs: "By default, uninstall also removes the plugin install directory under the active state-dir plugin root."

The files should be deleted.

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - ✅(Solved) Fix [Bug]: plugins uninstall does not remove extension files for --link or manually installed plugins [3 pull requests, 1 comments, 2 participants]