lp-file-archiver
v3.0.0
Published
A loopengine ability: a create_zip_archive tool that bundles local files and/or http(s) URLs into one zip archive, saved locally or to GCS with a real signed URL, plus a skill on when to use it.
Maintainers
Readme
lp-file-archiver
A loopengine ability: a
create_zip_archive tool that bundles a set of files into one zip
archive, plus a skill on when it's actually worth doing that. Built to
compose with any batch tool's output — not tied to any one ability —
so an operator can get one downloadable artifact instead of picking
through many separate files or links.
What's in it
Tool —
create_zip_archive(files, archive_name?).filesis an array where each entry is either anhttp(s)URL (fetched), a local filesystem path (read directly), or another loopengine ability's own/storage-redirectURL (looped back through this same server, with the sameLOOPENGINE_ADMIN_AUTHcredentials a browser session would already have cached — see lp-product-ad-images's ownpath/download_pathfor an example of a tool that returns one) — notgs://or any other scheme. Runs synchronously and returns once the archive is written:{ "archive_path": "...", "file_count": 24, "total_bytes": 18234112, "results": [ { "source": "https://.../a.png", "status": "included", "entry_name": "a.png", "bytes": 512340 }, { "source": "https://.../b.png", "status": "failed", "error": "HTTP 404" } ] }A source that fails to fetch/read is skipped and reported in
results, not treated as fatal for the whole archive — only every source failing is an error, since then there'd be nothing to zip. Duplicate basenames across sources are automatically disambiguated (image.png,image-2.png, ...) rather than one silently overwriting another inside the archive.Fetching URLs uses the same hostname-blocking SSRF guard lp-web-search's own
web_fetchtool does (localhost, private network ranges, link-local/ cloud-metadata addresses) — this tool fetches whatever URL a model hands it, and a model's choice of URL can be influenced by content it already read elsewhere, not just the operator.Storage, chosen once via
ARCHIVE_STORAGE(defaultlocal):local— writes the zip underARCHIVE_OUTPUT_DIR;archive_pathis a short/local-file?...URL — loopengine core's own generic file-serving route (requires loopengine >= 0.1.57), givinglocalstorage the same download-button treatmentgcsgets below — as long asARCHIVE_OUTPUT_DIRresolves inside this deployment's own project directory (true for its own relative-path default; an absolute path elsewhere falls back to a bare filesystem path with no URL, same as before this route existed).gcs— uploads it toARCHIVE_GCS_BUCKET(optionally underARCHIVE_GCS_PREFIX);archive_pathis a short/storage-redirect?...URL — loopengine core's own generic route (requires loopengine >= 0.1.55), which signs a fresh, short-lived V4 URL and redirects on every click, rather than this tool signing one long-lived URL itself at generation time. Only openable from a browser already authenticated to this same loopengine server (the same Basic Auth every other route there needs) — not a standalone link you can share outside it. If Application Default Credentials alone can't sign (plaingcloud auth application-default logincan't; a service account key or IAMsignBlobvia impersonation can), setGOOGLE_APPLICATION_CREDENTIALS_JSONto the entire contents of a downloaded service-account key file — the one setup path that needs nothing but the GCP Console and the Admin UI's Environment tab, no shell/SSH access to wherever this is running required; a click just 502s otherwise, since/storage-redirecthas no fallback for that the way this tool's own upload step does. Requiresnpm install @google-cloud/storagein your own project (lazily imported by both this tool's own upload step and loopengine core's redirect route, solocalusers never need it).
Skill —
file-archiving: when bundling into a zip is actually worth it versus leaving individual files/URLs as-is, what counts as a valid source, and how to report partial failures rather than treating one bad entry as a reason to fail the whole archive.actauth rule —
create-zip-archive-allowed,decision: allow. No metered cost and no destructive side effect to gate — see the rule file's own comment for why, and for how the real risk (fetching an arbitrary URL) is bounded instead.
Install
npx loopengine add-ability lp-file-archiver --agent <your-agent>Then:
- Optionally set
ARCHIVE_OUTPUT_DIRif you don't want zips landing under./generated/archives. - Optionally set
ARCHIVE_STORAGE=gcsplusARCHIVE_GCS_BUCKET(and optionallyARCHIVE_GCS_PREFIX,ARCHIVE_GCS_SIGNED_URL_EXPIRY) to upload archives to GCS instead of writing them locally. npm install jszipin your own project. If you setARCHIVE_STORAGE=gcs, alsonpm install @google-cloud/storage. Installing an ability copies its files in, it doesn't manage your project's ownpackage.json, so these are one-time manual steps (see loopengine's ownABILITIES.mdon why abilities are copied rather than imported).- If using
localstorage, add wherever archives land (ARCHIVE_OUTPUT_DIR, defaultgenerated/archives) to your project's own.gitignoreif you don't want to commit them.
Upgrading
npx loopengine upgrade-ability lp-file-archiver --agent <your-agent>See loopengine's own ABILITIES.md for how abilities, installs, and
upgrades work in general.
