@toon-protocol/rig 2.6.0 → 2.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +370 -213
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,252 +1,409 @@
|
|
|
1
1
|
# @toon-protocol/rig
|
|
2
2
|
|
|
3
|
-
Git
|
|
3
|
+
**Git, with a TOON remote.** `rig` is a drop-in `git` wrapper that publishes your
|
|
4
|
+
repository to the TOON network — a decentralized control plane where repo state
|
|
5
|
+
lives in NIP-34 Nostr events and the objects live on Arweave.
|
|
4
6
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
| `rig help` / `rig --version` | rig | usage / version |
|
|
22
|
-
| everything else | **git** | executed as `git <args...>` with rig's stdio and git's exit code |
|
|
23
|
-
|
|
24
|
-
## `rig` quickstart
|
|
7
|
+
- **Reads are free** — clone, fetch, and browse issues/PRs need no identity, no
|
|
8
|
+
wallet, nothing configured.
|
|
9
|
+
- **Writes are paid** — pushing objects and publishing events spends from a
|
|
10
|
+
payment channel funded by your wallet. Writes are permanent and non-refundable.
|
|
11
|
+
- **Standalone by default** — `rig` embeds its own payment client built from your
|
|
12
|
+
seed phrase. No daemon is required (though a running `toon-clientd` makes paid
|
|
13
|
+
commands faster — see [Daemon as accelerator](#daemon-as-accelerator)).
|
|
14
|
+
|
|
15
|
+
`rig` owns a handful of TOON verbs (`init`, `remote`, `clone`, `fetch`, `push`,
|
|
16
|
+
`issue`, `pr`, `comment`, `identity`, `fund`, `balance`, `channel`). **Every other
|
|
17
|
+
command passes through to system `git` verbatim** — `rig status`, `rig add -p`,
|
|
18
|
+
`rig commit`, `rig rebase -i` all behave exactly like git.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Install
|
|
25
23
|
|
|
26
24
|
```sh
|
|
27
25
|
npm install -g @toon-protocol/rig
|
|
26
|
+
rig --version
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Requires Node.js and a system `git` on your `PATH` (rig shells out to it for all
|
|
30
|
+
passthrough commands and object plumbing).
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## From your code to a published repo
|
|
35
|
+
|
|
36
|
+
This is the full happy path: an idea on your disk → a repository anyone can clone
|
|
37
|
+
from TOON. It uses the shared **devnet** (free faucet money) so you can complete
|
|
38
|
+
it end to end without spending anything real.
|
|
39
|
+
|
|
40
|
+
### 1. Start with your code
|
|
41
|
+
|
|
42
|
+
Already have a git repo? `cd` into it. Starting fresh? An empty directory is fine —
|
|
43
|
+
`rig init` will offer to `git init` for you in the next step.
|
|
44
|
+
|
|
45
|
+
```sh
|
|
46
|
+
mkdir hello-toon && cd hello-toon
|
|
47
|
+
echo "# hello-toon" > README.md
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### 2. Create an identity
|
|
28
51
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
52
|
+
Your identity is a BIP-39 seed phrase; its derived Nostr pubkey is who *owns* the
|
|
53
|
+
repo, and its wallet is what *pays* for writes. Mint one on the spot — the phrase is
|
|
54
|
+
shown **once**, so write it down. It's stored in an encrypted keystore under
|
|
55
|
+
`~/.toon-client`.
|
|
32
56
|
|
|
33
|
-
|
|
34
|
-
# phrase is shown ONCE (write it down) and stored in an encrypted keystore
|
|
35
|
-
# under ~/.toon-client.
|
|
57
|
+
```sh
|
|
36
58
|
rig identity create
|
|
37
|
-
rig identity show
|
|
38
|
-
# Already have a phrase? Bring it instead of generating:
|
|
39
|
-
export RIG_MNEMONIC="abandon abandon … about" # env, or…
|
|
40
|
-
echo 'RIG_MNEMONIC="abandon abandon … about"' >> .env # project .env (gitignore it!)
|
|
41
|
-
rig identity import # …or import it into the keystore (reads stdin)
|
|
42
|
-
|
|
43
|
-
# 2. one-shot repo setup (free): writes toon.repoid + toon.owner to the
|
|
44
|
-
# repo's local git config and reports which identity source is active.
|
|
45
|
-
# Not a git repo yet? `rig init` offers to `git init` here (or pass
|
|
46
|
-
# --git-init). No identity yet? It offers to generate one (or pass
|
|
47
|
-
# --generate-identity). `--git-init --generate-identity` is a fully
|
|
48
|
-
# non-interactive fresh setup: empty dir → rig-ready in one command.
|
|
49
|
-
# It ALSO sets the repo-local git commit-author from your nostr identity
|
|
50
|
-
# (never --global) so `rig commit`/`git commit` work out of the box and
|
|
51
|
-
# every commit is attributed to the signer: user.email = <npub>@nostr,
|
|
52
|
-
# user.name = your kind:0 profile display name when published (read
|
|
53
|
-
# best-effort from a relay) else the npub. Re-run to refresh the name.
|
|
54
|
-
rig init # default repo id = directory name
|
|
55
|
-
rig init --repo-id my-repo # or pick one
|
|
56
|
-
|
|
57
|
-
# 3. add your relay as an origin (free) — a REAL git remote, so
|
|
58
|
-
# `git remote -v` shows it and git tooling round-trips it
|
|
59
|
-
rig remote add origin wss://relay.example
|
|
60
|
-
rig remote list # names + URLs; --json for machines
|
|
61
|
-
rig remote remove origin
|
|
62
|
-
|
|
63
|
-
# 4. work exactly like git — unowned commands pass through to system git.
|
|
64
|
-
# `rig commit`/`git commit` already work: `rig init` set this repo's
|
|
65
|
-
# author to your nostr identity (no `git config user.*` step needed).
|
|
66
|
-
rig status # IS `git status`
|
|
67
|
-
rig add -p && rig commit -m "fix"
|
|
68
|
-
rig log --oneline # pagers, colors, prompts all behave like git
|
|
69
|
-
rig rebase -i HEAD~3 # interactive works (stdio is inherited)
|
|
70
|
-
|
|
71
|
-
# 5. push (paid) — defaults to the "origin" remote, exactly like git
|
|
72
|
-
rig push # plan + price the current branch, confirm, push
|
|
73
|
-
rig push main v1.0.0 --yes # specific refs, skip the confirm prompt
|
|
74
|
-
rig push staging main # push via another configured remote
|
|
75
|
-
rig push --all --tags --json # machine-readable plan/receipts (agents)
|
|
76
|
-
|
|
77
|
-
# issues, comments, patches, and statuses use the same rig init config:
|
|
78
|
-
rig issue create --title "Fix the flux" --body "It broke." # kind:1621
|
|
79
|
-
echo "longer body" | rig issue create --title t --yes # body via stdin
|
|
80
|
-
rig comment <root-event-id> --body "Nice catch." # kind:1622
|
|
81
|
-
rig pr create --title "Add feature" --range main..feature # kind:1617 with
|
|
82
|
-
# REAL format-patch text
|
|
83
|
-
rig pr status <event-id> applied # kind:1631
|
|
84
|
-
# (bare `rig status` is git's)
|
|
59
|
+
rig identity show # your active pubkey + npub (never the phrase)
|
|
85
60
|
```
|
|
86
61
|
|
|
87
|
-
|
|
62
|
+
Already have a phrase? Bring it instead: `export RIG_MNEMONIC="abandon abandon … about"`
|
|
63
|
+
(or `rig identity import`, which reads the phrase from stdin). See
|
|
64
|
+
[Identity](#identity) for the full resolution order.
|
|
65
|
+
|
|
66
|
+
### 3. Set up the repo
|
|
88
67
|
|
|
89
|
-
|
|
90
|
-
|
|
68
|
+
One free command wires everything together: it writes `toon.repoid` / `toon.owner`
|
|
69
|
+
into the repo's **local** git config, and sets the repo-local git commit author to
|
|
70
|
+
your Nostr identity so `rig commit` works out of the box.
|
|
91
71
|
|
|
92
72
|
```sh
|
|
93
|
-
|
|
73
|
+
rig init # repo id defaults to the directory name
|
|
74
|
+
# rig init --repo-id hello-toon # …or name it explicitly
|
|
75
|
+
# rig init --git-init --generate-identity # fully non-interactive fresh setup
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Not a git repo yet? `rig init` offers to `git init` (or pass `--git-init`). No
|
|
79
|
+
identity yet? It offers to generate one (or pass `--generate-identity`).
|
|
80
|
+
|
|
81
|
+
### 4. Point at a relay
|
|
82
|
+
|
|
83
|
+
Relays are configured as **real git remotes**. Add the shared devnet relay as
|
|
84
|
+
`origin` — this is your default publish target, and it also tells `rig fund` (next
|
|
85
|
+
step) which faucet to use.
|
|
86
|
+
|
|
87
|
+
```sh
|
|
88
|
+
rig remote add origin wss://relay-ws.devnet.toonprotocol.dev
|
|
89
|
+
rig remote list
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### 5. Fund your wallet
|
|
93
|
+
|
|
94
|
+
Pushing is paid, so your wallet needs a balance. On devnet, `rig fund` drips test
|
|
95
|
+
funds (native coin **and** USDC) to every supported chain — it's free and needs no
|
|
96
|
+
faucet URL because it infers devnet from your `origin` remote.
|
|
97
|
+
|
|
98
|
+
```sh
|
|
99
|
+
rig fund # devnet faucet drip (Mina can take ~75s)
|
|
100
|
+
rig balance # confirm the funds landed
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
> On any non-devnet network there is no faucet: `rig fund` prints your wallet
|
|
104
|
+
> address(es) so you can fund them externally, then `rig push` draws from there.
|
|
105
|
+
|
|
106
|
+
### 6. Commit your work
|
|
107
|
+
|
|
108
|
+
This is just git — unowned commands pass straight through, and step 3 already set
|
|
109
|
+
your commit author.
|
|
94
110
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
rig
|
|
98
|
-
cd their-repo # toon.* config + origin remote already set
|
|
99
|
-
|
|
100
|
-
# 2. read the tracker from the terminal
|
|
101
|
-
rig issue list # issues + derived state (latest status wins)
|
|
102
|
-
rig issue show <event-id> # one issue + its comments
|
|
103
|
-
rig pr list --state open # patches/PRs
|
|
104
|
-
rig pr show <event-id> --json | jq -r .pr.content | git am # apply a patch
|
|
105
|
-
|
|
106
|
-
# 3. stay current — fetch downloads only the missing delta
|
|
107
|
-
rig fetch # updates refs/remotes/origin/*, like git fetch
|
|
108
|
-
rig merge origin/main # integrating is plain git (passthrough)
|
|
109
|
-
|
|
110
|
-
# 4. ready to contribute back? writes are paid — add an identity + funds:
|
|
111
|
-
export RIG_MNEMONIC="abandon abandon … about"
|
|
112
|
-
export TOON_CLIENT_NETWORK=devnet # shared devnet: enables `rig fund` (no faucet URL needed)
|
|
113
|
-
rig fund # devnet faucet drip
|
|
114
|
-
rig issue create --title "found a bug" --body "details" # kind:1621
|
|
115
|
-
rig push # or publish commits (your own repos)
|
|
111
|
+
```sh
|
|
112
|
+
rig add -A
|
|
113
|
+
rig commit -m "initial commit"
|
|
116
114
|
```
|
|
117
115
|
|
|
118
|
-
|
|
119
|
-
from Arweave gateways — `rig clone`/`rig fetch` right after a push reports
|
|
120
|
-
the missing SHAs honestly; retry after propagation. A failed clone never
|
|
121
|
-
leaves a partial repository behind.
|
|
116
|
+
### 7. Push — the paid publish
|
|
122
117
|
|
|
123
|
-
|
|
118
|
+
`rig push` uploads your objects to Arweave and publishes the NIP-34 refs event
|
|
119
|
+
(plus the repo announcement on the first push). It prints a **fee table** — refs,
|
|
120
|
+
object count, bytes, itemized and total fee — and asks you to confirm before
|
|
121
|
+
spending. On this first paid write it **opens a payment channel from your funded
|
|
122
|
+
wallet automatically** (recorded and reused on later pushes; no manual
|
|
123
|
+
`rig channel open` needed).
|
|
124
124
|
|
|
125
|
-
|
|
125
|
+
```sh
|
|
126
|
+
rig push # plan + price the current branch, confirm, then publish
|
|
127
|
+
# rig push main --yes # a specific ref, skipping the confirm prompt
|
|
128
|
+
```
|
|
126
129
|
|
|
127
|
-
|
|
130
|
+
That's it — your repository is live on TOON. 🎉
|
|
128
131
|
|
|
129
|
-
|
|
132
|
+
### 8. Verify it's live
|
|
130
133
|
|
|
131
|
-
|
|
134
|
+
Clone it back from a clean directory (a free read) to prove the round-trip. Use
|
|
135
|
+
your own pubkey as the owner — `rig identity show` prints it as an `npub1…`.
|
|
132
136
|
|
|
133
|
-
|
|
137
|
+
```sh
|
|
138
|
+
cd /tmp
|
|
139
|
+
rig clone wss://relay-ws.devnet.toonprotocol.dev npub1youriden…/hello-toon
|
|
140
|
+
cd hello-toon && rig log --oneline
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
You can also browse the repo (code, commits, issues, PRs) in the **Rig web UI**,
|
|
144
|
+
which reads the same relay + Arweave data your CLI just wrote.
|
|
145
|
+
|
|
146
|
+
> **Propagation note:** freshly pushed objects can take **10–20 minutes** to become
|
|
147
|
+
> fetchable from Arweave gateways. A `rig clone` / `rig fetch` right after a push
|
|
148
|
+
> reports any not-yet-propagated SHAs honestly — just retry after a few minutes. A
|
|
149
|
+
> failed clone never leaves a partial repo behind.
|
|
150
|
+
|
|
151
|
+
### Keep working
|
|
134
152
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
153
|
+
Iterate exactly like git; re-pushing only pays for **new** objects (uploads are
|
|
154
|
+
content-addressed, so known objects are skipped for free).
|
|
155
|
+
|
|
156
|
+
```sh
|
|
157
|
+
rig add -p && rig commit -m "add a feature"
|
|
158
|
+
rig push
|
|
159
|
+
```
|
|
138
160
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
161
|
+
### Collaborate
|
|
162
|
+
|
|
163
|
+
Issues, comments, and patches are paid writes against the same repo config; reading
|
|
164
|
+
them is free.
|
|
165
|
+
|
|
166
|
+
```sh
|
|
167
|
+
# reads (free)
|
|
168
|
+
rig issue list
|
|
169
|
+
rig pr list --state open
|
|
170
|
+
rig pr show <event-id> --json | jq -r .pr.content | git am # apply a patch locally
|
|
171
|
+
|
|
172
|
+
# writes (paid)
|
|
173
|
+
rig issue create --title "Fix the flux" --body "It broke."
|
|
174
|
+
rig comment <root-event-id> --body "Nice catch."
|
|
175
|
+
rig pr create --title "Add feature" --range main..feature
|
|
176
|
+
rig pr status <event-id> applied
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## Command reference
|
|
182
|
+
|
|
183
|
+
| command | cost | what it does |
|
|
184
|
+
| --- | --- | --- |
|
|
185
|
+
| `rig identity create` | free | mint a fresh BIP-39 identity into the encrypted keystore — the phrase is shown ONCE |
|
|
186
|
+
| `rig identity show` | free | the active identity's source + derived pubkey (never the phrase) |
|
|
187
|
+
| `rig identity import` | free | write an existing phrase (read from stdin, never argv) to the keystore |
|
|
188
|
+
| `rig init` | free | one-shot repo setup: git repo + identity + `toon.*` config + repo-local git commit-author from your Nostr identity |
|
|
189
|
+
| `rig remote add/remove/list` | free | relays as REAL git remotes (`origin` = default publish target) |
|
|
190
|
+
| `rig fund [--chain <c>]` | free | devnet faucet drip (native + USDC) to the active identity's wallet; prints addresses to fund externally off-devnet |
|
|
191
|
+
| `rig balance` | free | the active wallet's multi-chain balances |
|
|
192
|
+
| `rig clone <relay-url> <owner>/<repo-id> [dir]` | free | bootstrap a repo from TOON: relay state + SHA-verified Arweave objects → a real git repo. Shadows `git clone` |
|
|
193
|
+
| `rig fetch [remote]` | free | download the missing object delta + update `refs/remotes/<remote>/*`. Shadows `git fetch` |
|
|
194
|
+
| `rig push [remote] [refspecs...]` | **paid** | the TOON push: Arweave upload + NIP-34 refs publish. Shadows `git push` |
|
|
195
|
+
| `rig issue list` / `rig issue show <id>` | free | the repo's issues + comments from the terminal |
|
|
196
|
+
| `rig pr list` / `rig pr show <id>` | free | the repo's patches/PRs; `show` prints the full patch text (pipe to `git am`) |
|
|
197
|
+
| `rig issue create` | **paid** | file an issue (kind:1621) |
|
|
198
|
+
| `rig comment <root-event-id>` | **paid** | comment (kind:1622) on an issue/patch |
|
|
199
|
+
| `rig pr create` | **paid** | publish a patch (kind:1617) from real `git format-patch` |
|
|
200
|
+
| `rig pr status <event-id> <state>` | **paid** | set issue/patch status (kind:1630–1633) |
|
|
201
|
+
| `rig channel list/open/close/settle` | free / **paid** | inspect or manage the payment channels paid commands hold |
|
|
202
|
+
| `rig help` / `rig --version` | free | usage / version |
|
|
203
|
+
| everything else | — | executed as `git <args...>` with rig's stdio and git's exit code |
|
|
204
|
+
|
|
205
|
+
Every paid command supports `--yes` (skip the confirm prompt; **required** when
|
|
206
|
+
stdin is not a TTY) and `--json` (a `--json` run *without* `--yes` is a free
|
|
207
|
+
estimate — nothing is executed or paid).
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## Money: fund, balance, channels
|
|
212
|
+
|
|
213
|
+
Paid commands spend from a **payment channel** — an on-chain-collateralized channel
|
|
214
|
+
between your wallet and a payment peer, from which each write draws an off-chain
|
|
215
|
+
claim. You rarely touch this directly:
|
|
216
|
+
|
|
217
|
+
- **`rig fund`** tops up your wallet (devnet faucet, or prints addresses to fund
|
|
218
|
+
externally). Both the native coin (gas) and USDC (collateral) are needed.
|
|
219
|
+
- **`rig balance`** shows what your wallet holds across chains.
|
|
220
|
+
- **Channels open lazily.** The first paid write opens a channel from your funded
|
|
221
|
+
wallet and records it under `~/.toon-client` (`rig-channels.json`); later writes
|
|
222
|
+
resume the same channel instead of opening a new one.
|
|
223
|
+
- **`rig channel list`** (free) shows current holdings and nonce watermarks.
|
|
224
|
+
**`rig channel open`** pre-opens one (or `--deposit`s more collateral) using the
|
|
225
|
+
exact lazy-open path; **`rig channel close`** starts the settlement challenge
|
|
226
|
+
window; **`rig channel settle`** releases collateral once the window elapses.
|
|
227
|
+
|
|
228
|
+
The `open`/`close`/`settle` lifecycle commands are on-chain wallet operations (gas +
|
|
229
|
+
collateral movement), so they follow the same confirm idiom as `push`: they print
|
|
230
|
+
what will happen, then require `--yes` or an interactive confirm.
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
## Strict `--json` stdout (machine consumers)
|
|
235
|
+
|
|
236
|
+
With `--json`, stdout carries **exactly one JSON document** — everything
|
|
237
|
+
human-facing (identity reports, deprecation nudges, progress lines, even stray
|
|
238
|
+
`console.log` from dependencies) is routed to stderr, so `rig <command> --json | jq`
|
|
239
|
+
always parses. Errors emit one machine envelope (`{"error": "<code>", "detail": …}`)
|
|
240
|
+
on stdout with the human detail on stderr and a non-zero exit. `--json` is a
|
|
241
|
+
per-subcommand flag on the commands rig owns, **not** a global rig flag.
|
|
242
|
+
|
|
243
|
+
## Git passthrough
|
|
244
|
+
|
|
245
|
+
Any subcommand rig does not own is executed as `git <args...>` verbatim: the exact
|
|
246
|
+
argv tail is handed to system git with `stdio: 'inherit'` (interactive commands,
|
|
247
|
+
pagers, colors, and prompts work), and git's exit code becomes rig's exit code (a
|
|
248
|
+
child killed by a signal maps to the shell convention 128+N). rig-owned verbs always
|
|
249
|
+
take precedence — in particular `rig push` is the TOON transport and shadows
|
|
250
|
+
`git push`; plain-git pushes remain available by calling `git push` directly. If no
|
|
251
|
+
system git is installed, passthrough fails with a clear error (exit 127).
|
|
252
|
+
|
|
253
|
+
The passthrough is exempt from the `--json` contract: `rig status --json` runs
|
|
254
|
+
`git status --json` (git rejects the flag), and flags before the subcommand
|
|
255
|
+
(`rig --json status`) pass through to git untouched.
|
|
256
|
+
|
|
257
|
+
## Identity
|
|
258
|
+
|
|
259
|
+
The CLI is **standalone by default**: it embeds its own payment client built from
|
|
260
|
+
your seed phrase (`@toon-protocol/client` is a regular dependency, installed
|
|
261
|
+
automatically) — no daemon is ever required.
|
|
262
|
+
|
|
263
|
+
**No phrase yet? Generate one — `rig identity create`.** It mints a fresh BIP-39
|
|
264
|
+
mnemonic, shows it ONCE with a backup warning, and writes it to the encrypted
|
|
265
|
+
keystore under `TOON_CLIENT_HOME`. It refuses to overwrite an existing identity
|
|
266
|
+
without `--force`. `rig identity show` reports the active source + pubkey (never the
|
|
267
|
+
phrase); `rig identity import` writes an existing phrase (read from stdin, never a
|
|
268
|
+
CLI argument) to the keystore. `--json` on **`create`** is the ONE sanctioned path
|
|
269
|
+
that emits the phrase (in a `mnemonic` field — treat as secret); `show`/`import`
|
|
270
|
+
never do.
|
|
149
271
|
|
|
150
272
|
The mnemonic is resolved along one precedence chain — highest first:
|
|
151
273
|
|
|
152
274
|
1. `RIG_MNEMONIC` environment variable
|
|
153
|
-
2. `TOON_CLIENT_MNEMONIC` environment variable — deprecated alias, warns on
|
|
154
|
-
|
|
155
|
-
3. project-local `.env` — found by walking up from the working directory
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
then the `mnemonic` config field
|
|
275
|
+
2. `TOON_CLIENT_MNEMONIC` environment variable — deprecated alias, warns on stderr;
|
|
276
|
+
rename it to `RIG_MNEMONIC`
|
|
277
|
+
3. project-local `.env` — found by walking up from the working directory (through
|
|
278
|
+
the repo root); ONLY the `RIG_MNEMONIC` line is parsed out of it. **Gitignore
|
|
279
|
+
it** — the phrase must never be committed.
|
|
280
|
+
4. the shared `~/.toon-client` state dir (`TOON_CLIENT_HOME` override): encrypted
|
|
281
|
+
keystore (`keystorePath` + `TOON_CLIENT_KEYSTORE_PASSWORD`), then the `mnemonic`
|
|
282
|
+
config field
|
|
162
283
|
|
|
163
284
|
Every paid command reports which source is active and the derived pubkey
|
|
164
|
-
(`Identity: <pubkey> (from …)`, and an `identity` object in `--json`
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
the
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
- `rig
|
|
285
|
+
(`Identity: <pubkey> (from …)`, and an `identity` object in `--json` output) — the
|
|
286
|
+
phrase itself is never printed and never written to git config or any repo file.
|
|
287
|
+
|
|
288
|
+
## Daemon as accelerator
|
|
289
|
+
|
|
290
|
+
Every standalone paid command pays a fixed bootstrap cost (relay discovery, peer
|
|
291
|
+
negotiation, channel resume). Two things remove most of it:
|
|
292
|
+
|
|
293
|
+
- **Automatic daemon delegation** — when a running `toon-clientd` on the loopback
|
|
294
|
+
control port (`TOON_CLIENT_HTTP_PORT`, default 8787) holds the **same identity**,
|
|
295
|
+
paid write commands (`push`, `issue`, `comment`, `pr create`, `pr status`)
|
|
296
|
+
delegate to its `/git/*` routes instead of bootstrapping an embedded client. The
|
|
297
|
+
daemon already owns the payment channel's cumulative-claim watermark, so one
|
|
298
|
+
process signs all claims. The identity match is confirmed against `GET /status`
|
|
299
|
+
**before** anything is sent; a daemon on a different identity, or none at all,
|
|
300
|
+
runs standalone. The chosen path prints on stderr (`rig: paid path: …`) and lands
|
|
301
|
+
in `--json` as `"path": "daemon" | "standalone"`. Commands the daemon has no route
|
|
302
|
+
for — `rig fund`, `rig balance`, `rig channel open|close|settle` — always run
|
|
303
|
+
standalone (the on-chain channel mutations among them refuse while a same-identity
|
|
304
|
+
daemon runs, so as not to race its live claims: stop the daemon for those).
|
|
305
|
+
- **Standalone topology cache** — the resolved network topology (announce discovery,
|
|
306
|
+
payment-peer pick, settlement-chain selection) is cached under `TOON_CLIENT_HOME`
|
|
307
|
+
(`rig-topology-cache.json`), keyed by relay + identity + explicit config, for 15
|
|
308
|
+
minutes (`RIG_TOPOLOGY_TTL_MS` overrides; `0` disables). A cached topology that
|
|
309
|
+
fails to bootstrap is invalidated and re-resolved live. Money state (claim
|
|
310
|
+
watermarks, channel map) is never cached.
|
|
311
|
+
|
|
312
|
+
The `rig` bin also exits as soon as a command finishes and stdio is flushed, rather
|
|
313
|
+
than letting the embedded client's keep-alive socket hold the process open for ~30s.
|
|
314
|
+
|
|
315
|
+
## Pushing
|
|
316
|
+
|
|
317
|
+
`rig push [remote] [refspecs...]` uploads the object delta to Arweave (paid,
|
|
318
|
+
content-addressed — a re-push never re-pays for known objects) and publishes the
|
|
319
|
+
NIP-34 refs event (kind:30618; plus the kind:30617 announcement on first push). It
|
|
320
|
+
renders the fee table (refs with classification, objects, bytes, itemized + total
|
|
321
|
+
fee) and asks for confirmation before spending — writes are permanent and
|
|
322
|
+
non-refundable. `--yes` skips the prompt (and is required when stdin is not a TTY);
|
|
323
|
+
`--json` without `--yes` is a pure estimate (nothing executed). `--force` allows
|
|
324
|
+
non-fast-forward updates; `--repo-id <id>` overrides the configured repo id.
|
|
325
|
+
|
|
326
|
+
Repo addressing (`30617:<owner>:<repoId>`) comes from the `toon.repoid` / `toon.owner`
|
|
327
|
+
git config keys `rig init` writes — an unconfigured repo is a clear "run `rig init`"
|
|
328
|
+
error, and pushing never mutates git config. Objects over 95KB are a hard error in
|
|
329
|
+
v1 (large-object support: toon-client#235).
|
|
330
|
+
|
|
331
|
+
## Relays are origins
|
|
332
|
+
|
|
333
|
+
Relays are configured as **real git remotes** (`rig remote add` is `git remote add`
|
|
334
|
+
underneath — `git remote -v` shows them, and remotes added with plain git work too,
|
|
335
|
+
as long as the URL is `ws://`/`wss://`/`http://`/`https://`):
|
|
336
|
+
|
|
337
|
+
- `rig remote add origin <relay-url>` / `rig remote remove <name>` / `rig remote list`
|
|
338
|
+
(`--json` supported). Junk URLs are rejected at add time.
|
|
339
|
+
- `rig push` publishes via `origin`; `rig push <remote> [refspecs...]` via a named
|
|
340
|
+
remote. Git-like resolution: when the first positional matches a configured remote
|
|
341
|
+
name it is the remote, otherwise it is a refspec and the remote defaults to
|
|
342
|
+
`origin`.
|
|
217
343
|
- The event commands take `--remote <name>` (default `origin`).
|
|
218
|
-
- `--relay <url>` stays as an **ad-hoc override** on every paid command: it bypasses
|
|
219
|
-
|
|
220
|
-
-
|
|
344
|
+
- `--relay <url>` stays as an **ad-hoc override** on every paid command: it bypasses
|
|
345
|
+
the configured remotes entirely.
|
|
346
|
+
- One relay URL per remote: a remote with multiple URLs is refused **before**
|
|
347
|
+
anything is uploaded, published, or paid.
|
|
221
348
|
|
|
222
|
-
The single-event subcommands follow the same paid-write discipline as push — the
|
|
349
|
+
The single-event subcommands follow the same paid-write discipline as push — the
|
|
350
|
+
per-event fee is quoted and confirmed before publishing; `--yes` skips, `--json`
|
|
351
|
+
without `--yes` is a free estimate:
|
|
223
352
|
|
|
224
353
|
- `rig issue create --title <t> [--body <b> | --body-file <f> | stdin] [--label <l>]…` — kind:1621.
|
|
225
354
|
- `rig comment <root-event-id> --body <b> [--parent-author <pubkey>] [--marker root|reply]` — kind:1622.
|
|
226
|
-
- `rig pr create --title <t> (--range <A..B> | --patch-file <f>) [--body <b> | --body-file <f>] [--branch <name>]` —
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
`--
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
355
|
+
- `rig pr create --title <t> (--range <A..B> | --patch-file <f>) [--body <b> | --body-file <f>] [--branch <name>]` —
|
|
356
|
+
kind:1617; `--range` runs real `git format-patch --stdout` locally and derives the
|
|
357
|
+
`commit`/`parent-commit` tags. A multi-commit range publishes ONE event carrying
|
|
358
|
+
the whole series. `--body`/`--body-file` attach the PR description in a dedicated
|
|
359
|
+
`description` tag — the event content stays pure format-patch output, so
|
|
360
|
+
`rig pr show`'s patch text still pipes straight into `git am`.
|
|
361
|
+
- `rig pr status <target-event-id> <open|applied|closed|draft>` — kind:1630–1633.
|
|
362
|
+
|
|
363
|
+
`--repo-id` / `--owner` override the git config address (use `--owner` for repos you
|
|
364
|
+
don't own).
|
|
365
|
+
|
|
366
|
+
## Cloning & fetching (free reads)
|
|
367
|
+
|
|
368
|
+
`rig clone <relay-url> <owner>/<repo-id> [dir]` reconstructs the repository from
|
|
369
|
+
public data alone: the kind:30618 `arweave` sha→txId map drives parallel downloads
|
|
370
|
+
across the gateway fallback chain (SHAs the map misses resolve via the Arweave
|
|
371
|
+
GraphQL `Git-SHA` tag index), **every body is verified against its SHA-1 before it
|
|
372
|
+
is written**, and the repository is materialized through git's own plumbing
|
|
373
|
+
(`git hash-object -w`, `git update-ref`, HEAD from the 30618 symref, checked-out
|
|
374
|
+
worktree). Everything happens in a temp dir moved into place on success, so a failed
|
|
375
|
+
clone never leaves a partial repo. `rig fetch [remote]` is the same pipeline as a
|
|
376
|
+
delta: only locally-missing objects are downloaded, and `refs/remotes/<remote>/*`
|
|
377
|
+
(tags → `refs/tags/*`) move with a `git fetch`-style report.
|
|
378
|
+
|
|
379
|
+
`rig issue list|show` and `rig pr list|show` are pure relay reads (kind:1621/1617 by
|
|
380
|
+
the repo `#a` tag; state from kind:1630-1633, latest wins; kind:1622 comments under
|
|
381
|
+
`show`).
|
|
236
382
|
|
|
237
383
|
## Library
|
|
238
384
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
- `
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
- `
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
- `
|
|
249
|
-
|
|
250
|
-
- `
|
|
251
|
-
|
|
252
|
-
|
|
385
|
+
`rig` is also the git-to-TOON write-path core. No signing or payment code lives in
|
|
386
|
+
it — that stays behind the `Publisher` seam:
|
|
387
|
+
|
|
388
|
+
- `objects.ts` — git object construction with SHA-1 envelope hashing: `createGitBlob`,
|
|
389
|
+
`createGitTree`, `createGitCommit`, `createGitTag`, `hashGitObject`, and the
|
|
390
|
+
`MAX_OBJECT_SIZE` (95KB) upload guard.
|
|
391
|
+
- `nip34-events.ts` — NIP-34 event builders returning `UnsignedEvent`:
|
|
392
|
+
`buildRepoAnnouncement` (30617), `buildRepoRefs` (30618), `buildIssue` (1621),
|
|
393
|
+
`buildComment` (1622), `buildPatch` (1617), `buildStatus` (1630–1633).
|
|
394
|
+
- `repo-reader.ts` — `GitRepoReader`, read-only local-repo access via injection-safe
|
|
395
|
+
`execFile` git plumbing.
|
|
396
|
+
- `remote-state.ts` — `fetchRemoteState`, the "what does the remote have?" reader.
|
|
397
|
+
- `object-fetch.ts` / `read-pipeline.ts` / `materialize.ts` — the read path
|
|
398
|
+
(gateway fallback + concurrency cap + SHA-1 verification, object-graph closure,
|
|
399
|
+
git plumbing writers with hostile-refname gating).
|
|
400
|
+
- `npub.ts` — dependency-free bech32 `npubToHex` / `hexToNpub` / `ownerToHex`.
|
|
401
|
+
- `publisher.ts` — the `Publisher` interface (paid transport seam), implemented by
|
|
402
|
+
the daemon and the standalone embedded client.
|
|
403
|
+
- `push.ts` — `planPush` (ref classification, object delta, fee estimate) and
|
|
404
|
+
`executePush` (crash-resume safe via content-addressed skip).
|
|
405
|
+
- `routes.ts` — the JSON wire shapes of the daemon's `/git/*` control routes.
|
|
406
|
+
- `cli/` — the `rig` bin.
|
|
407
|
+
|
|
408
|
+
Part of [epic #222](https://github.com/toon-protocol/toon-client/issues/222) and
|
|
409
|
+
[epic #246](https://github.com/toon-protocol/toon-client/issues/246).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@toon-protocol/rig",
|
|
3
|
-
"version": "2.6.
|
|
3
|
+
"version": "2.6.2",
|
|
4
4
|
"description": "Git-to-TOON write path core — build git objects and NIP-34 events for the Rig control plane",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Jonathan Green",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"dependencies": {
|
|
45
45
|
"@toon-format/toon": "^1.0.0",
|
|
46
46
|
"@toon-protocol/core": "^2.0.1",
|
|
47
|
-
"@toon-protocol/client": "^0.
|
|
47
|
+
"@toon-protocol/client": "^0.17.0"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
50
|
"@types/node": "^20.0.0",
|