@cogcoin/client 1.1.4 → 1.1.5
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 +4 -5
- package/dist/bitcoind/progress/tty-renderer.js +3 -2
- package/dist/bitcoind/service.js +1 -1
- package/dist/cli/command-registry.d.ts +39 -0
- package/dist/cli/command-registry.js +1132 -0
- package/dist/cli/commands/client-admin.js +6 -56
- package/dist/cli/commands/mining-admin.js +9 -32
- package/dist/cli/commands/mining-read.js +15 -56
- package/dist/cli/commands/mining-runtime.js +258 -57
- package/dist/cli/commands/service-runtime.js +1 -64
- package/dist/cli/commands/status.js +2 -15
- package/dist/cli/commands/update.js +6 -21
- package/dist/cli/commands/wallet-admin.js +18 -120
- package/dist/cli/commands/wallet-mutation.js +4 -7
- package/dist/cli/commands/wallet-read.js +31 -138
- package/dist/cli/context.js +2 -4
- package/dist/cli/mining-format.js +8 -2
- package/dist/cli/mutation-command-groups.d.ts +11 -11
- package/dist/cli/mutation-command-groups.js +9 -18
- package/dist/cli/mutation-json.d.ts +1 -17
- package/dist/cli/mutation-json.js +1 -28
- package/dist/cli/mutation-success.d.ts +0 -1
- package/dist/cli/mutation-success.js +0 -19
- package/dist/cli/output.d.ts +1 -10
- package/dist/cli/output.js +52 -481
- package/dist/cli/parse.d.ts +1 -1
- package/dist/cli/parse.js +38 -695
- package/dist/cli/runner.js +28 -113
- package/dist/cli/types.d.ts +7 -8
- package/dist/cli/update-notifier.js +1 -1
- package/dist/cli/wallet-format.js +1 -1
- package/dist/wallet/lifecycle/managed-core.d.ts +23 -0
- package/dist/wallet/lifecycle/managed-core.js +257 -0
- package/dist/wallet/lifecycle/repair-mining.d.ts +49 -0
- package/dist/wallet/lifecycle/repair-mining.js +304 -0
- package/dist/wallet/lifecycle/repair-runtime.d.ts +36 -0
- package/dist/wallet/lifecycle/repair-runtime.js +206 -0
- package/dist/wallet/lifecycle/repair.d.ts +11 -0
- package/dist/wallet/lifecycle/repair.js +368 -0
- package/dist/wallet/lifecycle/setup.d.ts +16 -0
- package/dist/wallet/lifecycle/setup.js +430 -0
- package/dist/wallet/lifecycle/types.d.ts +125 -0
- package/dist/wallet/lifecycle/types.js +1 -0
- package/dist/wallet/lifecycle.d.ts +4 -165
- package/dist/wallet/lifecycle.js +3 -1656
- package/dist/wallet/mining/candidate.d.ts +60 -0
- package/dist/wallet/mining/candidate.js +290 -0
- package/dist/wallet/mining/competitiveness.d.ts +22 -0
- package/dist/wallet/mining/competitiveness.js +640 -0
- package/dist/wallet/mining/control.js +7 -251
- package/dist/wallet/mining/cycle.d.ts +39 -0
- package/dist/wallet/mining/cycle.js +542 -0
- package/dist/wallet/mining/engine-state.d.ts +66 -0
- package/dist/wallet/mining/engine-state.js +211 -0
- package/dist/wallet/mining/engine-types.d.ts +173 -0
- package/dist/wallet/mining/engine-types.js +1 -0
- package/dist/wallet/mining/engine-utils.d.ts +7 -0
- package/dist/wallet/mining/engine-utils.js +75 -0
- package/dist/wallet/mining/events.d.ts +2 -0
- package/dist/wallet/mining/events.js +19 -0
- package/dist/wallet/mining/lifecycle.d.ts +71 -0
- package/dist/wallet/mining/lifecycle.js +355 -0
- package/dist/wallet/mining/projection.d.ts +61 -0
- package/dist/wallet/mining/projection.js +319 -0
- package/dist/wallet/mining/publish.d.ts +79 -0
- package/dist/wallet/mining/publish.js +614 -0
- package/dist/wallet/mining/runner.d.ts +12 -418
- package/dist/wallet/mining/runner.js +274 -3433
- package/dist/wallet/mining/supervisor.d.ts +134 -0
- package/dist/wallet/mining/supervisor.js +558 -0
- package/dist/wallet/mining/visualizer-sync.d.ts +42 -0
- package/dist/wallet/mining/visualizer-sync.js +166 -0
- package/dist/wallet/mining/visualizer.d.ts +1 -0
- package/dist/wallet/mining/visualizer.js +33 -18
- package/dist/wallet/reset.d.ts +1 -1
- package/dist/wallet/reset.js +35 -11
- package/dist/wallet/runtime.d.ts +0 -6
- package/dist/wallet/runtime.js +2 -38
- package/dist/wallet/tx/common.d.ts +18 -0
- package/dist/wallet/tx/common.js +40 -26
- package/package.json +1 -1
- package/dist/wallet/state/seed-index.d.ts +0 -43
- package/dist/wallet/state/seed-index.js +0 -151
|
@@ -1,21 +1,19 @@
|
|
|
1
1
|
import { dirname } from "node:path";
|
|
2
2
|
import { DEFAULT_SNAPSHOT_METADATA, resolveBootstrapPathsForTesting } from "../../bitcoind/bootstrap.js";
|
|
3
|
+
import { createEmptyMiningFollowVisualizerState, MiningFollowVisualizer, } from "../../wallet/mining/visualizer.js";
|
|
3
4
|
import { resolveWalletRootIdFromLocalArtifacts } from "../../wallet/root-resolution.js";
|
|
4
5
|
import { withInteractiveWalletSecretProvider } from "../../wallet/state/provider.js";
|
|
5
|
-
import { ManagedIndexerProgressObserver, pollManagedIndexerUntilCaughtUp, } from "../managed-indexer-observer.js";
|
|
6
|
-
import { buildMineStartData, buildMineStopData, } from "../mining-json.js";
|
|
7
|
-
import { buildMineStartPreviewData, buildMineStopPreviewData, } from "../preview-json.js";
|
|
6
|
+
import { ManagedIndexerProgressObserver, assertManagedIndexerStatusRecoverable, isManagedIndexerCaughtUp, pollManagedIndexerUntilCaughtUp, } from "../managed-indexer-observer.js";
|
|
8
7
|
import { usesTtyProgress, writeLine } from "../io.js";
|
|
9
|
-
import {
|
|
10
|
-
import { createPreviewSuccessEnvelope, createMutationSuccessEnvelope, describeCanonicalCommand, resolvePreviewJsonSchema, resolveStableMiningControlJsonSchema, writeHandledCliError, writeJsonValue, } from "../output.js";
|
|
8
|
+
import { writeHandledCliError } from "../output.js";
|
|
11
9
|
import { formatNextStepLines, getMineStopNextSteps, } from "../workflow-hints.js";
|
|
12
10
|
import { createCloseSignalWatcher, waitForCompletionOrStop } from "../signals.js";
|
|
13
11
|
import { createSyncProgressReporter } from "../sync-progress.js";
|
|
14
12
|
import { PASSIVE_UPDATE_CHECK_TIMEOUT_MS, applyUpdateCheckResult, compareSemver, createEmptyUpdateCheckCache, fetchLatestPublishedVersion, isUpdateCheckDisabled, loadUpdateCheckCache, persistUpdateCheckCache, shouldRefreshUpdateCheck, } from "../update-service.js";
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
13
|
+
const MANAGED_MINING_READINESS_POLL_INTERVAL_MS = 500;
|
|
14
|
+
const EMPTY_MINING_VISUALIZER_STATE = createEmptyMiningFollowVisualizerState();
|
|
15
|
+
function createCommandPrompter(context) {
|
|
16
|
+
return context.createPrompter();
|
|
19
17
|
}
|
|
20
18
|
async function ensureMiningProviderSetup(options) {
|
|
21
19
|
const setupReady = await options.context.ensureBuiltInMiningSetupIfNeeded({
|
|
@@ -27,6 +25,202 @@ async function ensureMiningProviderSetup(options) {
|
|
|
27
25
|
throw new Error("Built-in mining provider is not configured. Run `cogcoin mine setup`.");
|
|
28
26
|
}
|
|
29
27
|
}
|
|
28
|
+
function sleep(ms, signal) {
|
|
29
|
+
return new Promise((resolve) => {
|
|
30
|
+
const timer = setTimeout(resolve, ms);
|
|
31
|
+
signal?.addEventListener("abort", () => {
|
|
32
|
+
clearTimeout(timer);
|
|
33
|
+
resolve();
|
|
34
|
+
}, { once: true });
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
function mapManagedIndexerStateToMiningState(state) {
|
|
38
|
+
switch (state) {
|
|
39
|
+
case "starting":
|
|
40
|
+
case "catching-up":
|
|
41
|
+
case "reorging":
|
|
42
|
+
case "synced":
|
|
43
|
+
case "failed":
|
|
44
|
+
case "schema-mismatch":
|
|
45
|
+
case "service-version-mismatch":
|
|
46
|
+
return state;
|
|
47
|
+
case "stopping":
|
|
48
|
+
return "starting";
|
|
49
|
+
default:
|
|
50
|
+
return "unavailable";
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function mapManagedIndexerHealth(state) {
|
|
54
|
+
switch (state) {
|
|
55
|
+
case "synced":
|
|
56
|
+
return "synced";
|
|
57
|
+
case "catching-up":
|
|
58
|
+
return "catching-up";
|
|
59
|
+
case "reorging":
|
|
60
|
+
return "reorging";
|
|
61
|
+
case "starting":
|
|
62
|
+
case "stopping":
|
|
63
|
+
return "starting";
|
|
64
|
+
case "failed":
|
|
65
|
+
return "failed";
|
|
66
|
+
case "schema-mismatch":
|
|
67
|
+
return "schema-mismatch";
|
|
68
|
+
case "service-version-mismatch":
|
|
69
|
+
return "service-version-mismatch";
|
|
70
|
+
default:
|
|
71
|
+
return "unavailable";
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
function createMiningReadinessSnapshot(options) {
|
|
75
|
+
const status = options.observedStatus;
|
|
76
|
+
const bitcoindReachable = status?.rpcReachable === true;
|
|
77
|
+
const indexerTipAligned = status === null
|
|
78
|
+
? null
|
|
79
|
+
: status.coreBestHeight !== null
|
|
80
|
+
&& status.appliedTipHeight !== null
|
|
81
|
+
&& status.appliedTipHeight === status.coreBestHeight
|
|
82
|
+
&& (status.coreBestHash === null
|
|
83
|
+
|| status.appliedTipHash === null
|
|
84
|
+
|| status.appliedTipHash === status.coreBestHash);
|
|
85
|
+
return {
|
|
86
|
+
schemaVersion: 1,
|
|
87
|
+
walletRootId: options.walletRootId,
|
|
88
|
+
workerApiVersion: null,
|
|
89
|
+
workerBinaryVersion: null,
|
|
90
|
+
workerBuildId: null,
|
|
91
|
+
updatedAtUnixMs: status?.updatedAtUnixMs ?? Date.now(),
|
|
92
|
+
runMode: "foreground",
|
|
93
|
+
backgroundWorkerPid: null,
|
|
94
|
+
backgroundWorkerRunId: null,
|
|
95
|
+
backgroundWorkerHeartbeatAtUnixMs: null,
|
|
96
|
+
backgroundWorkerHealth: null,
|
|
97
|
+
indexerDaemonState: mapManagedIndexerStateToMiningState(status?.state),
|
|
98
|
+
indexerDaemonInstanceId: status?.daemonInstanceId ?? null,
|
|
99
|
+
indexerSnapshotSeq: status?.snapshotSeq ?? null,
|
|
100
|
+
indexerSnapshotOpenedAtUnixMs: null,
|
|
101
|
+
indexerTruthSource: "none",
|
|
102
|
+
indexerHeartbeatAtUnixMs: status?.heartbeatAtUnixMs ?? null,
|
|
103
|
+
coreBestHeight: status?.coreBestHeight ?? null,
|
|
104
|
+
coreBestHash: status?.coreBestHash ?? null,
|
|
105
|
+
indexerTipHeight: status?.appliedTipHeight ?? null,
|
|
106
|
+
indexerTipHash: status?.appliedTipHash ?? null,
|
|
107
|
+
indexerReorgDepth: status?.reorgDepth ?? null,
|
|
108
|
+
indexerTipAligned,
|
|
109
|
+
corePublishState: bitcoindReachable ? "healthy" : null,
|
|
110
|
+
providerState: null,
|
|
111
|
+
lastSuspendDetectedAtUnixMs: null,
|
|
112
|
+
reconnectSettledUntilUnixMs: null,
|
|
113
|
+
tipSettledUntilUnixMs: null,
|
|
114
|
+
miningState: "idle",
|
|
115
|
+
currentPhase: "waiting-indexer",
|
|
116
|
+
currentPublishState: "none",
|
|
117
|
+
targetBlockHeight: status?.coreBestHeight === null || status?.coreBestHeight === undefined
|
|
118
|
+
? null
|
|
119
|
+
: status.coreBestHeight + 1,
|
|
120
|
+
referencedBlockHashDisplay: null,
|
|
121
|
+
currentDomainId: null,
|
|
122
|
+
currentDomainName: null,
|
|
123
|
+
currentSentenceDisplay: null,
|
|
124
|
+
currentCanonicalBlend: null,
|
|
125
|
+
currentTxid: null,
|
|
126
|
+
currentWtxid: null,
|
|
127
|
+
livePublishInMempool: null,
|
|
128
|
+
currentFeeRateSatVb: null,
|
|
129
|
+
currentAbsoluteFeeSats: null,
|
|
130
|
+
currentBlockFeeSpentSats: "0",
|
|
131
|
+
sessionFeeSpentSats: "0",
|
|
132
|
+
lifetimeFeeSpentSats: "0",
|
|
133
|
+
sameDomainCompetitorSuppressed: null,
|
|
134
|
+
higherRankedCompetitorDomainCount: null,
|
|
135
|
+
dedupedCompetitorDomainCount: null,
|
|
136
|
+
competitivenessGateIndeterminate: null,
|
|
137
|
+
mempoolSequenceCacheStatus: null,
|
|
138
|
+
currentPublishDecision: null,
|
|
139
|
+
lastMempoolSequence: null,
|
|
140
|
+
lastCompetitivenessGateAtUnixMs: null,
|
|
141
|
+
pauseReason: null,
|
|
142
|
+
providerConfigured: true,
|
|
143
|
+
providerKind: null,
|
|
144
|
+
bitcoindHealth: bitcoindReachable ? "ready" : status === null ? "starting" : "unavailable",
|
|
145
|
+
bitcoindServiceState: bitcoindReachable ? "ready" : status === null ? "starting" : null,
|
|
146
|
+
bitcoindReplicaStatus: "not-proven",
|
|
147
|
+
nodeHealth: bitcoindReachable ? "synced" : status === null ? "starting" : "unavailable",
|
|
148
|
+
indexerHealth: mapManagedIndexerHealth(status?.state),
|
|
149
|
+
tipsAligned: indexerTipAligned,
|
|
150
|
+
lastEventAtUnixMs: null,
|
|
151
|
+
lastError: status?.lastError ?? null,
|
|
152
|
+
note: null,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
async function pollManagedMiningReadinessWithVisualizer(options) {
|
|
156
|
+
while (true) {
|
|
157
|
+
if (options.signal?.aborted) {
|
|
158
|
+
throw options.signal.reason instanceof Error
|
|
159
|
+
? options.signal.reason
|
|
160
|
+
: new Error("managed_indexer_observer_aborted");
|
|
161
|
+
}
|
|
162
|
+
const status = await options.monitor.getStatus();
|
|
163
|
+
options.visualizer.update(createMiningReadinessSnapshot({
|
|
164
|
+
walletRootId: options.walletRootId,
|
|
165
|
+
observedStatus: status,
|
|
166
|
+
}), EMPTY_MINING_VISUALIZER_STATE);
|
|
167
|
+
assertManagedIndexerStatusRecoverable(status);
|
|
168
|
+
if (isManagedIndexerCaughtUp(status)) {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
await sleep(options.pollIntervalMs ?? MANAGED_MINING_READINESS_POLL_INTERVAL_MS, options.signal);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
async function syncManagedMiningReadinessWithVisualizer(options) {
|
|
175
|
+
let monitor = null;
|
|
176
|
+
const walletRoot = await resolveWalletRootIdFromLocalArtifacts({
|
|
177
|
+
paths: options.runtimePaths,
|
|
178
|
+
provider: options.provider,
|
|
179
|
+
loadRawWalletStateEnvelope: options.context.loadRawWalletStateEnvelope,
|
|
180
|
+
});
|
|
181
|
+
options.visualizer.update(createMiningReadinessSnapshot({
|
|
182
|
+
walletRootId: walletRoot.walletRootId,
|
|
183
|
+
observedStatus: null,
|
|
184
|
+
}), EMPTY_MINING_VISUALIZER_STATE);
|
|
185
|
+
await options.context.ensureDirectory(dirname(options.databasePath));
|
|
186
|
+
monitor = await options.context.openManagedIndexerMonitor({
|
|
187
|
+
dataDir: options.dataDir,
|
|
188
|
+
databasePath: options.databasePath,
|
|
189
|
+
walletRootId: walletRoot.walletRootId,
|
|
190
|
+
expectedBinaryVersion: options.expectedBinaryVersion,
|
|
191
|
+
});
|
|
192
|
+
const abortController = new AbortController();
|
|
193
|
+
const stopWatcher = createCloseSignalWatcher({
|
|
194
|
+
signalSource: options.context.signalSource,
|
|
195
|
+
stderr: options.context.stderr,
|
|
196
|
+
closeable: {
|
|
197
|
+
close: async () => {
|
|
198
|
+
abortController.abort(new Error("managed_indexer_preflight_aborted"));
|
|
199
|
+
await monitor?.close().catch(() => undefined);
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
forceExit: options.context.forceExit,
|
|
203
|
+
firstMessage: "Stopping managed mining readiness observation...",
|
|
204
|
+
successMessage: "Stopped observing managed mining readiness.",
|
|
205
|
+
failureMessage: "Managed mining readiness observation cleanup failed.",
|
|
206
|
+
});
|
|
207
|
+
try {
|
|
208
|
+
const syncOutcome = await waitForCompletionOrStop(pollManagedMiningReadinessWithVisualizer({
|
|
209
|
+
monitor,
|
|
210
|
+
walletRootId: walletRoot.walletRootId,
|
|
211
|
+
visualizer: options.visualizer,
|
|
212
|
+
signal: abortController.signal,
|
|
213
|
+
}), stopWatcher);
|
|
214
|
+
if (syncOutcome.kind === "stopped") {
|
|
215
|
+
return syncOutcome.code;
|
|
216
|
+
}
|
|
217
|
+
return null;
|
|
218
|
+
}
|
|
219
|
+
finally {
|
|
220
|
+
stopWatcher.cleanup();
|
|
221
|
+
await monitor?.close().catch(() => undefined);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
30
224
|
async function syncManagedMiningReadiness(options) {
|
|
31
225
|
const ttyProgressActive = usesTtyProgress(options.parsed.progressOutput, options.context.stderr);
|
|
32
226
|
let monitor = null;
|
|
@@ -121,38 +315,63 @@ export async function runMiningRuntimeCommand(parsed, context) {
|
|
|
121
315
|
const dbPath = parsed.dbPath ?? context.resolveDefaultClientDatabasePath();
|
|
122
316
|
const dataDir = parsed.dataDir ?? context.resolveDefaultBitcoindDataDir();
|
|
123
317
|
const packageVersion = await context.readPackageVersion();
|
|
124
|
-
const runtimePaths = context.resolveWalletRuntimePaths(
|
|
318
|
+
const runtimePaths = context.resolveWalletRuntimePaths();
|
|
125
319
|
if (parsed.command === "mine") {
|
|
126
320
|
const prompter = context.createPrompter();
|
|
127
321
|
const provider = withInteractiveWalletSecretProvider(context.walletSecretProvider, prompter);
|
|
322
|
+
const ttyProgressActive = usesTtyProgress(parsed.progressOutput, context.stderr);
|
|
128
323
|
await ensureMiningProviderSetup({
|
|
129
324
|
context,
|
|
130
325
|
provider,
|
|
131
326
|
prompter,
|
|
132
327
|
runtimePaths,
|
|
133
328
|
});
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
dataDir,
|
|
138
|
-
databasePath: dbPath,
|
|
139
|
-
expectedBinaryVersion: packageVersion,
|
|
140
|
-
provider,
|
|
141
|
-
runtimePaths,
|
|
142
|
-
});
|
|
143
|
-
if (preflightCode !== null) {
|
|
144
|
-
return preflightCode;
|
|
145
|
-
}
|
|
146
|
-
const updateAvailable = usesTtyProgress(parsed.progressOutput, context.stderr)
|
|
147
|
-
? await resolveMineUpdateAvailable(packageVersion, context)
|
|
148
|
-
: false;
|
|
149
|
-
const abortController = new AbortController();
|
|
150
|
-
const onStop = () => {
|
|
151
|
-
abortController.abort();
|
|
152
|
-
};
|
|
153
|
-
context.signalSource.on("SIGINT", onStop);
|
|
154
|
-
context.signalSource.on("SIGTERM", onStop);
|
|
329
|
+
let visualizer = null;
|
|
330
|
+
let abortController = null;
|
|
331
|
+
let onStop = null;
|
|
155
332
|
try {
|
|
333
|
+
if (ttyProgressActive) {
|
|
334
|
+
visualizer = new MiningFollowVisualizer({
|
|
335
|
+
clientVersion: packageVersion,
|
|
336
|
+
progressOutput: parsed.progressOutput,
|
|
337
|
+
stream: context.stderr,
|
|
338
|
+
});
|
|
339
|
+
visualizer.update(createMiningReadinessSnapshot({
|
|
340
|
+
walletRootId: null,
|
|
341
|
+
observedStatus: null,
|
|
342
|
+
}), EMPTY_MINING_VISUALIZER_STATE);
|
|
343
|
+
}
|
|
344
|
+
const preflightCode = ttyProgressActive && visualizer !== null
|
|
345
|
+
? await syncManagedMiningReadinessWithVisualizer({
|
|
346
|
+
context,
|
|
347
|
+
dataDir,
|
|
348
|
+
databasePath: dbPath,
|
|
349
|
+
expectedBinaryVersion: packageVersion,
|
|
350
|
+
provider,
|
|
351
|
+
runtimePaths,
|
|
352
|
+
visualizer,
|
|
353
|
+
})
|
|
354
|
+
: await syncManagedMiningReadiness({
|
|
355
|
+
parsed,
|
|
356
|
+
context,
|
|
357
|
+
dataDir,
|
|
358
|
+
databasePath: dbPath,
|
|
359
|
+
expectedBinaryVersion: packageVersion,
|
|
360
|
+
provider,
|
|
361
|
+
runtimePaths,
|
|
362
|
+
});
|
|
363
|
+
if (preflightCode !== null) {
|
|
364
|
+
return preflightCode;
|
|
365
|
+
}
|
|
366
|
+
const updateAvailable = ttyProgressActive
|
|
367
|
+
? await resolveMineUpdateAvailable(packageVersion, context)
|
|
368
|
+
: false;
|
|
369
|
+
abortController = new AbortController();
|
|
370
|
+
onStop = () => {
|
|
371
|
+
abortController?.abort();
|
|
372
|
+
};
|
|
373
|
+
context.signalSource.on("SIGINT", onStop);
|
|
374
|
+
context.signalSource.on("SIGTERM", onStop);
|
|
156
375
|
await context.runForegroundMining({
|
|
157
376
|
clientVersion: packageVersion,
|
|
158
377
|
updateAvailable,
|
|
@@ -166,16 +385,20 @@ export async function runMiningRuntimeCommand(parsed, context) {
|
|
|
166
385
|
progressOutput: parsed.progressOutput,
|
|
167
386
|
builtInSetupEnsured: true,
|
|
168
387
|
paths: runtimePaths,
|
|
388
|
+
visualizer: visualizer ?? undefined,
|
|
169
389
|
});
|
|
170
390
|
}
|
|
171
391
|
finally {
|
|
172
|
-
|
|
173
|
-
|
|
392
|
+
if (onStop !== null) {
|
|
393
|
+
context.signalSource.off("SIGINT", onStop);
|
|
394
|
+
context.signalSource.off("SIGTERM", onStop);
|
|
395
|
+
}
|
|
396
|
+
visualizer?.close();
|
|
174
397
|
}
|
|
175
398
|
return 0;
|
|
176
399
|
}
|
|
177
400
|
if (parsed.command === "mine-start") {
|
|
178
|
-
const prompter = createCommandPrompter(
|
|
401
|
+
const prompter = createCommandPrompter(context);
|
|
179
402
|
const provider = withInteractiveWalletSecretProvider(context.walletSecretProvider, prompter);
|
|
180
403
|
await ensureMiningProviderSetup({
|
|
181
404
|
context,
|
|
@@ -203,14 +426,6 @@ export async function runMiningRuntimeCommand(parsed, context) {
|
|
|
203
426
|
builtInSetupEnsured: true,
|
|
204
427
|
paths: runtimePaths,
|
|
205
428
|
});
|
|
206
|
-
if (parsed.outputMode === "preview-json") {
|
|
207
|
-
writeJsonValue(context.stdout, createPreviewSuccessEnvelope(resolvePreviewJsonSchema(parsed), describeCanonicalCommand(parsed), result.started ? "started" : "already-active", buildMineStartPreviewData(result)));
|
|
208
|
-
return 0;
|
|
209
|
-
}
|
|
210
|
-
if (parsed.outputMode === "json") {
|
|
211
|
-
writeJsonValue(context.stdout, createMutationSuccessEnvelope(resolveStableMiningControlJsonSchema(parsed), "cogcoin mine start", result.started ? "started" : "already-active", buildMineStartData(result)));
|
|
212
|
-
return 0;
|
|
213
|
-
}
|
|
214
429
|
if (!result.started) {
|
|
215
430
|
writeLine(context.stdout, "Background mining is already active.");
|
|
216
431
|
if (result.snapshot?.backgroundWorkerPid !== null && result.snapshot?.backgroundWorkerPid !== undefined) {
|
|
@@ -225,9 +440,7 @@ export async function runMiningRuntimeCommand(parsed, context) {
|
|
|
225
440
|
return 0;
|
|
226
441
|
}
|
|
227
442
|
if (parsed.command === "mine-stop") {
|
|
228
|
-
const provider =
|
|
229
|
-
? withInteractiveWalletSecretProvider(context.walletSecretProvider, context.createPrompter())
|
|
230
|
-
: context.walletSecretProvider;
|
|
443
|
+
const provider = withInteractiveWalletSecretProvider(context.walletSecretProvider, context.createPrompter());
|
|
231
444
|
const snapshot = await context.stopBackgroundMining({
|
|
232
445
|
dataDir,
|
|
233
446
|
databasePath: dbPath,
|
|
@@ -235,18 +448,6 @@ export async function runMiningRuntimeCommand(parsed, context) {
|
|
|
235
448
|
paths: runtimePaths,
|
|
236
449
|
});
|
|
237
450
|
const nextSteps = getMineStopNextSteps();
|
|
238
|
-
if (parsed.outputMode === "preview-json") {
|
|
239
|
-
writeJsonValue(context.stdout, createPreviewSuccessEnvelope(resolvePreviewJsonSchema(parsed), describeCanonicalCommand(parsed), snapshot === null ? "not-active" : "stopped", buildMineStopPreviewData(snapshot), {
|
|
240
|
-
nextSteps,
|
|
241
|
-
}));
|
|
242
|
-
return 0;
|
|
243
|
-
}
|
|
244
|
-
if (parsed.outputMode === "json") {
|
|
245
|
-
writeJsonValue(context.stdout, createMutationSuccessEnvelope(resolveStableMiningControlJsonSchema(parsed), "cogcoin mine stop", snapshot === null ? "not-active" : "stopped", buildMineStopData(snapshot), {
|
|
246
|
-
nextSteps,
|
|
247
|
-
}));
|
|
248
|
-
return 0;
|
|
249
|
-
}
|
|
250
451
|
writeLine(context.stdout, snapshot?.note ?? "Background mining was not active.");
|
|
251
452
|
for (const line of formatNextStepLines(nextSteps)) {
|
|
252
453
|
writeLine(context.stdout, line);
|
|
@@ -5,7 +5,7 @@ import { UNINITIALIZED_WALLET_ROOT_ID, resolveManagedServicePaths } from "../../
|
|
|
5
5
|
import { INDEXER_DAEMON_BACKGROUND_FOLLOW_RECOVERY_FAILED, } from "../../bitcoind/indexer-daemon.js";
|
|
6
6
|
import { resolveWalletRootIdFromLocalArtifacts, } from "../../wallet/root-resolution.js";
|
|
7
7
|
import { writeLine } from "../io.js";
|
|
8
|
-
import {
|
|
8
|
+
import { writeHandledCliError, } from "../output.js";
|
|
9
9
|
function formatBool(value) {
|
|
10
10
|
return value === null ? "unknown" : (value ? "yes" : "no");
|
|
11
11
|
}
|
|
@@ -286,44 +286,11 @@ function formatIndexerStatusReport(payload) {
|
|
|
286
286
|
: null,
|
|
287
287
|
});
|
|
288
288
|
}
|
|
289
|
-
function buildStatusMessages(payload) {
|
|
290
|
-
const warnings = [];
|
|
291
|
-
const explanations = [];
|
|
292
|
-
const nextSteps = [];
|
|
293
|
-
if (payload.compatibility !== "compatible") {
|
|
294
|
-
warnings.push(`Managed service compatibility is ${payload.compatibility}.`);
|
|
295
|
-
}
|
|
296
|
-
if ("nodeError" in payload && payload.nodeError !== null) {
|
|
297
|
-
explanations.push(payload.nodeError);
|
|
298
|
-
}
|
|
299
|
-
if ("service" in payload && payload.service?.lastError) {
|
|
300
|
-
explanations.push(payload.service.lastError);
|
|
301
|
-
}
|
|
302
|
-
if ("daemon" in payload && payload.daemon?.lastError) {
|
|
303
|
-
explanations.push(payload.daemon.lastError);
|
|
304
|
-
}
|
|
305
|
-
if ("service" in payload && payload.compatibility === "unreachable") {
|
|
306
|
-
nextSteps.push("Run `cogcoin bitcoin start` to start the managed Bitcoin service.");
|
|
307
|
-
}
|
|
308
|
-
if ("daemon" in payload && payload.compatibility === "unreachable") {
|
|
309
|
-
nextSteps.push("Run `cogcoin indexer start` to start the managed Cogcoin indexer.");
|
|
310
|
-
}
|
|
311
|
-
return {
|
|
312
|
-
warnings,
|
|
313
|
-
explanations,
|
|
314
|
-
nextSteps,
|
|
315
|
-
};
|
|
316
|
-
}
|
|
317
289
|
export async function runServiceRuntimeCommand(parsed, context) {
|
|
318
290
|
try {
|
|
319
291
|
const dataDir = parsed.dataDir ?? context.resolveDefaultBitcoindDataDir();
|
|
320
292
|
if (parsed.command === "bitcoin-status") {
|
|
321
293
|
const payload = await inspectManagedBitcoindStatus(dataDir, context);
|
|
322
|
-
const messages = buildStatusMessages(payload);
|
|
323
|
-
if (parsed.outputMode === "json") {
|
|
324
|
-
writeJsonValue(context.stdout, createSuccessEnvelope("cogcoin/bitcoin-status/v1", describeCanonicalCommand(parsed), payload, messages));
|
|
325
|
-
return 0;
|
|
326
|
-
}
|
|
327
294
|
context.stdout.write(formatBitcoinStatusReport(payload));
|
|
328
295
|
return 0;
|
|
329
296
|
}
|
|
@@ -332,11 +299,6 @@ export async function runServiceRuntimeCommand(parsed, context) {
|
|
|
332
299
|
const packageVersion = await context.readPackageVersion();
|
|
333
300
|
await context.ensureDirectory(dirname(dbPath));
|
|
334
301
|
const payload = await inspectManagedIndexerStatus(dataDir, dbPath, packageVersion, context);
|
|
335
|
-
const messages = buildStatusMessages(payload);
|
|
336
|
-
if (parsed.outputMode === "json") {
|
|
337
|
-
writeJsonValue(context.stdout, createSuccessEnvelope("cogcoin/indexer-status/v1", describeCanonicalCommand(parsed), payload, messages));
|
|
338
|
-
return 0;
|
|
339
|
-
}
|
|
340
302
|
context.stdout.write(formatIndexerStatusReport(payload));
|
|
341
303
|
return 0;
|
|
342
304
|
}
|
|
@@ -364,15 +326,6 @@ export async function runServiceRuntimeCommand(parsed, context) {
|
|
|
364
326
|
status: bitcoindStatus,
|
|
365
327
|
},
|
|
366
328
|
};
|
|
367
|
-
if (parsed.outputMode === "json") {
|
|
368
|
-
writeJsonValue(context.stdout, createSuccessEnvelope("cogcoin/bitcoin-start/v1", describeCanonicalCommand(parsed), payload, {
|
|
369
|
-
nextSteps: [
|
|
370
|
-
"Run `cogcoin bitcoin status` to inspect the managed Bitcoin node.",
|
|
371
|
-
"Run `cogcoin indexer start` or `cogcoin sync` when you want the managed Cogcoin indexer.",
|
|
372
|
-
],
|
|
373
|
-
}));
|
|
374
|
-
return 0;
|
|
375
|
-
}
|
|
376
329
|
writeLine(context.stdout, bitcoindStatus === "already-running" ? "Managed bitcoind already running." : "Managed bitcoind started.");
|
|
377
330
|
writeLine(context.stdout, `Wallet root: ${resolution.walletRootId}`);
|
|
378
331
|
return 0;
|
|
@@ -394,10 +347,6 @@ export async function runServiceRuntimeCommand(parsed, context) {
|
|
|
394
347
|
bitcoind,
|
|
395
348
|
indexer,
|
|
396
349
|
};
|
|
397
|
-
if (parsed.outputMode === "json") {
|
|
398
|
-
writeJsonValue(context.stdout, createSuccessEnvelope("cogcoin/bitcoin-stop/v1", describeCanonicalCommand(parsed), payload));
|
|
399
|
-
return 0;
|
|
400
|
-
}
|
|
401
350
|
writeLine(context.stdout, bitcoind.status === "stopped" ? "Managed bitcoind stopped." : "Managed bitcoind already stopped.");
|
|
402
351
|
writeLine(context.stdout, indexer.status === "stopped" ? "Paired indexer stopped." : "Paired indexer already stopped.");
|
|
403
352
|
return 0;
|
|
@@ -440,14 +389,6 @@ export async function runServiceRuntimeCommand(parsed, context) {
|
|
|
440
389
|
status: indexerProbe.compatibility === "compatible" ? "already-running" : "started",
|
|
441
390
|
},
|
|
442
391
|
};
|
|
443
|
-
if (parsed.outputMode === "json") {
|
|
444
|
-
writeJsonValue(context.stdout, createSuccessEnvelope("cogcoin/indexer-start/v1", describeCanonicalCommand(parsed), payload, {
|
|
445
|
-
nextSteps: [
|
|
446
|
-
"Run `cogcoin indexer status` to inspect the managed Cogcoin indexer.",
|
|
447
|
-
],
|
|
448
|
-
}));
|
|
449
|
-
return 0;
|
|
450
|
-
}
|
|
451
392
|
writeLine(context.stdout, payload.indexer.status === "already-running" ? "Managed indexer already running." : "Managed indexer started.");
|
|
452
393
|
if (payload.bitcoind.status === "started") {
|
|
453
394
|
writeLine(context.stdout, "Managed bitcoind started automatically.");
|
|
@@ -466,10 +407,6 @@ export async function runServiceRuntimeCommand(parsed, context) {
|
|
|
466
407
|
walletRootSource: resolution.source,
|
|
467
408
|
indexer,
|
|
468
409
|
};
|
|
469
|
-
if (parsed.outputMode === "json") {
|
|
470
|
-
writeJsonValue(context.stdout, createSuccessEnvelope("cogcoin/indexer-stop/v1", describeCanonicalCommand(parsed), payload));
|
|
471
|
-
return 0;
|
|
472
|
-
}
|
|
473
410
|
writeLine(context.stdout, indexer.status === "stopped" ? "Managed indexer stopped." : "Managed indexer already stopped.");
|
|
474
411
|
return 0;
|
|
475
412
|
}
|
|
@@ -1,19 +1,15 @@
|
|
|
1
1
|
import { dirname } from "node:path";
|
|
2
|
-
import { buildStatusJson } from "../read-json.js";
|
|
3
2
|
import { formatBalanceReport, formatWalletOverviewReport } from "../wallet-format.js";
|
|
4
3
|
import { writeLine } from "../io.js";
|
|
5
4
|
import { createTerminalPrompter } from "../prompt.js";
|
|
6
|
-
import { createSuccessEnvelope, describeCanonicalCommand, writeJsonValue } from "../output.js";
|
|
7
5
|
import { withInteractiveWalletSecretProvider } from "../../wallet/state/provider.js";
|
|
8
6
|
export async function runStatusCommand(parsed, context) {
|
|
9
7
|
const dbPath = parsed.dbPath ?? context.resolveDefaultClientDatabasePath();
|
|
10
8
|
const dataDir = parsed.dataDir ?? context.resolveDefaultBitcoindDataDir();
|
|
11
9
|
const packageVersion = await context.readPackageVersion();
|
|
12
|
-
const runtimePaths = context.resolveWalletRuntimePaths(
|
|
10
|
+
const runtimePaths = context.resolveWalletRuntimePaths();
|
|
13
11
|
await context.ensureDirectory(dirname(dbPath));
|
|
14
|
-
const provider =
|
|
15
|
-
? withInteractiveWalletSecretProvider(context.walletSecretProvider, context.createPrompter?.() ?? createTerminalPrompter(context.stdin, context.stdout))
|
|
16
|
-
: context.walletSecretProvider;
|
|
12
|
+
const provider = withInteractiveWalletSecretProvider(context.walletSecretProvider, context.createPrompter?.() ?? createTerminalPrompter(context.stdin, context.stdout));
|
|
17
13
|
const readContext = await context.openWalletReadContext({
|
|
18
14
|
dataDir,
|
|
19
15
|
databasePath: dbPath,
|
|
@@ -22,15 +18,6 @@ export async function runStatusCommand(parsed, context) {
|
|
|
22
18
|
paths: runtimePaths,
|
|
23
19
|
});
|
|
24
20
|
try {
|
|
25
|
-
if (parsed.outputMode === "json") {
|
|
26
|
-
const result = buildStatusJson(readContext);
|
|
27
|
-
writeJsonValue(context.stdout, createSuccessEnvelope("cogcoin/status/v1", describeCanonicalCommand(parsed), result.data, {
|
|
28
|
-
warnings: result.warnings,
|
|
29
|
-
explanations: result.explanations,
|
|
30
|
-
nextSteps: result.nextSteps,
|
|
31
|
-
}));
|
|
32
|
-
return 0;
|
|
33
|
-
}
|
|
34
21
|
writeLine(context.stdout, formatWalletOverviewReport(readContext, packageVersion));
|
|
35
22
|
writeLine(context.stdout, formatBalanceReport(readContext));
|
|
36
23
|
return 0;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { writeLine } from "../io.js";
|
|
2
|
-
import {
|
|
2
|
+
import { writeHandledCliError } from "../output.js";
|
|
3
3
|
import { CLI_INSTALL_COMMAND, EXPLICIT_UPDATE_CHECK_TIMEOUT_MS, applyUpdateCheckResult, compareSemver, createEmptyUpdateCheckCache, fetchLatestPublishedVersion, loadUpdateCheckCache, persistUpdateCheckCache, } from "../update-service.js";
|
|
4
4
|
function createUpdateResult(currentVersion, latestVersion, status, applied) {
|
|
5
5
|
return {
|
|
@@ -31,10 +31,6 @@ async function confirmApplyUpdate(context) {
|
|
|
31
31
|
prompter.writeLine("Enter \"y\" to continue or \"n\" to cancel.");
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
|
-
function writeSuccessJson(parsed, context, result) {
|
|
35
|
-
writeJsonValue(context.stdout, createMutationSuccessEnvelope(resolveStableMutationJsonSchema(parsed), describeCanonicalCommand(parsed), result.status, result));
|
|
36
|
-
return 0;
|
|
37
|
-
}
|
|
38
34
|
export async function runUpdateCommand(parsed, context) {
|
|
39
35
|
try {
|
|
40
36
|
const currentVersion = await context.readPackageVersion();
|
|
@@ -54,39 +50,28 @@ export async function runUpdateCommand(parsed, context) {
|
|
|
54
50
|
throw new Error("cli_update_registry_unavailable");
|
|
55
51
|
}
|
|
56
52
|
if (comparison <= 0) {
|
|
57
|
-
|
|
58
|
-
if (parsed.outputMode === "json") {
|
|
59
|
-
return writeSuccessJson(parsed, context, result);
|
|
60
|
-
}
|
|
53
|
+
createUpdateResult(currentVersion, latestVersion, "up-to-date", false);
|
|
61
54
|
writeVersionSummary(context, currentVersion, latestVersion);
|
|
62
55
|
writeLine(context.stdout, "Cogcoin is already up to date.");
|
|
63
56
|
return 0;
|
|
64
57
|
}
|
|
65
58
|
if (!parsed.assumeYes) {
|
|
66
|
-
if (parsed.outputMode !== "text") {
|
|
67
|
-
throw new Error("cli_update_requires_tty");
|
|
68
|
-
}
|
|
69
59
|
writeVersionSummary(context, currentVersion, latestVersion);
|
|
70
60
|
if (!(await confirmApplyUpdate(context))) {
|
|
71
61
|
writeLine(context.stdout, "Update canceled.");
|
|
72
62
|
return 0;
|
|
73
63
|
}
|
|
74
64
|
}
|
|
75
|
-
else
|
|
65
|
+
else {
|
|
76
66
|
writeVersionSummary(context, currentVersion, latestVersion);
|
|
77
67
|
}
|
|
78
|
-
|
|
79
|
-
writeLine(context.stdout, "Installing update...");
|
|
80
|
-
}
|
|
68
|
+
writeLine(context.stdout, "Installing update...");
|
|
81
69
|
await context.runGlobalClientUpdateInstall({
|
|
82
|
-
stdout:
|
|
70
|
+
stdout: context.stdout,
|
|
83
71
|
stderr: context.stderr,
|
|
84
72
|
env: context.env,
|
|
85
73
|
});
|
|
86
|
-
|
|
87
|
-
if (parsed.outputMode === "json") {
|
|
88
|
-
return writeSuccessJson(parsed, context, result);
|
|
89
|
-
}
|
|
74
|
+
createUpdateResult(currentVersion, latestVersion, "updated", true);
|
|
90
75
|
writeLine(context.stdout, "Update completed. The next cogcoin invocation will use the new install.");
|
|
91
76
|
return 0;
|
|
92
77
|
}
|