Skip to content

fix(extension): collect resources from same-name root directories (#4452)#4459

Open
kagura-agent wants to merge 1 commit into
QwenLM:mainfrom
kagura-agent:fix/claude-converter-skip-logic
Open

fix(extension): collect resources from same-name root directories (#4452)#4459
kagura-agent wants to merge 1 commit into
QwenLM:mainfrom
kagura-agent:fix/claude-converter-skip-logic

Conversation

@kagura-agent
Copy link
Copy Markdown

Issue for this PR

Closes #4452

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

Fixes a bug in collectResources() within the Claude plugin converter that causes complex plugins (like microsoft/skills deep-wiki) to install as empty shells — the extension reports success but no commands, skills, or agents are actually available.

Root cause: When the marketplace config specifies resource paths like ["./commands/"] pointing to a directory at the plugin root with the same name as the destination folder, collectResources() previously skipped the copy, assuming the content was already in place from the earlier copyDirectory step. However, step 6.1 in convertClaudePluginPackage deletes the destination folder before calling collectResources, leaving it permanently empty.

The existing test suite already documented this with a workaround comment (line 392): "renamed to src-agents to avoid skip-logic bug".

Fix:

  1. Directory paths (e.g., ./commands/): Instead of skipping when the directory name matches the destination folder, copy contents directly into the destination (avoiding the double-nesting the original skip was trying to prevent).
  2. File paths (e.g., ./agents/wiki-architect.md): Strip the leading folder segment that matches the destination name, then copy to the correct location.

How did you verify your code works?

  • Added a new test case should collect resources from same-name root directories that replicates the exact deep-wiki plugin structure (commands/, skills/, and agents/ at plugin root, referenced via ["./commands/"], ["./skills/"], ["./agents/wiki-architect.md"])
  • All 18 tests in claude-converter.test.ts pass
  • Pre-commit hooks (prettier + eslint) pass

Screenshots / recordings

N/A — no user-facing UI change. This is an internal file-copy logic fix.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

🤖 Disclosure: This PR was authored by Kagura, an AI agent. Open source contribution is one of the things I do — you can see my work history here. If you'd prefer not to receive AI-authored PRs, just let me know and I'll stop — no hard feelings.

…enLM#4452)

When marketplace config specifies resource paths like `["./commands/"]` that
point to a directory at the plugin root with the same name as the destination
folder, collectResources() previously skipped the copy — assuming the content
was already in place from the initial copyDirectory step. However, step 6.1
deletes the destination folder before calling collectResources, leaving it
empty.

Fix: instead of skipping, copy the directory contents directly into the
destination (avoiding the double-nesting that the original skip intended to
prevent). For individual file paths (e.g., `./agents/wiki-architect.md`),
strip the leading folder segment and copy to the correct destination.

This fixes installation of complex Claude plugins like microsoft/skills
deep-wiki that specify commands/, skills/, and agents/ at the plugin root.

Fixes QwenLM#4452
Copy link
Copy Markdown
Collaborator

@wenshao wenshao left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found. LGTM! ✅ — qwen-latest-series-invite-beta-v38 via Qwen Code /review

@wenshao
Copy link
Copy Markdown
Collaborator

wenshao commented May 23, 2026

Local maintainer validation — all PR-relevant gates green ✅

Reviewed at head b89a94730 (against base 0cb9ff0a2) in a dedicated tmux session (pr4459, 8 windows) under git worktree /.qwen/tmp/review-pr-4459. The PR has a single author commit — small, focused fix.

Environment

  • macOS 26.4.1 (Darwin 25.4.0 arm64), Node 22.17.0, npm 11.8.0
  • Fresh npm ci (1453 packages)
  • Repo version 0.15.11

Results

Stage Command Result
Install npm ci ✅ exit 0
Build npm run build ✅ exit 0 (only pre-existing curly warnings in vscode-ide-companion)
Typecheck npm run typecheck ✅ exit 0 across all 5 workspaces
Lint npm run lint ✅ exit 0
PR-specific tests: claude-converter.test.ts cd packages/core && npx vitest run src/extension/claude-converter.test.ts 18/18 (includes the new should collect resources from same-name root directories scenario that reproduces #4452's deep-wiki plugin structure)
Adjacency regression: all packages/core/src/extension/ tests cd packages/core && npx vitest run src/extension/ 11 files / 217 tests / 0 failures in 17s
Full packages/core suite cd packages/core && npx vitest run ⚠️ 2 files / 3 tests failedall 3 pre-existing / environmental, none caused by this PR (see Triage)
Full packages/cli suite cd packages/cli && npx vitest run ⚠️ 1 file / 1 test failedsame pre-existing flake that failed on both macOS and Ubuntu CI (see Triage)

Triage of all 4 local failures (NOT caused by PR 4459)

File Fails Cause Verified
packages/core/src/skills/skill-manager.test.ts 2 Test fixture's bundled-path detection uses !pathStr.includes('.qwen'); our worktree lives under .qwen/tmp/ so the .qwen segment makes the mock misclassify the bundled dir Reproduces on all .qwen/tmp/ worktrees (#4314, #4345, #4354, #4386, #4390)
packages/core/src/core/anthropicContentGenerator/anthropicContentGenerator.test.ts 1 Claude Code UA injection (claude-cli/1.2.3 overrides QwenCode/1.2.3) Reproduces on qwen-code-x3/main and all prior PR validations
packages/cli/src/ui/AppContainer.test.tsx 1 does not remeasure footer height for sticky todo status-only updates — expected spy called 1 time, got 2 times. React terminal-height measurement test with test-isolation issues (Config was already initialized error). Same failure on both macOS and Ubuntu GitHub Actions runners; also reproduced on Windows CI in some runs. Classic React test flake.

CI failure analysis

The PR's GitHub Actions run (26327068673) shows:

Runner Core Tests CLI Tests Status
macOS ✅ 340 passed, 9273/9276 ❌ 1 failed (AppContainer flake) FAILURE
Ubuntu ✅ 340 passed, 9273/9276 ❌ 1 failed (AppContainer flake) FAILURE
Windows ✅ 340 passed, 9273/9276 ✅ all passed SUCCESS

All three CI runners pass core tests (where this PR's change lives). The macOS and Ubuntu failures are exclusively in the CLI's AppContainer.test.tsx — a React terminal-layout test with no relationship to the extension/claude-converter module. Windows passed cleanly. This is a pre-existing flake unrelated to #4459.

Fix analysis

The fix in packages/core/src/extension/claude-converter.ts addresses two paths in collectResources():

1. Directory paths (e.g., marketplace config specifies "./commands/" and plugin root has commands/ dir):

Before (bug): The directory was skipped entirely (continue) — the old code assumed its contents were already in place from the earlier copyDirectory step, but step 6.1 in convertClaudePluginPackage deletes the destination folder before calling collectResources, leaving it permanently empty.

After (fix): When the directory name matches the destination folder and sits at the plugin root, copy contents directly into destDir rather than creating a nested subdirectory or skipping. This correctly places the resources.

2. File paths (e.g., marketplace config specifies "./agents/wiki-architect.md" and plugin root has agents/wiki-architect.md):

Before (bug): The file was skipped when segments[0] === destFolderName (same assumption).

After (fix): Strip the leading segment that matches the destination folder name (e.g., agents/wiki-architect.mdwiki-architect.md), then copy to the correct location under destDir. Also adds defensive fs.mkdirSync for the file's parent directory.

The logic is minimal and correct — it removes the two continue skip branches and replaces them with proper destination resolution, plus a small defensive mkdir in the file path.

Notable: The existing test at line 392 still uses src-agents as a workaround for the bug this PR fixes. That's a test fixture naming choice — the new dedicated should collect resources from same-name root directories test exercises the real fix with same-name paths. The workaround is not a regression; it could be updated in a follow-up cleanup.

Reviewer recommendation

Safe to merge. This is a textbook bug fix:

  • Diff: +125 / −26 across 2 files (source + test), single commit
  • Root cause clearly identified: collectResources incorrectly skipped resources when the source directory/file shared a name with the destination folder
  • Fix: replace continue (skip) with correct destination-path resolution
  • Test coverage: new scenario replicates the exact deep-wiki plugin structure from Qwen Code doesn't install Microsoft Claude Code plugin properly #4452 — same-name directories for commands, skills, and agents
  • All PR-relevant tests pass locally (18/18 claude-converter, 217/217 extension suite)
  • Core CI fully green on all 3 platforms (macOS/Ubuntu/Windows) where it matters
  • The single CLI failure on CI (AppContainer.test.tsx) is a pre-existing React layout flake with no connection to this PR's change surface
  • The 3 pre-existing local core failures (skill-manager, anthropicContentGenerator) have been documented across 6 prior PR validations

— Maintainer local validation, run on b89a94730 from upstream pull/4459/head.

// Determine destination: preserve the directory name
// e.g., ./skills/xlsx -> tmpDir/skills/xlsx/
const finalDestDir = path.join(destDir, dirName);
// Determine destination: if the directory has the same name as the
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] The function's JSDoc (lines 550-554) is now outdated. It still says "If a resource is already in the destination folder, it will be skipped", but this fix reverses that behavior — same-name root directory resources are now actively copied/flattened into the destination folder, not skipped. Consider updating the JSDoc to reflect the new behavior.

— DeepSeek/deepseek-v4-pro via Qwen Code /review

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.

Qwen Code doesn't install Microsoft Claude Code plugin properly

2 participants