Skip to content

feat: remote source support for floop packs#179

Open
nvandessel wants to merge 2 commits intomainfrom
feature/floop-packs
Open

feat: remote source support for floop packs#179
nvandessel wants to merge 2 commits intomainfrom
feature/floop-packs

Conversation

@nvandessel
Copy link
Owner

Summary

  • Remote pack installation: floop pack install now accepts HTTP URLs (https://...) and GitHub shorthand (gh:owner/repo[@version]) in addition to local file paths
  • Smart update checking: floop pack update <pack-id> looks up the recorded source, checks the remote version against installed version, and skips download if already up-to-date
  • Batch updates: floop pack update --all updates all installed packs that have remote sources
  • Multi-asset support: --all-assets flag installs all .fpack files from a GitHub release with multiple pack assets
  • MCP handler: floop_pack_install tool now accepts a source field (backward-compatible file_path deprecated); path validation only applies to local sources

New files (6)

File Purpose
internal/pack/resolve.go Source string parsing: SourceLocal, SourceHTTP, SourceGitHub
internal/pack/resolve_test.go 18 table-driven test cases
internal/pack/github.go GitHub REST API client, token resolution (GITHUB_TOKENgh auth token → unauthenticated)
internal/pack/github_test.go Tests with httptest mock server
internal/pack/fetch.go HTTP download with local caching, 50MB size limit, atomic writes
internal/pack/fetch_test.go Cache hit/miss, force redownload, size limit, auth token tests

Modified files (6)

File Changes
internal/pack/install.go Source field on InstallOptions, fixed recordInstall to populate source, added InstallFromSource()
cmd/floop/cmd_pack.go Install uses InstallFromSource, update reworked with pack-id lookup / --all / version check
internal/mcp/handlers.go Accepts source field, conditional path validation, uses InstallFromSource for remote
internal/mcp/schema.go Added Source field to FloopPackInstallInput
cmd/floop/cmd_pack_test.go Updated test expectations for new Use strings and flags
docs/CLI_REFERENCE.md Updated install/update docs with source formats, new flags, auth info

Test plan

  • go vet ./... passes
  • gofmt clean
  • go test ./internal/pack/... — all 33 tests pass (resolve, github, fetch, install)
  • go test ./cmd/floop/... — all pass
  • go build ./internal/mcp/... — compiles
  • Manual smoke test: floop pack install gh:nvandessel/floop (once release is published)
  • Manual smoke test: floop pack update --all

🤖 Generated with Claude Code

Add URL-based and GitHub release-based pack installation. Users can now
install packs from HTTP URLs and GitHub repos (gh:owner/repo[@Version])
in addition to local files. Includes smart caching, version checking
for updates, and multi-asset GitHub release support.

New files:
- resolve.go: source string parsing (local/HTTP/GitHub)
- github.go: GitHub REST API client with token resolution
- fetch.go: HTTP download with caching, size limits, atomic writes

Changes:
- install.go: InstallFromSource() wiring, Source field in InstallOptions
- cmd_pack.go: install accepts any source, update gains --all and
  pack-id lookup with version checking
- handlers.go: MCP handler accepts source field, path-validates only
  local sources
- CLI_REFERENCE.md: updated docs for new source formats and flags

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@greptile-apps
Copy link

greptile-apps bot commented Feb 28, 2026

Greptile Summary

Introduced remote pack installation capabilities for floop, enabling installs from HTTP URLs and GitHub releases using gh:owner/repo[@version] shorthand. The implementation adds smart version checking to skip unnecessary downloads, batch update support via --all, and proper source tracking in config.

Major changes:

  • Added source resolution layer (resolve.go) supporting local/HTTP/GitHub formats
  • Implemented GitHub REST API client with token auto-discovery (GITHUB_TOKEN → gh auth token → unauthenticated)
  • Added HTTP fetching with local caching, atomic writes, and 50MB size limit
  • Extended InstallFromSource to handle all source types with proper error handling
  • Updated CLI commands (install, update) to accept remote sources
  • Modified MCP handler to support source field with backward-compatible file_path

Code quality:

  • Comprehensive test coverage (33+ tests across resolve, github, fetch)
  • Proper error wrapping and context propagation
  • Good separation of concerns across new modules
  • Atomic file operations prevent partial downloads

Confidence Score: 4/5

  • This PR is safe to merge with minor improvements recommended
  • Strong implementation with excellent test coverage and proper error handling. One minor issue with gh auth token lacking timeout, but doesn't affect core functionality. The feature is well-architected with clear separation of concerns.
  • internal/pack/github.go needs timeout added to exec.Command

Important Files Changed

Filename Overview
internal/pack/resolve.go Added source parsing logic for local paths, HTTP URLs, and GitHub shorthand (gh:owner/repo[@Version])
internal/pack/github.go GitHub REST API client with token resolution (GITHUB_TOKEN, gh auth token); potential timeout issue in token resolution
internal/pack/fetch.go HTTP download with local caching, atomic writes, 50MB size limit, and proper cleanup of temp files
internal/pack/install.go Added InstallFromSource function supporting local/HTTP/GitHub sources; properly records source in config
cmd/floop/cmd_pack.go Updated install/update commands to support remote sources; added --all flag for batch updates and version checking
internal/mcp/handlers.go Updated floop_pack_install to accept source field; path validation now conditional on local sources only

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[User: floop pack install source] --> B{ResolveSource}
    B -->|Local| C[Validate Path]
    B -->|HTTP| D[HTTPCachePath]
    B -->|GitHub| E[GitHubClient.ResolveRelease]
    
    C --> F[Install from FilePath]
    
    D --> G[Fetch URL]
    G --> H{Cached?}
    H -->|Yes| I[Return Cached]
    H -->|No| J[HTTP Download]
    J --> K[Atomic Write to Cache]
    K --> F
    I --> F
    
    E --> L[FindPackAssets]
    L --> M{Multi-asset?}
    M -->|Yes + --all-assets| N[Download All .fpack]
    M -->|Single| O[Download Asset]
    M -->|Multi + no flag| P[Error: use --all-assets]
    
    N --> Q[GitHubCachePath]
    O --> Q
    Q --> G
    
    F --> R[Install Behaviors]
    R --> S[Stamp Provenance]
    S --> T[Record Source in Config]
    T --> U[Sync Store]
    
    U --> V{Update Command?}
    V -->|Yes| W{Version Check}
    W -->|Up-to-date| X[Skip Download]
    W -->|Outdated| A
    V -->|No| Y[Complete]
Loading

Last reviewed commit: 1c0eece

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

12 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Comment on lines 144 to 150
cmd := exec.Command("gh", "auth", "token")
out, err := cmd.Output()
if err == nil {
token := strings.TrimSpace(string(out))
if token != "" {
return token
}
Copy link

Choose a reason for hiding this comment

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

Add timeout to gh auth token command. Without context/timeout, this could hang indefinitely if gh is unresponsive.

Suggested change
cmd := exec.Command("gh", "auth", "token")
out, err := cmd.Output()
if err == nil {
token := strings.TrimSpace(string(out))
if token != "" {
return token
}
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
cmd := exec.CommandContext(ctx, "gh", "auth", "token")
out, err := cmd.Output()

- Fix gofmt field alignment in resolve_test.go
- Add 5s context timeout to `gh auth token` exec.Command to prevent
  hangs if gh CLI is unresponsive

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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