Skip to content

fix(extensions): reject quality and fmt on pulled extensions (swamp-club#239)#1328

Merged
stack72 merged 1 commit intomainfrom
worktree-239
May 6, 2026
Merged

fix(extensions): reject quality and fmt on pulled extensions (swamp-club#239)#1328
stack72 merged 1 commit intomainfrom
worktree-239

Conversation

@stack72
Copy link
Copy Markdown
Contributor

@stack72 stack72 commented May 6, 2026

Summary

  • extension quality and extension fmt fail on pulled extensions because the manifest's paths.base defaults to typedDir, resolving model files against extensions/models/ in the repo root instead of the pulled extension's directory
  • Added isPulledExtensionManifest() helper that detects manifests under .swamp/pulled-extensions/ and rejects both commands early with a clear error message
  • Pulled extensions are read-only registry copies — running fmt/quality on them is not useful

Test Plan

  • Unit tests for isPulledExtensionManifest (absolute/relative/local/non-.swamp paths)
  • Reproduced original bug in scratch repo: extension quality on pulled manifest → "Model file not found"
  • Verified fix: both commands now reject with clear error message
  • Verified local extensions still work normally
  • Full test suite passes (5570 tests, 0 failures)
  • deno check, deno lint, deno fmt all clean

Closes swamp-club#239

🤖 Generated with Claude Code

…lub#239)

Pulled extension manifests use paths.base: typedDir (the default), so
quality/fmt resolve model files against extensions/models/ in the repo
root instead of the pulled extension directory. Rather than fixing path
resolution for read-only copies, block both commands early with a clear
error when the manifest is under .swamp/pulled-extensions/.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

CLI UX Review

Blocking

None.

Suggestions

  1. Neither UserError throw includes a machine-readable code argument (second param to the constructor). Adding something like "pulled-extension" would let --json consumers detect this case without fragile message-string matching — e.g. swamp extension quality --json | jq '.code'. Not a blocker since there's no established per-error-code pattern in this area of the CLI.

Verdict

PASS — Early-rejection errors are clear, actionable, and symmetric between the two commands. "Cannot run fmt/quality on a pulled extension" tells users exactly what went wrong; the follow-up sentence points them to the correct path (extensions/). Log mode shows a clean one-liner (no stack), JSON mode emits { "error": "..." } via the standard renderError path. Consistent with UserError conventions throughout the codebase.

Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

Code Review

Clean, well-scoped fix. The early guard catches the invalid operation before any expensive repo/manifest resolution work, and the error messages are clear and actionable.

Blocking Issues

None.

Suggestions

  1. SEPARATOR instead of hardcoded separators (src/cli/resolve_extension_files.ts:110-111): The startsWith(pulledRoot + "/") || startsWith(pulledRoot + "\\") pattern works correctly, but since resolve() normalizes to the platform separator, a single startsWith(pulledRoot + SEPARATOR) (from @std/path) would be sufficient and more consistent with the CLAUDE.md guidance to use @std/path for path operations. The current approach is defensive and harmless, so not blocking.

  2. Test naming convention: The test names use a colon after the function name (e.g., "isPulledExtensionManifest: returns true for...") which matches the project convention in CLAUDE.md — good.

Overall: focused fix, good test coverage (5 tests covering absolute/relative paths, positive/negative cases, and the prefix-attack edge case), no import boundary violations, no security concerns. The + separator suffix correctly prevents prefix-matching attacks like .swamp/pulled-extensions-evil/.

@stack72 stack72 merged commit 5729ac5 into main May 6, 2026
11 checks passed
@stack72 stack72 deleted the worktree-239 branch May 6, 2026 23:36
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