Skip to content

feat(hub): pre-install read surface + cache eviction#419

Merged
wolfy-j merged 1 commit into
feat/module-entriesfrom
feat/hub-read-surface
Jul 4, 2026
Merged

feat(hub): pre-install read surface + cache eviction#419
wolfy-j merged 1 commit into
feat/module-entriesfrom
feat/hub-read-surface

Conversation

@wolfy-j

@wolfy-j wolfy-j commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Builds on #417 (its hub.versions.entries is the base of this branch) to give the hub module a full pre-install read surface — so a caller (esp. an AI agent) can inspect a module's metadata, entries, and actual file contents before installing it, to scan dependencies and run security checks — plus a cache-eviction surface so inspected-but-uninstalled artifacts don't accumulate forever.

Design was reviewed for idiomaticity against the existing registry / fs / resource / lock modules (two independent passes) before implementation.

Surface

-- owned handle (fs.File pattern): opens the cached .wapp once, auto-closed at frame end
local pkg = hub.versions.open(module, version, opts?)   -- opts {registry, token, timeout}
pkg.version, pkg.digest, pkg.packed
pkg:metadata()                       -- pack manifest table
pkg:entries({kind?, include_data?})  -- array of { id="ns:name", kind, meta, data }  (data RAW)
pkg:resources()                      -- array of { id, type, hash, size, file_count, meta }
local vfs = pkg:fs(resource_id)      -- a real fs handle (same as fs.get) over the embedded filesystem
pkg:close()

-- flat one-shot sugar
hub.versions.resources(module, version, opts?)
hub.versions.read_file(module, version, resource, path, opts?)   -- file bytes as a string

-- cache eviction (name+version addressed, lockfile = pins; mirrors pruneModuleArtifacts)
hub.cache.list(opts?)                       -- { {module, version, size, pinned}, ... }
hub.cache.remove(module, version, {force?}) -- refuses lock-pinned unless force
hub.cache.prune({dry_run?})                 -- removes only artifacts absent from the lockfile

Idioms followed

  • Handle is the fs.File owned-handle pattern, not a resource lease — an uninstalled artifact has no registry entry to Acquire. It keeps the open *os.File + *wapp.Reader, registers resource.GetStore(ctx).AddCleanup(...) for frame-end auto-close, and :close() is idempotent. The file stays open so pkg:fs() reads lazily.
  • pkg:fs() returns the real fs handlewapp.Reader.GetFSfsapi.NewReadOnlyFS → the fs module (new exported fs.PushFS), so callers use the standard stat/readdir/read_file verbs. No parallel fs abstraction.
  • Entries: bare array, id="ns:name" string, data converted structurally (raw — ${env:...}/_env stay literal, matching the sealing model).
  • Cache: name+version-addressed under the vendor dir, lockfile modules are the pin set; prune skips pinned, remove refuses pinned unless force — same semantics as pruneModuleArtifacts.
  • Base opts / error-as-second-value / dotted security actions / gate-once-at-call-site match the existing hub methods.

Notes / decisions

  • Scoped to packed .wapp modules. Unpacked-directory modules load entries from _index.yaml rather than wapp.Reader; a directory-backed path can be a follow-up (pkg.packed already exposes the distinction).
  • Orphan cache filenames are parsed by splitting version at the final hyphen; pinned artifacts get exact module/version from the lockfile (hyphenated prerelease orphans noted in a code comment).

Tests

read_surface_test.go: open → metadata/entries(raw + kind/include_data filters)/resources/pkg:fs read/close(+use-after-close); flat resources + read_file (incl. leading-slash + missing-file); cache list/remove(pinned-refusal + force)/prune(dry-run + orphan-only). Build, vet, go test, gofmt, and golangci-lint all green.

Credit to @msmakouz for the entries() groundwork this builds on.

Add a Lua read surface over the verified .wippy/vendor cache so a module can be
fully inspected before install: hub.versions.open returns an owned package
handle (fs.File-style, auto-closed via the resource store) exposing metadata,
entries, resources, and a real fs handle over each embedded filesystem; flat
hub.versions.resources / read_file cover one-shot reads. Adds hub.cache
list/remove/prune (name+version addressed, lockfile as the pin set, mirroring
pruneModuleArtifacts) so inspected-but-uninstalled artifacts can be reclaimed.

Entry data is returned raw (placeholders/_env unresolved); the fs surface reuses
the fs module (new fs.PushFS helper) rather than a parallel abstraction.

Builds on #417's hub.versions.entries.
@wolfy-j wolfy-j merged commit 9aae6fa into feat/module-entries Jul 4, 2026
2 of 3 checks passed
@wolfy-j wolfy-j deleted the feat/hub-read-surface branch July 4, 2026 01:01
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