@toon-protocol/rig 2.4.1 → 2.6.0
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 +18 -5
- package/dist/{chunk-OIJNRACA.js → chunk-6SQ7723I.js} +11 -11
- package/dist/chunk-6SQ7723I.js.map +1 -0
- package/dist/chunk-AFJNFDUQ.js +281 -0
- package/dist/chunk-AFJNFDUQ.js.map +1 -0
- package/dist/{chunk-X2CZPPDM.js → chunk-B5ISARMU.js} +3 -1
- package/dist/chunk-B5ISARMU.js.map +1 -0
- package/dist/{chunk-W2SDL2PE.js → chunk-NIRC5LFS.js} +31 -11
- package/dist/chunk-NIRC5LFS.js.map +1 -0
- package/dist/cli/rig.js +376 -73
- package/dist/cli/rig.js.map +1 -1
- package/dist/index.d.ts +21 -0
- package/dist/index.js +9 -9
- package/dist/network-bootstrap-WNSHRC5P.js +34 -0
- package/dist/network-bootstrap-WNSHRC5P.js.map +1 -0
- package/dist/standalone/index.d.ts +48 -23
- package/dist/standalone/index.js +2 -2
- package/dist/{standalone-mode-VH2XPOPK.js → standalone-mode-WEMJBHME.js} +20 -270
- package/dist/standalone-mode-WEMJBHME.js.map +1 -0
- package/package.json +2 -2
- package/dist/chunk-OIJNRACA.js.map +0 -1
- package/dist/chunk-W2SDL2PE.js.map +0 -1
- package/dist/chunk-X2CZPPDM.js.map +0 -1
- package/dist/standalone-mode-VH2XPOPK.js.map +0 -1
package/dist/cli/rig.js
CHANGED
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
OversizeObjectsError,
|
|
7
7
|
collectRepoObjects,
|
|
8
8
|
executePush,
|
|
9
|
+
hexToNpub,
|
|
9
10
|
isSafeRefname,
|
|
10
11
|
missingObjectsMessage,
|
|
11
12
|
ownerToHex,
|
|
@@ -17,7 +18,7 @@ import {
|
|
|
17
18
|
setHeadSymref,
|
|
18
19
|
updateRef,
|
|
19
20
|
writeGitObjects
|
|
20
|
-
} from "../chunk-
|
|
21
|
+
} from "../chunk-NIRC5LFS.js";
|
|
21
22
|
import {
|
|
22
23
|
DEFAULT_KEYSTORE_PASSWORD,
|
|
23
24
|
MissingIdentityError,
|
|
@@ -27,6 +28,15 @@ import {
|
|
|
27
28
|
readClientConfigFile,
|
|
28
29
|
resolveIdentity
|
|
29
30
|
} from "../chunk-XGFBDUQX.js";
|
|
31
|
+
import {
|
|
32
|
+
ChannelMapStore,
|
|
33
|
+
channelStatus,
|
|
34
|
+
defaultDaemonPort,
|
|
35
|
+
resolveChannelPaths
|
|
36
|
+
} from "../chunk-SW7ZHMGS.js";
|
|
37
|
+
import {
|
|
38
|
+
MAX_OBJECT_SIZE
|
|
39
|
+
} from "../chunk-B5ISARMU.js";
|
|
30
40
|
import {
|
|
31
41
|
COMMENT_KIND,
|
|
32
42
|
authorizedStatusAuthors,
|
|
@@ -39,15 +49,6 @@ import {
|
|
|
39
49
|
parseMaintainers,
|
|
40
50
|
queryRelay
|
|
41
51
|
} from "../chunk-3HRFDH7H.js";
|
|
42
|
-
import {
|
|
43
|
-
ChannelMapStore,
|
|
44
|
-
channelStatus,
|
|
45
|
-
defaultDaemonPort,
|
|
46
|
-
resolveChannelPaths
|
|
47
|
-
} from "../chunk-SW7ZHMGS.js";
|
|
48
|
-
import {
|
|
49
|
-
MAX_OBJECT_SIZE
|
|
50
|
-
} from "../chunk-X2CZPPDM.js";
|
|
51
52
|
|
|
52
53
|
// src/cli/rig.ts
|
|
53
54
|
import { createInterface as createInterface2 } from "readline/promises";
|
|
@@ -59,6 +60,9 @@ import { createRequire } from "module";
|
|
|
59
60
|
import { parseArgs as parseArgs3 } from "util";
|
|
60
61
|
|
|
61
62
|
// src/cli/daemon-session.ts
|
|
63
|
+
function daemonSupportsGit(probe) {
|
|
64
|
+
return Array.isArray(probe.capabilities) && probe.capabilities.includes("git");
|
|
65
|
+
}
|
|
62
66
|
function daemonBaseUrl(env) {
|
|
63
67
|
const raw = env["TOON_CLIENT_HTTP_PORT"];
|
|
64
68
|
const parsed = raw ? Number(raw) : NaN;
|
|
@@ -83,6 +87,11 @@ async function probeDaemon(env, fetchImpl, timeoutMs = 1500) {
|
|
|
83
87
|
if (typeof body?.feePerEvent === "string" && body.feePerEvent !== "") {
|
|
84
88
|
probe.feePerEvent = body.feePerEvent;
|
|
85
89
|
}
|
|
90
|
+
if (Array.isArray(body?.capabilities)) {
|
|
91
|
+
probe.capabilities = body.capabilities.filter(
|
|
92
|
+
(c) => typeof c === "string"
|
|
93
|
+
);
|
|
94
|
+
}
|
|
86
95
|
return probe;
|
|
87
96
|
} catch {
|
|
88
97
|
return { baseUrl, reachable: false };
|
|
@@ -98,6 +107,19 @@ var DaemonRouteError = class extends Error {
|
|
|
98
107
|
status;
|
|
99
108
|
envelope;
|
|
100
109
|
};
|
|
110
|
+
var DaemonTooOldForGitError = class extends Error {
|
|
111
|
+
constructor(baseUrl, pubkey) {
|
|
112
|
+
const holds = pubkey !== void 0 && pubkey !== "" ? ` holds this identity (${pubkey.slice(0, 8)}\u2026)` : " holds this identity";
|
|
113
|
+
super(
|
|
114
|
+
`toon-clientd at ${baseUrl}${holds} but is too old to handle git operations (missing /git routes). Upgrade the daemon (npm i -g @toon-protocol/client-mcp@latest, then restart it) \u2014 or stop it to let rig run standalone.`
|
|
115
|
+
);
|
|
116
|
+
this.baseUrl = baseUrl;
|
|
117
|
+
this.pubkey = pubkey;
|
|
118
|
+
this.name = "DaemonTooOldForGitError";
|
|
119
|
+
}
|
|
120
|
+
baseUrl;
|
|
121
|
+
pubkey;
|
|
122
|
+
};
|
|
101
123
|
var DaemonUnreachableError = class extends Error {
|
|
102
124
|
constructor(baseUrl, cause) {
|
|
103
125
|
super(
|
|
@@ -109,12 +131,14 @@ var DaemonUnreachableError = class extends Error {
|
|
|
109
131
|
baseUrl;
|
|
110
132
|
};
|
|
111
133
|
var DaemonGitClient = class {
|
|
112
|
-
constructor(baseUrl, fetchImpl) {
|
|
134
|
+
constructor(baseUrl, fetchImpl, pubkey) {
|
|
113
135
|
this.baseUrl = baseUrl;
|
|
114
136
|
this.fetchImpl = fetchImpl;
|
|
137
|
+
this.pubkey = pubkey;
|
|
115
138
|
}
|
|
116
139
|
baseUrl;
|
|
117
140
|
fetchImpl;
|
|
141
|
+
pubkey;
|
|
118
142
|
gitEstimate(req) {
|
|
119
143
|
return this.post("/git/estimate", req);
|
|
120
144
|
}
|
|
@@ -144,6 +168,9 @@ var DaemonGitClient = class {
|
|
|
144
168
|
} catch (err) {
|
|
145
169
|
throw new DaemonUnreachableError(this.baseUrl, err);
|
|
146
170
|
}
|
|
171
|
+
if (res.status === 404) {
|
|
172
|
+
throw new DaemonTooOldForGitError(this.baseUrl, this.pubkey);
|
|
173
|
+
}
|
|
147
174
|
const text = await res.text();
|
|
148
175
|
let parsed;
|
|
149
176
|
try {
|
|
@@ -174,12 +201,15 @@ async function resolvePaidSession(options) {
|
|
|
174
201
|
warn: options.warn
|
|
175
202
|
});
|
|
176
203
|
if (identity.pubkey === probe.identity) {
|
|
204
|
+
if (!daemonSupportsGit(probe)) {
|
|
205
|
+
throw new DaemonTooOldForGitError(probe.baseUrl, identity.pubkey);
|
|
206
|
+
}
|
|
177
207
|
options.warn(
|
|
178
208
|
`rig: paid path: daemon \u2014 toon-clientd at ${probe.baseUrl} holds this identity (${identity.pubkey.slice(0, 8)}\u2026), delegating`
|
|
179
209
|
);
|
|
180
210
|
return {
|
|
181
211
|
path: "daemon",
|
|
182
|
-
client: new DaemonGitClient(probe.baseUrl, fetchImpl),
|
|
212
|
+
client: new DaemonGitClient(probe.baseUrl, fetchImpl, identity.pubkey),
|
|
183
213
|
baseUrl: probe.baseUrl,
|
|
184
214
|
identity: {
|
|
185
215
|
pubkey: identity.pubkey,
|
|
@@ -263,7 +293,7 @@ var NotAGitRepositoryError = class extends Error {
|
|
|
263
293
|
constructor(cwd) {
|
|
264
294
|
super(
|
|
265
295
|
`not a git repository: ${cwd}
|
|
266
|
-
rig
|
|
296
|
+
rig can create one for you: re-run \`rig init --git-init\` (in a terminal, plain \`rig init\` offers the same via a prompt). Or run \`git init\` yourself first, then re-run.`
|
|
267
297
|
);
|
|
268
298
|
this.name = "NotAGitRepositoryError";
|
|
269
299
|
}
|
|
@@ -401,6 +431,18 @@ function describeError(err, command = "push") {
|
|
|
401
431
|
json: { error: "daemon_unreachable", detail: err.message }
|
|
402
432
|
};
|
|
403
433
|
}
|
|
434
|
+
if (err instanceof DaemonTooOldForGitError) {
|
|
435
|
+
return {
|
|
436
|
+
code: "daemon_too_old_for_git",
|
|
437
|
+
lines: err.message.split("\n"),
|
|
438
|
+
json: {
|
|
439
|
+
error: "daemon_too_old_for_git",
|
|
440
|
+
detail: err.message,
|
|
441
|
+
baseUrl: err.baseUrl,
|
|
442
|
+
...err.pubkey !== void 0 ? { pubkey: err.pubkey } : {}
|
|
443
|
+
}
|
|
444
|
+
};
|
|
445
|
+
}
|
|
404
446
|
const name = err instanceof Error ? err.name : "";
|
|
405
447
|
const message = err instanceof Error ? err.message : String(err);
|
|
406
448
|
if (name === "DaemonIdentityConflictError") {
|
|
@@ -507,8 +549,9 @@ function renderPlan(plan) {
|
|
|
507
549
|
for (const update of plan.refUpdates) lines.push(refLine(update));
|
|
508
550
|
const est = plan.estimate;
|
|
509
551
|
const skipped = Object.keys(plan.knownShaToTxId).length;
|
|
552
|
+
const emptySkipped = est.skippedEmptyCount ?? 0;
|
|
510
553
|
lines.push(
|
|
511
|
-
`Objects: ${est.objectCount} to upload (${formatNumber(est.totalObjectBytes)} bytes)` + (skipped > 0 ? `; ${skipped} already on Arweave (free)` : "")
|
|
554
|
+
`Objects: ${est.objectCount} to upload (${formatNumber(est.totalObjectBytes)} bytes)` + (skipped > 0 ? `; ${skipped} already on Arweave (free)` : "") + (emptySkipped > 0 ? `; ${emptySkipped} empty blob${emptySkipped === 1 ? "" : "s"} skipped (reconstructed on clone)` : "")
|
|
512
555
|
);
|
|
513
556
|
lines.push("Fees (base units):");
|
|
514
557
|
lines.push(
|
|
@@ -554,6 +597,12 @@ function renderResult(result) {
|
|
|
554
597
|
lines.push(
|
|
555
598
|
`Uploads: ${paid.length} paid, ${skipped.length} skipped (content-addressed).`
|
|
556
599
|
);
|
|
600
|
+
const emptySkipped = result.estimate.skippedEmptyCount ?? 0;
|
|
601
|
+
if (emptySkipped > 0) {
|
|
602
|
+
lines.push(
|
|
603
|
+
`Empty blobs: ${emptySkipped} skipped (zero-byte, not uploaded \u2014 reconstructed on clone).`
|
|
604
|
+
);
|
|
605
|
+
}
|
|
557
606
|
if (result.announceReceipt) {
|
|
558
607
|
lines.push(
|
|
559
608
|
`Announcement (kind:30617): ${result.announceReceipt.eventId} paid ${formatNumber(result.announceReceipt.feePaid)}`
|
|
@@ -607,6 +656,14 @@ async function resolveRepoRoot(cwd) {
|
|
|
607
656
|
);
|
|
608
657
|
}
|
|
609
658
|
}
|
|
659
|
+
async function initGitRepository(dir) {
|
|
660
|
+
try {
|
|
661
|
+
await git(dir, ["init", "--initial-branch=main"]);
|
|
662
|
+
} catch {
|
|
663
|
+
await git(dir, ["init"]);
|
|
664
|
+
await git(dir, ["symbolic-ref", "HEAD", "refs/heads/main"]);
|
|
665
|
+
}
|
|
666
|
+
}
|
|
610
667
|
async function readToonConfig(repoPath) {
|
|
611
668
|
const [repoId, owner, relays] = await Promise.all([
|
|
612
669
|
git(repoPath, ["config", "--get", "toon.repoid"], [1]),
|
|
@@ -639,6 +696,10 @@ async function listGitRemotes(repoPath) {
|
|
|
639
696
|
}
|
|
640
697
|
return remotes;
|
|
641
698
|
}
|
|
699
|
+
async function setGitAuthor(repoPath, author) {
|
|
700
|
+
await git(repoPath, ["config", "--local", "user.name", author.name]);
|
|
701
|
+
await git(repoPath, ["config", "--local", "user.email", author.email]);
|
|
702
|
+
}
|
|
642
703
|
async function addGitRemote(repoPath, name, url) {
|
|
643
704
|
await git(repoPath, ["remote", "add", name, url]);
|
|
644
705
|
}
|
|
@@ -905,7 +966,7 @@ function loadPaidSession(deps, relayUrl) {
|
|
|
905
966
|
});
|
|
906
967
|
}
|
|
907
968
|
var defaultLoadStandalone = async (options) => {
|
|
908
|
-
const mod = await import("../standalone-mode-
|
|
969
|
+
const mod = await import("../standalone-mode-WEMJBHME.js");
|
|
909
970
|
return mod.createStandaloneContext(options);
|
|
910
971
|
};
|
|
911
972
|
function identityReport(ctx) {
|
|
@@ -946,7 +1007,20 @@ Options:
|
|
|
946
1007
|
--repo-id <id> repository id / NIP-34 d-tag (default: git config
|
|
947
1008
|
toon.repoid \u2014 run \`rig init\` to set it)
|
|
948
1009
|
-h, --help show this help`;
|
|
949
|
-
|
|
1010
|
+
function noSuchRefMessage(spec, head, refs, remoteName) {
|
|
1011
|
+
const branches = refs.filter((r) => r.refname.startsWith("refs/heads/")).map((r) => r.refname.slice("refs/heads/".length));
|
|
1012
|
+
const current = head && head.startsWith("refs/heads/") ? head.slice("refs/heads/".length) : void 0;
|
|
1013
|
+
let msg = `no local branch or tag ${JSON.stringify(spec)}`;
|
|
1014
|
+
if (current) {
|
|
1015
|
+
msg += ` \u2014 your current branch is ${JSON.stringify(current)} (did you mean \`rig push ${remoteName} ${current}\`?)`;
|
|
1016
|
+
} else if (branches.length > 0) {
|
|
1017
|
+
msg += ` \u2014 local branches: ${branches.join(", ")}`;
|
|
1018
|
+
} else {
|
|
1019
|
+
msg += " \u2014 this repository has no branches yet (make a commit first)";
|
|
1020
|
+
}
|
|
1021
|
+
return msg;
|
|
1022
|
+
}
|
|
1023
|
+
async function selectRefspecs(reader, positionals, all, tags, remoteName = "origin") {
|
|
950
1024
|
const { head, refs } = await reader.listRefs();
|
|
951
1025
|
const byName = new Set(refs.map((r) => r.refname));
|
|
952
1026
|
const selected = [];
|
|
@@ -960,10 +1034,12 @@ async function selectRefspecs(reader, positionals, all, tags) {
|
|
|
960
1034
|
add(`refs/heads/${spec}`);
|
|
961
1035
|
} else if (byName.has(`refs/tags/${spec}`)) {
|
|
962
1036
|
add(`refs/tags/${spec}`);
|
|
963
|
-
} else {
|
|
1037
|
+
} else if (spec.startsWith(":")) {
|
|
964
1038
|
throw new Error(
|
|
965
|
-
`
|
|
1039
|
+
`deleting remote refs (${JSON.stringify(spec)}) is out of scope in v1`
|
|
966
1040
|
);
|
|
1041
|
+
} else {
|
|
1042
|
+
throw new Error(noSuchRefMessage(spec, head, refs, remoteName));
|
|
967
1043
|
}
|
|
968
1044
|
}
|
|
969
1045
|
if (all) {
|
|
@@ -1060,7 +1136,8 @@ async function runPush(args, deps) {
|
|
|
1060
1136
|
reader,
|
|
1061
1137
|
refspecArgs,
|
|
1062
1138
|
flags.all,
|
|
1063
|
-
flags.tags
|
|
1139
|
+
flags.tags,
|
|
1140
|
+
remoteName ?? "origin"
|
|
1064
1141
|
);
|
|
1065
1142
|
const resolved = await resolveRelays({
|
|
1066
1143
|
relayFlags: flags.relay,
|
|
@@ -1215,14 +1292,26 @@ async function runPush(args, deps) {
|
|
|
1215
1292
|
// src/cli/balance.ts
|
|
1216
1293
|
var BALANCE_USAGE = `Usage: rig balance [--json]
|
|
1217
1294
|
|
|
1218
|
-
Show the active identity's money: on-chain wallet
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1295
|
+
Show the active identity's money: the full on-chain wallet view \u2014 native coin
|
|
1296
|
+
plus USDC on every configured chain (EVM / Solana / Mina) \u2014 and recorded
|
|
1297
|
+
payment-channel holdings (deposited / claimed / available). Free \u2014 reads chain
|
|
1298
|
+
RPCs and local state only; nothing is signed or paid. An unreachable chain RPC
|
|
1299
|
+
degrades to a per-chain notice without failing the others.
|
|
1222
1300
|
|
|
1223
1301
|
Options:
|
|
1224
1302
|
--json machine-readable envelope (base units as strings)
|
|
1225
1303
|
-h, --help show this help`;
|
|
1304
|
+
function formatUnits(amount, decimals) {
|
|
1305
|
+
if (decimals === void 0 || decimals <= 0) return amount;
|
|
1306
|
+
const neg = amount.startsWith("-");
|
|
1307
|
+
const digits = (neg ? amount.slice(1) : amount).padStart(decimals + 1, "0");
|
|
1308
|
+
const whole = digits.slice(0, digits.length - decimals);
|
|
1309
|
+
const frac = digits.slice(digits.length - decimals).replace(/0+$/, "");
|
|
1310
|
+
return (neg ? "-" : "") + (frac ? `${whole}.${frac}` : whole);
|
|
1311
|
+
}
|
|
1312
|
+
function renderAmount(a) {
|
|
1313
|
+
return `${a.symbol ?? "token"} ${formatUnits(a.amount, a.decimals)}`;
|
|
1314
|
+
}
|
|
1226
1315
|
async function runBalance(args, deps) {
|
|
1227
1316
|
const { io: io2, env } = deps;
|
|
1228
1317
|
let json = false;
|
|
@@ -1254,7 +1343,7 @@ async function runBalance(args, deps) {
|
|
|
1254
1343
|
requireUplink: false
|
|
1255
1344
|
});
|
|
1256
1345
|
const identity = identityReport(ctx);
|
|
1257
|
-
const wallet = ctx.money ? await ctx.money.
|
|
1346
|
+
const wallet = ctx.money ? await ctx.money.walletChainBalances() : [];
|
|
1258
1347
|
const store = new ChannelMapStore(resolveChannelPaths(env));
|
|
1259
1348
|
const channels = store.list().filter((record) => record.identity === identity.pubkey).map((record) => {
|
|
1260
1349
|
const watermark = store.readWatermark(record.channelId);
|
|
@@ -1291,13 +1380,23 @@ async function runBalance(args, deps) {
|
|
|
1291
1380
|
io2.out("Wallet (on-chain):");
|
|
1292
1381
|
if (wallet.length === 0) {
|
|
1293
1382
|
io2.out(
|
|
1294
|
-
" (no
|
|
1383
|
+
" (no chain configured for this identity \u2014 nothing to read)"
|
|
1295
1384
|
);
|
|
1296
1385
|
}
|
|
1297
|
-
for (const
|
|
1298
|
-
io2.out(
|
|
1299
|
-
|
|
1300
|
-
|
|
1386
|
+
for (const chain of wallet) {
|
|
1387
|
+
io2.out(` ${chain.chainKey.padEnd(11)} ${chain.address}`);
|
|
1388
|
+
if (chain.unreadable) {
|
|
1389
|
+
io2.out(
|
|
1390
|
+
` unreadable (RPC unreachable)` + (chain.error ? ` \u2014 ${chain.error}` : "")
|
|
1391
|
+
);
|
|
1392
|
+
continue;
|
|
1393
|
+
}
|
|
1394
|
+
const assets = [...chain.native ? [chain.native] : [], ...chain.tokens];
|
|
1395
|
+
if (assets.length === 0) {
|
|
1396
|
+
io2.out(" (no balance readable)");
|
|
1397
|
+
continue;
|
|
1398
|
+
}
|
|
1399
|
+
io2.out(` ${assets.map(renderAmount).join(" ")}`);
|
|
1301
1400
|
}
|
|
1302
1401
|
io2.out("");
|
|
1303
1402
|
io2.out("Channels (recorded):");
|
|
@@ -3432,24 +3531,37 @@ import { join as join2 } from "path";
|
|
|
3432
3531
|
import { parseArgs as parseArgs9 } from "util";
|
|
3433
3532
|
var DEVNET_FAUCET_URL = "https://faucet.devnet.toonprotocol.dev";
|
|
3434
3533
|
var CHAINS = ["evm", "solana", "mina"];
|
|
3534
|
+
var CHAIN_CHOICES = [...CHAINS, "all"];
|
|
3535
|
+
var NATIVE_COIN = {
|
|
3536
|
+
evm: "ETH",
|
|
3537
|
+
solana: "SOL",
|
|
3538
|
+
mina: "MINA"
|
|
3539
|
+
};
|
|
3435
3540
|
var FUND_USAGE = `Usage: rig fund [options]
|
|
3436
3541
|
|
|
3437
3542
|
Drip devnet test funds to the active identity's wallet \u2014 free (the faucet
|
|
3438
|
-
pays).
|
|
3543
|
+
pays). By default funds ALL supported chains (evm + solana + mina), each drip
|
|
3544
|
+
covering the native coin AND USDC, so the wallet matches the multi-chain
|
|
3545
|
+
\`rig balance\` view in one run. The per-chain drips run in parallel and are
|
|
3546
|
+
independent \u2014 one chain's faucet failing does not abort the others (exit 0
|
|
3547
|
+
only when every targeted chain funded; exit 1 if any failed, with the
|
|
3548
|
+
per-chain breakdown always shown).
|
|
3549
|
+
|
|
3550
|
+
The identity comes from RIG_MNEMONIC (env or a project .env) or the
|
|
3439
3551
|
~/.toon-client keystore/config; the faucet from TOON_CLIENT_FAUCET_URL, the
|
|
3440
3552
|
faucetUrl config field, or the deployed devnet faucet when the network is
|
|
3441
3553
|
devnet \u2014 including when a configured *.devnet.toonprotocol.dev origin infers
|
|
3442
3554
|
it (a devnet relay/proxy/btp endpoint, or the git origin remote from
|
|
3443
3555
|
\`rig remote add origin <devnet relay>\`). The faucet drips a FIXED amount per
|
|
3444
|
-
chain (there is no --amount). On a
|
|
3445
|
-
|
|
3446
|
-
instead.
|
|
3556
|
+
chain (there is no --amount). On a network without a faucet, prints the wallet
|
|
3557
|
+
address(es) to fund externally instead.
|
|
3447
3558
|
|
|
3448
3559
|
Options:
|
|
3449
|
-
--chain <chain> evm | solana | mina
|
|
3450
|
-
|
|
3560
|
+
--chain <chain> evm | solana | mina | all \u2014 fund one chain, or all
|
|
3561
|
+
(default: all supported chains)
|
|
3451
3562
|
--address <address> fund this address instead of the identity's own
|
|
3452
|
-
|
|
3563
|
+
(requires an explicit single --chain)
|
|
3564
|
+
--json machine-readable envelope (per-chain results array)
|
|
3453
3565
|
-h, --help show this help`;
|
|
3454
3566
|
var SHARED_DEVNET_SUFFIX = ".devnet.toonprotocol.dev";
|
|
3455
3567
|
function devnetHost(url) {
|
|
@@ -3543,9 +3655,14 @@ async function runFund(args, deps) {
|
|
|
3543
3655
|
chainFlag = values.chain;
|
|
3544
3656
|
addressFlag = values.address;
|
|
3545
3657
|
json = values.json ?? false;
|
|
3546
|
-
if (chainFlag !== void 0 && !
|
|
3658
|
+
if (chainFlag !== void 0 && !CHAIN_CHOICES.includes(chainFlag)) {
|
|
3547
3659
|
throw new Error(
|
|
3548
|
-
`--chain must be one of ${
|
|
3660
|
+
`--chain must be one of ${CHAIN_CHOICES.join(" | ")}, got ${JSON.stringify(chainFlag)}`
|
|
3661
|
+
);
|
|
3662
|
+
}
|
|
3663
|
+
if (addressFlag !== void 0 && (chainFlag === void 0 || chainFlag === "all")) {
|
|
3664
|
+
throw new Error(
|
|
3665
|
+
"--address requires an explicit single --chain (evm | solana | mina) \u2014 a single address cannot fund every chain"
|
|
3549
3666
|
);
|
|
3550
3667
|
}
|
|
3551
3668
|
} catch (err) {
|
|
@@ -3555,12 +3672,7 @@ async function runFund(args, deps) {
|
|
|
3555
3672
|
}
|
|
3556
3673
|
try {
|
|
3557
3674
|
const { file } = readFundConfig(env);
|
|
3558
|
-
const
|
|
3559
|
-
if (!CHAINS.includes(chain)) {
|
|
3560
|
-
throw new Error(
|
|
3561
|
-
`configured settlement chain ${JSON.stringify(chain)} has no faucet \u2014 pass --chain ${CHAINS.join(" | ")}`
|
|
3562
|
-
);
|
|
3563
|
-
}
|
|
3675
|
+
const targetChains = chainFlag === void 0 || chainFlag === "all" ? [...CHAINS] : [chainFlag];
|
|
3564
3676
|
const network = env["TOON_CLIENT_NETWORK"] ?? file.network;
|
|
3565
3677
|
const canInfer = network === void 0 || network === "custom";
|
|
3566
3678
|
const originRelays = canInfer ? await resolveOriginRelays(deps.cwd) : [];
|
|
@@ -3596,7 +3708,6 @@ async function runFund(args, deps) {
|
|
|
3596
3708
|
identity,
|
|
3597
3709
|
funded: false,
|
|
3598
3710
|
network: network ?? null,
|
|
3599
|
-
chain,
|
|
3600
3711
|
addresses,
|
|
3601
3712
|
guidance
|
|
3602
3713
|
});
|
|
@@ -3610,46 +3721,85 @@ async function runFund(args, deps) {
|
|
|
3610
3721
|
io2.out(` mina ${addresses.mina ?? "(no key derived \u2014 optional mina-signer dependency missing)"}`);
|
|
3611
3722
|
return 0;
|
|
3612
3723
|
}
|
|
3613
|
-
const address = addressFlag ?? addresses[chain];
|
|
3614
|
-
if (!address) {
|
|
3615
|
-
throw new Error(
|
|
3616
|
-
`no ${chain} address could be derived for this identity \u2014 pass an explicit --address (for mina, install the optional mina-signer dependency)`
|
|
3617
|
-
);
|
|
3618
|
-
}
|
|
3619
3724
|
const timeoutEnv = env["TOON_CLIENT_FAUCET_TIMEOUT_MS"];
|
|
3620
|
-
const
|
|
3725
|
+
const timeoutFor = (chain) => {
|
|
3726
|
+
if (timeoutEnv && Number.isFinite(Number(timeoutEnv))) return Number(timeoutEnv);
|
|
3727
|
+
if (file.faucetTimeoutMs !== void 0) return file.faucetTimeoutMs;
|
|
3728
|
+
return chain === "mina" ? 13e4 : 9e4;
|
|
3729
|
+
};
|
|
3621
3730
|
if (!json && inferredDevnet) {
|
|
3622
3731
|
io2.out(
|
|
3623
3732
|
`Inferred network 'devnet' from the configured origin ${devnetOrigin} (network was ${JSON.stringify(network ?? "custom")}). Set TOON_CLIENT_NETWORK explicitly to override.`
|
|
3624
3733
|
);
|
|
3625
3734
|
}
|
|
3626
3735
|
if (!json) {
|
|
3736
|
+
const list = targetChains.join(", ");
|
|
3627
3737
|
io2.out(
|
|
3628
|
-
`Requesting ${
|
|
3738
|
+
`Requesting ${targetChains.length === 1 ? "" : "parallel "}drip${targetChains.length === 1 ? "" : "s"} from ${faucetUrl} for ${list} \u2026` + (targetChains.includes("mina") ? " (mina settles slowly; this can take ~2 minutes)" : "")
|
|
3629
3739
|
);
|
|
3630
3740
|
}
|
|
3631
|
-
const
|
|
3632
|
-
|
|
3633
|
-
|
|
3741
|
+
const singleChain = targetChains.length === 1;
|
|
3742
|
+
const drips = targetChains.map(async (chain) => {
|
|
3743
|
+
const address = (singleChain ? addressFlag : void 0) ?? addresses[chain];
|
|
3744
|
+
if (!address) {
|
|
3745
|
+
return {
|
|
3746
|
+
chain,
|
|
3747
|
+
funded: false,
|
|
3748
|
+
address: null,
|
|
3749
|
+
error: `no ${chain} address could be derived for this identity` + (chain === "mina" ? " (install the optional mina-signer dependency)" : "")
|
|
3750
|
+
};
|
|
3751
|
+
}
|
|
3752
|
+
const started = Date.now();
|
|
3753
|
+
try {
|
|
3754
|
+
const { response } = await client.fundWallet(faucetUrl, address, chain, {
|
|
3755
|
+
timeout: timeoutFor(chain),
|
|
3756
|
+
...deps.fetchImpl ? { fetchImpl: deps.fetchImpl } : {}
|
|
3757
|
+
});
|
|
3758
|
+
return {
|
|
3759
|
+
chain,
|
|
3760
|
+
funded: true,
|
|
3761
|
+
address,
|
|
3762
|
+
response,
|
|
3763
|
+
elapsedMs: Date.now() - started
|
|
3764
|
+
};
|
|
3765
|
+
} catch (err) {
|
|
3766
|
+
return {
|
|
3767
|
+
chain,
|
|
3768
|
+
funded: false,
|
|
3769
|
+
address,
|
|
3770
|
+
error: err instanceof Error ? err.message : String(err),
|
|
3771
|
+
elapsedMs: Date.now() - started
|
|
3772
|
+
};
|
|
3773
|
+
}
|
|
3634
3774
|
});
|
|
3775
|
+
const results = await Promise.all(drips);
|
|
3776
|
+
const allFunded = results.every((r) => r.funded);
|
|
3635
3777
|
if (json) {
|
|
3636
3778
|
io2.emitJson({
|
|
3637
3779
|
command: "fund",
|
|
3638
3780
|
identity,
|
|
3639
|
-
funded:
|
|
3781
|
+
funded: allFunded,
|
|
3640
3782
|
network: effectiveNetwork ?? null,
|
|
3641
|
-
chain,
|
|
3642
|
-
address,
|
|
3643
3783
|
faucetUrl,
|
|
3644
|
-
|
|
3784
|
+
results,
|
|
3645
3785
|
...inferredDevnet ? { inferredDevnetFrom: devnetOrigin } : {}
|
|
3646
3786
|
});
|
|
3647
|
-
return 0;
|
|
3787
|
+
return allFunded ? 0 : 1;
|
|
3788
|
+
}
|
|
3789
|
+
for (const r of results) {
|
|
3790
|
+
const label = r.chain.padEnd(6);
|
|
3791
|
+
const addr = r.address ? ` \u2192 ${r.address}` : "";
|
|
3792
|
+
if (r.funded) {
|
|
3793
|
+
const slow = r.elapsedMs !== void 0 && r.elapsedMs >= 5e3;
|
|
3794
|
+
const time = slow ? ` (${Math.round(r.elapsedMs / 1e3)}s)` : "";
|
|
3795
|
+
io2.out(` ${label} \u2713 funded (${NATIVE_COIN[r.chain]} + USDC)${addr}${time}`);
|
|
3796
|
+
} else {
|
|
3797
|
+
io2.out(` ${label} \u2717${addr} \u2014 ${r.error ?? "failed"}`);
|
|
3798
|
+
}
|
|
3648
3799
|
}
|
|
3649
|
-
io2.out(`Faucet drip succeeded: ${chain} \u2192 ${address}`);
|
|
3650
3800
|
io2.out(renderIdentityLine(identity));
|
|
3651
3801
|
io2.out("Re-check with `rig balance` (a drip can take a few blocks to land).");
|
|
3652
|
-
return 0;
|
|
3802
|
+
return allFunded ? 0 : 1;
|
|
3653
3803
|
} catch (err) {
|
|
3654
3804
|
return emitCliError(io2, json, "fund", err);
|
|
3655
3805
|
}
|
|
@@ -4093,6 +4243,82 @@ async function defaultReadSecretLine(prompt, isInteractive) {
|
|
|
4093
4243
|
// src/cli/init.ts
|
|
4094
4244
|
import { basename as basename2 } from "path";
|
|
4095
4245
|
import { parseArgs as parseArgs11 } from "util";
|
|
4246
|
+
|
|
4247
|
+
// src/cli/git-author.ts
|
|
4248
|
+
var PROFILE_KIND = 0;
|
|
4249
|
+
var DEFAULT_PROFILE_TIMEOUT_MS = 3e3;
|
|
4250
|
+
var PROFILE_TIMEOUT_ENV = "RIG_PROFILE_TIMEOUT_MS";
|
|
4251
|
+
function isWebSocketRelay(url) {
|
|
4252
|
+
return /^wss?:\/\//i.test(url);
|
|
4253
|
+
}
|
|
4254
|
+
function displayNameFromKind0(content) {
|
|
4255
|
+
let parsed;
|
|
4256
|
+
try {
|
|
4257
|
+
parsed = JSON.parse(content);
|
|
4258
|
+
} catch {
|
|
4259
|
+
return void 0;
|
|
4260
|
+
}
|
|
4261
|
+
if (typeof parsed !== "object" || parsed === null) return void 0;
|
|
4262
|
+
const fields = parsed;
|
|
4263
|
+
for (const key of ["display_name", "name"]) {
|
|
4264
|
+
const value = fields[key];
|
|
4265
|
+
if (typeof value === "string" && value.trim() !== "") return value.trim();
|
|
4266
|
+
}
|
|
4267
|
+
return void 0;
|
|
4268
|
+
}
|
|
4269
|
+
async function resolveGitAuthor(options) {
|
|
4270
|
+
const npub = hexToNpub(options.pubkey);
|
|
4271
|
+
const email = `${npub}@nostr`;
|
|
4272
|
+
const fallback = { name: npub, email, npub, source: "npub" };
|
|
4273
|
+
const { relayUrl } = options;
|
|
4274
|
+
if (relayUrl === void 0 || !isWebSocketRelay(relayUrl)) {
|
|
4275
|
+
return fallback;
|
|
4276
|
+
}
|
|
4277
|
+
const query = options.queryRelayImpl ?? queryRelay;
|
|
4278
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_PROFILE_TIMEOUT_MS;
|
|
4279
|
+
const factory = options.webSocketFactory ?? defaultWebSocketFactory2;
|
|
4280
|
+
try {
|
|
4281
|
+
const events = await query(
|
|
4282
|
+
relayUrl,
|
|
4283
|
+
{ kinds: [PROFILE_KIND], authors: [options.pubkey], limit: 20 },
|
|
4284
|
+
timeoutMs,
|
|
4285
|
+
factory
|
|
4286
|
+
);
|
|
4287
|
+
let latest;
|
|
4288
|
+
for (const event of events) {
|
|
4289
|
+
if (event.kind !== PROFILE_KIND) continue;
|
|
4290
|
+
if (event.pubkey !== options.pubkey) continue;
|
|
4291
|
+
if (!latest || event.created_at > latest.created_at) {
|
|
4292
|
+
latest = { created_at: event.created_at, content: event.content };
|
|
4293
|
+
}
|
|
4294
|
+
}
|
|
4295
|
+
if (latest) {
|
|
4296
|
+
const name = displayNameFromKind0(latest.content);
|
|
4297
|
+
if (name !== void 0) {
|
|
4298
|
+
return { name, email, npub, source: "profile" };
|
|
4299
|
+
}
|
|
4300
|
+
}
|
|
4301
|
+
} catch {
|
|
4302
|
+
}
|
|
4303
|
+
return fallback;
|
|
4304
|
+
}
|
|
4305
|
+
function profileTimeoutFromEnv(env) {
|
|
4306
|
+
const raw = env[PROFILE_TIMEOUT_ENV]?.trim();
|
|
4307
|
+
if (!raw) return void 0;
|
|
4308
|
+
const ms = Number.parseInt(raw, 10);
|
|
4309
|
+
return Number.isFinite(ms) && ms > 0 ? ms : void 0;
|
|
4310
|
+
}
|
|
4311
|
+
function defaultWebSocketFactory2(url) {
|
|
4312
|
+
const ctor = globalThis.WebSocket;
|
|
4313
|
+
if (!ctor) {
|
|
4314
|
+
throw new Error(
|
|
4315
|
+
"No global WebSocket constructor (Node >= 22 required) for the kind:0 read"
|
|
4316
|
+
);
|
|
4317
|
+
}
|
|
4318
|
+
return new ctor(url);
|
|
4319
|
+
}
|
|
4320
|
+
|
|
4321
|
+
// src/cli/init.ts
|
|
4096
4322
|
var INIT_USAGE = `Usage: rig init [options]
|
|
4097
4323
|
|
|
4098
4324
|
Set up the current git repository for rig (one-shot, idempotent, free):
|
|
@@ -4101,19 +4327,35 @@ keystore/config), then writes toon.repoid and toon.owner to the repo's
|
|
|
4101
4327
|
LOCAL git config. Re-running updates and reports; it never errors on an
|
|
4102
4328
|
already-initialized repo. The seed phrase is never written anywhere.
|
|
4103
4329
|
|
|
4330
|
+
It also sets the repo's LOCAL git commit-author from your nostr identity
|
|
4331
|
+
(never --global) so \`rig commit\`/\`git commit\` work out of the box and every
|
|
4332
|
+
commit is attributed to the signer: user.email = <npub>@nostr, user.name =
|
|
4333
|
+
your kind:0 profile display name when published (read best-effort from a
|
|
4334
|
+
relay, latest-wins) else the npub. Re-running refreshes the name from a
|
|
4335
|
+
now-readable profile.
|
|
4336
|
+
|
|
4104
4337
|
The follow-up step is adding a relay: \`rig remote add origin <relay-url>\`
|
|
4105
4338
|
(a real git remote \u2014 \`git remote -v\` shows it). A deprecated v0.1
|
|
4106
4339
|
\`git config toon.relay\` is migrated to the origin remote automatically
|
|
4107
4340
|
when no origin exists (the old key stays readable and is removed in v0.3).
|
|
4108
4341
|
|
|
4109
|
-
When
|
|
4110
|
-
|
|
4111
|
-
does it non-interactively
|
|
4112
|
-
|
|
4342
|
+
When the directory is NOT inside a git repository, init does not dead-end: in
|
|
4343
|
+
a terminal it offers to create one (\`Initialize a git repository here?
|
|
4344
|
+
[y/N]\`), and \`--git-init\` does it non-interactively. Likewise, when NO
|
|
4345
|
+
identity resolves it offers to generate one (\`Create a new identity now?
|
|
4346
|
+
[y/N]\`), and \`--generate-identity\` does it non-interactively (equivalent to
|
|
4347
|
+
\`rig identity create\` \u2014 the phrase is shown once to back up). Nothing \u2014 repo
|
|
4348
|
+
or identity \u2014 is ever created without your yes. \`--git-init
|
|
4349
|
+
--generate-identity\` is a fully non-interactive fresh setup.
|
|
4113
4350
|
|
|
4114
4351
|
Options:
|
|
4115
4352
|
--repo-id <id> repository id / NIP-34 d-tag (default: the existing
|
|
4116
4353
|
toon.repoid, then the repo directory basename)
|
|
4354
|
+
--git-init when the cwd is not a git repo, run \`git init\` here
|
|
4355
|
+
first, then proceed (no prompt)
|
|
4356
|
+
--relay <url> relay to read your kind:0 profile from for the git
|
|
4357
|
+
author name (default: origin/toon.relay, then the
|
|
4358
|
+
genesis seed; skipped if none is resolvable)
|
|
4117
4359
|
--generate-identity when no identity resolves, mint a fresh one (no prompt)
|
|
4118
4360
|
--json machine-readable report
|
|
4119
4361
|
-h, --help show this help`;
|
|
@@ -4122,6 +4364,8 @@ function parseInitArgs(args) {
|
|
|
4122
4364
|
args,
|
|
4123
4365
|
options: {
|
|
4124
4366
|
"repo-id": { type: "string" },
|
|
4367
|
+
"git-init": { type: "boolean", default: false },
|
|
4368
|
+
relay: { type: "string" },
|
|
4125
4369
|
"generate-identity": { type: "boolean", default: false },
|
|
4126
4370
|
json: { type: "boolean", default: false },
|
|
4127
4371
|
help: { type: "boolean", short: "h", default: false }
|
|
@@ -4132,6 +4376,7 @@ function parseInitArgs(args) {
|
|
|
4132
4376
|
throw new Error(`rig init takes no positional arguments`);
|
|
4133
4377
|
}
|
|
4134
4378
|
const flags = {
|
|
4379
|
+
gitInit: values["git-init"] ?? false,
|
|
4135
4380
|
generateIdentity: values["generate-identity"] ?? false,
|
|
4136
4381
|
json: values.json ?? false,
|
|
4137
4382
|
help: values.help ?? false
|
|
@@ -4141,8 +4386,46 @@ function parseInitArgs(args) {
|
|
|
4141
4386
|
if (repoId.trim() === "") throw new Error("--repo-id must not be empty");
|
|
4142
4387
|
flags.repoId = repoId;
|
|
4143
4388
|
}
|
|
4389
|
+
const relay = values.relay;
|
|
4390
|
+
if (relay !== void 0) {
|
|
4391
|
+
if (relay.trim() === "") throw new Error("--relay must not be empty");
|
|
4392
|
+
flags.relay = relay.trim();
|
|
4393
|
+
}
|
|
4144
4394
|
return flags;
|
|
4145
4395
|
}
|
|
4396
|
+
function isWebSocketRelay2(url) {
|
|
4397
|
+
return /^wss?:\/\//i.test(url);
|
|
4398
|
+
}
|
|
4399
|
+
async function resolveProfileRelay(flagRelay, originRelay, toonRelays) {
|
|
4400
|
+
const candidates = [
|
|
4401
|
+
flagRelay,
|
|
4402
|
+
originRelay,
|
|
4403
|
+
...toonRelays
|
|
4404
|
+
].filter((u) => u !== void 0 && isWebSocketRelay2(u));
|
|
4405
|
+
if (candidates[0] !== void 0) return candidates[0];
|
|
4406
|
+
try {
|
|
4407
|
+
const { loadGenesisSeed } = await import("../network-bootstrap-WNSHRC5P.js");
|
|
4408
|
+
const seed = loadGenesisSeed();
|
|
4409
|
+
if (seed?.relayUrl && isWebSocketRelay2(seed.relayUrl)) return seed.relayUrl;
|
|
4410
|
+
} catch {
|
|
4411
|
+
}
|
|
4412
|
+
return void 0;
|
|
4413
|
+
}
|
|
4414
|
+
async function resolveOrInitGitRepo(deps, flags) {
|
|
4415
|
+
const { io: io2 } = deps;
|
|
4416
|
+
try {
|
|
4417
|
+
return { repoRoot: await resolveRepoRoot(deps.cwd), initialized: false };
|
|
4418
|
+
} catch {
|
|
4419
|
+
let doInit = flags.gitInit;
|
|
4420
|
+
if (!doInit && io2.isInteractive && !flags.json) {
|
|
4421
|
+
io2.err("Not a git repository \u2014 rig keeps its config and objects in one.");
|
|
4422
|
+
doInit = await io2.confirm("Initialize a git repository here? [y/N] ");
|
|
4423
|
+
}
|
|
4424
|
+
if (!doInit) throw new NotAGitRepositoryError(deps.cwd);
|
|
4425
|
+
await initGitRepository(deps.cwd);
|
|
4426
|
+
return { repoRoot: await resolveRepoRoot(deps.cwd), initialized: true };
|
|
4427
|
+
}
|
|
4428
|
+
}
|
|
4146
4429
|
async function resolveOrGenerateIdentity(deps, flags) {
|
|
4147
4430
|
const { io: io2, env } = deps;
|
|
4148
4431
|
const resolve2 = deps.resolveIdentityImpl ?? resolveIdentity;
|
|
@@ -4188,12 +4471,7 @@ async function runInit(args, deps) {
|
|
|
4188
4471
|
return 0;
|
|
4189
4472
|
}
|
|
4190
4473
|
try {
|
|
4191
|
-
|
|
4192
|
-
try {
|
|
4193
|
-
repoRoot = await resolveRepoRoot(deps.cwd);
|
|
4194
|
-
} catch {
|
|
4195
|
-
throw new NotAGitRepositoryError(deps.cwd);
|
|
4196
|
-
}
|
|
4474
|
+
const { repoRoot, initialized: initializedGitRepo } = await resolveOrInitGitRepo(deps, flags);
|
|
4197
4475
|
const { identity, generated } = await resolveOrGenerateIdentity(deps, flags);
|
|
4198
4476
|
const existing = await readToonConfig(repoRoot);
|
|
4199
4477
|
const repoId = flags.repoId ?? existing.repoId ?? basename2(repoRoot);
|
|
@@ -4212,10 +4490,26 @@ async function runInit(args, deps) {
|
|
|
4212
4490
|
}
|
|
4213
4491
|
const origin = remotes.find((r) => r.name === "origin");
|
|
4214
4492
|
const originRelay = origin !== void 0 && origin.urls.length === 1 && isRelayUrl(origin.urls[0]) ? origin.urls[0] : void 0;
|
|
4493
|
+
const profileRelay = await resolveProfileRelay(
|
|
4494
|
+
flags.relay,
|
|
4495
|
+
originRelay,
|
|
4496
|
+
existing.relays
|
|
4497
|
+
);
|
|
4498
|
+
const resolveAuthor = deps.resolveGitAuthorImpl ?? resolveGitAuthor;
|
|
4499
|
+
const gitAuthor = await resolveAuthor({
|
|
4500
|
+
pubkey: identity.pubkey,
|
|
4501
|
+
relayUrl: profileRelay,
|
|
4502
|
+
...profileTimeoutFromEnv(deps.env) !== void 0 ? { timeoutMs: profileTimeoutFromEnv(deps.env) } : {}
|
|
4503
|
+
});
|
|
4504
|
+
await setGitAuthor(repoRoot, {
|
|
4505
|
+
name: gitAuthor.name,
|
|
4506
|
+
email: gitAuthor.email
|
|
4507
|
+
});
|
|
4215
4508
|
if (flags.json) {
|
|
4216
4509
|
const output = {
|
|
4217
4510
|
command: "init",
|
|
4218
4511
|
repoRoot,
|
|
4512
|
+
initializedGitRepo,
|
|
4219
4513
|
repoId,
|
|
4220
4514
|
owner: identity.pubkey,
|
|
4221
4515
|
identity: {
|
|
@@ -4228,6 +4522,11 @@ async function runInit(args, deps) {
|
|
|
4228
4522
|
remotes,
|
|
4229
4523
|
origin: originRelay ?? null,
|
|
4230
4524
|
migratedToonRelay,
|
|
4525
|
+
gitAuthor: {
|
|
4526
|
+
name: gitAuthor.name,
|
|
4527
|
+
email: gitAuthor.email,
|
|
4528
|
+
source: gitAuthor.source
|
|
4529
|
+
},
|
|
4231
4530
|
changed,
|
|
4232
4531
|
...generated ? {
|
|
4233
4532
|
generatedIdentity: {
|
|
@@ -4251,6 +4550,7 @@ async function runInit(args, deps) {
|
|
|
4251
4550
|
for (const line of createdIdentityBanner(generated)) io2.out(line);
|
|
4252
4551
|
if (generated.shadowedBy) io2.err(shadowNote(generated.shadowedBy));
|
|
4253
4552
|
}
|
|
4553
|
+
if (initializedGitRepo) io2.out(`Created a git repository at ${repoRoot}`);
|
|
4254
4554
|
io2.out(`Initialized rig for ${repoRoot}`);
|
|
4255
4555
|
io2.out(renderIdentityLine(identity));
|
|
4256
4556
|
io2.out(
|
|
@@ -4259,6 +4559,9 @@ async function runInit(args, deps) {
|
|
|
4259
4559
|
io2.out(
|
|
4260
4560
|
` toon.owner = ${identity.pubkey}` + (changed.owner ? "" : " (unchanged)") + (existing.owner && changed.owner ? ` (was ${existing.owner})` : "")
|
|
4261
4561
|
);
|
|
4562
|
+
io2.out(
|
|
4563
|
+
`Git author: ${gitAuthor.name} <${gitAuthor.email}> (from ${gitAuthor.source === "profile" ? "nostr profile" : "npub"})`
|
|
4564
|
+
);
|
|
4262
4565
|
if (originRelay !== void 0) {
|
|
4263
4566
|
io2.out(
|
|
4264
4567
|
` origin = ${originRelay}` + (migratedToonRelay ? " (migrated from git config toon.relay)" : "")
|