@cogcoin/client 0.5.14 → 1.0.0

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 (172) hide show
  1. package/README.md +80 -25
  2. package/dist/app-paths.d.ts +5 -6
  3. package/dist/app-paths.js +8 -16
  4. package/dist/art/balance.txt +10 -0
  5. package/dist/art/welcome.txt +16 -0
  6. package/dist/bitcoind/bootstrap/controller.d.ts +1 -0
  7. package/dist/bitcoind/bootstrap/controller.js +53 -1
  8. package/dist/bitcoind/client/follow-block-times.d.ts +1 -0
  9. package/dist/bitcoind/client/follow-block-times.js +1 -1
  10. package/dist/bitcoind/client/internal-types.d.ts +7 -3
  11. package/dist/bitcoind/client/managed-client.d.ts +4 -2
  12. package/dist/bitcoind/client/managed-client.js +14 -0
  13. package/dist/bitcoind/client/sync-engine.js +72 -11
  14. package/dist/bitcoind/hash-order.d.ts +4 -0
  15. package/dist/bitcoind/hash-order.js +13 -0
  16. package/dist/bitcoind/indexer-daemon-main.js +11 -3
  17. package/dist/bitcoind/normalize.js +3 -2
  18. package/dist/bitcoind/processing-start-height.d.ts +5 -0
  19. package/dist/bitcoind/processing-start-height.js +7 -0
  20. package/dist/bitcoind/progress/constants.d.ts +4 -0
  21. package/dist/bitcoind/progress/constants.js +4 -0
  22. package/dist/bitcoind/progress/controller.d.ts +2 -1
  23. package/dist/bitcoind/progress/controller.js +3 -3
  24. package/dist/bitcoind/progress/follow-scene.d.ts +6 -2
  25. package/dist/bitcoind/progress/follow-scene.js +29 -6
  26. package/dist/bitcoind/progress/formatting.d.ts +1 -0
  27. package/dist/bitcoind/progress/formatting.js +6 -0
  28. package/dist/bitcoind/progress/train-scene.js +37 -18
  29. package/dist/bitcoind/progress/tty-renderer.d.ts +6 -1
  30. package/dist/bitcoind/progress/tty-renderer.js +8 -4
  31. package/dist/bitcoind/rpc.d.ts +2 -1
  32. package/dist/bitcoind/rpc.js +3 -0
  33. package/dist/bitcoind/types.d.ts +16 -0
  34. package/dist/bytes.d.ts +1 -0
  35. package/dist/bytes.js +3 -0
  36. package/dist/cli/art.d.ts +2 -0
  37. package/dist/cli/art.js +37 -0
  38. package/dist/cli/commands/client-admin.d.ts +2 -0
  39. package/dist/cli/commands/client-admin.js +91 -0
  40. package/dist/cli/commands/follow.js +0 -2
  41. package/dist/cli/commands/mining-admin.js +6 -47
  42. package/dist/cli/commands/mining-read.js +11 -50
  43. package/dist/cli/commands/mining-runtime.js +38 -3
  44. package/dist/cli/commands/service-runtime.js +0 -2
  45. package/dist/cli/commands/status.js +8 -2
  46. package/dist/cli/commands/sync.js +51 -4
  47. package/dist/cli/commands/wallet-admin.js +142 -136
  48. package/dist/cli/commands/wallet-mutation.js +91 -79
  49. package/dist/cli/commands/wallet-read.js +15 -18
  50. package/dist/cli/context.js +4 -14
  51. package/dist/cli/mining-format.d.ts +0 -1
  52. package/dist/cli/mining-format.js +5 -37
  53. package/dist/cli/mining-json.d.ts +0 -18
  54. package/dist/cli/mining-json.js +0 -35
  55. package/dist/cli/mutation-command-groups.d.ts +1 -2
  56. package/dist/cli/mutation-command-groups.js +0 -5
  57. package/dist/cli/mutation-json.d.ts +24 -145
  58. package/dist/cli/mutation-json.js +30 -136
  59. package/dist/cli/mutation-resolved-json.d.ts +0 -7
  60. package/dist/cli/mutation-resolved-json.js +4 -10
  61. package/dist/cli/mutation-success.d.ts +2 -0
  62. package/dist/cli/mutation-success.js +11 -1
  63. package/dist/cli/mutation-text-format.js +1 -3
  64. package/dist/cli/output.d.ts +1 -1
  65. package/dist/cli/output.js +254 -231
  66. package/dist/cli/parse.d.ts +1 -1
  67. package/dist/cli/parse.js +93 -122
  68. package/dist/cli/preview-json.d.ts +17 -120
  69. package/dist/cli/preview-json.js +14 -97
  70. package/dist/cli/prompt.js +8 -13
  71. package/dist/cli/read-json.d.ts +15 -37
  72. package/dist/cli/read-json.js +44 -140
  73. package/dist/cli/runner.js +10 -13
  74. package/dist/cli/types.d.ts +8 -17
  75. package/dist/cli/types.js +0 -2
  76. package/dist/cli/wallet-format.d.ts +1 -0
  77. package/dist/cli/wallet-format.js +205 -144
  78. package/dist/cli/workflow-hints.d.ts +3 -3
  79. package/dist/cli/workflow-hints.js +11 -8
  80. package/dist/client/default-client.d.ts +3 -1
  81. package/dist/client/default-client.js +45 -2
  82. package/dist/client/factory.js +1 -1
  83. package/dist/client/initialization.js +23 -0
  84. package/dist/client/persistence.js +5 -5
  85. package/dist/client/store-adapter.js +1 -0
  86. package/dist/sqlite/checkpoints.d.ts +1 -0
  87. package/dist/sqlite/checkpoints.js +7 -0
  88. package/dist/sqlite/store.js +14 -1
  89. package/dist/types.d.ts +1 -0
  90. package/dist/wallet/coin-control.d.ts +41 -11
  91. package/dist/wallet/coin-control.js +100 -357
  92. package/dist/wallet/descriptor-normalization.d.ts +1 -3
  93. package/dist/wallet/descriptor-normalization.js +0 -16
  94. package/dist/wallet/lifecycle.d.ts +7 -99
  95. package/dist/wallet/lifecycle.js +513 -968
  96. package/dist/wallet/managed-core-wallet.d.ts +13 -0
  97. package/dist/wallet/managed-core-wallet.js +20 -0
  98. package/dist/wallet/mining/constants.d.ts +5 -12
  99. package/dist/wallet/mining/constants.js +5 -12
  100. package/dist/wallet/mining/control.d.ts +1 -13
  101. package/dist/wallet/mining/control.js +45 -349
  102. package/dist/wallet/mining/index.d.ts +3 -4
  103. package/dist/wallet/mining/index.js +1 -2
  104. package/dist/wallet/mining/runner.d.ts +179 -6
  105. package/dist/wallet/mining/runner.js +891 -501
  106. package/dist/wallet/mining/runtime-artifacts.js +23 -3
  107. package/dist/wallet/mining/sentence-protocol.d.ts +44 -0
  108. package/dist/wallet/mining/sentence-protocol.js +123 -0
  109. package/dist/wallet/mining/sentences.d.ts +4 -8
  110. package/dist/wallet/mining/sentences.js +3 -52
  111. package/dist/wallet/mining/state.d.ts +11 -6
  112. package/dist/wallet/mining/state.js +7 -6
  113. package/dist/wallet/mining/types.d.ts +2 -30
  114. package/dist/wallet/mining/visualizer.d.ts +31 -3
  115. package/dist/wallet/mining/visualizer.js +135 -13
  116. package/dist/wallet/read/context.d.ts +0 -2
  117. package/dist/wallet/read/context.js +119 -140
  118. package/dist/wallet/read/filter.js +2 -11
  119. package/dist/wallet/read/index.d.ts +1 -1
  120. package/dist/wallet/read/project.js +24 -77
  121. package/dist/wallet/read/types.d.ts +10 -25
  122. package/dist/wallet/reset.d.ts +0 -1
  123. package/dist/wallet/reset.js +60 -138
  124. package/dist/wallet/root-resolution.d.ts +1 -5
  125. package/dist/wallet/root-resolution.js +0 -18
  126. package/dist/wallet/runtime.d.ts +0 -6
  127. package/dist/wallet/runtime.js +0 -8
  128. package/dist/wallet/state/client-password-agent.js +208 -0
  129. package/dist/wallet/state/client-password.d.ts +65 -0
  130. package/dist/wallet/state/client-password.js +952 -0
  131. package/dist/wallet/state/crypto.d.ts +1 -20
  132. package/dist/wallet/state/crypto.js +0 -63
  133. package/dist/wallet/state/provider.d.ts +23 -11
  134. package/dist/wallet/state/provider.js +248 -290
  135. package/dist/wallet/state/storage.d.ts +2 -2
  136. package/dist/wallet/state/storage.js +48 -16
  137. package/dist/wallet/tx/anchor.d.ts +3 -28
  138. package/dist/wallet/tx/anchor.js +349 -1240
  139. package/dist/wallet/tx/bitcoin-transfer.d.ts +35 -0
  140. package/dist/wallet/tx/bitcoin-transfer.js +200 -0
  141. package/dist/wallet/tx/cog.d.ts +5 -1
  142. package/dist/wallet/tx/cog.js +149 -185
  143. package/dist/wallet/tx/common.d.ts +74 -10
  144. package/dist/wallet/tx/common.js +315 -138
  145. package/dist/wallet/tx/domain-admin.d.ts +3 -1
  146. package/dist/wallet/tx/domain-admin.js +61 -99
  147. package/dist/wallet/tx/domain-market.d.ts +5 -1
  148. package/dist/wallet/tx/domain-market.js +221 -228
  149. package/dist/wallet/tx/field.d.ts +4 -10
  150. package/dist/wallet/tx/field.js +84 -914
  151. package/dist/wallet/tx/identity-selector.d.ts +9 -3
  152. package/dist/wallet/tx/identity-selector.js +17 -35
  153. package/dist/wallet/tx/index.d.ts +3 -1
  154. package/dist/wallet/tx/index.js +2 -1
  155. package/dist/wallet/tx/register.d.ts +3 -1
  156. package/dist/wallet/tx/register.js +62 -220
  157. package/dist/wallet/tx/reputation.d.ts +3 -1
  158. package/dist/wallet/tx/reputation.js +58 -95
  159. package/dist/wallet/types.d.ts +8 -122
  160. package/package.json +5 -5
  161. package/dist/wallet/archive.d.ts +0 -4
  162. package/dist/wallet/archive.js +0 -41
  163. package/dist/wallet/mining/hook-protocol.d.ts +0 -47
  164. package/dist/wallet/mining/hook-protocol.js +0 -161
  165. package/dist/wallet/mining/hook-runner.js +0 -52
  166. package/dist/wallet/mining/hooks.d.ts +0 -38
  167. package/dist/wallet/mining/hooks.js +0 -520
  168. package/dist/wallet/state/explicit-lock.d.ts +0 -4
  169. package/dist/wallet/state/explicit-lock.js +0 -19
  170. package/dist/wallet/state/session.d.ts +0 -12
  171. package/dist/wallet/state/session.js +0 -23
  172. /package/dist/wallet/{mining/hook-runner.d.ts → state/client-password-agent.d.ts} +0 -0
@@ -1,3 +1,4 @@
1
+ import { FileLockBusyError } from "../wallet/fs/lock.js";
1
2
  export function writeJsonValue(stream, value) {
2
3
  stream.write(`${JSON.stringify(value, jsonReplacer)}\n`);
3
4
  }
@@ -125,50 +126,26 @@ export function classifyCliError(error) {
125
126
  if (/^wallet_init_confirmation_failed_word_\d+$/.test(message)) {
126
127
  return { exitCode: 2, errorCode: message, message };
127
128
  }
128
- if (message === "mining_hooks_enable_trust_acknowledgement_required") {
129
- return { exitCode: 2, errorCode: message, message };
130
- }
131
129
  if (message === "mining_setup_invalid_provider"
132
130
  || message === "mining_setup_missing_api_key") {
133
131
  return { exitCode: 2, errorCode: message, message };
134
132
  }
135
- if (message.startsWith("mining_hooks_enable_template_created:")) {
136
- return {
137
- exitCode: 4,
138
- errorCode: "mining_hooks_enable_template_created",
139
- message,
140
- };
141
- }
142
- if (message.startsWith("mining_hooks_enable_validation_failed:")) {
143
- return {
144
- exitCode: 5,
145
- errorCode: "mining_hooks_enable_validation_failed",
146
- message,
147
- };
148
- }
149
133
  if (message.endsWith("_typed_ack_required")) {
150
134
  return { exitCode: 2, errorCode: message, message };
151
135
  }
152
136
  if (message === "wallet_typed_confirmation_rejected"
153
- || message === "wallet_export_overwrite_declined"
154
137
  || message === "wallet_delete_confirmation_required"
155
138
  || message === "wallet_prompt_value_required"
156
- || message === "wallet_archive_passphrase_mismatch"
157
139
  || message === "wallet_restore_mnemonic_invalid"
158
140
  || message === "wallet_restore_replace_confirmation_required"
159
141
  || message === "wallet_seed_name_invalid"
160
142
  || message === "wallet_seed_name_reserved"
161
- || message === "reset_wallet_choice_invalid"
162
- || message === "reset_wallet_passphrase_required"
163
- || message === "reset_wallet_access_failed") {
143
+ || message === "reset_wallet_choice_invalid") {
164
144
  return { exitCode: 2, errorCode: message, message };
165
145
  }
166
146
  if (message === "not_found") {
167
147
  return { exitCode: 3, errorCode: "not_found", message: "Requested object not found." };
168
148
  }
169
- if (message === "wallet_import_archive_not_found") {
170
- return { exitCode: 3, errorCode: message, message };
171
- }
172
149
  if (message === "wallet_seed_not_found") {
173
150
  return { exitCode: 3, errorCode: message, message };
174
151
  }
@@ -188,17 +165,12 @@ export function classifyCliError(error) {
188
165
  }
189
166
  function isBlockedError(message) {
190
167
  if (message === "wallet_control_lock_busy"
191
- || message.startsWith("file_lock_busy_")
192
- || message.startsWith("wallet_anchor_clear_pending_first_")) {
168
+ || message.startsWith("file_lock_busy_")) {
193
169
  return true;
194
170
  }
195
- if (message === "wallet_locked"
196
- || message === "wallet_uninitialized"
171
+ if (message === "wallet_uninitialized"
197
172
  || message === "local-state-corrupt"
198
173
  || message === "wallet_already_initialized"
199
- || message === "wallet_export_core_replica_not_ready"
200
- || message === "wallet_export_tip_mismatch"
201
- || message === "wallet_export_requires_quiescent_local_state"
202
174
  || message === "wallet_restore_requires_main_wallet"
203
175
  || message === "wallet_seed_name_exists"
204
176
  || message === "wallet_seed_not_found"
@@ -211,11 +183,14 @@ function isBlockedError(message) {
211
183
  || message === "indexer_daemon_wallet_root_mismatch"
212
184
  || message === "indexer_daemon_schema_mismatch"
213
185
  || message === "mine_setup_requires_tty"
214
- || message === "mining_hooks_enable_requires_tty"
215
186
  || message === "mining_preemption_timeout"
216
- || message === "wallet_secret_provider_linux_secret_tool_missing"
217
- || message === "wallet_secret_provider_linux_secret_service_unavailable"
218
- || message === "wallet_secret_provider_linux_runtime_error") {
187
+ || message === "wallet_client_password_setup_required"
188
+ || message === "wallet_client_password_migration_required"
189
+ || message === "wallet_client_password_locked"
190
+ || message === "wallet_secret_provider_linux_runtime_error"
191
+ || message === "wallet_secret_provider_macos_runtime_error"
192
+ || message === "wallet_secret_provider_windows_runtime_error"
193
+ || message === "wallet_state_legacy_envelope_unsupported") {
219
194
  return true;
220
195
  }
221
196
  return /(?:^|_)(?:locked|uninitialized|repair_required|requires_tty|typed_ack_required|confirmation_rejected|tip_mismatch|core_replica_not_ready|setup|no_eligible_sender|ambiguous_sender|insufficient|stale|paused|validation|catching_up|starting|unavailable|schema_mismatch|service_version_mismatch|wallet_root_mismatch|runtime_mismatch|replica_missing|replica_mismatch|failed)(?:_|$)/.test(message)
@@ -223,7 +198,7 @@ function isBlockedError(message) {
223
198
  }
224
199
  export function formatCliTextError(error) {
225
200
  const classified = classifyCliError(error);
226
- const presentation = createCliErrorPresentation(classified.errorCode, classified.message);
201
+ const presentation = createCliErrorPresentation(classified.errorCode, classified.message, error);
227
202
  if (presentation === null) {
228
203
  return null;
229
204
  }
@@ -236,19 +211,41 @@ export function formatCliTextError(error) {
236
211
  }
237
212
  return lines;
238
213
  }
239
- export function createCliErrorPresentation(errorCode, fallbackMessage) {
240
- if (errorCode === "wallet_locked") {
214
+ export function createCliErrorPresentation(errorCode, fallbackMessage, error) {
215
+ if (errorCode.endsWith("_sender_utxo_unavailable")) {
241
216
  return {
242
- what: "Wallet is locked.",
243
- why: "This command needs access to the unlocked local wallet state before it can continue. Provider-backed wallets unlock on demand unless they were explicitly locked or the local secret store is unavailable.",
244
- next: "Run `cogcoin unlock --for 15m` and retry.",
217
+ what: "Sender identity has no spendable confirmed BTC input.",
218
+ why: "This command preserves the Cogcoin sender identity in vin[0]. The selected sender currently has no confirmed spendable UTXO available for that role.",
219
+ next: "Wait for the sender's BTC output to confirm, or fund that sender identity and retry.",
245
220
  };
246
221
  }
247
222
  if (errorCode === "wallet_control_lock_busy") {
248
223
  return {
249
224
  what: "Another Cogcoin command is already controlling this wallet.",
250
225
  why: "Commands that sync, follow, or mutate the local index take an exclusive wallet control lock so they do not write the same sqlite store concurrently.",
251
- next: "Wait for the other Cogcoin command to finish, or stop it cleanly before retrying.",
226
+ next: "Run `cogcoin repair` to reset the local lock state, then retry.",
227
+ };
228
+ }
229
+ if (errorCode.startsWith("file_lock_busy_")) {
230
+ const lockPath = errorCode.slice("file_lock_busy_".length);
231
+ const lockPurpose = error instanceof FileLockBusyError
232
+ ? error.existingMetadata?.purpose ?? null
233
+ : null;
234
+ if (lockPath.includes("wallet-control.lock")) {
235
+ return {
236
+ what: lockPurpose === null
237
+ ? "Wallet control lock is busy."
238
+ : `Wallet control lock is busy (purpose: ${lockPurpose}).`,
239
+ why: "Another Cogcoin command currently holds the exclusive wallet control lock for this wallet.",
240
+ next: "Run `cogcoin repair` to reset the local lock state, then retry.",
241
+ };
242
+ }
243
+ return {
244
+ what: lockPurpose === null
245
+ ? `Lock file is busy: ${lockPath}.`
246
+ : `Lock file is busy: ${lockPath} (purpose: ${lockPurpose}).`,
247
+ why: "The command was blocked by the current local wallet or service state.",
248
+ next: "Run `cogcoin repair` to reset the local lock state, then retry.",
252
249
  };
253
250
  }
254
251
  if (errorCode === "reset_wallet_choice_invalid") {
@@ -258,20 +255,6 @@ export function createCliErrorPresentation(errorCode, fallbackMessage) {
258
255
  next: "Rerun `cogcoin reset` and enter one of the accepted wallet reset choices.",
259
256
  };
260
257
  }
261
- if (errorCode === "reset_wallet_passphrase_required") {
262
- return {
263
- what: "Wallet-state passphrase is required.",
264
- 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.",
265
- next: "Rerun `cogcoin reset` and enter the wallet-state passphrase, or choose \"skip\" or \"delete wallet\" instead.",
266
- };
267
- }
268
- if (errorCode === "reset_wallet_access_failed") {
269
- return {
270
- what: "Wallet state could not be opened for entropy-retaining reset.",
271
- why: "The wallet-state passphrase was not accepted, or the passphrase-wrapped wallet state could not be decrypted cleanly.",
272
- next: "Rerun `cogcoin reset`, enter the correct wallet-state passphrase, or choose \"skip\" or \"delete wallet\" instead.",
273
- };
274
- }
275
258
  if (errorCode === "reset_wallet_entropy_reset_unavailable") {
276
259
  return {
277
260
  what: "Entropy-retaining wallet reset is unavailable.",
@@ -295,9 +278,9 @@ export function createCliErrorPresentation(errorCode, fallbackMessage) {
295
278
  }
296
279
  if (errorCode === "reset_secret_cleanup_failed") {
297
280
  return {
298
- what: "Reset finished the filesystem wipe but could not fully clean up wallet secret-provider entries.",
299
- why: "The local Cogcoin files were already removed or rewritten, but at least one discoverable OS secret-store entry could not be deleted cleanly.",
300
- next: "Remove the remaining Cogcoin wallet secret from the local secret store, then rerun `cogcoin status` to confirm the new state.",
281
+ what: "Reset finished the filesystem wipe but could not fully clean up wallet secret-provider material.",
282
+ why: "The local Cogcoin files were already removed or rewritten, but at least one tracked wallet secret could not be deleted cleanly.",
283
+ next: "Remove the remaining wallet secret material, then rerun `cogcoin status` to confirm the new state.",
301
284
  };
302
285
  }
303
286
  if (errorCode === "reset_snapshot_preserve_failed") {
@@ -325,7 +308,35 @@ export function createCliErrorPresentation(errorCode, fallbackMessage) {
325
308
  return {
326
309
  what: "Wallet is already initialized.",
327
310
  why: "This machine already has a local wallet root, so initialization cannot safely create a second one in the same runtime location.",
328
- next: "Run `cogcoin status` to inspect the existing wallet, or export/import it instead of reinitializing.",
311
+ next: "Run `cogcoin status` to inspect the existing wallet.",
312
+ };
313
+ }
314
+ if (errorCode === "wallet_client_password_setup_required") {
315
+ return {
316
+ what: "Client password setup is still required.",
317
+ why: "This machine has not finished configuring password-protected local wallet secrets yet.",
318
+ next: "Run `cogcoin init` to create the client password and finish local secret setup.",
319
+ };
320
+ }
321
+ if (errorCode === "wallet_client_password_migration_required") {
322
+ return {
323
+ what: "Client password migration is still required.",
324
+ why: "This machine still has wallet secrets in the older platform-specific local format, so Cogcoin will not use them until they are migrated into password-protected local files.",
325
+ next: "Run `cogcoin init` to create the client password and migrate local wallet secrets.",
326
+ };
327
+ }
328
+ if (errorCode === "wallet_client_password_locked") {
329
+ return {
330
+ what: "Client password is locked.",
331
+ why: "This command needs the password-protected local wallet secret, but no active unlock session is available.",
332
+ next: "Run `cogcoin client unlock`, or rerun the command in an interactive terminal so Cogcoin can prompt for the client password.",
333
+ };
334
+ }
335
+ if (errorCode === "wallet_client_password_change_requires_tty") {
336
+ return {
337
+ what: "Client password change needs an interactive terminal.",
338
+ why: "Cogcoin has to securely prompt for the current client password and the new password twice before it can rotate local wallet-secret protection.",
339
+ next: "Run `cogcoin client change-password` in an interactive terminal.",
329
340
  };
330
341
  }
331
342
  if (errorCode === "wallet_restore_requires_main_wallet") {
@@ -384,13 +395,6 @@ export function createCliErrorPresentation(errorCode, fallbackMessage) {
384
395
  next: "Rerun the command in an interactive terminal and type the requested acknowledgement.",
385
396
  };
386
397
  }
387
- if (errorCode === "wallet_export_overwrite_declined") {
388
- return {
389
- what: "Archive overwrite was declined.",
390
- why: "The export path already exists, and the command will not replace that archive unless you explicitly approve it.",
391
- next: "Rerun the command and type `yes` when prompted if you want to overwrite the archive.",
392
- };
393
- }
394
398
  if (/^wallet_init_confirmation_failed_word_\d+$/.test(errorCode)) {
395
399
  return {
396
400
  what: "Mnemonic confirmation failed.",
@@ -426,54 +430,67 @@ export function createCliErrorPresentation(errorCode, fallbackMessage) {
426
430
  next: "Rerun the command with `--seed <name>`.",
427
431
  };
428
432
  }
429
- if (errorCode === "cli_seed_not_supported_for_command" || errorCode === "wallet_init_seed_not_supported" || errorCode === "wallet_import_seed_not_supported") {
433
+ if (errorCode === "cli_seed_not_supported_for_command" || errorCode === "wallet_init_seed_not_supported") {
430
434
  return {
431
435
  what: "This command does not support `--seed`.",
432
436
  why: "Only wallet-aware commands are seed-selectable. Global lifecycle and shared service commands still operate on the shared local client state.",
433
437
  next: "Drop `--seed` for this command and retry.",
434
438
  };
435
439
  }
436
- if (errorCode === "wallet_anchor_clear_inconsistent_state") {
440
+ if (errorCode === "cli_from_not_supported_for_command") {
441
+ return {
442
+ what: "`--from` is no longer supported.",
443
+ why: "Cogcoin now uses a single wallet address for local transaction authorship, so sender selection is no longer part of the CLI.",
444
+ next: "Retry the command without `--from`.",
445
+ };
446
+ }
447
+ if (errorCode === "cli_missing_satvb") {
448
+ return {
449
+ what: "A sat/vB value is required.",
450
+ why: "`--satvb` needs an explicit positive fee rate value in sat/vB for the mutation you are submitting.",
451
+ next: "Rerun the command with `--satvb <number>`.",
452
+ };
453
+ }
454
+ if (errorCode === "cli_invalid_satvb") {
437
455
  return {
438
- what: "Pending anchor state is inconsistent.",
439
- why: "The domain still shows local pending anchor state, but the wallet could not find a matching clearable reserved anchor family.",
440
- next: "Run `cogcoin repair`, then inspect the domain again before retrying `cogcoin anchor clear`.",
456
+ what: "The sat/vB value is invalid.",
457
+ why: "`--satvb` accepts only a positive finite decimal number such as `12` or `12.5`.",
458
+ next: "Choose a positive sat/vB value and retry.",
441
459
  };
442
460
  }
443
- if (errorCode.startsWith("wallet_anchor_clear_pending_first_")) {
444
- const domainName = errorCode.slice("wallet_anchor_clear_pending_first_".length) || "<domain>";
461
+ if (errorCode === "cli_satvb_not_supported_for_command") {
445
462
  return {
446
- what: `A local pending anchor already exists for "${domainName}".`,
447
- why: "The wallet found a same-domain anchor reservation that is still local-only and safely clearable, so it stopped before creating a conflicting family.",
448
- next: `Run \`cogcoin anchor clear ${domainName}\`, then rerun \`cogcoin anchor ${domainName}\`.`,
463
+ what: "This command does not support `--satvb`.",
464
+ why: "The fee-rate override only applies to wallet mutation commands that build and broadcast transactions.",
465
+ next: "Drop `--satvb` for this command, or use it with a wallet mutation command like `cogcoin register` or `cogcoin send`.",
449
466
  };
450
467
  }
451
- if (errorCode.startsWith("wallet_anchor_clear_not_clearable_")) {
468
+ if (errorCode === "cli_anchor_clear_removed") {
452
469
  return {
453
- what: "Pending anchor cannot be cleared safely.",
454
- why: "This command only clears a local pre-broadcast reservation. The anchor family is already beyond that safe stage or may have been observed by the wallet.",
455
- next: "Rerun `cogcoin anchor <domain>` to reconcile the family, or run `cogcoin repair` if it remains unresolved.",
470
+ what: "`anchor clear` is no longer available.",
471
+ why: "Anchor is now a direct single-transaction wallet mutation, so there is no separate cleanup command for reserved local workflow state.",
472
+ next: "Retry with `cogcoin anchor <domain>` or inspect the domain with `cogcoin show <domain>`.",
456
473
  };
457
474
  }
458
- if (errorCode === "mining_hooks_enable_trust_acknowledgement_required") {
475
+ if (errorCode === "cli_wallet_export_removed") {
459
476
  return {
460
- what: "Trust acknowledgement is still required.",
461
- why: "Enabling a custom mining hook grants unsandboxed local JavaScript full access to the current OS account and readable local data.",
462
- next: "Rerun `cogcoin hooks enable mining` in an interactive terminal and type the requested trust acknowledgement.",
477
+ what: "`wallet export` is no longer available.",
478
+ why: "Portable encrypted wallet archives were removed from the client, so wallet state is no longer exported through a `.cogcoin` archive file.",
479
+ next: "Use the wallet mnemonic as the supported recovery path, or retry with another wallet command.",
463
480
  };
464
481
  }
465
- if (errorCode === "mining_hooks_enable_template_created") {
482
+ if (errorCode === "cli_wallet_import_removed") {
466
483
  return {
467
- what: "Default mining hook template was created.",
468
- why: "The wallet wrote starter custom-hook files and stopped before enabling custom mode so you can review and edit them first.",
469
- next: "Edit `generate-sentences.js`, then rerun `cogcoin hooks enable mining`.",
484
+ what: "`wallet import` is no longer available.",
485
+ why: "Portable encrypted wallet archives were removed from the client, so this version no longer imports wallet state from archive files.",
486
+ next: "Use `cogcoin restore --seed <name>` with the recovery mnemonic instead.",
470
487
  };
471
488
  }
472
- if (errorCode === "mining_hooks_enable_validation_failed") {
489
+ if (errorCode === "cli_field_create_initial_value_not_supported") {
473
490
  return {
474
- what: "Custom mining hook validation failed.",
475
- why: "The hook files, package shape, trust checks, or isolated validation run did not pass the required checks.",
476
- next: "Fix the custom mining hook and rerun `cogcoin hooks enable mining`.",
491
+ what: "`field create` no longer accepts an initial value.",
492
+ why: "Field creation is now always a single FIELD_REG transaction. Any field value must be written afterward with a separate `field set` command.",
493
+ next: "Create the field first, then run `cogcoin field set <domain> <field> ...`.",
477
494
  };
478
495
  }
479
496
  if (errorCode === "mining_setup_invalid_provider") {
@@ -516,32 +533,32 @@ export function createCliErrorPresentation(errorCode, fallbackMessage) {
516
533
  next: "Rerun the command in an interactive terminal and enter the requested value.",
517
534
  };
518
535
  }
519
- if (errorCode === "wallet_archive_passphrase_mismatch") {
536
+ if (errorCode === "wallet_secret_provider_linux_runtime_error") {
520
537
  return {
521
- what: "Archive passphrases did not match.",
522
- why: "The archive passphrase must be entered the same way twice so the wallet does not seal the archive with a typo.",
523
- next: "Rerun the command and enter the same archive passphrase both times.",
538
+ what: "Linux local wallet-secret access failed.",
539
+ why: "Cogcoin could not read or write the local wallet secret file for this Linux account.",
540
+ next: "Check that the Cogcoin state directory is readable and writable for this Linux user, then retry.",
524
541
  };
525
542
  }
526
- if (errorCode === "wallet_secret_provider_linux_secret_tool_missing") {
543
+ if (errorCode === "wallet_secret_provider_macos_runtime_error") {
527
544
  return {
528
- what: "Linux secret-store support (`secret-tool`) is not installed.",
529
- why: "Cogcoin uses `secret-tool` to talk to Secret Service on Linux, but that helper is not available in this environment.",
530
- next: "Install `secret-tool`/libsecret for this machine, then rerun the command.",
545
+ what: "macOS local wallet-secret access failed.",
546
+ why: "Cogcoin could not read or write the password-protected local wallet secret file for this macOS account.",
547
+ next: "Check that the Cogcoin state directory is readable and writable for this macOS user, then retry.",
531
548
  };
532
549
  }
533
- if (errorCode === "wallet_secret_provider_linux_secret_service_unavailable") {
550
+ if (errorCode === "wallet_secret_provider_windows_runtime_error") {
534
551
  return {
535
- what: "Linux Secret Service is unavailable or locked.",
536
- why: "The local Secret Service session could not be reached for wallet-secret storage, so the wallet cannot read or write its encryption keys.",
537
- next: "Start or unlock your desktop keyring/Secret Service session, then rerun the command.",
552
+ what: "Windows local wallet-secret access failed.",
553
+ why: "Cogcoin could not read or write the local wallet secret file for this Windows account.",
554
+ next: "Check that the Cogcoin state directory is readable and writable for this Windows user, then retry.",
538
555
  };
539
556
  }
540
- if (errorCode === "wallet_secret_provider_linux_runtime_error") {
557
+ if (errorCode === "wallet_state_legacy_envelope_unsupported") {
541
558
  return {
542
- what: "Linux secret-store operation failed.",
543
- why: "`secret-tool` ran but did not complete a usable wallet-secret operation for this command.",
544
- next: "Check that Secret Service is running correctly on this machine, then retry.",
559
+ what: "Legacy wallet state is no longer supported.",
560
+ why: "This wallet state was created by an older Cogcoin format that this version no longer loads directly.",
561
+ next: "Restore or otherwise recover the wallet into the current format, then retry the command.",
545
562
  };
546
563
  }
547
564
  if (errorCode.endsWith("_requires_tty")) {
@@ -551,20 +568,6 @@ export function createCliErrorPresentation(errorCode, fallbackMessage) {
551
568
  next: "Rerun the command in an interactive terminal.",
552
569
  };
553
570
  }
554
- if (errorCode === "wallet_import_archive_not_found") {
555
- return {
556
- what: "Wallet archive was not found.",
557
- why: "The specified import archive path does not exist or is not readable from this machine.",
558
- next: "Check the archive path and retry.",
559
- };
560
- }
561
- if (errorCode === "wallet_export_requires_quiescent_local_state") {
562
- return {
563
- what: "Wallet export is blocked until local state is quiescent.",
564
- why: "Portable export waits for mining, proactive families, and pending mutations to settle so the archive reflects trustworthy local state.",
565
- next: "Wait for active local work to finish or repair it, then retry the export.",
566
- };
567
- }
568
571
  if (errorCode.includes("tip_mismatch") || errorCode.includes("stale") || errorCode.includes("catching_up") || errorCode.includes("starting")) {
569
572
  return {
570
573
  what: "Trusted service state is not ready.",
@@ -656,95 +659,102 @@ export function createCliErrorPresentation(errorCode, fallbackMessage) {
656
659
  next: "Review the local status output, finish the required setup or repair step, and retry.",
657
660
  };
658
661
  }
662
+ if (errorCode === "wallet_bitcoin_transfer_insufficient_funds") {
663
+ return {
664
+ what: "Wallet address does not have enough BTC.",
665
+ why: "The requested satoshi amount plus the mining fee exceeds the wallet's spendable BTC balance.",
666
+ next: "Reduce the amount or add more BTC to the wallet address, then retry.",
667
+ };
668
+ }
659
669
  if (errorCode.includes("insufficient")) {
660
670
  return {
661
671
  what: "Available funds are insufficient.",
662
- why: "The selected wallet identity does not currently have enough spendable funds for this operation.",
663
- next: "Choose a different identity or add more funds, then retry.",
672
+ why: "The wallet address does not currently have enough spendable funds for this operation.",
673
+ next: "Add more funds to the wallet address, then retry.",
664
674
  };
665
675
  }
666
676
  if (errorCode === "wallet_register_from_not_supported_for_subdomain") {
667
677
  return {
668
678
  what: "`--from` is not supported for subdomain registration.",
669
- why: "Subdomain registration always derives the sender from the anchored parent owner, so this command will not accept an explicit sender override.",
670
- next: "Retry without `--from`, or register a root domain if you need explicit sender selection.",
679
+ why: "Cogcoin now uses a single wallet address for local writes, so sender overrides are no longer part of subdomain registration.",
680
+ next: "Retry without `--from`.",
671
681
  };
672
682
  }
673
683
  if (errorCode === "wallet_register_sender_not_root_eligible") {
674
684
  return {
675
- what: "Selected sender is not eligible for root registration.",
676
- why: "Root registration can use funding identity `0` or a locally controlled anchored owner identity with a current canonical anchor outpoint.",
677
- next: "Run `cogcoin ids`, then retry with `--from id:0` or an anchored local owner selector.",
685
+ what: "Root registration sender is not eligible.",
686
+ why: "Root registration now always uses the wallet address, and the local wallet state did not produce a usable sender.",
687
+ next: "Inspect `cogcoin address` and retry.",
678
688
  };
679
689
  }
680
690
  if (errorCode === "wallet_register_sender_not_found") {
681
691
  return {
682
- what: "Selected sender was not found locally.",
683
- why: "The provided selector did not resolve to a locally controlled identity in this wallet.",
684
- next: "Run `cogcoin ids` and retry with one of the listed selectors.",
692
+ what: "Local sender was not found.",
693
+ why: "The wallet could not resolve a usable local wallet sender for this command.",
694
+ next: "Inspect `cogcoin address` and retry.",
685
695
  };
686
696
  }
687
697
  if (errorCode === "wallet_register_sender_read_only") {
688
698
  return {
689
- what: "Selected sender is read-only.",
690
- why: "This local identity is tracked for visibility only and cannot author new owner transactions.",
691
- next: "Retry with a locally controlled non-read-only sender.",
699
+ what: "Wallet sender is not spendable.",
700
+ why: "This command needs the wallet address to author the transaction, but the local wallet sender is not spendable.",
701
+ next: "Check `cogcoin address`, restore the spendable wallet, and retry.",
692
702
  };
693
703
  }
694
704
  if (errorCode === "wallet_register_sender_address_unavailable") {
695
705
  return {
696
- what: "Selected sender could not be displayed.",
697
- why: "The selector resolved to a local identity, but the wallet does not have a usable display address for it.",
698
- next: "Run `cogcoin ids` and retry with a different local sender selector.",
706
+ what: "Wallet address is unavailable.",
707
+ why: "The local wallet sender was resolved, but the wallet does not currently have a usable display address for it.",
708
+ next: "Inspect `cogcoin address` and retry.",
699
709
  };
700
710
  }
701
711
  if (errorCode === "wallet_buy_sender_not_found") {
702
712
  return {
703
- what: "Selected buyer was not found locally.",
704
- why: "The provided `--from` selector did not resolve to a locally controlled identity in this wallet.",
705
- next: "Run `cogcoin ids` and retry with one of the listed selectors.",
713
+ what: "Local buyer was not found.",
714
+ why: "The wallet could not resolve a usable local wallet sender for this purchase.",
715
+ next: "Inspect `cogcoin address` and retry.",
706
716
  };
707
717
  }
708
718
  if (errorCode === "wallet_buy_sender_read_only") {
709
719
  return {
710
- what: "Selected buyer is read-only.",
711
- why: "This local identity is tracked for visibility only and cannot author a domain purchase.",
712
- next: "Retry with a locally controlled non-read-only buyer selector.",
720
+ what: "Wallet sender is not spendable.",
721
+ why: "Buying now always uses the wallet address, but the local wallet sender is not spendable.",
722
+ next: "Check `cogcoin address`, restore the spendable wallet, and retry.",
713
723
  };
714
724
  }
715
725
  if (errorCode === "wallet_buy_sender_address_unavailable") {
716
726
  return {
717
- what: "Selected buyer could not be displayed.",
718
- why: "The selector resolved to a local identity, but the wallet does not have a usable display address for it.",
719
- next: "Run `cogcoin ids` and retry with a different local buyer selector.",
727
+ what: "Wallet address is unavailable.",
728
+ why: "The wallet could not produce a usable display address for the local sender.",
729
+ next: "Inspect `cogcoin address` and retry.",
720
730
  };
721
731
  }
722
732
  if (errorCode === "wallet_buy_already_owner") {
723
733
  return {
724
- what: "Selected buyer already owns the domain.",
725
- why: "A buy mutation must come from a different local identity than the current domain owner.",
726
- next: "Choose a different buyer with `--from`, or inspect the current owner with `cogcoin show <domain>`.",
734
+ what: "The wallet already owns the domain.",
735
+ why: "A buy mutation cannot target a domain already owned by this wallet address.",
736
+ next: "Inspect the current owner with `cogcoin show <domain>` and choose a different domain.",
727
737
  };
728
738
  }
729
739
  if (errorCode === "wallet_buy_insufficient_cog_balance") {
730
740
  return {
731
- what: "Selected buyer does not have enough COG.",
732
- why: "The chosen local identity does not currently have the listed domain price available in spendable COG balance.",
733
- next: "Choose a different buyer or add more COG to that identity, then retry.",
741
+ what: "The wallet does not have enough COG.",
742
+ why: "The wallet address does not currently have the listed domain price available in spendable COG balance.",
743
+ next: "Add more COG to the wallet address, then retry.",
734
744
  };
735
745
  }
736
746
  if (errorCode === "wallet_transfer_owner_not_locally_controlled" || errorCode === "wallet_sell_owner_not_locally_controlled") {
737
747
  return {
738
748
  what: "Domain owner is not locally controlled.",
739
- why: "This command must be authored by the current unanchored domain owner, and that owner identity is not available in this wallet with a usable address.",
740
- next: "Inspect the current owner with `cogcoin show <domain>`, then retry from the wallet that controls that owner identity.",
749
+ why: "This command must be authored by the current unanchored domain owner, and that current owner script/address is not controlled by this wallet.",
750
+ next: "Inspect the current owner with `cogcoin show <domain>`, then retry from the wallet that controls the owner.",
741
751
  };
742
752
  }
743
753
  if (errorCode === "wallet_transfer_owner_read_only" || errorCode === "wallet_sell_owner_read_only") {
744
754
  return {
745
- what: "Domain owner is read-only.",
746
- why: "The current domain owner is tracked locally for visibility, but this wallet cannot author owner mutations from a read-only identity.",
747
- next: "Use the wallet that controls the owner identity, or import the spendable owner into this wallet before retrying.",
755
+ what: "Domain owner is not spendable in this wallet.",
756
+ why: "The current domain owner is visible locally, but this wallet cannot author owner mutations from it.",
757
+ next: "Use the wallet that controls the owner, or import the spendable owner into this wallet before retrying.",
748
758
  };
749
759
  }
750
760
  if (errorCode === "wallet_field_create_owner_not_locally_controlled"
@@ -752,17 +762,17 @@ export function createCliErrorPresentation(errorCode, fallbackMessage) {
752
762
  || errorCode === "wallet_field_clear_owner_not_locally_controlled") {
753
763
  return {
754
764
  what: "Anchored field owner is not locally controlled.",
755
- why: "Field mutations must be authored by the current anchored owner of the domain, and that owner identity is not available in this wallet with a usable address.",
756
- next: "Inspect the current owner with `cogcoin show <domain>`, then retry from the wallet that controls that anchored owner identity.",
765
+ why: "Field mutations must be authored by the current anchored owner of the domain, and that current owner script/address is not controlled by this wallet.",
766
+ next: "Inspect the current owner with `cogcoin show <domain>`, then retry from the wallet that controls the owner.",
757
767
  };
758
768
  }
759
769
  if (errorCode === "wallet_field_create_owner_read_only"
760
770
  || errorCode === "wallet_field_set_owner_read_only"
761
771
  || errorCode === "wallet_field_clear_owner_read_only") {
762
772
  return {
763
- what: "Anchored field owner is read-only.",
764
- why: "The current anchored owner is tracked locally for visibility, but this wallet cannot author field mutations from a read-only identity.",
765
- next: "Use the wallet that controls the anchored owner identity, or import the spendable owner into this wallet before retrying.",
773
+ what: "Anchored field owner is not spendable in this wallet.",
774
+ why: "The current anchored owner is visible locally, but this wallet cannot author field mutations from it.",
775
+ next: "Use the wallet that controls the owner, or import the spendable owner into this wallet before retrying.",
766
776
  };
767
777
  }
768
778
  if (errorCode === "wallet_domain_endpoint_owner_not_locally_controlled"
@@ -771,8 +781,8 @@ export function createCliErrorPresentation(errorCode, fallbackMessage) {
771
781
  || errorCode === "wallet_domain_canonical_owner_not_locally_controlled") {
772
782
  return {
773
783
  what: "Anchored domain owner is not locally controlled.",
774
- why: "This anchored domain-admin command must be authored by the current anchored owner, and that owner identity is not available in this wallet with a usable address.",
775
- next: "Inspect the current owner with `cogcoin show <domain>`, then retry from the wallet that controls that anchored owner identity.",
784
+ why: "This anchored domain-admin command must be authored by the current anchored owner, and that current owner script/address is not controlled by this wallet.",
785
+ next: "Inspect the current owner with `cogcoin show <domain>`, then retry from the wallet that controls the owner.",
776
786
  };
777
787
  }
778
788
  if (errorCode === "wallet_domain_endpoint_owner_read_only"
@@ -780,53 +790,95 @@ export function createCliErrorPresentation(errorCode, fallbackMessage) {
780
790
  || errorCode === "wallet_domain_miner_owner_read_only"
781
791
  || errorCode === "wallet_domain_canonical_owner_read_only") {
782
792
  return {
783
- what: "Anchored domain owner is read-only.",
784
- why: "The current anchored owner is tracked locally for visibility, but this wallet cannot author anchored admin mutations from a read-only identity.",
785
- next: "Use the wallet that controls the anchored owner identity, or import the spendable owner into this wallet before retrying.",
793
+ what: "Anchored domain owner is not spendable in this wallet.",
794
+ why: "The current anchored owner is visible locally, but this wallet cannot author anchored admin mutations from it.",
795
+ next: "Use the wallet that controls the owner, or import the spendable owner into this wallet before retrying.",
786
796
  };
787
797
  }
788
798
  if (errorCode === "wallet_rep_give_source_owner_not_locally_controlled"
789
799
  || errorCode === "wallet_rep_revoke_source_owner_not_locally_controlled") {
790
800
  return {
791
801
  what: "Anchored reputation source owner is not locally controlled.",
792
- why: "Reputation mutations must be authored by the current anchored owner of the source domain, and that owner identity is not available in this wallet with a usable address.",
793
- next: "Inspect the current source-domain owner with `cogcoin show <domain>`, then retry from the wallet that controls that anchored owner identity.",
802
+ why: "Reputation mutations must be authored by the current anchored owner of the source domain, and that current owner script/address is not controlled by this wallet.",
803
+ next: "Inspect the current source-domain owner with `cogcoin show <domain>`, then retry from the wallet that controls the owner.",
794
804
  };
795
805
  }
796
806
  if (errorCode === "wallet_rep_give_source_owner_read_only"
797
807
  || errorCode === "wallet_rep_revoke_source_owner_read_only") {
798
808
  return {
799
- what: "Anchored reputation source owner is read-only.",
800
- why: "The current anchored source-domain owner is tracked locally for visibility, but this wallet cannot author reputation mutations from a read-only identity.",
801
- next: "Use the wallet that controls the anchored source-domain owner identity, or import the spendable owner into this wallet before retrying.",
809
+ what: "Anchored reputation source owner is not spendable in this wallet.",
810
+ why: "The current anchored source-domain owner is visible locally, but this wallet cannot author reputation mutations from it.",
811
+ next: "Use the wallet that controls the owner, or import the spendable owner into this wallet before retrying.",
802
812
  };
803
813
  }
804
814
  if (errorCode === "wallet_send_sender_address_unavailable" || errorCode === "wallet_lock_sender_address_unavailable") {
805
815
  return {
806
- what: "Selected sender could not be displayed.",
807
- why: "The wallet resolved a local sender identity, but it does not have a usable display address for that identity.",
808
- next: "Run `cogcoin ids` and retry with a different local sender selector.",
816
+ what: "Wallet address is unavailable.",
817
+ why: "The wallet could not produce a usable display address for the local sender.",
818
+ next: "Inspect `cogcoin address` and retry.",
819
+ };
820
+ }
821
+ if (errorCode === "wallet_bitcoin_transfer_invalid_amount") {
822
+ return {
823
+ what: "Bitcoin transfer amount is invalid.",
824
+ why: "This command accepts only a positive whole-number satoshi amount such as `1200`.",
825
+ next: "Rerun `cogcoin bitcoin transfer <sats> --to <address>` with a positive integer satoshi amount.",
826
+ };
827
+ }
828
+ if (errorCode === "wallet_bitcoin_transfer_invalid_address") {
829
+ return {
830
+ what: "Bitcoin transfer recipient address is invalid.",
831
+ why: "This command only accepts a standard mainnet BTC address in `--to`.",
832
+ next: "Rerun `cogcoin bitcoin transfer <sats> --to <address>` with a valid mainnet BTC address.",
833
+ };
834
+ }
835
+ if (errorCode === "wallet_bitcoin_transfer_address_required") {
836
+ return {
837
+ what: "Bitcoin transfer recipient must be a standard BTC address.",
838
+ why: "V1 of this command does not support opaque script targets such as `spk:<hex>`.",
839
+ next: "Rerun `cogcoin bitcoin transfer <sats> --to <address>` with a standard mainnet BTC address.",
840
+ };
841
+ }
842
+ if (errorCode === "wallet_bitcoin_transfer_self_transfer") {
843
+ return {
844
+ what: "Bitcoin transfer recipient matches the wallet address.",
845
+ why: "This command rejects self-transfers to the wallet funding script/address.",
846
+ next: "Choose a different recipient address and retry.",
847
+ };
848
+ }
849
+ if (errorCode === "wallet_bitcoin_transfer_confirmation_rejected") {
850
+ return {
851
+ what: "Bitcoin transfer confirmation was rejected.",
852
+ why: "The interactive confirmation was declined before the BTC payment was broadcast.",
853
+ next: "Review the recipient address and amount, then rerun the command if you still want to send BTC.",
854
+ };
855
+ }
856
+ if (errorCode === "wallet_bitcoin_transfer_requires_tty") {
857
+ return {
858
+ what: "Bitcoin transfer confirmation needs an interactive terminal.",
859
+ why: "Without `--yes`, Cogcoin must ask for an interactive confirmation before publishing a BTC payment.",
860
+ next: "Rerun the command in an interactive terminal, or add `--yes` if that is appropriate for your workflow.",
809
861
  };
810
862
  }
811
863
  if (errorCode === "wallet_claim_sender_not_local") {
812
864
  return {
813
865
  what: "The claim sender is not locally controlled.",
814
866
  why: "Before timeout, the wallet may only claim as the current recipient-domain owner, and that owner is not available in this wallet.",
815
- next: "Check the current recipient-domain owner with `cogcoin show <domain>` or use the wallet that controls that owner identity.",
867
+ next: "Check the current recipient-domain owner with `cogcoin show <domain>` or use the wallet that controls the owner.",
816
868
  };
817
869
  }
818
870
  if (errorCode === "wallet_reclaim_sender_not_local") {
819
871
  return {
820
872
  what: "The reclaim sender is not locally controlled.",
821
- why: "After timeout, the wallet may only reclaim as the original locker, and that locker identity is not available in this wallet.",
822
- next: "Use the wallet that controls the original locker identity, or inspect the lock details with `cogcoin locks`.",
873
+ why: "After timeout, the wallet may only reclaim as the original locker, and that locker is not controlled by this wallet.",
874
+ next: "Use the wallet that controls the original locker, or inspect the lock details with `cogcoin locks`.",
823
875
  };
824
876
  }
825
877
  if (errorCode.includes("ambiguous_sender") || errorCode.includes("no_eligible_sender")) {
826
878
  return {
827
879
  what: "Sender selection could not be resolved.",
828
- why: "The wallet could not determine one eligible local sender for this command.",
829
- next: "Inspect `cogcoin ids` and rerun the command with an explicit `--from` selector when supported.",
880
+ why: "The wallet could not determine a usable local sender for this command.",
881
+ next: "Inspect `cogcoin address` and `cogcoin status`, then retry.",
830
882
  };
831
883
  }
832
884
  if (classifiedAsBlockedMessage(errorCode)) {
@@ -854,21 +906,21 @@ export function describeCanonicalCommand(parsed) {
854
906
  return "cogcoin wallet delete";
855
907
  case "wallet-show-mnemonic":
856
908
  return "cogcoin wallet show-mnemonic";
857
- case "unlock":
858
- case "wallet-unlock":
859
- return "cogcoin unlock";
909
+ case "client-unlock":
910
+ return "cogcoin client unlock";
911
+ case "client-lock":
912
+ return "cogcoin client lock";
913
+ case "client-change-password":
914
+ return "cogcoin client change-password";
915
+ case "bitcoin-transfer":
916
+ return `cogcoin bitcoin transfer ${args[0] ?? "<sats>"}`;
860
917
  case "reset":
861
918
  return "cogcoin reset";
862
919
  case "repair":
863
920
  return "cogcoin repair";
864
- case "wallet-lock":
865
- return "cogcoin wallet lock";
866
921
  case "anchor":
867
922
  case "domain-anchor":
868
923
  return `cogcoin anchor ${args[0] ?? "<domain>"}`;
869
- case "anchor-clear":
870
- case "domain-anchor-clear":
871
- return `cogcoin anchor clear ${args[0] ?? "<domain>"}`;
872
924
  case "register":
873
925
  case "domain-register":
874
926
  return `cogcoin register ${args[0] ?? "<domain>"}`;
@@ -927,12 +979,6 @@ export function describeCanonicalCommand(parsed) {
927
979
  return "cogcoin ids";
928
980
  case "wallet-status":
929
981
  return "cogcoin wallet status";
930
- case "hooks-mining-status":
931
- return `cogcoin hooks status${parsed.verify ? " --verify" : ""}`;
932
- case "hooks-mining-enable":
933
- return "cogcoin hooks enable mining";
934
- case "hooks-mining-disable":
935
- return "cogcoin hooks disable mining";
936
982
  case "mine-setup":
937
983
  return "cogcoin mine setup";
938
984
  case "mine-start":
@@ -1002,8 +1048,6 @@ export function resolveStableJsonSchema(parsed) {
1002
1048
  return "cogcoin/ids/v1";
1003
1049
  case "wallet-status":
1004
1050
  return "cogcoin/wallet-status/v1";
1005
- case "hooks-mining-status":
1006
- return "cogcoin/hooks-status/v1";
1007
1051
  case "mine-status":
1008
1052
  return "cogcoin/mine-status/v1";
1009
1053
  case "mine-log":
@@ -1038,27 +1082,23 @@ export function resolveStableMutationJsonSchema(parsed) {
1038
1082
  case "restore":
1039
1083
  case "wallet-restore":
1040
1084
  return "cogcoin/restore/v1";
1085
+ case "client-unlock":
1086
+ return "cogcoin/client-unlock/v1";
1087
+ case "client-lock":
1088
+ return "cogcoin/client-lock/v1";
1089
+ case "client-change-password":
1090
+ return "cogcoin/client-change-password/v1";
1091
+ case "bitcoin-transfer":
1092
+ return "cogcoin/bitcoin-transfer/v1";
1041
1093
  case "wallet-delete":
1042
1094
  return "cogcoin/wallet-delete/v1";
1043
- case "unlock":
1044
- case "wallet-unlock":
1045
- return "cogcoin/unlock/v1";
1046
1095
  case "reset":
1047
1096
  return "cogcoin/reset/v1";
1048
- case "wallet-export":
1049
- return "cogcoin/wallet-export/v1";
1050
- case "wallet-import":
1051
- return "cogcoin/wallet-import/v1";
1052
- case "wallet-lock":
1053
- return "cogcoin/wallet-lock/v1";
1054
1097
  case "repair":
1055
1098
  return "cogcoin/repair/v1";
1056
1099
  case "anchor":
1057
1100
  case "domain-anchor":
1058
1101
  return "cogcoin/anchor/v1";
1059
- case "anchor-clear":
1060
- case "domain-anchor-clear":
1061
- return "cogcoin/anchor-clear/v1";
1062
1102
  case "register":
1063
1103
  case "domain-register":
1064
1104
  return "cogcoin/register/v1";
@@ -1115,10 +1155,6 @@ export function resolveStableMutationJsonSchema(parsed) {
1115
1155
  }
1116
1156
  export function resolveStableMiningControlJsonSchema(parsed) {
1117
1157
  switch (parsed.command) {
1118
- case "hooks-mining-enable":
1119
- return "cogcoin/hooks-enable-mining/v1";
1120
- case "hooks-mining-disable":
1121
- return "cogcoin/hooks-disable-mining/v1";
1122
1158
  case "mine-setup":
1123
1159
  return "cogcoin/mine-setup/v1";
1124
1160
  case "mine-start":
@@ -1133,13 +1169,10 @@ export function resolvePreviewJsonSchema(parsed) {
1133
1169
  const stableMutationSchema = resolveStableMutationJsonSchema(parsed);
1134
1170
  const stableMiningControlSchema = resolveStableMiningControlJsonSchema(parsed);
1135
1171
  switch (parsed.command) {
1136
- case "wallet-lock":
1137
1172
  case "reset":
1138
1173
  case "repair":
1139
1174
  case "anchor":
1140
- case "anchor-clear":
1141
1175
  case "domain-anchor":
1142
- case "domain-anchor-clear":
1143
1176
  case "register":
1144
1177
  case "domain-register":
1145
1178
  case "transfer":
@@ -1172,8 +1205,6 @@ export function resolvePreviewJsonSchema(parsed) {
1172
1205
  return stableMutationSchema === null
1173
1206
  ? null
1174
1207
  : stableMutationSchema.replace(/^cogcoin\//, "cogcoin-preview/");
1175
- case "hooks-mining-enable":
1176
- case "hooks-mining-disable":
1177
1208
  case "mine-setup":
1178
1209
  case "mine-start":
1179
1210
  case "mine-stop":
@@ -1197,6 +1228,7 @@ function createSchemaProbe(command) {
1197
1228
  seedName: null,
1198
1229
  unlockFor: null,
1199
1230
  assumeYes: false,
1231
+ force: false,
1200
1232
  forceRace: false,
1201
1233
  anchorMessage: null,
1202
1234
  transferTarget: null,
@@ -1206,12 +1238,12 @@ function createSchemaProbe(command) {
1206
1238
  fieldPermanent: false,
1207
1239
  fieldFormat: null,
1208
1240
  fieldValue: null,
1209
- fromIdentity: null,
1210
1241
  lockRecipientDomain: null,
1211
1242
  conditionHex: null,
1212
1243
  untilHeight: null,
1213
1244
  preimageHex: null,
1214
1245
  reviewText: null,
1246
+ satvb: null,
1215
1247
  locksClaimableOnly: false,
1216
1248
  locksReclaimableOnly: false,
1217
1249
  domainsAnchoredOnly: false,
@@ -1219,7 +1251,6 @@ function createSchemaProbe(command) {
1219
1251
  domainsMineableOnly: false,
1220
1252
  listLimit: null,
1221
1253
  listAll: false,
1222
- verify: false,
1223
1254
  follow: false,
1224
1255
  };
1225
1256
  }
@@ -1246,7 +1277,7 @@ export function isPreviewJsonOutputSupportedCommand(command) {
1246
1277
  }
1247
1278
  export function createCommandJsonErrorEnvelope(parsed, error) {
1248
1279
  const classified = classifyCliError(error);
1249
- const presentation = createCliErrorPresentation(classified.errorCode, classified.message);
1280
+ const presentation = createCliErrorPresentation(classified.errorCode, classified.message, error);
1250
1281
  const humanMessage = presentation?.what ?? classified.message;
1251
1282
  const explanations = presentation?.why === null || presentation?.why === undefined ? [] : [presentation.why];
1252
1283
  const nextSteps = presentation?.next === null || presentation?.next === undefined ? [] : [presentation.next];
@@ -1291,17 +1322,9 @@ export function createCommandJsonErrorEnvelope(parsed, error) {
1291
1322
  function createCliErrorDetails(errorCode, humanMessage, rawMessage) {
1292
1323
  const details = {};
1293
1324
  const initMatch = /^wallet_init_confirmation_failed_word_(\d+)$/.exec(errorCode);
1294
- const hooksTemplateMatch = /^mining_hooks_enable_template_created:(.+)$/.exec(rawMessage);
1295
- const hooksValidationMatch = /^mining_hooks_enable_validation_failed:(.+)$/.exec(rawMessage);
1296
1325
  if (initMatch !== null) {
1297
1326
  details.wordIndex = Number.parseInt(initMatch[1], 10);
1298
1327
  }
1299
- if (hooksTemplateMatch !== null) {
1300
- details.hookRootPath = hooksTemplateMatch[1];
1301
- }
1302
- if (hooksValidationMatch !== null) {
1303
- details.validationError = hooksValidationMatch[1];
1304
- }
1305
1328
  if (humanMessage !== rawMessage) {
1306
1329
  details.rawMessage = rawMessage;
1307
1330
  }