Skip to content

fix(claude-mem-heal): create legacy marketplace junction/symlink (BUG-012)#70

Merged
mlorentedev merged 3 commits into
mainfrom
fix/BUG-012-claude-mem-marketplace-junction
May 21, 2026
Merged

fix(claude-mem-heal): create legacy marketplace junction/symlink (BUG-012)#70
mlorentedev merged 3 commits into
mainfrom
fix/BUG-012-claude-mem-marketplace-junction

Conversation

@mlorentedev
Copy link
Copy Markdown
Owner

@mlorentedev mlorentedev commented May 21, 2026

Summary

  • thedotmack/claude-mem plugin's bundled hooks.json hardcodes the fallback discovery path marketplaces/thedotmack/plugin/scripts/... (the marketplace's declared name), but Claude Code clones the marketplace under the GitHub repo name marketplaces/thedotmack-claude-mem/. When CLAUDE_PLUGIN_ROOT is unset/stale (typical Windows case — plugin cache stays unpopulated), plugin hooks hit the broken fallback, exit 1, and block UserPromptSubmit.
  • Same mismatch silently neutered scripts/claude-mem-heal.{sh,ps1} — both hardcoded marketplaces/thedotmack/plugin, no-op'd on dir-absent, never applied upstream .mcp.json / missing-zod patches to the actual install.
  • Fix: both heal scripts now create a junction (Windows) / symlink (Linux) from marketplaces/thedotmackmarketplaces/thedotmack-claude-mem when the source exists and target is absent. Heal walks extended to cover both legacy and current marketplace paths.

Why this bug only surfaced on Windows

On Linux, Claude Code typically injects CLAUDE_PLUGIN_ROOT correctly at hook invocation, so the broken fallback is never consulted. On Windows the plugin cache (cache/thedotmack/claude-mem/) stays empty, the env var stays unset or stale, and the fallback IS consulted — landing on the non-existent marketplaces/thedotmack/plugin/. The visible Windows symptom (printf: write error: Permission denied) is Git Bash + Claude Code's hook subprocess sandbox quirk; the underlying exit 1 is cross-OS. Fix applied to both heal scripts for parity.

Empirical validation (Windows)

BEFORE: thedotmack exists = False
[claude-mem-heal] created legacy marketplace junction:
  C:\Users\Manu\.claude\plugins\marketplaces\thedotmack -> thedotmack-claude-mem
AFTER: thedotmack exists = True
LinkType: Junction
Target: C:\Users\Manu\.claude\plugins\marketplaces\thedotmack-claude-mem

Second run is silent (exit 0, no output) — silent-on-healthy contract preserved.

Test plan

  • CI bats job green — 4 new asserts in tests/setup-linux.bats + 2 in tests/setup-windows.bats.
  • shellcheck --severity=error scripts/claude-mem-heal.sh clean.
  • pwsh -Command "Invoke-ScriptAnalyzer -Path scripts/claude-mem-heal.ps1 -Severity Error" clean (locally: clean).
  • bash -n scripts/claude-mem-heal.sh clean (locally: clean).
  • PowerShell AST parse of claude-mem-heal.ps1 (locally: clean).
  • Linux empirical: pending — no Linux test machine in this session; logic mirrors PowerShell with identical guards.

Discovered during

BUG-011 hook-failure diagnosis (PR #69). Sibling fix — same plugin, different layer.

Spec

specs/BUG-012-claude-mem-marketplace-junction/{proposal,tasks,verification}.md

mlorentedev and others added 3 commits May 20, 2026 19:41
…-012)

The thedotmack/claude-mem plugin's bundled hooks.json hardcodes the fallback
discovery path `marketplaces/thedotmack/plugin/scripts/...` (the marketplace's
declared `name`), but Claude Code clones the marketplace under the GitHub repo
name `marketplaces/thedotmack-claude-mem/`. When CLAUDE_PLUGIN_ROOT is unset or
stale (the typical Windows case where the plugin cache stays unpopulated),
plugin hooks fall through to that path and fail with `claude-mem: plugin
scripts not found` -> exit 1, blocking UserPromptSubmit. On Windows the
visible symptom is `printf: write error: Permission denied` (Git Bash + hook
subprocess sandbox quirk); on Linux it would fail more cleanly with the
not-found message.

Same root cause silently neuters scripts/claude-mem-heal.{sh,ps1}: both
hardcoded `marketplaces/thedotmack/plugin` -> dir absent -> heal no-ops.
Upstream .mcp.json / missing-zod patches never reach the actual install.

Fix (both heal scripts):
- New ensure_marketplace_compat_symlink() / Repair-MarketplaceCompatJunction
  function. Creates symlink (Linux) / Junction (Windows, no admin) from
  `marketplaces/thedotmack` -> `marketplaces/thedotmack-claude-mem` when the
  source exists and the target is absent. Idempotent: skip otherwise.
- Extend marketplace healing walks to cover both legacy and current path
  variants (path-aware backstop in case junction creation fails).
- Bats parity assertions in tests/setup-{linux,windows}.bats lock the
  junction-creation block in both heal scripts.

Empirically validated on Windows: junction created on first run (LinkType
= Junction, Target = thedotmack-claude-mem), silent on second run (exit 0,
no output) -- contract preserved. Linux side: bash -n + manual review only;
no Linux test machine available this session.

Specs: specs/BUG-012-claude-mem-marketplace-junction/{proposal,tasks,verification}.md

Discovered during BUG-011 hook-failure diagnosis. Sibling of PR #69.

Co-Authored-By: Claude Opus 4.7 <[email protected]>
Two failures in CI test job for PR #70:

1. `grep -qF '-ItemType Junction'` -> GNU grep parses `-ItemType` as flag set
   before checking the pattern. Fix: add `--` separator before the pattern.
   Same convention used by the existing `--ignore-scripts` assert above.
2. `grep -B2 -A6 'ln -s.*thedotmack-claude-mem'` -> the literal `ln -s` line
   in claude-mem-heal.sh is `ln -s "$actual" "$legacy"` (no marketplace name
   on that line; the name is in the earlier variable assignment). The
   regex never matched, so `-B2 -A6` returned empty and the piped grep
   failed. Rewrite to grep the actual guard expressions:
   `[ ! -d "$actual" ]` (source-exists check) and
   `[ -e "$legacy" ]` (target-absent check) -- both required for the
   idempotence contract.

All four patterns verified locally against the heal scripts.

Co-Authored-By: Claude Opus 4.7 <[email protected]>
@mlorentedev mlorentedev merged commit 3009b21 into main May 21, 2026
6 checks passed
@mlorentedev mlorentedev deleted the fix/BUG-012-claude-mem-marketplace-junction branch May 21, 2026 01:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant