feat(client): list + get — the download half of the sync flow
`add` pushed a local folder up; nothing pulled a cloud repo down, so the "show me my repos -> download -> start working" half of onboarding had no implementation. Both new commands read the forge directly with the scoped user token the link already handed us, so neither needs a granthi-link endpoint, a service restart, or a VPS config edit. - list: GET /api/v1/user/repos, pagination followed to a short page, with a FORGE_MAX_PAGES guard whose trip is REPORTED — a bounded page must never read as "that is all of them". Shows which repos are already local. - get: clones with --origin granthi (the remote name watch looks for) and -c credential.helper (the repo does not exist yet, so the helper cannot be installed first), then registers the folder in the same shape `add` writes — without that, watch silently ignores everything cloned. - require_linked(): one failure mode for every forge-touching command. - VERSION 1.0.0 -> 1.1.0, matching the README and the 1.1.0 hardening. Tests 55 -> 65. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01LTARYHX7GPepi3CH3tp5pg
This commit is contained in:
co-authored by
Claude Opus 5
parent
14ccbd59f0
commit
88604a90f6
@@ -114,6 +114,20 @@ Empirically verified mechanics on Gitea **1.27.1** (beta forge):
|
||||
(`authorization_pending`/`slow_down` handled), then calls `/v1/link`.
|
||||
`--token` skips the device flow with a ready Zitadel token (headless/dev).
|
||||
Result stored in `~/.granthi-sync/config.json` (0600).
|
||||
* `list` — every repo the linked token can see, with the local folder each
|
||||
is already synced to. Reads `GET /api/v1/user/repos` on the forge
|
||||
**directly** with the scoped user token — no granthi-link round-trip, so
|
||||
the read path needs no service change. Pagination is followed to a short
|
||||
page; if the `FORGE_MAX_PAGES` guard trips, the output says the list is
|
||||
incomplete rather than letting a bounded page read as the whole set.
|
||||
* `get <repo|owner/repo> [--into DIR]` — the download half of `add`. Clones
|
||||
with `--origin granthi` (the remote name `watch` looks for) and
|
||||
`-c credential.helper=…` (the repo does not exist yet, so the helper
|
||||
cannot be installed first; git also persists it into the new config), then
|
||||
registers the folder in `config.json` with the same shape `add` writes —
|
||||
so a cloned repo is picked up by `watch` immediately. Refuses a non-empty
|
||||
destination. Branch is read with `symbolic-ref` (an empty repo has an
|
||||
unborn HEAD) and falls back to `main`.
|
||||
* `add <folder> [--name N] [--private|--public]` — `git init -b main` if
|
||||
needed, creates the cloud repo via `/v1/repos`, adds remote `granthi`,
|
||||
initial commit + push. The token is delivered by a **git credential
|
||||
@@ -129,7 +143,7 @@ Empirically verified mechanics on Gitea **1.27.1** (beta forge):
|
||||
|
||||
## Tests
|
||||
|
||||
* `python3 -m unittest discover -s tests` — 53 tests: autocommit/ff/diverged
|
||||
* `python3 -m unittest discover -s tests` — 65 tests: autocommit/ff/diverged
|
||||
logic against real temp git repos (including "diverged never touches the
|
||||
remote"), config 0600 handling (including umask-proof creation and a
|
||||
no-chmod guard), credential-helper quoting/injection, mocked device-flow
|
||||
@@ -137,7 +151,12 @@ Empirically verified mechanics on Gitea **1.27.1** (beta forge):
|
||||
in-process stub playing Zitadel + Gitea, all identity-binding rules
|
||||
(collision 409, verified-email adoption, deleted-login re-create/refuse,
|
||||
concurrent-create race, corrupt-state fail-closed), the test_mode env
|
||||
gate, config-permission refusal, and the 64 KB body cap.
|
||||
gate, config-permission refusal, and the 64 KB body cap. The `list`/`get`
|
||||
set covers pagination-to-a-short-page, truncation being reported rather
|
||||
than hidden, HTTP errors being fatal instead of a silent empty list,
|
||||
non-empty-destination refusal, owner-qualified names, unborn-HEAD branch
|
||||
fallback, no token in the remote URL, and — the one that matters — that a
|
||||
`get` folder is actually picked up by a subsequent `sync_folder` pass.
|
||||
* Live E2E against the beta forge is recorded in the delivery notes
|
||||
(link → add → watch ff/push → forced divergence → DIVERGED skip verified
|
||||
via API, remote sha untouched).
|
||||
|
||||
Reference in New Issue
Block a user