[READ-ONLY] Mirror of https://github.com/just-cameron/tangled-cli. Automation-first CLI for Tangled.org

Support Tangled's repository stores, scoped OAuth, and fork pull requests #24

Merged cameron.stream
targeting main from center.for.cybernetic.beauty/tangled-cli:main
Merged opened by and assigned to cameron.stream
targeting main from center.for.cybernetic.beauty/tangled-cli:main

Summary #

Three things, in 24 small commits (each message says why):

  1. Repository stores. Where a repository's knot keeps a store of its own (org.tangled.repo.declaration), issues, comments, labels and pull requests are read and written there as tangled.org keeps them now. Repositories without one keep the legacy path.
  2. Scoped OAuth. auth login asks only for the permissions tang uses, built from one list in permissions.ts.
  3. Pull requests from forks. tang -R <upstream> pr create from a fork's clone. This PR was opened that way.
 issue / label / pr command
   resolveRepositoryDid          # + from org.tangled.repo.declaration
+  resolveKnotStore(repoDid)
+  ├─ store  → tickets-api       # org.tangled.track.ticket, comments, tangledLabels,
+  │                             #   pulls via org.tangled.review.submitPatch
   └─ none   → legacy sh.tangled.repo.* records in your PDS
 src/
 ├── commands/
+│   └── issue-tickets.ts   # issue commands against a store
 └── lib/
+    ├── knot-store.ts      # a repo DID's record store on its knot: reads, service-auth writes
+    ├── tickets-api.ts     # issues, comments, labels, pulls as org.tangled.* records
+    └── permissions.ts     # every PDS write and getServiceAuth call; the OAuth scope built from them

Pull request from a fork, the same calls tangled.org's web app makes (PullCompose.svelte):

tang -R upstream pr create --head feature
  head checked on the fork's own remote
  upstream's base branch fetched (FETCH_HEAD only), merge base taken against it
  ticket written to upstream's store
  submitPatch on upstream's knot { sourceRepo: fork DID, sourceBranch, base, head }
    refused → ticket taken back

Also: issue comment --edit, auth status --diagnostic (the scope granted), handle resolution on Node 26, SSH remotes with any user, and pr list/view show a fork's repo beside its branch.

Evidence #

  • Before (main, 4f0e085): bun run test → 350 passed, 2 failed (formatDate locale tests, which fail the same way on both: they expect M/D/YYYY and get 15.6.2023 under a non-US locale) After: 473 passed, the same 2 failed; bun run typecheck and bun run lint clean
  • Each behaviour change was seen red first; the commit messages name the tests.
  • Used against tangled.org: issues, comments and labels on stored repositories, pr create into a store (the first attempt is what showed the knot only takes patches through submitPatch), and this PR, opened from the fork with tang -R cameron.stream/tangled-cli pr create.

Merge Danger #

Door: two-way for the code, one-way for what it writes

Reverting restores the old behaviour, but tickets, comments and labels written to a repository's store while this was in stay there.

Blast Radius: sign-in

auth login asks for a different OAuth scope, so every existing OAuth session must sign in again before it can write to a store or submit a patch. In repositories with a store, issue and pr commands no longer show legacy sh.tangled.repo.issue/pull records by default (issue list --legacy still lists them).

🤖 Generated with Claude Code

Commits 0