Skip to content

feat(extensions): add extension info command for registry metadata (#428)#1445

Merged
stack72 merged 1 commit into
mainfrom
worktree-428
May 25, 2026
Merged

feat(extensions): add extension info command for registry metadata (#428)#1445
stack72 merged 1 commit into
mainfrom
worktree-428

Conversation

@stack72
Copy link
Copy Markdown
Contributor

@stack72 stack72 commented May 25, 2026

Summary

  • Add swamp extension info <name> command to fetch and display full registry metadata for a specific extension
  • Widen ExtensionInfo interface to capture all fields the server returns (author, namespace, platforms, labels, content types, quality score, pull count, repository verification, yank state)
  • Add optional authentication (via AuthRepository) to both extension info and extension search for higher rate limits
  • Not-found responses show a helpful suggestion: Try: swamp extension search <basename>

Closes swamp-club#428

Test Plan

  • 4 unit tests for the libswamp info operation (full metadata, nullable fields, not found, API error)
  • Existing search and version tests pass (no regressions from wider ExtensionInfo)
  • Full test suite passes (6195 tests)
  • deno check, deno lint, deno fmt all clean

🤖 Generated with Claude Code

)

Add `swamp extension info <name>` to fetch and display full registry
metadata for a specific extension. Widens ExtensionInfo to capture all
fields the server returns (author, platforms, labels, content types,
quality score, pull count, repository verification, yank state). Adds
optional authentication to both info and search commands for higher
rate limits.

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.

Code Review

No blocking issues found. This is a clean, well-structured addition that follows existing patterns in the codebase.

What looks good

  • Import boundary: CLI command (extension_info.ts) and renderer (extension_info.ts) both import from ../../libswamp/mod.ts — correct.
  • libswamp-internal imports: info.ts inside src/libswamp/extensions/ imports from ../../infrastructure/ which is allowed for libswamp-internal code per CLAUDE.md.
  • DDD alignment: The generator function (extensionInfo) is a proper Application Service — it orchestrates deps, yields progress events, and decouples the domain data shape (ExtensionInfoData) from the infrastructure type (ExtensionInfo). Dependency injection via ExtensionInfoDeps enables clean testing.
  • Test coverage: 4 unit tests covering happy path, nullable fields, not-found, and API error — all using injected deps with no network calls.
  • Dual output modes: Both "log" and "json" renderers are implemented as required by CLAUDE.md.
  • License headers: Present on all new files.
  • any type pattern: The deno-lint-ignore no-explicit-any for Cliffy options matches every other extension command in the codebase.
  • Security: getExtension uses encodeURIComponent(name) for the path parameter, preventing path traversal. The shared fetch() wrapper provides a 15s AbortSignal.timeout, satisfying the no-fire-and-forget-promises rule.

Suggestions

  1. ExtensionInfoData duplicates ExtensionInfo: The libswamp type is field-for-field identical to the infrastructure type, and the mapping in the generator copies every property individually. This is defensible as a decoupling boundary, but if ExtensionInfo gains fields later, both must be updated in lockstep. Consider whether a mapped type or spread would reduce maintenance — though the current explicit approach is also fine for discoverability.

  2. resolveServerUrl imported from pull.ts: The info.ts module imports resolveServerUrl from ./pull.ts. This works, but pull.ts is a large module (~1100 lines) with its own generator, deps, and types — the coupling is purely for one utility function. If more commands need it, extracting to a shared server.ts would be cleaner. Not urgent since both live in the same bounded context.

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. extension info placement in subcommand list (src/cli/commands/extension.ts): The info command lands between push and fmt, which are operational commands. It would be more discoverable adjacent to search or list (the other browse/inspect commands). Not blocking — just makes --help output easier to scan.

  2. Raw ISO timestamps in log mode (src/presentation/renderers/extension_info.ts, Created: / Updated: / Yanked: lines): Users see 2026-01-15T10:30:00.000Z verbatim. A locale-formatted string (e.g., Jan 15 2026) would be more readable. Other renderers don't format dates either, so this is a consistency-neutral suggestion rather than a regression.

  3. No progress feedback during network call: The resolving handler is a no-op, so there's a silent pause while the API is contacted. extension pull shows progress via its resolving events. A brief logger.info\Fetching ${input.extensionName}...`would match the pull pattern. Consistent withextension version` (which is also silent), so not a regression.

  4. not_found search suggestion in JSON mode (JsonExtensionInfoRenderer): Log mode includes Try: swamp extension search <basename> in the error message; JSON mode omits it. Scripts consuming JSON output won't see the hint. Consider including the suggestion in the JSON error message too (it's still human-readable there and costs nothing).

Verdict

PASS — both output modes are implemented correctly, error messages are clear and actionable, the not_found suggestion (Try: swamp extension search <basename>) is a nice touch, and the field layout in log mode is readable and logically grouped. No issues block merge.

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.

Adversarial Review

Reviewed all 8 files: the new extension info command, widened ExtensionInfo interface, auth plumbing for search, libswamp generator, renderer, tests, and barrel exports.

Critical / High

None.

Medium

  1. src/serve/open/http.ts:1063-1068 — stale comment and unnecessary cast after ExtensionInfo widening. The existing code comments that ExtensionInfo "only declares the minimum fields" and casts to Record<string, unknown> to forward the server's richer payload. After this PR widens ExtensionInfo to include all those fields, the comment is misleading and the cast is no longer necessary. Not a bug — the existing behavior is correct either way — but worth a follow-up cleanup so the next reader doesn't wonder why the cast exists.

Low

  1. src/libswamp/extensions/info.ts:115-119 — error event drops cause. The catch block constructs a SwampError with code and message but omits the optional cause field, losing the original exception for stack-trace debugging. This matches the pattern in version.ts so it's consistent, but the SwampError type exists to carry cause and it would be useful here. Purely a diagnostic quality issue, not a correctness bug.

  2. src/libswamp/extensions/info.ts:40-56ExtensionInfoData is a field-for-field duplicate of ExtensionInfo. The domain type and the infrastructure type have identical shapes. A type ExtensionInfoData = ExtensionInfo alias would eliminate the duplication risk if fields are added to one but not the other. That said, keeping them separate is a defensible domain-boundary choice.

Verdict

PASS. The code is solid. All event kinds are exhaustively handled (enforced by EventHandlers<E>). The ExtensionInfo widening is backward-compatible — existing callers only read a subset and the new fields are either nullable or already present in server responses. Auth plumbing correctly threads the optional apiKey through closures without changing the ExtensionSearchDeps contract. Network timeouts are covered by the client's default 15-second AbortSignal. encodeURIComponent is correctly applied to path segments. Tests cover success, nullable fields, not-found, and API failure paths.

@stack72 stack72 merged commit 329cc39 into main May 25, 2026
11 checks passed
@stack72 stack72 deleted the worktree-428 branch May 25, 2026 18:03
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