@cogcoin/client 1.0.1 → 1.0.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 +2 -1
- package/dist/bitcoind/indexer-daemon.d.ts +3 -0
- package/dist/bitcoind/indexer-daemon.js +58 -8
- package/dist/bitcoind/retryable-rpc.js +3 -0
- package/dist/bitcoind/service.d.ts +1 -0
- package/dist/bitcoind/service.js +31 -9
- package/dist/cli/commands/mining-admin.js +9 -0
- package/dist/cli/commands/update.d.ts +2 -0
- package/dist/cli/commands/update.js +101 -0
- package/dist/cli/context.js +31 -0
- package/dist/cli/mining-format.js +28 -0
- package/dist/cli/mining-json.js +6 -0
- package/dist/cli/output.js +50 -2
- package/dist/cli/parse.d.ts +1 -1
- package/dist/cli/parse.js +5 -0
- package/dist/cli/prompt.js +109 -0
- package/dist/cli/read-json.d.ts +13 -0
- package/dist/cli/read-json.js +17 -0
- package/dist/cli/runner.js +4 -0
- package/dist/cli/types.d.ts +6 -1
- package/dist/cli/update-notifier.js +7 -222
- package/dist/cli/update-service.d.ts +44 -0
- package/dist/cli/update-service.js +218 -0
- package/dist/client/initialization.js +5 -0
- package/dist/wallet/lifecycle.d.ts +10 -0
- package/dist/wallet/lifecycle.js +6 -0
- package/dist/wallet/mining/config.js +13 -3
- package/dist/wallet/mining/control.d.ts +2 -1
- package/dist/wallet/mining/control.js +143 -19
- package/dist/wallet/mining/index.d.ts +1 -1
- package/dist/wallet/mining/provider-model.d.ts +30 -0
- package/dist/wallet/mining/provider-model.js +134 -0
- package/dist/wallet/mining/runner.d.ts +98 -3
- package/dist/wallet/mining/runner.js +493 -95
- package/dist/wallet/mining/runtime-artifacts.js +1 -0
- package/dist/wallet/mining/sentences.d.ts +2 -2
- package/dist/wallet/mining/sentences.js +25 -2
- package/dist/wallet/mining/types.d.ts +9 -1
- package/dist/wallet/mining/visualizer.js +28 -5
- package/dist/wallet/read/context.js +3 -0
- package/dist/wallet/reset.js +1 -0
- package/dist/wallet/tx/anchor.js +1 -0
- package/dist/wallet/tx/bitcoin-transfer.js +1 -0
- package/dist/wallet/tx/cog.js +3 -0
- package/dist/wallet/tx/domain-admin.js +1 -0
- package/dist/wallet/tx/domain-market.js +3 -0
- package/dist/wallet/tx/field.js +1 -0
- package/dist/wallet/tx/register.js +1 -0
- package/dist/wallet/tx/reputation.js +1 -0
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# `@cogcoin/client`
|
|
2
2
|
|
|
3
|
-
`@cogcoin/client@1.0.
|
|
3
|
+
`@cogcoin/client@1.0.2` is the reference Cogcoin client package for applications that want a local wallet, durable SQLite-backed state, and a managed Bitcoin Core integration around `@cogcoin/indexer`. It publishes the reusable client APIs, the SQLite adapter, the managed `bitcoind` integration, and the first-party `cogcoin` CLI in one package.
|
|
4
4
|
|
|
5
5
|
Use Node 22 or newer.
|
|
6
6
|
|
|
@@ -130,6 +130,7 @@ Managed node subpath:
|
|
|
130
130
|
|
|
131
131
|
The installed `cogcoin` command covers the first-party local wallet and node workflow:
|
|
132
132
|
|
|
133
|
+
- update commands such as `update` to compare the current CLI version with the latest npm release and install it
|
|
133
134
|
- wallet lifecycle commands such as `init`, `restore`, `wallet delete`, `wallet show-mnemonic`, and `repair`
|
|
134
135
|
- sync and service commands such as `status`, `sync`, `follow`, `bitcoin start`, `bitcoin stop`, `bitcoin status`, `indexer start`, `indexer stop`, and `indexer status`
|
|
135
136
|
- domain and field commands such as `register`, `anchor`, `show`, `domains`, `fields`, `buy`, `sell`, and `transfer`
|
|
@@ -84,6 +84,7 @@ export interface CoherentIndexerSnapshotLease {
|
|
|
84
84
|
payload: IndexerSnapshotPayload;
|
|
85
85
|
status: ManagedIndexerDaemonStatus;
|
|
86
86
|
}
|
|
87
|
+
type ManagedIndexerDaemonServiceLifetime = "persistent" | "ephemeral";
|
|
87
88
|
export declare function stopIndexerDaemonServiceWithLockHeld(options: {
|
|
88
89
|
dataDir: string;
|
|
89
90
|
walletRootId?: string;
|
|
@@ -104,6 +105,8 @@ export declare function attachOrStartIndexerDaemon(options: {
|
|
|
104
105
|
databasePath: string;
|
|
105
106
|
walletRootId?: string;
|
|
106
107
|
startupTimeoutMs?: number;
|
|
108
|
+
shutdownTimeoutMs?: number;
|
|
109
|
+
serviceLifetime?: ManagedIndexerDaemonServiceLifetime;
|
|
107
110
|
}): Promise<IndexerDaemonClient>;
|
|
108
111
|
export declare function stopIndexerDaemonService(options: {
|
|
109
112
|
dataDir: string;
|
|
@@ -80,7 +80,8 @@ export async function stopIndexerDaemonServiceWithLockHeld(options) {
|
|
|
80
80
|
walletRootId,
|
|
81
81
|
};
|
|
82
82
|
}
|
|
83
|
-
function createIndexerDaemonClient(socketPath) {
|
|
83
|
+
function createIndexerDaemonClient(socketPath, closeOptions = null) {
|
|
84
|
+
let closed = false;
|
|
84
85
|
async function sendRequest(request) {
|
|
85
86
|
return new Promise((resolve, reject) => {
|
|
86
87
|
const socket = net.createConnection(socketPath);
|
|
@@ -181,7 +182,18 @@ function createIndexerDaemonClient(socketPath) {
|
|
|
181
182
|
});
|
|
182
183
|
},
|
|
183
184
|
async close() {
|
|
184
|
-
|
|
185
|
+
if (closed) {
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
closed = true;
|
|
189
|
+
if (closeOptions === null || closeOptions.serviceLifetime !== "ephemeral" || closeOptions.ownership === "attached") {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
await stopIndexerDaemonService({
|
|
193
|
+
dataDir: closeOptions.dataDir,
|
|
194
|
+
walletRootId: closeOptions.walletRootId,
|
|
195
|
+
shutdownTimeoutMs: closeOptions.shutdownTimeoutMs,
|
|
196
|
+
});
|
|
185
197
|
},
|
|
186
198
|
};
|
|
187
199
|
}
|
|
@@ -308,7 +320,8 @@ async function waitForIndexerDaemon(dataDir, walletRootId, timeoutMs) {
|
|
|
308
320
|
while (Date.now() < deadline) {
|
|
309
321
|
const probe = await probeIndexerDaemonAtSocket(paths.indexerDaemonSocketPath, walletRootId);
|
|
310
322
|
if (probe.compatibility === "compatible" && probe.client !== null) {
|
|
311
|
-
|
|
323
|
+
await probe.client.close().catch(() => undefined);
|
|
324
|
+
return;
|
|
312
325
|
}
|
|
313
326
|
if (probe.compatibility !== "unreachable") {
|
|
314
327
|
throw new Error(probe.error ?? "indexer_daemon_protocol_error");
|
|
@@ -358,6 +371,7 @@ export async function attachOrStartIndexerDaemon(options) {
|
|
|
358
371
|
const walletRootId = options.walletRootId ?? UNINITIALIZED_WALLET_ROOT_ID;
|
|
359
372
|
const paths = resolveManagedServicePaths(options.dataDir, walletRootId);
|
|
360
373
|
const startupTimeoutMs = options.startupTimeoutMs ?? DEFAULT_STARTUP_TIMEOUT_MS;
|
|
374
|
+
const serviceLifetime = options.serviceLifetime ?? "persistent";
|
|
361
375
|
const existingProbe = await probeIndexerDaemonAtSocket(paths.indexerDaemonSocketPath, walletRootId);
|
|
362
376
|
if (existingProbe.compatibility === "compatible" && existingProbe.client !== null) {
|
|
363
377
|
return existingProbe.client;
|
|
@@ -382,17 +396,46 @@ export async function attachOrStartIndexerDaemon(options) {
|
|
|
382
396
|
}
|
|
383
397
|
await mkdir(paths.indexerServiceRoot, { recursive: true });
|
|
384
398
|
const daemonEntryPath = fileURLToPath(new URL("./indexer-daemon-main.js", import.meta.url));
|
|
399
|
+
const spawnOptions = serviceLifetime === "ephemeral"
|
|
400
|
+
? {
|
|
401
|
+
stdio: "ignore",
|
|
402
|
+
}
|
|
403
|
+
: {
|
|
404
|
+
detached: true,
|
|
405
|
+
stdio: "ignore",
|
|
406
|
+
};
|
|
385
407
|
const child = spawn(process.execPath, [
|
|
386
408
|
daemonEntryPath,
|
|
387
409
|
`--data-dir=${options.dataDir}`,
|
|
388
410
|
`--database-path=${options.databasePath}`,
|
|
389
411
|
`--wallet-root-id=${walletRootId}`,
|
|
390
412
|
], {
|
|
391
|
-
|
|
392
|
-
|
|
413
|
+
...spawnOptions,
|
|
414
|
+
});
|
|
415
|
+
if (serviceLifetime !== "ephemeral") {
|
|
416
|
+
child.unref();
|
|
417
|
+
}
|
|
418
|
+
try {
|
|
419
|
+
await waitForIndexerDaemon(options.dataDir, walletRootId, startupTimeoutMs);
|
|
420
|
+
}
|
|
421
|
+
catch (error) {
|
|
422
|
+
if (child.pid !== undefined) {
|
|
423
|
+
try {
|
|
424
|
+
process.kill(child.pid, "SIGTERM");
|
|
425
|
+
}
|
|
426
|
+
catch {
|
|
427
|
+
// ignore shutdown failures while unwinding startup errors
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
throw error;
|
|
431
|
+
}
|
|
432
|
+
return createIndexerDaemonClient(paths.indexerDaemonSocketPath, {
|
|
433
|
+
dataDir: options.dataDir,
|
|
434
|
+
walletRootId,
|
|
435
|
+
serviceLifetime,
|
|
436
|
+
ownership: "started",
|
|
437
|
+
shutdownTimeoutMs: options.shutdownTimeoutMs,
|
|
393
438
|
});
|
|
394
|
-
child.unref();
|
|
395
|
-
return await waitForIndexerDaemon(options.dataDir, walletRootId, startupTimeoutMs);
|
|
396
439
|
}
|
|
397
440
|
finally {
|
|
398
441
|
await lock.release();
|
|
@@ -400,7 +443,14 @@ export async function attachOrStartIndexerDaemon(options) {
|
|
|
400
443
|
}
|
|
401
444
|
catch (error) {
|
|
402
445
|
if (error instanceof FileLockBusyError) {
|
|
403
|
-
|
|
446
|
+
await waitForIndexerDaemon(options.dataDir, walletRootId, startupTimeoutMs);
|
|
447
|
+
return createIndexerDaemonClient(paths.indexerDaemonSocketPath, {
|
|
448
|
+
dataDir: options.dataDir,
|
|
449
|
+
walletRootId,
|
|
450
|
+
serviceLifetime,
|
|
451
|
+
ownership: "attached",
|
|
452
|
+
shutdownTimeoutMs: options.shutdownTimeoutMs,
|
|
453
|
+
});
|
|
404
454
|
}
|
|
405
455
|
throw error;
|
|
406
456
|
}
|
|
@@ -19,6 +19,9 @@ export function isRetryableManagedRpcError(error) {
|
|
|
19
19
|
if (message === "bitcoind_rpc_timeout") {
|
|
20
20
|
return true;
|
|
21
21
|
}
|
|
22
|
+
if (/^bitcoind_rpc_[^_]+_-28(?:_|$)/.test(message)) {
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
22
25
|
if (message.startsWith("The managed Bitcoin RPC request to ")) {
|
|
23
26
|
return message.includes(" failed");
|
|
24
27
|
}
|
|
@@ -24,6 +24,7 @@ type ManagedBitcoindServiceOptions = Pick<InternalManagedBitcoindOptions, "dataD
|
|
|
24
24
|
getblockArchivePath?: string | null;
|
|
25
25
|
getblockArchiveEndHeight?: number | null;
|
|
26
26
|
getblockArchiveSha256?: string | null;
|
|
27
|
+
serviceLifetime?: "persistent" | "ephemeral";
|
|
27
28
|
};
|
|
28
29
|
export type ManagedBitcoindServiceCompatibility = "compatible" | "service-version-mismatch" | "wallet-root-mismatch" | "runtime-mismatch" | "unreachable" | "protocol-error";
|
|
29
30
|
export interface ManagedBitcoindServiceProbeResult {
|
package/dist/bitcoind/service.js
CHANGED
|
@@ -681,9 +681,10 @@ async function refreshManagedBitcoindStatus(status, paths, options) {
|
|
|
681
681
|
return nextStatus;
|
|
682
682
|
}
|
|
683
683
|
}
|
|
684
|
-
function createNodeHandle(status, paths, options) {
|
|
684
|
+
function createNodeHandle(status, paths, options, ownership) {
|
|
685
685
|
let currentStatus = status;
|
|
686
686
|
const rpc = createRpcClient(currentStatus.rpc);
|
|
687
|
+
let stopped = false;
|
|
687
688
|
return {
|
|
688
689
|
rpc: currentStatus.rpc,
|
|
689
690
|
zmq: currentStatus.zmq,
|
|
@@ -706,9 +707,20 @@ function createNodeHandle(status, paths, options) {
|
|
|
706
707
|
return currentStatus;
|
|
707
708
|
},
|
|
708
709
|
async stop() {
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
710
|
+
if (stopped) {
|
|
711
|
+
return;
|
|
712
|
+
}
|
|
713
|
+
stopped = true;
|
|
714
|
+
if (options.serviceLifetime !== "ephemeral" || ownership === "attached") {
|
|
715
|
+
// Public managed clients detach from persistent services, and ephemeral
|
|
716
|
+
// attach callers must not shut down services they did not launch.
|
|
717
|
+
return;
|
|
718
|
+
}
|
|
719
|
+
await stopManagedBitcoindService({
|
|
720
|
+
dataDir: currentStatus.dataDir,
|
|
721
|
+
walletRootId: currentStatus.walletRootId,
|
|
722
|
+
shutdownTimeoutMs: options.shutdownTimeoutMs,
|
|
723
|
+
});
|
|
712
724
|
},
|
|
713
725
|
};
|
|
714
726
|
}
|
|
@@ -720,7 +732,7 @@ async function tryAttachExistingManagedBitcoindService(options) {
|
|
|
720
732
|
return null;
|
|
721
733
|
}
|
|
722
734
|
const refreshed = await refreshManagedBitcoindStatus(probe.status, paths, options);
|
|
723
|
-
return createNodeHandle(refreshed, paths, options);
|
|
735
|
+
return createNodeHandle(refreshed, paths, options, "attached");
|
|
724
736
|
}
|
|
725
737
|
async function waitForManagedBitcoindService(options, timeoutMs) {
|
|
726
738
|
const deadline = Date.now() + timeoutMs;
|
|
@@ -765,6 +777,7 @@ export async function attachOrStartManagedBitcoindService(options) {
|
|
|
765
777
|
const resolvedOptions = {
|
|
766
778
|
...options,
|
|
767
779
|
dataDir: options.dataDir,
|
|
780
|
+
serviceLifetime: options.serviceLifetime ?? "persistent",
|
|
768
781
|
walletRootId: options.walletRootId ?? UNINITIALIZED_WALLET_ROOT_ID,
|
|
769
782
|
};
|
|
770
783
|
const startupTimeoutMs = resolvedOptions.startupTimeoutMs ?? DEFAULT_STARTUP_TIMEOUT_MS;
|
|
@@ -815,11 +828,20 @@ export async function attachOrStartManagedBitcoindService(options) {
|
|
|
815
828
|
port: runtimeConfig.zmqPort,
|
|
816
829
|
pollIntervalMs: startOptions.pollIntervalMs ?? 15_000,
|
|
817
830
|
};
|
|
831
|
+
const spawnOptions = startOptions.serviceLifetime === "ephemeral"
|
|
832
|
+
? {
|
|
833
|
+
stdio: "ignore",
|
|
834
|
+
}
|
|
835
|
+
: {
|
|
836
|
+
detached: true,
|
|
837
|
+
stdio: "ignore",
|
|
838
|
+
};
|
|
818
839
|
const child = spawn(bitcoindPath, buildManagedServiceArgs(startOptions, runtimeConfig), {
|
|
819
|
-
|
|
820
|
-
stdio: "ignore",
|
|
840
|
+
...spawnOptions,
|
|
821
841
|
});
|
|
822
|
-
|
|
842
|
+
if (startOptions.serviceLifetime !== "ephemeral") {
|
|
843
|
+
child.unref();
|
|
844
|
+
}
|
|
823
845
|
const rpc = createRpcClient(rpcConfig);
|
|
824
846
|
try {
|
|
825
847
|
await waitForRpcReady(rpc, rpcConfig.cookieFile, startOptions.chain, startupTimeoutMs);
|
|
@@ -876,7 +898,7 @@ export async function attachOrStartManagedBitcoindService(options) {
|
|
|
876
898
|
});
|
|
877
899
|
}
|
|
878
900
|
await writeBitcoindStatus(paths, status);
|
|
879
|
-
return createNodeHandle(status, paths, resolvedOptions);
|
|
901
|
+
return createNodeHandle(status, paths, resolvedOptions, "started");
|
|
880
902
|
}
|
|
881
903
|
finally {
|
|
882
904
|
await lock.release();
|
|
@@ -36,6 +36,15 @@ export async function runMiningAdminCommand(parsed, context) {
|
|
|
36
36
|
}
|
|
37
37
|
writeLine(context.stdout, "Built-in mining provider configured.");
|
|
38
38
|
writeLine(context.stdout, `Provider: ${view.provider.provider ?? "unknown"}`);
|
|
39
|
+
if (view.provider.modelId !== null) {
|
|
40
|
+
writeLine(context.stdout, `Selected model: ${view.provider.modelId}`);
|
|
41
|
+
}
|
|
42
|
+
if (view.provider.modelSelectionSource !== null) {
|
|
43
|
+
writeLine(context.stdout, `Selection source: ${view.provider.modelSelectionSource}`);
|
|
44
|
+
}
|
|
45
|
+
if (view.provider.estimatedDailyCostDisplay !== null) {
|
|
46
|
+
writeLine(context.stdout, `Approximate daily cost: ${view.provider.estimatedDailyCostDisplay}`);
|
|
47
|
+
}
|
|
39
48
|
for (const line of formatNextStepLines(nextSteps)) {
|
|
40
49
|
writeLine(context.stdout, line);
|
|
41
50
|
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { writeLine } from "../io.js";
|
|
2
|
+
import { createMutationSuccessEnvelope, describeCanonicalCommand, resolveStableMutationJsonSchema, writeHandledCliError, writeJsonValue, } from "../output.js";
|
|
3
|
+
import { CLI_INSTALL_COMMAND, EXPLICIT_UPDATE_CHECK_TIMEOUT_MS, applyUpdateCheckResult, compareSemver, createEmptyUpdateCheckCache, fetchLatestPublishedVersion, loadUpdateCheckCache, persistUpdateCheckCache, } from "../update-service.js";
|
|
4
|
+
function createUpdateResult(currentVersion, latestVersion, status, applied) {
|
|
5
|
+
return {
|
|
6
|
+
currentVersion,
|
|
7
|
+
latestVersion,
|
|
8
|
+
installCommand: CLI_INSTALL_COMMAND,
|
|
9
|
+
status,
|
|
10
|
+
applied,
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
function writeVersionSummary(context, currentVersion, latestVersion) {
|
|
14
|
+
writeLine(context.stdout, `Current version: ${currentVersion}`);
|
|
15
|
+
writeLine(context.stdout, `Latest version: ${latestVersion}`);
|
|
16
|
+
writeLine(context.stdout, `Run: ${CLI_INSTALL_COMMAND}`);
|
|
17
|
+
}
|
|
18
|
+
async function confirmApplyUpdate(context) {
|
|
19
|
+
const prompter = context.createPrompter();
|
|
20
|
+
if (!prompter.isInteractive) {
|
|
21
|
+
throw new Error("cli_update_requires_tty");
|
|
22
|
+
}
|
|
23
|
+
while (true) {
|
|
24
|
+
const answer = (await prompter.prompt("Install update now? [Y/n]: ")).trim().toLowerCase();
|
|
25
|
+
if (answer === "" || answer === "y" || answer === "yes") {
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
if (answer === "n" || answer === "no") {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
prompter.writeLine("Enter \"y\" to continue or \"n\" to cancel.");
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function writeSuccessJson(parsed, context, result) {
|
|
35
|
+
writeJsonValue(context.stdout, createMutationSuccessEnvelope(resolveStableMutationJsonSchema(parsed), describeCanonicalCommand(parsed), result.status, result));
|
|
36
|
+
return 0;
|
|
37
|
+
}
|
|
38
|
+
export async function runUpdateCommand(parsed, context) {
|
|
39
|
+
try {
|
|
40
|
+
const currentVersion = await context.readPackageVersion();
|
|
41
|
+
const cachePath = context.resolveUpdateCheckStatePath();
|
|
42
|
+
const now = context.now();
|
|
43
|
+
const cache = await loadUpdateCheckCache(cachePath) ?? createEmptyUpdateCheckCache();
|
|
44
|
+
const updateResult = await fetchLatestPublishedVersion(context.fetchImpl, {
|
|
45
|
+
timeoutMs: EXPLICIT_UPDATE_CHECK_TIMEOUT_MS,
|
|
46
|
+
});
|
|
47
|
+
if (updateResult.kind !== "success") {
|
|
48
|
+
throw new Error("cli_update_registry_unavailable");
|
|
49
|
+
}
|
|
50
|
+
await persistUpdateCheckCache(cachePath, applyUpdateCheckResult(cache, updateResult, now));
|
|
51
|
+
const latestVersion = updateResult.latestVersion;
|
|
52
|
+
const comparison = compareSemver(latestVersion, currentVersion);
|
|
53
|
+
if (comparison === null) {
|
|
54
|
+
throw new Error("cli_update_registry_unavailable");
|
|
55
|
+
}
|
|
56
|
+
if (comparison <= 0) {
|
|
57
|
+
const result = createUpdateResult(currentVersion, latestVersion, "up-to-date", false);
|
|
58
|
+
if (parsed.outputMode === "json") {
|
|
59
|
+
return writeSuccessJson(parsed, context, result);
|
|
60
|
+
}
|
|
61
|
+
writeVersionSummary(context, currentVersion, latestVersion);
|
|
62
|
+
writeLine(context.stdout, "Cogcoin is already up to date.");
|
|
63
|
+
return 0;
|
|
64
|
+
}
|
|
65
|
+
if (!parsed.assumeYes) {
|
|
66
|
+
if (parsed.outputMode !== "text") {
|
|
67
|
+
throw new Error("cli_update_requires_tty");
|
|
68
|
+
}
|
|
69
|
+
writeVersionSummary(context, currentVersion, latestVersion);
|
|
70
|
+
if (!(await confirmApplyUpdate(context))) {
|
|
71
|
+
writeLine(context.stdout, "Update canceled.");
|
|
72
|
+
return 0;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
else if (parsed.outputMode === "text") {
|
|
76
|
+
writeVersionSummary(context, currentVersion, latestVersion);
|
|
77
|
+
}
|
|
78
|
+
if (parsed.outputMode === "text") {
|
|
79
|
+
writeLine(context.stdout, "Installing update...");
|
|
80
|
+
}
|
|
81
|
+
await context.runGlobalClientUpdateInstall({
|
|
82
|
+
stdout: parsed.outputMode === "json" ? context.stderr : context.stdout,
|
|
83
|
+
stderr: context.stderr,
|
|
84
|
+
env: context.env,
|
|
85
|
+
});
|
|
86
|
+
const result = createUpdateResult(currentVersion, latestVersion, "updated", true);
|
|
87
|
+
if (parsed.outputMode === "json") {
|
|
88
|
+
return writeSuccessJson(parsed, context, result);
|
|
89
|
+
}
|
|
90
|
+
writeLine(context.stdout, "Update completed. The next cogcoin invocation will use the new install.");
|
|
91
|
+
return 0;
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
return writeHandledCliError({
|
|
95
|
+
parsed,
|
|
96
|
+
stdout: context.stdout,
|
|
97
|
+
stderr: context.stderr,
|
|
98
|
+
error,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
}
|
package/dist/cli/context.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
1
2
|
import { mkdir, readFile } from "node:fs/promises";
|
|
2
3
|
import { attachOrStartIndexerDaemon, probeIndexerDaemon, readObservedIndexerDaemonStatus, stopIndexerDaemonService, } from "../bitcoind/indexer-daemon.js";
|
|
3
4
|
import { createRpcClient } from "../bitcoind/node.js";
|
|
@@ -36,6 +37,35 @@ export async function readPackageVersionFromDisk() {
|
|
|
36
37
|
}
|
|
37
38
|
return "0.0.0";
|
|
38
39
|
}
|
|
40
|
+
async function runGlobalClientUpdateInstall(options) {
|
|
41
|
+
const binary = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
42
|
+
await new Promise((resolve, reject) => {
|
|
43
|
+
const child = spawn(binary, ["install", "-g", "@cogcoin/client"], {
|
|
44
|
+
env: options.env,
|
|
45
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
46
|
+
});
|
|
47
|
+
child.stdout?.on("data", (chunk) => {
|
|
48
|
+
options.stdout.write(typeof chunk === "string" ? chunk : chunk.toString("utf8"));
|
|
49
|
+
});
|
|
50
|
+
child.stderr?.on("data", (chunk) => {
|
|
51
|
+
options.stderr.write(typeof chunk === "string" ? chunk : chunk.toString("utf8"));
|
|
52
|
+
});
|
|
53
|
+
child.on("error", (error) => {
|
|
54
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
55
|
+
reject(new Error("cli_update_npm_not_found"));
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
reject(new Error("cli_update_install_failed"));
|
|
59
|
+
});
|
|
60
|
+
child.on("close", (code) => {
|
|
61
|
+
if (code === 0) {
|
|
62
|
+
resolve();
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
reject(new Error("cli_update_install_failed"));
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
}
|
|
39
69
|
export function createDefaultContext(overrides = {}) {
|
|
40
70
|
return {
|
|
41
71
|
stdout: overrides.stdout ?? process.stdout,
|
|
@@ -48,6 +78,7 @@ export function createDefaultContext(overrides = {}) {
|
|
|
48
78
|
process.exit(code);
|
|
49
79
|
}),
|
|
50
80
|
fetchImpl: overrides.fetchImpl ?? fetch,
|
|
81
|
+
runGlobalClientUpdateInstall: overrides.runGlobalClientUpdateInstall ?? runGlobalClientUpdateInstall,
|
|
51
82
|
openSqliteStore: overrides.openSqliteStore ?? openSqliteStore,
|
|
52
83
|
openManagedBitcoindClient: overrides.openManagedBitcoindClient ?? openManagedBitcoindClient,
|
|
53
84
|
inspectPassiveClientStatus: overrides.inspectPassiveClientStatus ?? inspectPassiveClientStatus,
|
|
@@ -13,6 +13,20 @@ function formatIndexerTruthSource(source) {
|
|
|
13
13
|
return "none";
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
|
+
function formatProviderModel(mining) {
|
|
17
|
+
if (mining.provider.effectiveModel === null || mining.provider.usingDefaultModel === null) {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
return `${mining.provider.effectiveModel} (${mining.provider.usingDefaultModel ? "default" : "override"})`;
|
|
21
|
+
}
|
|
22
|
+
function formatProviderModelSource(mining) {
|
|
23
|
+
return mining.provider.modelSelectionSource;
|
|
24
|
+
}
|
|
25
|
+
function resolveProviderNotFoundNextStep(mining) {
|
|
26
|
+
return mining.provider.usingDefaultModel === false
|
|
27
|
+
? "Next: run `cogcoin mine setup` and clear or correct the provider model."
|
|
28
|
+
: "Next: run `cogcoin mine setup` and choose a valid provider model.";
|
|
29
|
+
}
|
|
16
30
|
export function formatMiningSummaryLine(mining) {
|
|
17
31
|
const provider = mining.provider.configured
|
|
18
32
|
? `${mining.provider.provider} configured`
|
|
@@ -42,6 +56,17 @@ export function formatMineStatusReport(mining) {
|
|
|
42
56
|
lines.push(`Last suspend detected: ${formatMaybeIso(mining.runtime.lastSuspendDetectedAtUnixMs)}`);
|
|
43
57
|
}
|
|
44
58
|
lines.push(`Provider: ${mining.provider.configured ? `${mining.provider.provider} configured` : mining.provider.status}`);
|
|
59
|
+
const providerModel = formatProviderModel(mining);
|
|
60
|
+
if (providerModel !== null) {
|
|
61
|
+
lines.push(`Provider model: ${providerModel}`);
|
|
62
|
+
}
|
|
63
|
+
const providerModelSource = formatProviderModelSource(mining);
|
|
64
|
+
if (providerModelSource !== null) {
|
|
65
|
+
lines.push(`Provider model source: ${providerModelSource}`);
|
|
66
|
+
}
|
|
67
|
+
if (mining.provider.estimatedDailyCostDisplay !== null) {
|
|
68
|
+
lines.push(`Estimated daily cost: ${mining.provider.estimatedDailyCostDisplay}`);
|
|
69
|
+
}
|
|
45
70
|
if (mining.provider.message !== null) {
|
|
46
71
|
lines.push(`Provider note: ${mining.provider.message}`);
|
|
47
72
|
}
|
|
@@ -105,6 +130,9 @@ export function formatMineStatusReport(mining) {
|
|
|
105
130
|
if (mining.runtime.miningState === "repair-required") {
|
|
106
131
|
lines.push("Next: run `cogcoin repair` before mining again.");
|
|
107
132
|
}
|
|
133
|
+
else if (mining.runtime.providerState === "not-found") {
|
|
134
|
+
lines.push(resolveProviderNotFoundNextStep(mining));
|
|
135
|
+
}
|
|
108
136
|
else if (mining.runtime.pauseReason === "zero-reward") {
|
|
109
137
|
lines.push("Next: wait for the next positive-reward target height; mining resumes automatically.");
|
|
110
138
|
}
|
package/dist/cli/mining-json.js
CHANGED
|
@@ -18,8 +18,14 @@ export function buildMineSetupData(view) {
|
|
|
18
18
|
configured: view.provider.configured,
|
|
19
19
|
provider: view.provider.provider,
|
|
20
20
|
status: view.provider.status,
|
|
21
|
+
modelId: view.provider.modelId,
|
|
21
22
|
modelOverride: view.provider.modelOverride,
|
|
23
|
+
modelSelectionSource: view.provider.modelSelectionSource,
|
|
24
|
+
effectiveModel: view.provider.effectiveModel,
|
|
25
|
+
usingDefaultModel: view.provider.usingDefaultModel,
|
|
22
26
|
extraPromptConfigured: view.provider.extraPromptConfigured,
|
|
27
|
+
estimatedDailyCostUsd: view.provider.estimatedDailyCostUsd,
|
|
28
|
+
estimatedDailyCostDisplay: view.provider.estimatedDailyCostDisplay,
|
|
23
29
|
},
|
|
24
30
|
runtime: summarizeRuntime(view.runtime),
|
|
25
31
|
};
|
package/dist/cli/output.js
CHANGED
|
@@ -127,7 +127,9 @@ export function classifyCliError(error) {
|
|
|
127
127
|
return { exitCode: 2, errorCode: message, message };
|
|
128
128
|
}
|
|
129
129
|
if (message === "mining_setup_invalid_provider"
|
|
130
|
-
|| message === "mining_setup_missing_api_key"
|
|
130
|
+
|| message === "mining_setup_missing_api_key"
|
|
131
|
+
|| message === "mining_setup_missing_model_id"
|
|
132
|
+
|| message === "mining_setup_canceled") {
|
|
131
133
|
return { exitCode: 2, errorCode: message, message };
|
|
132
134
|
}
|
|
133
135
|
if (message.endsWith("_typed_ack_required")) {
|
|
@@ -507,6 +509,20 @@ export function createCliErrorPresentation(errorCode, fallbackMessage, error) {
|
|
|
507
509
|
next: "Rerun `cogcoin mine setup` and enter the provider API key when prompted.",
|
|
508
510
|
};
|
|
509
511
|
}
|
|
512
|
+
if (errorCode === "mining_setup_missing_model_id") {
|
|
513
|
+
return {
|
|
514
|
+
what: "Mining model ID is required.",
|
|
515
|
+
why: "Built-in mining setup cannot save a custom mining model choice unless it has a non-empty model ID.",
|
|
516
|
+
next: "Rerun `cogcoin mine setup`, choose `Custom model ID...`, and enter the model ID when prompted.",
|
|
517
|
+
};
|
|
518
|
+
}
|
|
519
|
+
if (errorCode === "mining_setup_canceled") {
|
|
520
|
+
return {
|
|
521
|
+
what: "Mining setup was canceled.",
|
|
522
|
+
why: "The interactive mining-model selection was canceled before any provider configuration was saved.",
|
|
523
|
+
next: "Rerun `cogcoin mine setup` when you are ready to choose a provider model.",
|
|
524
|
+
};
|
|
525
|
+
}
|
|
510
526
|
if (errorCode.endsWith("_confirmation_rejected")) {
|
|
511
527
|
return {
|
|
512
528
|
what: "Confirmation was declined.",
|
|
@@ -561,7 +577,7 @@ export function createCliErrorPresentation(errorCode, fallbackMessage, error) {
|
|
|
561
577
|
next: "Restore or otherwise recover the wallet into the current format, then retry the command.",
|
|
562
578
|
};
|
|
563
579
|
}
|
|
564
|
-
if (errorCode.endsWith("_requires_tty")) {
|
|
580
|
+
if (errorCode.endsWith("_requires_tty") && errorCode !== "cli_update_requires_tty") {
|
|
565
581
|
return {
|
|
566
582
|
what: "Interactive terminal input is required.",
|
|
567
583
|
why: "This command needs terminal input before it can continue safely.",
|
|
@@ -860,6 +876,34 @@ export function createCliErrorPresentation(errorCode, fallbackMessage, error) {
|
|
|
860
876
|
next: "Rerun the command in an interactive terminal, or add `--yes` if that is appropriate for your workflow.",
|
|
861
877
|
};
|
|
862
878
|
}
|
|
879
|
+
if (errorCode === "cli_update_requires_tty") {
|
|
880
|
+
return {
|
|
881
|
+
what: "Updating Cogcoin needs an interactive terminal or `--yes`.",
|
|
882
|
+
why: "When a newer client release is available, `cogcoin update` prompts before running the global npm install unless `--yes` is provided.",
|
|
883
|
+
next: "Rerun `cogcoin update` in an interactive terminal, or add `--yes` to apply the update non-interactively.",
|
|
884
|
+
};
|
|
885
|
+
}
|
|
886
|
+
if (errorCode === "cli_update_registry_unavailable") {
|
|
887
|
+
return {
|
|
888
|
+
what: "Cogcoin could not read the latest client version from the npm registry.",
|
|
889
|
+
why: "The explicit update command requires a fresh registry lookup before it can compare versions or run the install.",
|
|
890
|
+
next: "Check network access and rerun `cogcoin update`.",
|
|
891
|
+
};
|
|
892
|
+
}
|
|
893
|
+
if (errorCode === "cli_update_npm_not_found") {
|
|
894
|
+
return {
|
|
895
|
+
what: "Cogcoin could not find npm to install the update.",
|
|
896
|
+
why: "The update command runs `npm install -g @cogcoin/client`, and no usable `npm` executable was available on PATH.",
|
|
897
|
+
next: "Install Node.js/npm or fix PATH, then rerun `cogcoin update`.",
|
|
898
|
+
};
|
|
899
|
+
}
|
|
900
|
+
if (errorCode === "cli_update_install_failed") {
|
|
901
|
+
return {
|
|
902
|
+
what: "Cogcoin update installation failed.",
|
|
903
|
+
why: "The global npm install exited unsuccessfully before the client update completed.",
|
|
904
|
+
next: "Review the npm output above, fix the installation issue, then rerun `cogcoin update`.",
|
|
905
|
+
};
|
|
906
|
+
}
|
|
863
907
|
if (errorCode === "wallet_claim_sender_not_local") {
|
|
864
908
|
return {
|
|
865
909
|
what: "The claim sender is not locally controlled.",
|
|
@@ -918,6 +962,8 @@ export function describeCanonicalCommand(parsed) {
|
|
|
918
962
|
return "cogcoin reset";
|
|
919
963
|
case "repair":
|
|
920
964
|
return "cogcoin repair";
|
|
965
|
+
case "update":
|
|
966
|
+
return "cogcoin update";
|
|
921
967
|
case "anchor":
|
|
922
968
|
case "domain-anchor":
|
|
923
969
|
return `cogcoin anchor ${args[0] ?? "<domain>"}`;
|
|
@@ -1096,6 +1142,8 @@ export function resolveStableMutationJsonSchema(parsed) {
|
|
|
1096
1142
|
return "cogcoin/reset/v1";
|
|
1097
1143
|
case "repair":
|
|
1098
1144
|
return "cogcoin/repair/v1";
|
|
1145
|
+
case "update":
|
|
1146
|
+
return "cogcoin/update/v1";
|
|
1099
1147
|
case "anchor":
|
|
1100
1148
|
case "domain-anchor":
|
|
1101
1149
|
return "cogcoin/anchor/v1";
|
package/dist/cli/parse.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { ParsedCliArgs } from "./types.js";
|
|
2
|
-
export declare const HELP_TEXT = "Usage: cogcoin <command> [options]\n\nCommands:\n status Show wallet-aware local service and chain status\n status --output json Emit the stable v1 machine-readable status envelope\n client unlock Unlock password-protected local wallet secrets for a limited time\n client lock Flush the cached client password unlock session\n client change-password Rotate the client password that protects local wallet secrets\n bitcoin start Start the managed Bitcoin daemon\n bitcoin stop Stop the managed Bitcoin daemon and paired indexer\n bitcoin status Show managed Bitcoin daemon status without starting it\n bitcoin transfer <sats> --to <address>\n Send plain BTC from the wallet address\n indexer start Start the managed Cogcoin indexer (and bitcoind if needed)\n indexer stop Stop the managed Cogcoin indexer only\n indexer status Show managed Cogcoin indexer status without starting it\n init Initialize a new local wallet root\n init --output json Emit the stable v1 machine-readable init result envelope\n restore Restore an imported named seed from a 24-word mnemonic; run sync afterward\n reset Factory-reset local Cogcoin state with interactive retention prompts\n repair Recover bounded wallet/indexer/runtime state\n wallet address Alias for address\n wallet ids Alias for ids\n mine Run the miner in the foreground\n mine start Start the miner as a background worker\n mine stop Stop the active background miner\n mine setup Configure the built-in mining provider\n mine setup --output json\n Emit the stable v1 machine-readable mine setup result envelope\n mine status Show mining control-plane health and readiness\n mine log Show recent mining control-plane events\n anchor <domain> Anchor an owned unanchored domain with the wallet address\n register <domain>\n Register a root domain or subdomain\n transfer <domain> --to <btc-target>\n Transfer an unanchored domain to another BTC address or script\n sell <domain> <price> List an unanchored domain for sale in COG\n unsell <domain> Clear an active domain listing\n buy <domain>\n Buy an unanchored listed domain in COG\n send <amount> --to <btc-target>\n Send COG from the wallet address to another BTC target\n claim <lock-id> --preimage <32-byte-hex>\n Claim an active COG lock before timeout\n reclaim <lock-id> Reclaim an expired COG lock as the original locker\n cog lock <amount> --to-domain <domain> (--for <blocks-or-duration> | --until-height <height>) --condition <sha256hex>\n Lock COG to an anchored recipient domain\n wallet status Show detailed wallet-local status and service health\n wallet init Initialize a new local wallet root\n wallet restore Restore an imported named seed from a 24-word mnemonic; run sync afterward\n wallet delete Delete one imported named seed without affecting main\n wallet show-mnemonic Reveal the initialized wallet recovery phrase after typed confirmation\n address Show the BTC wallet address for this wallet\n ids Show the local wallet address\n balance Show local wallet COG balances\n locks Show locally related active COG locks\n domain list Alias for domains\n domain show <domain> Alias for show <domain>\n domains [--anchored] [--listed] [--mineable]\n Show locally related domains\n show <domain> Show one domain and its local-wallet relationship\n fields <domain> List current fields on a domain\n field <domain> <field> Show one current field value\n field create <domain> <field>\n Create a new empty anchored field\n field set <domain> <field>\n Update an existing anchored field value\n field clear <domain> <field>\n Clear an existing anchored field value\n rep give <source-domain> <target-domain> <amount>\n Burn COG as anchored-domain reputation support\n rep revoke <source-domain> <target-domain> <amount>\n Revoke visible support without refunding burned COG\n\nOptions:\n --db <path> Override the SQLite database path\n --data-dir <path> Override the managed bitcoin datadir\n --for <duration> Relative timeout for cog lock, like 15m, 2h, or 1d\n --message <text> Founding message text for anchor\n --to <btc-target> Transfer or send target as an address or spk:<hex>\n --to-domain <domain>\n Recipient domain for cog lock\n --condition <sha256hex>\n 32-byte lock condition hash\n --until-height <height>\n Absolute timeout height for cog lock\n --preimage <32-byte-hex>\n Claim preimage for an active lock\n --review <text> Optional public review text for reputation operations\n --satvb <n> Override the mutation fee rate in sat/vB\n --text <utf8> UTF-8 payload text for endpoint or field writes\n --json <json> UTF-8 payload JSON text for endpoint or field writes\n --bytes <spec> Payload bytes as hex:<hex> or @<path>\n --permanent Create the field as permanent\n --format <spec> Advanced field format as raw:<u8>\n --value <spec> Advanced field value as hex:<hex>, @<path>, or utf8:<text>\n --claimable Show only currently claimable locks\n --reclaimable Show only currently reclaimable locks\n --anchored Show only anchored domains\n --listed Show only currently listed domains\n --mineable Show only locally mineable root domains\n --limit <n> Limit list rows (1..1000)\n --all Show all rows for list commands\n --follow Follow mining log output\n --output <mode> Output mode: text, json, or preview-json\n --progress <mode> Progress output mode: auto, tty, or none\n --seed <name> Select an imported wallet seed for wallet-aware commands\n --force Reserved for future use\n --force-race Allow a visible root registration race\n --yes Approve eligible plain yes/no mutation confirmations non-interactively\n --help Show help\n --version Show package version\n\nQuickstart:\n 1. Run `cogcoin init` to create the wallet.\n 2. Run `cogcoin sync` to bootstrap assumeutxo and the managed Bitcoin/indexer state.\n 3. Run `cogcoin address`, then fund the wallet with about 0.0015 BTC so you can buy a 6+ character domain to start mining and still keep BTC available for mining transaction fees.\n\nExamples:\n cogcoin status --output json\n cogcoin bitcoin status\n cogcoin indexer status\n cogcoin init --output json\n cogcoin restore --seed trading\n cogcoin wallet address\n cogcoin domain list --mineable\n cogcoin register alpha-child\n cogcoin anchor alpha\n cogcoin register alpha --satvb 12.5\n cogcoin buy alpha\n cogcoin field set alpha bio --text \"hello\"\n cogcoin rep give alpha beta 10 --review \"great operator\"\n cogcoin mine setup --output json\n cogcoin register alpha-child --output preview-json\n cogcoin mine status\n";
|
|
2
|
+
export declare const HELP_TEXT = "Usage: cogcoin <command> [options]\n\nCommands:\n status Show wallet-aware local service and chain status\n status --output json Emit the stable v1 machine-readable status envelope\n update Show the current and latest client versions and install updates\n update --output json Emit the stable v1 machine-readable update result envelope\n client unlock Unlock password-protected local wallet secrets for a limited time\n client lock Flush the cached client password unlock session\n client change-password Rotate the client password that protects local wallet secrets\n bitcoin start Start the managed Bitcoin daemon\n bitcoin stop Stop the managed Bitcoin daemon and paired indexer\n bitcoin status Show managed Bitcoin daemon status without starting it\n bitcoin transfer <sats> --to <address>\n Send plain BTC from the wallet address\n indexer start Start the managed Cogcoin indexer (and bitcoind if needed)\n indexer stop Stop the managed Cogcoin indexer only\n indexer status Show managed Cogcoin indexer status without starting it\n init Initialize a new local wallet root\n init --output json Emit the stable v1 machine-readable init result envelope\n restore Restore an imported named seed from a 24-word mnemonic; run sync afterward\n reset Factory-reset local Cogcoin state with interactive retention prompts\n repair Recover bounded wallet/indexer/runtime state\n wallet address Alias for address\n wallet ids Alias for ids\n mine Run the miner in the foreground\n mine start Start the miner as a background worker\n mine stop Stop the active background miner\n mine setup Configure the built-in mining provider\n mine setup --output json\n Emit the stable v1 machine-readable mine setup result envelope\n mine status Show mining control-plane health and readiness\n mine log Show recent mining control-plane events\n anchor <domain> Anchor an owned unanchored domain with the wallet address\n register <domain>\n Register a root domain or subdomain\n transfer <domain> --to <btc-target>\n Transfer an unanchored domain to another BTC address or script\n sell <domain> <price> List an unanchored domain for sale in COG\n unsell <domain> Clear an active domain listing\n buy <domain>\n Buy an unanchored listed domain in COG\n send <amount> --to <btc-target>\n Send COG from the wallet address to another BTC target\n claim <lock-id> --preimage <32-byte-hex>\n Claim an active COG lock before timeout\n reclaim <lock-id> Reclaim an expired COG lock as the original locker\n cog lock <amount> --to-domain <domain> (--for <blocks-or-duration> | --until-height <height>) --condition <sha256hex>\n Lock COG to an anchored recipient domain\n wallet status Show detailed wallet-local status and service health\n wallet init Initialize a new local wallet root\n wallet restore Restore an imported named seed from a 24-word mnemonic; run sync afterward\n wallet delete Delete one imported named seed without affecting main\n wallet show-mnemonic Reveal the initialized wallet recovery phrase after typed confirmation\n address Show the BTC wallet address for this wallet\n ids Show the local wallet address\n balance Show local wallet COG balances\n locks Show locally related active COG locks\n domain list Alias for domains\n domain show <domain> Alias for show <domain>\n domains [--anchored] [--listed] [--mineable]\n Show locally related domains\n show <domain> Show one domain and its local-wallet relationship\n fields <domain> List current fields on a domain\n field <domain> <field> Show one current field value\n field create <domain> <field>\n Create a new empty anchored field\n field set <domain> <field>\n Update an existing anchored field value\n field clear <domain> <field>\n Clear an existing anchored field value\n rep give <source-domain> <target-domain> <amount>\n Burn COG as anchored-domain reputation support\n rep revoke <source-domain> <target-domain> <amount>\n Revoke visible support without refunding burned COG\n\nOptions:\n --db <path> Override the SQLite database path\n --data-dir <path> Override the managed bitcoin datadir\n --for <duration> Relative timeout for cog lock, like 15m, 2h, or 1d\n --message <text> Founding message text for anchor\n --to <btc-target> Transfer or send target as an address or spk:<hex>\n --to-domain <domain>\n Recipient domain for cog lock\n --condition <sha256hex>\n 32-byte lock condition hash\n --until-height <height>\n Absolute timeout height for cog lock\n --preimage <32-byte-hex>\n Claim preimage for an active lock\n --review <text> Optional public review text for reputation operations\n --satvb <n> Override the mutation fee rate in sat/vB\n --text <utf8> UTF-8 payload text for endpoint or field writes\n --json <json> UTF-8 payload JSON text for endpoint or field writes\n --bytes <spec> Payload bytes as hex:<hex> or @<path>\n --permanent Create the field as permanent\n --format <spec> Advanced field format as raw:<u8>\n --value <spec> Advanced field value as hex:<hex>, @<path>, or utf8:<text>\n --claimable Show only currently claimable locks\n --reclaimable Show only currently reclaimable locks\n --anchored Show only anchored domains\n --listed Show only currently listed domains\n --mineable Show only locally mineable root domains\n --limit <n> Limit list rows (1..1000)\n --all Show all rows for list commands\n --follow Follow mining log output\n --output <mode> Output mode: text, json, or preview-json\n --progress <mode> Progress output mode: auto, tty, or none\n --seed <name> Select an imported wallet seed for wallet-aware commands\n --force Reserved for future use\n --force-race Allow a visible root registration race\n --yes Approve eligible plain yes/no mutation confirmations non-interactively\n --help Show help\n --version Show package version\n\nQuickstart:\n 1. Run `cogcoin init` to create the wallet.\n 2. Run `cogcoin sync` to bootstrap assumeutxo and the managed Bitcoin/indexer state.\n 3. Run `cogcoin address`, then fund the wallet with about 0.0015 BTC so you can buy a 6+ character domain to start mining and still keep BTC available for mining transaction fees.\n\nExamples:\n cogcoin status --output json\n cogcoin bitcoin status\n cogcoin indexer status\n cogcoin init --output json\n cogcoin restore --seed trading\n cogcoin wallet address\n cogcoin domain list --mineable\n cogcoin register alpha-child\n cogcoin anchor alpha\n cogcoin register alpha --satvb 12.5\n cogcoin buy alpha\n cogcoin field set alpha bio --text \"hello\"\n cogcoin rep give alpha beta 10 --review \"great operator\"\n cogcoin mine setup --output json\n cogcoin register alpha-child --output preview-json\n cogcoin mine status\n";
|
|
3
3
|
export declare function parseCliArgs(argv: string[]): ParsedCliArgs;
|
package/dist/cli/parse.js
CHANGED
|
@@ -5,6 +5,8 @@ export const HELP_TEXT = `Usage: cogcoin <command> [options]
|
|
|
5
5
|
Commands:
|
|
6
6
|
status Show wallet-aware local service and chain status
|
|
7
7
|
status --output json Emit the stable v1 machine-readable status envelope
|
|
8
|
+
update Show the current and latest client versions and install updates
|
|
9
|
+
update --output json Emit the stable v1 machine-readable update result envelope
|
|
8
10
|
client unlock Unlock password-protected local wallet secrets for a limited time
|
|
9
11
|
client lock Flush the cached client password unlock session
|
|
10
12
|
client change-password Rotate the client password that protects local wallet secrets
|
|
@@ -138,6 +140,7 @@ Examples:
|
|
|
138
140
|
`;
|
|
139
141
|
function supportsYesFlag(command) {
|
|
140
142
|
switch (command) {
|
|
143
|
+
case "update":
|
|
141
144
|
case "sync":
|
|
142
145
|
case "follow":
|
|
143
146
|
case "bitcoin-transfer":
|
|
@@ -834,6 +837,7 @@ export function parseCliArgs(argv) {
|
|
|
834
837
|
|| token === "restore"
|
|
835
838
|
|| token === "reset"
|
|
836
839
|
|| token === "repair"
|
|
840
|
+
|| token === "update"
|
|
837
841
|
|| token === "sync"
|
|
838
842
|
|| token === "status"
|
|
839
843
|
|| token === "follow"
|
|
@@ -864,6 +868,7 @@ export function parseCliArgs(argv) {
|
|
|
864
868
|
args.push(token);
|
|
865
869
|
}
|
|
866
870
|
if ((command === "status"
|
|
871
|
+
|| command === "update"
|
|
867
872
|
|| command === "bitcoin-start"
|
|
868
873
|
|| command === "bitcoin-stop"
|
|
869
874
|
|| command === "bitcoin-status"
|