@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.
Files changed (83) hide show
  1. package/README.md +4 -5
  2. package/dist/bitcoind/progress/tty-renderer.js +3 -2
  3. package/dist/bitcoind/service.js +1 -1
  4. package/dist/cli/command-registry.d.ts +39 -0
  5. package/dist/cli/command-registry.js +1132 -0
  6. package/dist/cli/commands/client-admin.js +6 -56
  7. package/dist/cli/commands/mining-admin.js +9 -32
  8. package/dist/cli/commands/mining-read.js +15 -56
  9. package/dist/cli/commands/mining-runtime.js +258 -57
  10. package/dist/cli/commands/service-runtime.js +1 -64
  11. package/dist/cli/commands/status.js +2 -15
  12. package/dist/cli/commands/update.js +6 -21
  13. package/dist/cli/commands/wallet-admin.js +18 -120
  14. package/dist/cli/commands/wallet-mutation.js +4 -7
  15. package/dist/cli/commands/wallet-read.js +31 -138
  16. package/dist/cli/context.js +2 -4
  17. package/dist/cli/mining-format.js +8 -2
  18. package/dist/cli/mutation-command-groups.d.ts +11 -11
  19. package/dist/cli/mutation-command-groups.js +9 -18
  20. package/dist/cli/mutation-json.d.ts +1 -17
  21. package/dist/cli/mutation-json.js +1 -28
  22. package/dist/cli/mutation-success.d.ts +0 -1
  23. package/dist/cli/mutation-success.js +0 -19
  24. package/dist/cli/output.d.ts +1 -10
  25. package/dist/cli/output.js +52 -481
  26. package/dist/cli/parse.d.ts +1 -1
  27. package/dist/cli/parse.js +38 -695
  28. package/dist/cli/runner.js +28 -113
  29. package/dist/cli/types.d.ts +7 -8
  30. package/dist/cli/update-notifier.js +1 -1
  31. package/dist/cli/wallet-format.js +1 -1
  32. package/dist/wallet/lifecycle/managed-core.d.ts +23 -0
  33. package/dist/wallet/lifecycle/managed-core.js +257 -0
  34. package/dist/wallet/lifecycle/repair-mining.d.ts +49 -0
  35. package/dist/wallet/lifecycle/repair-mining.js +304 -0
  36. package/dist/wallet/lifecycle/repair-runtime.d.ts +36 -0
  37. package/dist/wallet/lifecycle/repair-runtime.js +206 -0
  38. package/dist/wallet/lifecycle/repair.d.ts +11 -0
  39. package/dist/wallet/lifecycle/repair.js +368 -0
  40. package/dist/wallet/lifecycle/setup.d.ts +16 -0
  41. package/dist/wallet/lifecycle/setup.js +430 -0
  42. package/dist/wallet/lifecycle/types.d.ts +125 -0
  43. package/dist/wallet/lifecycle/types.js +1 -0
  44. package/dist/wallet/lifecycle.d.ts +4 -165
  45. package/dist/wallet/lifecycle.js +3 -1656
  46. package/dist/wallet/mining/candidate.d.ts +60 -0
  47. package/dist/wallet/mining/candidate.js +290 -0
  48. package/dist/wallet/mining/competitiveness.d.ts +22 -0
  49. package/dist/wallet/mining/competitiveness.js +640 -0
  50. package/dist/wallet/mining/control.js +7 -251
  51. package/dist/wallet/mining/cycle.d.ts +39 -0
  52. package/dist/wallet/mining/cycle.js +542 -0
  53. package/dist/wallet/mining/engine-state.d.ts +66 -0
  54. package/dist/wallet/mining/engine-state.js +211 -0
  55. package/dist/wallet/mining/engine-types.d.ts +173 -0
  56. package/dist/wallet/mining/engine-types.js +1 -0
  57. package/dist/wallet/mining/engine-utils.d.ts +7 -0
  58. package/dist/wallet/mining/engine-utils.js +75 -0
  59. package/dist/wallet/mining/events.d.ts +2 -0
  60. package/dist/wallet/mining/events.js +19 -0
  61. package/dist/wallet/mining/lifecycle.d.ts +71 -0
  62. package/dist/wallet/mining/lifecycle.js +355 -0
  63. package/dist/wallet/mining/projection.d.ts +61 -0
  64. package/dist/wallet/mining/projection.js +319 -0
  65. package/dist/wallet/mining/publish.d.ts +79 -0
  66. package/dist/wallet/mining/publish.js +614 -0
  67. package/dist/wallet/mining/runner.d.ts +12 -418
  68. package/dist/wallet/mining/runner.js +274 -3433
  69. package/dist/wallet/mining/supervisor.d.ts +134 -0
  70. package/dist/wallet/mining/supervisor.js +558 -0
  71. package/dist/wallet/mining/visualizer-sync.d.ts +42 -0
  72. package/dist/wallet/mining/visualizer-sync.js +166 -0
  73. package/dist/wallet/mining/visualizer.d.ts +1 -0
  74. package/dist/wallet/mining/visualizer.js +33 -18
  75. package/dist/wallet/reset.d.ts +1 -1
  76. package/dist/wallet/reset.js +35 -11
  77. package/dist/wallet/runtime.d.ts +0 -6
  78. package/dist/wallet/runtime.js +2 -38
  79. package/dist/wallet/tx/common.d.ts +18 -0
  80. package/dist/wallet/tx/common.js +40 -26
  81. package/package.json +1 -1
  82. package/dist/wallet/state/seed-index.d.ts +0 -43
  83. 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 { createTerminalPrompter } from "../prompt.js";
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
- function createCommandPrompter(parsed, context) {
16
- return parsed.outputMode !== "text"
17
- ? createTerminalPrompter(context.stdin, context.stderr)
18
- : context.createPrompter();
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(parsed.seedName);
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
- const preflightCode = await syncManagedMiningReadiness({
135
- parsed,
136
- context,
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
- context.signalSource.off("SIGINT", onStop);
173
- context.signalSource.off("SIGTERM", onStop);
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(parsed, context);
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 = parsed.outputMode === "text"
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 { createSuccessEnvelope, describeCanonicalCommand, writeHandledCliError, writeJsonValue, } from "../output.js";
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(parsed.seedName);
10
+ const runtimePaths = context.resolveWalletRuntimePaths();
13
11
  await context.ensureDirectory(dirname(dbPath));
14
- const provider = parsed.outputMode === "text"
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 { createMutationSuccessEnvelope, describeCanonicalCommand, resolveStableMutationJsonSchema, writeHandledCliError, writeJsonValue, } from "../output.js";
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
- const result = createUpdateResult(currentVersion, latestVersion, "up-to-date", false);
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 if (parsed.outputMode === "text") {
65
+ else {
76
66
  writeVersionSummary(context, currentVersion, latestVersion);
77
67
  }
78
- if (parsed.outputMode === "text") {
79
- writeLine(context.stdout, "Installing update...");
80
- }
68
+ writeLine(context.stdout, "Installing update...");
81
69
  await context.runGlobalClientUpdateInstall({
82
- stdout: parsed.outputMode === "json" ? context.stderr : context.stdout,
70
+ stdout: context.stdout,
83
71
  stderr: context.stderr,
84
72
  env: context.env,
85
73
  });
86
- const result = createUpdateResult(currentVersion, latestVersion, "updated", true);
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
  }