Summary #
Three things, in 24 small commits (each message says why):
- 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. - Scoped OAuth.
auth loginasks only for the permissions tang uses, built from one list inpermissions.ts. - Pull requests from forks.
tang -R <upstream> pr createfrom 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 (formatDatelocale tests, which fail the same way on both: they expectM/D/YYYYand get15.6.2023under a non-US locale) After: 473 passed, the same 2 failed;bun run typecheckandbun run lintclean - 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 createinto a store (the first attempt is what showed the knot only takes patches throughsubmitPatch), and this PR, opened from the fork withtang -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