@cogcoin/client 0.5.3 → 0.5.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 (70) hide show
  1. package/README.md +11 -3
  2. package/dist/app-paths.d.ts +2 -0
  3. package/dist/app-paths.js +4 -0
  4. package/dist/art/wallet.txt +10 -0
  5. package/dist/bitcoind/bootstrap/chunk-manifest.d.ts +14 -0
  6. package/dist/bitcoind/bootstrap/chunk-manifest.js +85 -0
  7. package/dist/bitcoind/bootstrap/chunk-recovery.d.ts +4 -0
  8. package/dist/bitcoind/bootstrap/chunk-recovery.js +122 -0
  9. package/dist/bitcoind/bootstrap/constants.d.ts +3 -1
  10. package/dist/bitcoind/bootstrap/constants.js +3 -1
  11. package/dist/bitcoind/bootstrap/controller.d.ts +6 -1
  12. package/dist/bitcoind/bootstrap/controller.js +14 -7
  13. package/dist/bitcoind/bootstrap/default-snapshot-chunk-manifest.d.ts +2 -0
  14. package/dist/bitcoind/bootstrap/default-snapshot-chunk-manifest.js +2309 -0
  15. package/dist/bitcoind/bootstrap/download.js +177 -83
  16. package/dist/bitcoind/bootstrap/headers.d.ts +4 -2
  17. package/dist/bitcoind/bootstrap/headers.js +29 -4
  18. package/dist/bitcoind/bootstrap/state.d.ts +11 -1
  19. package/dist/bitcoind/bootstrap/state.js +50 -23
  20. package/dist/bitcoind/bootstrap/types.d.ts +12 -1
  21. package/dist/bitcoind/client/internal-types.d.ts +1 -0
  22. package/dist/bitcoind/client/managed-client.js +27 -13
  23. package/dist/bitcoind/client/sync-engine.js +42 -5
  24. package/dist/bitcoind/errors.js +9 -0
  25. package/dist/bitcoind/indexer-daemon.d.ts +9 -0
  26. package/dist/bitcoind/indexer-daemon.js +51 -14
  27. package/dist/bitcoind/service.d.ts +9 -0
  28. package/dist/bitcoind/service.js +65 -24
  29. package/dist/bitcoind/testing.d.ts +2 -2
  30. package/dist/bitcoind/testing.js +2 -2
  31. package/dist/bitcoind/types.d.ts +9 -0
  32. package/dist/cli/commands/service-runtime.d.ts +2 -0
  33. package/dist/cli/commands/service-runtime.js +432 -0
  34. package/dist/cli/commands/wallet-admin.js +227 -132
  35. package/dist/cli/commands/wallet-mutation.js +597 -580
  36. package/dist/cli/context.js +23 -1
  37. package/dist/cli/mutation-json.d.ts +17 -1
  38. package/dist/cli/mutation-json.js +42 -0
  39. package/dist/cli/output.js +113 -2
  40. package/dist/cli/parse.d.ts +1 -1
  41. package/dist/cli/parse.js +65 -0
  42. package/dist/cli/preview-json.d.ts +19 -1
  43. package/dist/cli/preview-json.js +31 -0
  44. package/dist/cli/prompt.js +40 -12
  45. package/dist/cli/runner.js +12 -0
  46. package/dist/cli/signals.d.ts +1 -0
  47. package/dist/cli/signals.js +44 -0
  48. package/dist/cli/types.d.ts +24 -2
  49. package/dist/cli/types.js +6 -0
  50. package/dist/cli/wallet-format.js +3 -0
  51. package/dist/cli/workflow-hints.d.ts +1 -0
  52. package/dist/cli/workflow-hints.js +3 -0
  53. package/dist/wallet/fs/lock.d.ts +2 -0
  54. package/dist/wallet/fs/lock.js +32 -0
  55. package/dist/wallet/lifecycle.d.ts +19 -1
  56. package/dist/wallet/lifecycle.js +315 -8
  57. package/dist/wallet/material.d.ts +2 -0
  58. package/dist/wallet/material.js +8 -1
  59. package/dist/wallet/mnemonic-art.d.ts +2 -0
  60. package/dist/wallet/mnemonic-art.js +54 -0
  61. package/dist/wallet/reset.d.ts +61 -0
  62. package/dist/wallet/reset.js +781 -0
  63. package/dist/wallet/runtime.d.ts +2 -0
  64. package/dist/wallet/runtime.js +2 -0
  65. package/dist/wallet/state/pending-init.d.ts +24 -0
  66. package/dist/wallet/state/pending-init.js +59 -0
  67. package/dist/wallet/state/provider.d.ts +1 -0
  68. package/dist/wallet/state/provider.js +7 -1
  69. package/dist/wallet/types.d.ts +8 -0
  70. package/package.json +6 -4
@@ -1,10 +1,11 @@
1
1
  import { parseUnlockDurationToMs } from "../../wallet/lifecycle.js";
2
- import { buildInitMutationData, buildUnlockMutationData, buildRepairMutationData, buildWalletExportMutationData, buildWalletImportMutationData, buildWalletLockMutationData, } from "../mutation-json.js";
3
- import { buildRepairPreviewData, buildWalletLockPreviewData, } from "../preview-json.js";
2
+ import { buildInitMutationData, buildResetMutationData, buildRestoreMutationData, buildUnlockMutationData, buildRepairMutationData, buildWalletExportMutationData, buildWalletImportMutationData, buildWalletLockMutationData, } from "../mutation-json.js";
3
+ import { buildResetPreviewData, buildRepairPreviewData, buildWalletLockPreviewData, } from "../preview-json.js";
4
4
  import { writeLine } from "../io.js";
5
5
  import { createTerminalPrompter } from "../prompt.js";
6
6
  import { createPreviewSuccessEnvelope, createMutationSuccessEnvelope, describeCanonicalCommand, resolvePreviewJsonSchema, resolveStableMutationJsonSchema, writeHandledCliError, writeJsonValue, } from "../output.js";
7
- import { formatNextStepLines, getFundingQuickstartGuidance, getInitNextSteps, } from "../workflow-hints.js";
7
+ import { formatNextStepLines, getFundingQuickstartGuidance, getInitNextSteps, getRestoreNextSteps, } from "../workflow-hints.js";
8
+ import { createOwnedLockCleanupSignalWatcher, waitForCompletionOrStop, } from "../signals.js";
8
9
  function createCommandPrompter(parsed, context) {
9
10
  return parsed.outputMode !== "text"
10
11
  ? createTerminalPrompter(context.stdin, context.stderr)
@@ -15,154 +16,245 @@ function getRepairWarnings(result) {
15
16
  ? [`Wallet repair succeeded, but background mining did not resume automatically: ${result.miningResumeError ?? "unknown error"}`]
16
17
  : [];
17
18
  }
19
+ function getResetWarnings(result) {
20
+ return result.secretCleanupStatus === "unknown"
21
+ ? ["Some existing Cogcoin secret-provider entries could not be discovered from the remaining local wallet artifacts and may need manual cleanup."]
22
+ : [];
23
+ }
18
24
  export async function runWalletAdminCommand(parsed, context) {
25
+ const runtimePaths = context.resolveWalletRuntimePaths();
26
+ const stopWatcher = createOwnedLockCleanupSignalWatcher(context.signalSource, context.forceExit, [
27
+ runtimePaths.walletControlLockPath,
28
+ runtimePaths.miningControlLockPath,
29
+ runtimePaths.bitcoindLockPath,
30
+ runtimePaths.indexerDaemonLockPath,
31
+ ]);
19
32
  try {
20
- const dataDir = parsed.dataDir ?? context.resolveDefaultBitcoindDataDir();
21
- const dbPath = parsed.dbPath ?? context.resolveDefaultClientDatabasePath();
22
- const provider = context.walletSecretProvider;
23
- if (parsed.command === "init" || parsed.command === "wallet-init") {
24
- const prompter = createCommandPrompter(parsed, context);
25
- const result = await context.initializeWallet({
26
- dataDir,
27
- provider,
28
- prompter,
29
- });
30
- const nextSteps = getInitNextSteps();
31
- if (parsed.outputMode === "json") {
32
- writeJsonValue(context.stdout, createMutationSuccessEnvelope(resolveStableMutationJsonSchema(parsed), describeCanonicalCommand(parsed), "initialized", buildInitMutationData(result), {
33
- explanations: [getFundingQuickstartGuidance()],
34
- nextSteps,
35
- }));
33
+ const outcome = await waitForCompletionOrStop((async () => {
34
+ const dataDir = parsed.dataDir ?? context.resolveDefaultBitcoindDataDir();
35
+ const provider = context.walletSecretProvider;
36
+ if (parsed.command === "init" || parsed.command === "wallet-init") {
37
+ const prompter = createCommandPrompter(parsed, context);
38
+ const result = await context.initializeWallet({
39
+ dataDir,
40
+ provider,
41
+ prompter,
42
+ });
43
+ const nextSteps = getInitNextSteps();
44
+ if (parsed.outputMode === "json") {
45
+ writeJsonValue(context.stdout, createMutationSuccessEnvelope(resolveStableMutationJsonSchema(parsed), describeCanonicalCommand(parsed), "initialized", buildInitMutationData(result), {
46
+ explanations: [getFundingQuickstartGuidance()],
47
+ nextSteps,
48
+ }));
49
+ return 0;
50
+ }
51
+ writeLine(context.stdout, `Wallet initialized.`);
52
+ writeLine(context.stdout, `Wallet root: ${result.walletRootId}`);
53
+ writeLine(context.stdout, `Funding address: ${result.fundingAddress}`);
54
+ writeLine(context.stdout, `Unlocked until: ${new Date(result.unlockUntilUnixMs).toISOString()}`);
55
+ writeLine(context.stdout, `Quickstart: ${getFundingQuickstartGuidance()}`);
56
+ for (const line of formatNextStepLines(nextSteps)) {
57
+ writeLine(context.stdout, line);
58
+ }
36
59
  return 0;
37
60
  }
38
- writeLine(context.stdout, `Wallet initialized.`);
39
- writeLine(context.stdout, `Wallet root: ${result.walletRootId}`);
40
- writeLine(context.stdout, `Funding address: ${result.fundingAddress}`);
41
- writeLine(context.stdout, `Unlocked until: ${new Date(result.unlockUntilUnixMs).toISOString()}`);
42
- writeLine(context.stdout, `Quickstart: ${getFundingQuickstartGuidance()}`);
43
- for (const line of formatNextStepLines(nextSteps)) {
44
- writeLine(context.stdout, line);
45
- }
46
- return 0;
47
- }
48
- if (parsed.command === "unlock" || parsed.command === "wallet-unlock") {
49
- const durationMs = parseUnlockDurationToMs(parsed.unlockFor);
50
- const result = await context.unlockWallet({
51
- provider,
52
- unlockDurationMs: durationMs,
53
- });
54
- if (parsed.outputMode === "json") {
55
- writeJsonValue(context.stdout, createMutationSuccessEnvelope(resolveStableMutationJsonSchema(parsed), describeCanonicalCommand(parsed), "unlocked", buildUnlockMutationData(result)));
61
+ if (parsed.command === "restore" || parsed.command === "wallet-restore") {
62
+ const prompter = createCommandPrompter(parsed, context);
63
+ const result = await context.restoreWalletFromMnemonic({
64
+ dataDir,
65
+ provider,
66
+ prompter,
67
+ });
68
+ const nextSteps = getRestoreNextSteps();
69
+ const explanations = ["Managed Bitcoin/indexer bootstrap is deferred until you run `cogcoin sync`."];
70
+ if (parsed.outputMode === "json") {
71
+ writeJsonValue(context.stdout, createMutationSuccessEnvelope(resolveStableMutationJsonSchema(parsed), describeCanonicalCommand(parsed), "restored", buildRestoreMutationData(result), {
72
+ explanations,
73
+ nextSteps,
74
+ warnings: result.warnings ?? [],
75
+ }));
76
+ return 0;
77
+ }
78
+ writeLine(context.stdout, "Wallet restored from mnemonic.");
79
+ writeLine(context.stdout, `Wallet root: ${result.walletRootId}`);
80
+ writeLine(context.stdout, `Funding address: ${result.fundingAddress}`);
81
+ writeLine(context.stdout, `Unlocked until: ${new Date(result.unlockUntilUnixMs).toISOString()}`);
82
+ writeLine(context.stdout, "Note: Managed Bitcoin/indexer bootstrap is deferred until you run `cogcoin sync`.");
83
+ for (const warning of result.warnings ?? []) {
84
+ writeLine(context.stdout, `Warning: ${warning}`);
85
+ }
86
+ for (const line of formatNextStepLines(nextSteps)) {
87
+ writeLine(context.stdout, line);
88
+ }
56
89
  return 0;
57
90
  }
58
- writeLine(context.stdout, `Wallet unlocked.`);
59
- writeLine(context.stdout, `Wallet root: ${result.state.walletRootId}`);
60
- writeLine(context.stdout, `Unlocked until: ${new Date(result.unlockUntilUnixMs).toISOString()}`);
61
- return 0;
62
- }
63
- if (parsed.command === "wallet-export") {
64
- const prompter = createCommandPrompter(parsed, context);
65
- const result = await context.exportWallet({
66
- archivePath: parsed.args[0],
67
- dataDir,
68
- databasePath: dbPath,
69
- provider,
70
- prompter,
71
- });
72
- if (parsed.outputMode === "json") {
73
- writeJsonValue(context.stdout, createMutationSuccessEnvelope(resolveStableMutationJsonSchema(parsed), describeCanonicalCommand(parsed), "exported", buildWalletExportMutationData(result)));
91
+ const dbPath = parsed.dbPath ?? context.resolveDefaultClientDatabasePath();
92
+ if (parsed.command === "unlock" || parsed.command === "wallet-unlock") {
93
+ const durationMs = parseUnlockDurationToMs(parsed.unlockFor);
94
+ const result = await context.unlockWallet({
95
+ provider,
96
+ unlockDurationMs: durationMs,
97
+ });
98
+ if (parsed.outputMode === "json") {
99
+ writeJsonValue(context.stdout, createMutationSuccessEnvelope(resolveStableMutationJsonSchema(parsed), describeCanonicalCommand(parsed), "unlocked", buildUnlockMutationData(result)));
100
+ return 0;
101
+ }
102
+ writeLine(context.stdout, `Wallet unlocked.`);
103
+ writeLine(context.stdout, `Wallet root: ${result.state.walletRootId}`);
104
+ writeLine(context.stdout, `Unlocked until: ${new Date(result.unlockUntilUnixMs).toISOString()}`);
74
105
  return 0;
75
106
  }
76
- writeLine(context.stdout, `Wallet exported.`);
77
- writeLine(context.stdout, `Wallet root: ${result.walletRootId}`);
78
- writeLine(context.stdout, `Archive path: ${result.archivePath}`);
79
- return 0;
80
- }
81
- if (parsed.command === "wallet-import") {
82
- const prompter = createCommandPrompter(parsed, context);
83
- const result = await context.importWallet({
84
- archivePath: parsed.args[0],
85
- dataDir,
86
- databasePath: dbPath,
87
- provider,
88
- prompter,
89
- });
90
- if (parsed.outputMode === "json") {
91
- writeJsonValue(context.stdout, createMutationSuccessEnvelope(resolveStableMutationJsonSchema(parsed), describeCanonicalCommand(parsed), "imported", buildWalletImportMutationData(result)));
107
+ if (parsed.command === "reset") {
108
+ if (parsed.outputMode === "preview-json") {
109
+ const preview = await context.previewResetWallet({
110
+ dataDir,
111
+ provider,
112
+ });
113
+ writeJsonValue(context.stdout, createPreviewSuccessEnvelope(resolvePreviewJsonSchema(parsed), describeCanonicalCommand(parsed), "planned", buildResetPreviewData(preview)));
114
+ return 0;
115
+ }
116
+ const prompter = createCommandPrompter(parsed, context);
117
+ const result = await context.resetWallet({
118
+ dataDir,
119
+ provider,
120
+ prompter,
121
+ });
122
+ if (parsed.outputMode === "json") {
123
+ writeJsonValue(context.stdout, createMutationSuccessEnvelope(resolveStableMutationJsonSchema(parsed), describeCanonicalCommand(parsed), "completed", buildResetMutationData(result), {
124
+ warnings: getResetWarnings(result),
125
+ nextSteps: result.walletAction === "deleted" || result.walletAction === "not-present"
126
+ ? ["Run `cogcoin init` to create a new wallet."]
127
+ : ["Run `cogcoin status` to inspect the reset local state."],
128
+ }));
129
+ return 0;
130
+ }
131
+ writeLine(context.stdout, "Cogcoin reset completed.");
132
+ writeLine(context.stdout, `Data root: ${result.dataRoot}`);
133
+ writeLine(context.stdout, `Wallet action: ${result.walletAction}`);
134
+ writeLine(context.stdout, `Snapshot: ${result.bootstrapSnapshot.status}`);
135
+ writeLine(context.stdout, `Secret cleanup: ${result.secretCleanupStatus}`);
136
+ writeLine(context.stdout, `Managed bitcoind processes stopped: ${result.stoppedProcesses.managedBitcoind}`);
137
+ writeLine(context.stdout, `Indexer daemons stopped: ${result.stoppedProcesses.indexerDaemon}`);
138
+ writeLine(context.stdout, `Background miners stopped: ${result.stoppedProcesses.backgroundMining}`);
139
+ if (result.walletOldRootId !== null) {
140
+ writeLine(context.stdout, `Previous wallet root: ${result.walletOldRootId}`);
141
+ }
142
+ if (result.walletNewRootId !== null) {
143
+ writeLine(context.stdout, `New wallet root: ${result.walletNewRootId}`);
144
+ }
145
+ for (const warning of getResetWarnings(result)) {
146
+ writeLine(context.stdout, `Warning: ${warning}`);
147
+ }
92
148
  return 0;
93
149
  }
94
- writeLine(context.stdout, `Wallet imported.`);
95
- writeLine(context.stdout, `Wallet root: ${result.walletRootId}`);
96
- writeLine(context.stdout, `Funding address: ${result.fundingAddress}`);
97
- writeLine(context.stdout, `Unlocked until: ${new Date(result.unlockUntilUnixMs).toISOString()}`);
98
- return 0;
99
- }
100
- if (parsed.command === "wallet-lock") {
101
- const result = await context.lockWallet({
102
- dataDir,
103
- provider,
104
- });
105
- if (parsed.outputMode === "preview-json") {
106
- writeJsonValue(context.stdout, createPreviewSuccessEnvelope(resolvePreviewJsonSchema(parsed), describeCanonicalCommand(parsed), "locked", buildWalletLockPreviewData(result)));
150
+ if (parsed.command === "wallet-export") {
151
+ const prompter = createCommandPrompter(parsed, context);
152
+ const result = await context.exportWallet({
153
+ archivePath: parsed.args[0],
154
+ dataDir,
155
+ databasePath: dbPath,
156
+ provider,
157
+ prompter,
158
+ });
159
+ if (parsed.outputMode === "json") {
160
+ writeJsonValue(context.stdout, createMutationSuccessEnvelope(resolveStableMutationJsonSchema(parsed), describeCanonicalCommand(parsed), "exported", buildWalletExportMutationData(result)));
161
+ return 0;
162
+ }
163
+ writeLine(context.stdout, `Wallet exported.`);
164
+ writeLine(context.stdout, `Wallet root: ${result.walletRootId}`);
165
+ writeLine(context.stdout, `Archive path: ${result.archivePath}`);
107
166
  return 0;
108
167
  }
109
- if (parsed.outputMode === "json") {
110
- writeJsonValue(context.stdout, createMutationSuccessEnvelope(resolveStableMutationJsonSchema(parsed), "cogcoin wallet lock", "locked", buildWalletLockMutationData(result)));
168
+ if (parsed.command === "wallet-import") {
169
+ const prompter = createCommandPrompter(parsed, context);
170
+ const result = await context.importWallet({
171
+ archivePath: parsed.args[0],
172
+ dataDir,
173
+ databasePath: dbPath,
174
+ provider,
175
+ prompter,
176
+ });
177
+ if (parsed.outputMode === "json") {
178
+ writeJsonValue(context.stdout, createMutationSuccessEnvelope(resolveStableMutationJsonSchema(parsed), describeCanonicalCommand(parsed), "imported", buildWalletImportMutationData(result)));
179
+ return 0;
180
+ }
181
+ writeLine(context.stdout, `Wallet imported.`);
182
+ writeLine(context.stdout, `Wallet root: ${result.walletRootId}`);
183
+ writeLine(context.stdout, `Funding address: ${result.fundingAddress}`);
184
+ writeLine(context.stdout, `Unlocked until: ${new Date(result.unlockUntilUnixMs).toISOString()}`);
111
185
  return 0;
112
186
  }
113
- writeLine(context.stdout, `Wallet locked.`);
114
- writeLine(context.stdout, `Wallet root: ${result.walletRootId ?? "none"}`);
115
- return 0;
116
- }
117
- if (parsed.command === "repair") {
118
- const result = await context.repairWallet({
119
- dataDir,
120
- databasePath: dbPath,
121
- provider,
122
- assumeYes: parsed.assumeYes,
123
- });
124
- if (parsed.outputMode === "preview-json") {
125
- writeJsonValue(context.stdout, createPreviewSuccessEnvelope(resolvePreviewJsonSchema(parsed), describeCanonicalCommand(parsed), "completed", buildRepairPreviewData(result), {
126
- nextSteps: ["Run `cogcoin status` to review the repaired local state."],
127
- warnings: getRepairWarnings(result),
128
- }));
187
+ if (parsed.command === "wallet-lock") {
188
+ const result = await context.lockWallet({
189
+ dataDir,
190
+ provider,
191
+ });
192
+ if (parsed.outputMode === "preview-json") {
193
+ writeJsonValue(context.stdout, createPreviewSuccessEnvelope(resolvePreviewJsonSchema(parsed), describeCanonicalCommand(parsed), "locked", buildWalletLockPreviewData(result)));
194
+ return 0;
195
+ }
196
+ if (parsed.outputMode === "json") {
197
+ writeJsonValue(context.stdout, createMutationSuccessEnvelope(resolveStableMutationJsonSchema(parsed), "cogcoin wallet lock", "locked", buildWalletLockMutationData(result)));
198
+ return 0;
199
+ }
200
+ writeLine(context.stdout, `Wallet locked.`);
201
+ writeLine(context.stdout, `Wallet root: ${result.walletRootId ?? "none"}`);
129
202
  return 0;
130
203
  }
131
- if (parsed.outputMode === "json") {
132
- writeJsonValue(context.stdout, createMutationSuccessEnvelope(resolveStableMutationJsonSchema(parsed), "cogcoin repair", "completed", buildRepairMutationData(result), {
133
- nextSteps: ["Run `cogcoin status` to review the repaired local state."],
134
- warnings: getRepairWarnings(result),
135
- }));
204
+ if (parsed.command === "repair") {
205
+ const result = await context.repairWallet({
206
+ dataDir,
207
+ databasePath: dbPath,
208
+ provider,
209
+ assumeYes: parsed.assumeYes,
210
+ });
211
+ if (parsed.outputMode === "preview-json") {
212
+ writeJsonValue(context.stdout, createPreviewSuccessEnvelope(resolvePreviewJsonSchema(parsed), describeCanonicalCommand(parsed), "completed", buildRepairPreviewData(result), {
213
+ nextSteps: ["Run `cogcoin status` to review the repaired local state."],
214
+ warnings: getRepairWarnings(result),
215
+ }));
216
+ return 0;
217
+ }
218
+ if (parsed.outputMode === "json") {
219
+ writeJsonValue(context.stdout, createMutationSuccessEnvelope(resolveStableMutationJsonSchema(parsed), "cogcoin repair", "completed", buildRepairMutationData(result), {
220
+ nextSteps: ["Run `cogcoin status` to review the repaired local state."],
221
+ warnings: getRepairWarnings(result),
222
+ }));
223
+ return 0;
224
+ }
225
+ writeLine(context.stdout, `Wallet repair completed.`);
226
+ writeLine(context.stdout, `Wallet root: ${result.walletRootId}`);
227
+ writeLine(context.stdout, `Recovered from backup: ${result.recoveredFromBackup ? "yes" : "no"}`);
228
+ writeLine(context.stdout, `Managed Core wallet recreated: ${result.recreatedManagedCoreWallet ? "yes" : "no"}`);
229
+ writeLine(context.stdout, `Managed bitcoind action: ${result.bitcoindServiceAction}`);
230
+ writeLine(context.stdout, `Managed bitcoind compatibility issue: ${result.bitcoindCompatibilityIssue}`);
231
+ writeLine(context.stdout, `Managed Core replica action: ${result.managedCoreReplicaAction}`);
232
+ writeLine(context.stdout, `Managed bitcoind post-repair health: ${result.bitcoindPostRepairHealth}`);
233
+ writeLine(context.stdout, `Indexer database reset: ${result.resetIndexerDatabase ? "yes" : "no"}`);
234
+ writeLine(context.stdout, `Indexer daemon action: ${result.indexerDaemonAction}`);
235
+ writeLine(context.stdout, `Indexer compatibility issue: ${result.indexerCompatibilityIssue}`);
236
+ writeLine(context.stdout, `Indexer post-repair health: ${result.indexerPostRepairHealth}`);
237
+ writeLine(context.stdout, `Mining mode before repair: ${result.miningPreRepairRunMode}`);
238
+ writeLine(context.stdout, `Mining resume action: ${result.miningResumeAction}`);
239
+ writeLine(context.stdout, `Mining mode after repair: ${result.miningPostRepairRunMode}`);
240
+ if (result.miningResumeError !== null) {
241
+ writeLine(context.stdout, `Mining resume error: ${result.miningResumeError}`);
242
+ }
243
+ if (result.note !== null) {
244
+ writeLine(context.stdout, `Note: ${result.note}`);
245
+ }
246
+ for (const warning of getRepairWarnings(result)) {
247
+ writeLine(context.stdout, `Warning: ${warning}`);
248
+ }
136
249
  return 0;
137
250
  }
138
- writeLine(context.stdout, `Wallet repair completed.`);
139
- writeLine(context.stdout, `Wallet root: ${result.walletRootId}`);
140
- writeLine(context.stdout, `Recovered from backup: ${result.recoveredFromBackup ? "yes" : "no"}`);
141
- writeLine(context.stdout, `Managed Core wallet recreated: ${result.recreatedManagedCoreWallet ? "yes" : "no"}`);
142
- writeLine(context.stdout, `Managed bitcoind action: ${result.bitcoindServiceAction}`);
143
- writeLine(context.stdout, `Managed bitcoind compatibility issue: ${result.bitcoindCompatibilityIssue}`);
144
- writeLine(context.stdout, `Managed Core replica action: ${result.managedCoreReplicaAction}`);
145
- writeLine(context.stdout, `Managed bitcoind post-repair health: ${result.bitcoindPostRepairHealth}`);
146
- writeLine(context.stdout, `Indexer database reset: ${result.resetIndexerDatabase ? "yes" : "no"}`);
147
- writeLine(context.stdout, `Indexer daemon action: ${result.indexerDaemonAction}`);
148
- writeLine(context.stdout, `Indexer compatibility issue: ${result.indexerCompatibilityIssue}`);
149
- writeLine(context.stdout, `Indexer post-repair health: ${result.indexerPostRepairHealth}`);
150
- writeLine(context.stdout, `Mining mode before repair: ${result.miningPreRepairRunMode}`);
151
- writeLine(context.stdout, `Mining resume action: ${result.miningResumeAction}`);
152
- writeLine(context.stdout, `Mining mode after repair: ${result.miningPostRepairRunMode}`);
153
- if (result.miningResumeError !== null) {
154
- writeLine(context.stdout, `Mining resume error: ${result.miningResumeError}`);
155
- }
156
- if (result.note !== null) {
157
- writeLine(context.stdout, `Note: ${result.note}`);
158
- }
159
- for (const warning of getRepairWarnings(result)) {
160
- writeLine(context.stdout, `Warning: ${warning}`);
161
- }
162
- return 0;
251
+ writeLine(context.stderr, `wallet admin command not implemented: ${parsed.command}`);
252
+ return 1;
253
+ })(), stopWatcher);
254
+ if (outcome.kind === "stopped") {
255
+ return outcome.code;
163
256
  }
164
- writeLine(context.stderr, `wallet admin command not implemented: ${parsed.command}`);
165
- return 1;
257
+ return outcome.value;
166
258
  }
167
259
  catch (error) {
168
260
  return writeHandledCliError({
@@ -172,4 +264,7 @@ export async function runWalletAdminCommand(parsed, context) {
172
264
  error,
173
265
  });
174
266
  }
267
+ finally {
268
+ stopWatcher.cleanup();
269
+ }
175
270
  }