Add ditto unpack CLI to turn clone result JSON into a project tree

The REST API returns a clone as a giant `files` map JSON blob with no
first-party way to use it — users were left staring at kilobytes of
escaped JSON with no path from "you got JSON" to "here's a project".

Add packages/cli: a zero-dependency `ditto` CLI whose `unpack` command
walks the files{} map from POST /v1/clones (or GET .../result) and
writes a real project tree to disk:

- text files written from inline content;
- binary assets materialized from inline base64, else fetched from their
  reference URL using $DITTO_API_URL / $DITTO_API_KEY (--no-fetch writes
  just the text tree and lists skipped assets);
- path-traversal guards (clone results are untrusted) and sha256
  integrity checks;
- reads JSON from stdin ("-") so a curl response pipes straight in;
- clear errors for queued jobs with no files yet, and a tip pointing at
  the /bundle endpoint when assets can't be fetched.

Document the pipe-from-curl one-liner prominently next to the REST
examples in README.md and docs/SERVICE.md, add a package README, a
Repository Map row, a root `unpack` script, and a CHANGELOG entry.
Covered by 9 tests (text tree, stdin, inline base64, live URL fetch with
auth + relative-URL resolution, --no-fetch, traversal refusal, queued-job
detection, sha256 mismatch).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Michael Cole
2026-07-01 15:40:28 -04:00
co-authored by Claude Opus 4.8
parent 4de6e244a0
commit 638a0516c5
9 changed files with 589 additions and 5 deletions
+11
View File
@@ -60,6 +60,17 @@ curl -s -X POST localhost:8787/v1/clones -H 'content-type: application/json' \
-d '{"url":"https://example.com/","options":{"mode":"single","styling":"tailwind"}}' | jq '.files | keys'
```
To turn that `files` map into a project on disk, pipe the response into the
`ditto` CLI (`packages/cli`) instead of inspecting the JSON by hand:
```bash
curl -s -X POST localhost:8787/v1/clones -H 'content-type: application/json' \
-d '{"url":"https://example.com/","options":{"mode":"single"}}' \
| npx ditto unpack - ./out
# binary assets: set DITTO_API_URL (and DITTO_API_KEY when authenticated) so the
# CLI can fetch each file's reference URL; --no-fetch writes only the text tree.
```
## REST surface
```