@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,17 @@
1
1
  import { mkdir, readFile } from "node:fs/promises";
2
+ import { attachOrStartIndexerDaemon, probeIndexerDaemon, readObservedIndexerDaemonStatus, stopIndexerDaemonService, } from "../bitcoind/indexer-daemon.js";
3
+ import { createRpcClient } from "../bitcoind/node.js";
4
+ import { attachOrStartManagedBitcoindService, probeManagedBitcoindService, stopManagedBitcoindService, } from "../bitcoind/service.js";
2
5
  import { resolveDefaultBitcoindDataDirForTesting, resolveDefaultClientDatabasePathForTesting, } from "../app-paths.js";
3
6
  import { openManagedBitcoindClient } from "../bitcoind/index.js";
4
7
  import { inspectPassiveClientStatus } from "../passive-status.js";
5
8
  import { openSqliteStore } from "../sqlite/index.js";
6
- import { exportWallet, importWallet, initializeWallet, lockWallet, repairWallet, unlockWallet, } from "../wallet/lifecycle.js";
9
+ import { exportWallet, importWallet, initializeWallet, lockWallet, previewResetWallet, repairWallet, resetWallet, restoreWalletFromMnemonic, unlockWallet, } from "../wallet/lifecycle.js";
10
+ import { resolveWalletRuntimePathsForTesting } from "../wallet/runtime.js";
7
11
  import { openWalletReadContext } from "../wallet/read/index.js";
12
+ import { loadWalletExplicitLock } from "../wallet/state/explicit-lock.js";
13
+ import { loadUnlockSession } from "../wallet/state/session.js";
14
+ import { loadWalletState } from "../wallet/state/storage.js";
8
15
  import { disableMiningHooks, enableMiningHooks, followMiningLog, inspectMiningControlPlane, readMiningLog, runForegroundMining, setupBuiltInMining, startBackgroundMining, stopBackgroundMining, } from "../wallet/mining/index.js";
9
16
  import { createLazyDefaultWalletSecretProvider } from "../wallet/state/provider.js";
10
17
  import { anchorDomain, buyDomain, claimCogLock, clearDomainDelegate, clearDomainEndpoint, clearDomainMiner, clearField, createField, giveReputation, lockCogToDomain, registerDomain, reclaimCogLock, revokeReputation, sendCog, setField, setDomainCanonical, setDomainDelegate, setDomainEndpoint, setDomainMiner, sellDomain, transferDomain, } from "../wallet/tx/index.js";
@@ -28,6 +35,8 @@ export function createDefaultContext(overrides = {}) {
28
35
  inspectPassiveClientStatus: overrides.inspectPassiveClientStatus ?? inspectPassiveClientStatus,
29
36
  openWalletReadContext: overrides.openWalletReadContext ?? openWalletReadContext,
30
37
  initializeWallet: overrides.initializeWallet ?? initializeWallet,
38
+ restoreWalletFromMnemonic: overrides.restoreWalletFromMnemonic ?? restoreWalletFromMnemonic,
39
+ previewResetWallet: overrides.previewResetWallet ?? previewResetWallet,
31
40
  exportWallet: overrides.exportWallet ?? exportWallet,
32
41
  importWallet: overrides.importWallet ?? importWallet,
33
42
  unlockWallet: overrides.unlockWallet ?? unlockWallet,
@@ -63,13 +72,26 @@ export function createDefaultContext(overrides = {}) {
63
72
  readMiningLog: overrides.readMiningLog ?? readMiningLog,
64
73
  followMiningLog: overrides.followMiningLog ?? followMiningLog,
65
74
  repairWallet: overrides.repairWallet ?? repairWallet,
75
+ resetWallet: overrides.resetWallet ?? resetWallet,
66
76
  walletSecretProvider: overrides.walletSecretProvider ?? createLazyDefaultWalletSecretProvider(),
67
77
  createPrompter: overrides.createPrompter ?? (() => createTerminalPrompter(overrides.stdin ?? process.stdin, overrides.stdout ?? process.stdout)),
68
78
  ensureDirectory: overrides.ensureDirectory ?? (async (path) => {
69
79
  await mkdir(path, { recursive: true });
70
80
  }),
81
+ attachManagedBitcoindService: overrides.attachManagedBitcoindService ?? attachOrStartManagedBitcoindService,
82
+ probeManagedBitcoindService: overrides.probeManagedBitcoindService ?? probeManagedBitcoindService,
83
+ stopManagedBitcoindService: overrides.stopManagedBitcoindService ?? stopManagedBitcoindService,
84
+ createBitcoinRpcClient: overrides.createBitcoinRpcClient ?? createRpcClient,
85
+ attachIndexerDaemon: overrides.attachIndexerDaemon ?? attachOrStartIndexerDaemon,
86
+ probeIndexerDaemon: overrides.probeIndexerDaemon ?? probeIndexerDaemon,
87
+ readObservedIndexerDaemonStatus: overrides.readObservedIndexerDaemonStatus ?? readObservedIndexerDaemonStatus,
88
+ stopIndexerDaemonService: overrides.stopIndexerDaemonService ?? stopIndexerDaemonService,
71
89
  readPackageVersion: overrides.readPackageVersion ?? readPackageVersionFromDisk,
90
+ loadWalletState: overrides.loadWalletState ?? loadWalletState,
91
+ loadUnlockSession: overrides.loadUnlockSession ?? loadUnlockSession,
92
+ loadWalletExplicitLock: overrides.loadWalletExplicitLock ?? loadWalletExplicitLock,
72
93
  resolveDefaultBitcoindDataDir: overrides.resolveDefaultBitcoindDataDir ?? resolveDefaultBitcoindDataDirForTesting,
73
94
  resolveDefaultClientDatabasePath: overrides.resolveDefaultClientDatabasePath ?? resolveDefaultClientDatabasePathForTesting,
95
+ resolveWalletRuntimePaths: overrides.resolveWalletRuntimePaths ?? resolveWalletRuntimePathsForTesting,
74
96
  };
75
97
  }
@@ -1,5 +1,5 @@
1
1
  import type { AnchorDomainResult, CogMutationResult, DomainAdminMutationResult, DomainMarketMutationResult, FieldMutationResult, RegisterDomainResult, ReputationMutationResult } from "../wallet/tx/index.js";
2
- import type { WalletInitializationResult, WalletExportResult, WalletImportResult, WalletRepairResult, WalletUnlockResult } from "../wallet/lifecycle.js";
2
+ import type { WalletInitializationResult, WalletExportResult, WalletImportResult, WalletRepairResult, WalletResetResult, WalletRestoreResult, WalletUnlockResult } from "../wallet/lifecycle.js";
3
3
  export declare function buildSingleTxMutationData(options: {
4
4
  kind: string;
5
5
  localStatus: string;
@@ -222,6 +222,13 @@ export declare function buildAnchorMutationData(result: AnchorDomainResult, opti
222
222
  };
223
223
  intent: Record<string, unknown>;
224
224
  };
225
+ export declare function buildResetMutationData(result: WalletResetResult): {
226
+ resultType: "operation";
227
+ operation: {
228
+ kind: string;
229
+ };
230
+ state: Record<string, unknown> | null;
231
+ };
225
232
  export declare function buildDomainAdminMutationData(result: DomainAdminMutationResult, options: {
226
233
  commandKind: "domain-endpoint-set" | "domain-endpoint-clear" | "domain-delegate-set" | "domain-delegate-clear" | "domain-miner-set" | "domain-miner-clear" | "domain-canonical";
227
234
  }): {
@@ -394,6 +401,15 @@ export declare function buildInitMutationData(result: WalletInitializationResult
394
401
  };
395
402
  state: Record<string, unknown>;
396
403
  };
404
+ export declare function buildRestoreMutationData(result: WalletRestoreResult): {
405
+ resultType: "state-change";
406
+ stateChange: {
407
+ kind: string;
408
+ before: Record<string, unknown> | null;
409
+ after: Record<string, unknown> | null;
410
+ };
411
+ state: Record<string, unknown>;
412
+ };
397
413
  export declare function buildUnlockMutationData(result: WalletUnlockResult): {
398
414
  resultType: "state-change";
399
415
  stateChange: {
@@ -140,6 +140,35 @@ export function buildAnchorMutationData(result, options) {
140
140
  },
141
141
  });
142
142
  }
143
+ export function buildResetMutationData(result) {
144
+ return buildOperationData({
145
+ kind: "reset",
146
+ state: {
147
+ dataRoot: result.dataRoot,
148
+ factoryResetReady: result.factoryResetReady,
149
+ walletAction: result.walletAction,
150
+ walletOldRootId: result.walletOldRootId,
151
+ walletNewRootId: result.walletNewRootId,
152
+ bootstrapSnapshot: result.bootstrapSnapshot,
153
+ stoppedProcesses: result.stoppedProcesses,
154
+ secretCleanupStatus: result.secretCleanupStatus,
155
+ },
156
+ operation: {
157
+ dataRoot: result.dataRoot,
158
+ factoryResetReady: result.factoryResetReady,
159
+ stoppedProcesses: result.stoppedProcesses,
160
+ secretCleanupStatus: result.secretCleanupStatus,
161
+ deletedSecretRefs: result.deletedSecretRefs,
162
+ failedSecretRefs: result.failedSecretRefs,
163
+ preservedSecretRefs: result.preservedSecretRefs,
164
+ walletAction: result.walletAction,
165
+ walletOldRootId: result.walletOldRootId,
166
+ walletNewRootId: result.walletNewRootId,
167
+ bootstrapSnapshot: result.bootstrapSnapshot,
168
+ removedPaths: result.removedPaths,
169
+ },
170
+ });
171
+ }
143
172
  export function buildDomainAdminMutationData(result, options) {
144
173
  const data = buildSingleTxMutationData({
145
174
  kind: options.commandKind,
@@ -242,6 +271,19 @@ export function buildInitMutationData(result) {
242
271
  after,
243
272
  });
244
273
  }
274
+ export function buildRestoreMutationData(result) {
275
+ const after = {
276
+ walletRootId: result.walletRootId,
277
+ fundingAddress: result.fundingAddress,
278
+ unlockUntilUnixMs: result.unlockUntilUnixMs,
279
+ locked: false,
280
+ };
281
+ return buildStateChangeData({
282
+ kind: "restore",
283
+ state: after,
284
+ after,
285
+ });
286
+ }
245
287
  export function buildUnlockMutationData(result) {
246
288
  const after = {
247
289
  walletRootId: result.state.walletRootId,
@@ -152,7 +152,12 @@ export function classifyCliError(error) {
152
152
  if (message === "wallet_typed_confirmation_rejected"
153
153
  || message === "wallet_export_overwrite_declined"
154
154
  || message === "wallet_prompt_value_required"
155
- || message === "wallet_archive_passphrase_mismatch") {
155
+ || message === "wallet_archive_passphrase_mismatch"
156
+ || message === "wallet_restore_mnemonic_invalid"
157
+ || message === "wallet_restore_replace_confirmation_required"
158
+ || message === "reset_wallet_choice_invalid"
159
+ || message === "reset_wallet_passphrase_required"
160
+ || message === "reset_wallet_access_failed") {
156
161
  return { exitCode: 2, errorCode: message, message };
157
162
  }
158
163
  if (message === "not_found") {
@@ -161,6 +166,12 @@ export function classifyCliError(error) {
161
166
  if (message === "wallet_import_archive_not_found") {
162
167
  return { exitCode: 3, errorCode: message, message };
163
168
  }
169
+ if (message === "reset_process_shutdown_failed"
170
+ || message === "reset_data_root_delete_failed"
171
+ || message === "reset_secret_cleanup_failed"
172
+ || message === "reset_snapshot_preserve_failed") {
173
+ return { exitCode: 5, errorCode: message, message };
174
+ }
164
175
  if (isBlockedError(message)) {
165
176
  return { exitCode: 4, errorCode: message, message };
166
177
  }
@@ -215,6 +226,62 @@ export function createCliErrorPresentation(errorCode, fallbackMessage) {
215
226
  next: "Run `cogcoin unlock --for 15m` and retry.",
216
227
  };
217
228
  }
229
+ if (errorCode === "reset_wallet_choice_invalid") {
230
+ return {
231
+ what: "Wallet reset choice is invalid.",
232
+ why: "This reset path accepts only Enter for the default entropy-retaining reset, \"skip\", or \"delete wallet\".",
233
+ next: "Rerun `cogcoin reset` and enter one of the accepted wallet reset choices.",
234
+ };
235
+ }
236
+ if (errorCode === "reset_wallet_passphrase_required") {
237
+ return {
238
+ what: "Wallet-state passphrase is required.",
239
+ why: "The current wallet is passphrase-wrapped, so the entropy-retaining reset path needs that passphrase before it can rebuild a fresh local wallet from the retained mnemonic.",
240
+ next: "Rerun `cogcoin reset` and enter the wallet-state passphrase, or choose \"skip\" or \"delete wallet\" instead.",
241
+ };
242
+ }
243
+ if (errorCode === "reset_wallet_access_failed") {
244
+ return {
245
+ what: "Wallet state could not be opened for entropy-retaining reset.",
246
+ why: "The wallet-state passphrase was not accepted, or the passphrase-wrapped wallet state could not be decrypted cleanly.",
247
+ next: "Rerun `cogcoin reset`, enter the correct wallet-state passphrase, or choose \"skip\" or \"delete wallet\" instead.",
248
+ };
249
+ }
250
+ if (errorCode === "reset_wallet_entropy_reset_unavailable") {
251
+ return {
252
+ what: "Entropy-retaining wallet reset is unavailable.",
253
+ why: "Cogcoin found wallet state, but it could not safely load and reconstruct it into a fresh wallet while preserving only the mnemonic-derived continuity data.",
254
+ next: "Rerun `cogcoin reset` and choose \"skip\" to keep the wallet unchanged, or type \"delete wallet\" to erase it fully.",
255
+ };
256
+ }
257
+ if (errorCode === "reset_process_shutdown_failed") {
258
+ return {
259
+ what: "Reset could not stop all tracked managed processes.",
260
+ why: "At least one Cogcoin-managed background process remained alive after the reset shutdown attempt, so the filesystem reset was aborted before deleting local state.",
261
+ next: "Stop the remaining managed process and rerun `cogcoin reset`.",
262
+ };
263
+ }
264
+ if (errorCode === "reset_data_root_delete_failed") {
265
+ return {
266
+ what: "Reset could not remove the local Cogcoin data roots.",
267
+ why: "The reset flow reached the destructive phase, but at least one local Cogcoin data root could not be deleted completely.",
268
+ next: "Check permissions and any open file handles under the Cogcoin data roots, then rerun `cogcoin reset`.",
269
+ };
270
+ }
271
+ if (errorCode === "reset_secret_cleanup_failed") {
272
+ return {
273
+ what: "Reset finished the filesystem wipe but could not fully clean up wallet secret-provider entries.",
274
+ why: "The local Cogcoin files were already removed or rewritten, but at least one discoverable OS secret-store entry could not be deleted cleanly.",
275
+ next: "Remove the remaining Cogcoin wallet secret from the local secret store, then rerun `cogcoin status` to confirm the new state.",
276
+ };
277
+ }
278
+ if (errorCode === "reset_snapshot_preserve_failed") {
279
+ return {
280
+ what: "Reset could not preserve the downloaded 910000 UTXO snapshot.",
281
+ why: "You asked reset to keep the valid snapshot, but staging or restoring that large bootstrap file did not complete successfully.",
282
+ next: "Rerun `cogcoin reset` and choose to delete the snapshot, or restore the snapshot file manually before retrying.",
283
+ };
284
+ }
218
285
  if (errorCode === "wallet_uninitialized") {
219
286
  return {
220
287
  what: "Wallet is not initialized.",
@@ -222,6 +289,13 @@ export function createCliErrorPresentation(errorCode, fallbackMessage) {
222
289
  next: "Run `cogcoin init` first.",
223
290
  };
224
291
  }
292
+ if (errorCode === "wallet_repair_indexer_reset_requires_yes") {
293
+ return {
294
+ what: "Repair needs permission to reset the local indexer database.",
295
+ why: "The local indexer database could not be opened as a healthy Cogcoin store, so repair would need to delete and rebuild it before continuing.",
296
+ next: "Rerun `cogcoin repair --yes` to allow repair to recreate the local indexer database.",
297
+ };
298
+ }
225
299
  if (errorCode === "wallet_already_initialized") {
226
300
  return {
227
301
  what: "Wallet is already initialized.",
@@ -261,7 +335,21 @@ export function createCliErrorPresentation(errorCode, fallbackMessage) {
261
335
  return {
262
336
  what: "Mnemonic confirmation failed.",
263
337
  why: "The requested recovery-phrase confirmation word did not match, so wallet initialization was canceled before it could finish.",
264
- next: "Run `cogcoin init` again and re-enter the requested confirmation words carefully.",
338
+ next: "Run `cogcoin init` again and re-enter the requested confirmation words carefully. The same recovery phrase will be shown until confirmation succeeds.",
339
+ };
340
+ }
341
+ if (errorCode === "wallet_restore_mnemonic_invalid") {
342
+ return {
343
+ what: "Recovery phrase is invalid.",
344
+ why: "Mnemonic-only restore accepts only a valid 24-word English BIP39 phrase with a matching checksum.",
345
+ next: "Rerun `cogcoin restore` and enter the 24 recovery words in the original order.",
346
+ };
347
+ }
348
+ if (errorCode === "wallet_restore_replace_confirmation_required") {
349
+ return {
350
+ what: "Typed replacement acknowledgement is still required.",
351
+ why: "Mnemonic restore will replace the existing local wallet state and managed Core wallet replica only after you type the exact replacement acknowledgement.",
352
+ next: "Rerun `cogcoin restore` in an interactive terminal and type \"RESTORE\" when prompted.",
265
353
  };
266
354
  }
267
355
  if (errorCode === "mining_hooks_enable_trust_acknowledgement_required") {
@@ -644,9 +732,14 @@ export function describeCanonicalCommand(parsed) {
644
732
  case "init":
645
733
  case "wallet-init":
646
734
  return "cogcoin init";
735
+ case "restore":
736
+ case "wallet-restore":
737
+ return "cogcoin restore";
647
738
  case "unlock":
648
739
  case "wallet-unlock":
649
740
  return "cogcoin unlock";
741
+ case "reset":
742
+ return "cogcoin reset";
650
743
  case "repair":
651
744
  return "cogcoin repair";
652
745
  case "wallet-lock":
@@ -767,6 +860,18 @@ export function resolveStableJsonSchema(parsed) {
767
860
  switch (parsed.command) {
768
861
  case "status":
769
862
  return "cogcoin/status/v1";
863
+ case "bitcoin-start":
864
+ return "cogcoin/bitcoin-start/v1";
865
+ case "bitcoin-stop":
866
+ return "cogcoin/bitcoin-stop/v1";
867
+ case "bitcoin-status":
868
+ return "cogcoin/bitcoin-status/v1";
869
+ case "indexer-start":
870
+ return "cogcoin/indexer-start/v1";
871
+ case "indexer-stop":
872
+ return "cogcoin/indexer-stop/v1";
873
+ case "indexer-status":
874
+ return "cogcoin/indexer-status/v1";
770
875
  case "wallet-address":
771
876
  case "address":
772
877
  return "cogcoin/address/v1";
@@ -808,9 +913,14 @@ export function resolveStableMutationJsonSchema(parsed) {
808
913
  case "init":
809
914
  case "wallet-init":
810
915
  return "cogcoin/init/v1";
916
+ case "restore":
917
+ case "wallet-restore":
918
+ return "cogcoin/restore/v1";
811
919
  case "unlock":
812
920
  case "wallet-unlock":
813
921
  return "cogcoin/unlock/v1";
922
+ case "reset":
923
+ return "cogcoin/reset/v1";
814
924
  case "wallet-export":
815
925
  return "cogcoin/wallet-export/v1";
816
926
  case "wallet-import":
@@ -897,6 +1007,7 @@ export function resolvePreviewJsonSchema(parsed) {
897
1007
  const stableMiningControlSchema = resolveStableMiningControlJsonSchema(parsed);
898
1008
  switch (parsed.command) {
899
1009
  case "wallet-lock":
1010
+ case "reset":
900
1011
  case "repair":
901
1012
  case "anchor":
902
1013
  case "domain-anchor":
@@ -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 init Initialize a new local wallet root\n init --output json Emit the stable v1 machine-readable init result envelope\n repair Recover bounded wallet/indexer/runtime state\n unlock Clear an explicit wallet lock and unlock for a limited duration\n wallet address Alias for address\n wallet ids Alias for ids\n hooks enable mining Enable a validated custom mining hook\n hooks disable mining Return to built-in mining hooks\n hooks status Show mining hook validation and trust status\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 Tx1/Tx2 family\n register <domain> [--from <identity>]\n Register a root domain or subdomain\n transfer <domain> --to <btc-target>\n Transfer an unanchored domain to another BTC identity\n sell <domain> <price> List an unanchored domain for sale in COG\n unsell <domain> Clear an active domain listing\n buy <domain> [--from <identity>]\n Buy an unanchored listed domain in COG\n send <amount> --to <btc-target>\n Send COG from one local identity 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 unlock Clear an explicit wallet lock and unlock for a limited duration\n wallet lock Lock the local wallet and disable on-demand unlock\n wallet export <path> Export a portable encrypted wallet archive\n wallet import <path> Import a portable encrypted wallet archive\n address Show the BTC funding identity for this wallet\n ids List locally controlled identities\n balance Show per-identity 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 anchored field, optionally with an initial value\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> Unlock duration like 15m, 2h, or 1d when unlocking explicitly\n --message <text> Founding message text for anchor\n --to <btc-target> Transfer or send target as an address or spk:<hex>\n --from <identity> Resolve sender identity as id:<n>, domain:<name>, 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 --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 --verify Run full custom-hook verification\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 --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 init --output json\n cogcoin wallet address\n cogcoin domain list --mineable\n cogcoin register alpha-child\n cogcoin register weatherbot --from id:1\n cogcoin anchor alpha\n cogcoin buy alpha\n cogcoin buy alpha --from id:1\n cogcoin field create alpha bio --text \"hello\"\n cogcoin rep give alpha beta 10 --review \"great operator\"\n cogcoin hooks status\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 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 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 a fresh local wallet 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 unlock Clear an explicit wallet lock and unlock for a limited duration\n wallet address Alias for address\n wallet ids Alias for ids\n hooks enable mining Enable a validated custom mining hook\n hooks disable mining Return to built-in mining hooks\n hooks status Show mining hook validation and trust status\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 Tx1/Tx2 family\n register <domain> [--from <identity>]\n Register a root domain or subdomain\n transfer <domain> --to <btc-target>\n Transfer an unanchored domain to another BTC identity\n sell <domain> <price> List an unanchored domain for sale in COG\n unsell <domain> Clear an active domain listing\n buy <domain> [--from <identity>]\n Buy an unanchored listed domain in COG\n send <amount> --to <btc-target>\n Send COG from one local identity 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 a fresh local wallet from a 24-word mnemonic; run sync afterward\n wallet unlock Clear an explicit wallet lock and unlock for a limited duration\n wallet lock Lock the local wallet and disable on-demand unlock\n wallet export <path> Export a portable encrypted wallet archive\n wallet import <path> Import a portable encrypted wallet archive\n address Show the BTC funding identity for this wallet\n ids List locally controlled identities\n balance Show per-identity 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 anchored field, optionally with an initial value\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> Unlock duration like 15m, 2h, or 1d when unlocking explicitly\n --message <text> Founding message text for anchor\n --to <btc-target> Transfer or send target as an address or spk:<hex>\n --from <identity> Resolve sender identity as id:<n>, domain:<name>, 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 --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 --verify Run full custom-hook verification\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 --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 wallet address\n cogcoin domain list --mineable\n cogcoin register alpha-child\n cogcoin register weatherbot --from id:1\n cogcoin anchor alpha\n cogcoin buy alpha\n cogcoin buy alpha --from id:1\n cogcoin field create alpha bio --text \"hello\"\n cogcoin rep give alpha beta 10 --review \"great operator\"\n cogcoin hooks status\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
@@ -4,8 +4,16 @@ export const HELP_TEXT = `Usage: cogcoin <command> [options]
4
4
  Commands:
5
5
  status Show wallet-aware local service and chain status
6
6
  status --output json Emit the stable v1 machine-readable status envelope
7
+ bitcoin start Start the managed Bitcoin daemon
8
+ bitcoin stop Stop the managed Bitcoin daemon and paired indexer
9
+ bitcoin status Show managed Bitcoin daemon status without starting it
10
+ indexer start Start the managed Cogcoin indexer (and bitcoind if needed)
11
+ indexer stop Stop the managed Cogcoin indexer only
12
+ indexer status Show managed Cogcoin indexer status without starting it
7
13
  init Initialize a new local wallet root
8
14
  init --output json Emit the stable v1 machine-readable init result envelope
15
+ restore Restore a fresh local wallet from a 24-word mnemonic; run sync afterward
16
+ reset Factory-reset local Cogcoin state with interactive retention prompts
9
17
  repair Recover bounded wallet/indexer/runtime state
10
18
  unlock Clear an explicit wallet lock and unlock for a limited duration
11
19
  wallet address Alias for address
@@ -39,6 +47,7 @@ Commands:
39
47
  Lock COG to an anchored recipient domain
40
48
  wallet status Show detailed wallet-local status and service health
41
49
  wallet init Initialize a new local wallet root
50
+ wallet restore Restore a fresh local wallet from a 24-word mnemonic; run sync afterward
42
51
  wallet unlock Clear an explicit wallet lock and unlock for a limited duration
43
52
  wallet lock Lock the local wallet and disable on-demand unlock
44
53
  wallet export <path> Export a portable encrypted wallet archive
@@ -110,6 +119,8 @@ Quickstart:
110
119
 
111
120
  Examples:
112
121
  cogcoin status --output json
122
+ cogcoin bitcoin status
123
+ cogcoin indexer status
113
124
  cogcoin init --output json
114
125
  cogcoin wallet address
115
126
  cogcoin domain list --mineable
@@ -435,6 +446,11 @@ export function parseCliArgs(argv) {
435
446
  index += 1;
436
447
  continue;
437
448
  }
449
+ if (subcommand === "restore") {
450
+ command = "wallet-restore";
451
+ index += 1;
452
+ continue;
453
+ }
438
454
  if (subcommand === "unlock") {
439
455
  command = "wallet-unlock";
440
456
  index += 1;
@@ -457,6 +473,44 @@ export function parseCliArgs(argv) {
457
473
  }
458
474
  throw new Error(`cli_unknown_command_wallet${subcommand === null ? "" : `_${subcommand}`}`);
459
475
  }
476
+ if (token === "bitcoin") {
477
+ const subcommand = argv[index + 1] ?? null;
478
+ if (subcommand === "start") {
479
+ command = "bitcoin-start";
480
+ index += 1;
481
+ continue;
482
+ }
483
+ if (subcommand === "stop") {
484
+ command = "bitcoin-stop";
485
+ index += 1;
486
+ continue;
487
+ }
488
+ if (subcommand === "status") {
489
+ command = "bitcoin-status";
490
+ index += 1;
491
+ continue;
492
+ }
493
+ throw new Error(`cli_unknown_command_bitcoin${subcommand === null ? "" : `_${subcommand}`}`);
494
+ }
495
+ if (token === "indexer") {
496
+ const subcommand = argv[index + 1] ?? null;
497
+ if (subcommand === "start") {
498
+ command = "indexer-start";
499
+ index += 1;
500
+ continue;
501
+ }
502
+ if (subcommand === "stop") {
503
+ command = "indexer-stop";
504
+ index += 1;
505
+ continue;
506
+ }
507
+ if (subcommand === "status") {
508
+ command = "indexer-status";
509
+ index += 1;
510
+ continue;
511
+ }
512
+ throw new Error(`cli_unknown_command_indexer${subcommand === null ? "" : `_${subcommand}`}`);
513
+ }
460
514
  if (token === "hooks") {
461
515
  const subcommand = argv[index + 1] ?? null;
462
516
  if (subcommand === "status") {
@@ -678,6 +732,8 @@ export function parseCliArgs(argv) {
678
732
  continue;
679
733
  }
680
734
  if (token === "init"
735
+ || token === "restore"
736
+ || token === "reset"
681
737
  || token === "repair"
682
738
  || token === "sync"
683
739
  || token === "status"
@@ -707,9 +763,18 @@ export function parseCliArgs(argv) {
707
763
  args.push(token);
708
764
  }
709
765
  if ((command === "status"
766
+ || command === "bitcoin-start"
767
+ || command === "bitcoin-stop"
768
+ || command === "bitcoin-status"
769
+ || command === "indexer-start"
770
+ || command === "indexer-stop"
771
+ || command === "indexer-status"
710
772
  || command === "init"
773
+ || command === "restore"
774
+ || command === "reset"
711
775
  || command === "unlock"
712
776
  || command === "wallet-init"
777
+ || command === "wallet-restore"
713
778
  || command === "wallet-lock"
714
779
  || command === "wallet-unlock"
715
780
  || command === "wallet-status"
@@ -1,5 +1,5 @@
1
1
  import type { AnchorDomainResult, CogMutationResult, DomainAdminMutationResult, DomainMarketMutationResult, FieldMutationResult, RegisterDomainResult, ReputationMutationResult } from "../wallet/tx/index.js";
2
- import type { WalletRepairResult } from "../wallet/lifecycle.js";
2
+ import type { WalletRepairResult, WalletResetPreview } from "../wallet/lifecycle.js";
3
3
  import type { MiningControlPlaneView, MiningRuntimeStatusV1 } from "../wallet/mining/index.js";
4
4
  export declare function buildSingleTxMutationPreviewData(options: {
5
5
  kind: string;
@@ -71,6 +71,17 @@ export declare function buildStateChangePreviewData(options: {
71
71
  };
72
72
  state: Record<string, unknown>;
73
73
  };
74
+ export declare function buildOperationPreviewData(options: {
75
+ kind: string;
76
+ state?: Record<string, unknown> | null;
77
+ operation: Record<string, unknown>;
78
+ }): {
79
+ resultType: "operation";
80
+ operation: {
81
+ kind: string;
82
+ };
83
+ state: Record<string, unknown> | null;
84
+ };
74
85
  export declare function buildRegisterPreviewData(result: RegisterDomainResult, options: {
75
86
  forceRace: boolean;
76
87
  fromIdentity: string | null;
@@ -375,6 +386,13 @@ export declare function buildWalletLockPreviewData(result: {
375
386
  };
376
387
  state: Record<string, unknown>;
377
388
  };
389
+ export declare function buildResetPreviewData(result: WalletResetPreview): {
390
+ resultType: "operation";
391
+ operation: {
392
+ kind: string;
393
+ };
394
+ state: Record<string, unknown> | null;
395
+ };
378
396
  export declare function buildRepairPreviewData(result: WalletRepairResult): {
379
397
  resultType: "state-change";
380
398
  stateChange: {
@@ -47,6 +47,16 @@ export function buildStateChangePreviewData(options) {
47
47
  state: options.state,
48
48
  };
49
49
  }
50
+ export function buildOperationPreviewData(options) {
51
+ return {
52
+ resultType: "operation",
53
+ operation: {
54
+ kind: options.kind,
55
+ ...options.operation,
56
+ },
57
+ state: options.state ?? null,
58
+ };
59
+ }
50
60
  export function buildRegisterPreviewData(result, options) {
51
61
  return {
52
62
  ...buildSingleTxMutationPreviewData({
@@ -216,6 +226,27 @@ export function buildWalletLockPreviewData(result) {
216
226
  },
217
227
  });
218
228
  }
229
+ export function buildResetPreviewData(result) {
230
+ return buildOperationPreviewData({
231
+ kind: "reset",
232
+ state: {
233
+ dataRoot: result.dataRoot,
234
+ trackedProcessKinds: result.trackedProcessKinds,
235
+ willDeleteOsSecrets: result.willDeleteOsSecrets,
236
+ bootstrapSnapshot: result.bootstrapSnapshot,
237
+ walletPrompt: result.walletPrompt,
238
+ },
239
+ operation: {
240
+ dataRoot: result.dataRoot,
241
+ confirmationPhrase: result.confirmationPhrase,
242
+ walletPrompt: result.walletPrompt,
243
+ bootstrapSnapshot: result.bootstrapSnapshot,
244
+ trackedProcessKinds: result.trackedProcessKinds,
245
+ willDeleteOsSecrets: result.willDeleteOsSecrets,
246
+ removedPaths: result.removedPaths,
247
+ },
248
+ });
249
+ }
219
250
  export function buildRepairPreviewData(result) {
220
251
  return buildStateChangePreviewData({
221
252
  kind: "repair",
@@ -1,25 +1,53 @@
1
1
  import { createInterface } from "node:readline/promises";
2
2
  const CLEAR_SENSITIVE_DISPLAY_SEQUENCE = "\u001B[2J\u001B[3J\u001B[H";
3
3
  export function createTerminalPrompter(input, output) {
4
+ const ensureReadableInput = () => {
5
+ if (!("on" in input) || !("off" in input)) {
6
+ throw new Error("wallet_prompt_input_unavailable");
7
+ }
8
+ return input;
9
+ };
10
+ const ensureWritableOutput = () => output;
11
+ const ask = async (message, questionOutput) => {
12
+ const readline = createInterface({
13
+ input: ensureReadableInput(),
14
+ output: questionOutput,
15
+ });
16
+ try {
17
+ return await readline.question(message);
18
+ }
19
+ finally {
20
+ readline.close();
21
+ }
22
+ };
4
23
  return {
5
24
  isInteractive: Boolean(input.isTTY && output.isTTY),
6
25
  writeLine(message) {
7
26
  output.write(`${message}\n`);
8
27
  },
9
28
  async prompt(message) {
10
- if (!("on" in input) || !("off" in input)) {
11
- throw new Error("wallet_prompt_input_unavailable");
12
- }
13
- const readline = createInterface({
14
- input: input,
15
- output: output,
29
+ return await ask(message, ensureWritableOutput());
30
+ },
31
+ async promptHidden(message) {
32
+ const writableOutput = ensureWritableOutput();
33
+ let promptShown = false;
34
+ const hiddenOutput = Object.create(writableOutput);
35
+ hiddenOutput.write = ((chunk) => {
36
+ if (!promptShown) {
37
+ promptShown = true;
38
+ output.write(chunk);
39
+ return true;
40
+ }
41
+ if (chunk === "\n" || chunk === "\r\n") {
42
+ output.write(chunk);
43
+ }
44
+ return true;
16
45
  });
17
- try {
18
- return await readline.question(message);
19
- }
20
- finally {
21
- readline.close();
22
- }
46
+ hiddenOutput.on ??= (() => hiddenOutput);
47
+ hiddenOutput.once ??= (() => hiddenOutput);
48
+ hiddenOutput.off ??= (() => hiddenOutput);
49
+ hiddenOutput.removeListener ??= (() => hiddenOutput);
50
+ return await ask(message, hiddenOutput);
23
51
  },
24
52
  clearSensitiveDisplay(scope) {
25
53
  if (!input.isTTY || !output.isTTY) {