@cogcoin/client 0.5.15 → 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 +6 -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 -12
  91. package/dist/wallet/coin-control.js +100 -428
  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 +116 -13
  105. package/dist/wallet/mining/runner.js +885 -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 -1250
  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 +61 -8
  144. package/dist/wallet/tx/common.js +266 -146
  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 +83 -924
  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,12 +1,23 @@
1
- import { findDomainField, findWalletDomain, formatFieldFormat, listDomainFields, listWalletLocks, } from "../wallet/read/index.js";
1
+ import { getBalance } from "@cogcoin/indexer/queries";
2
+ import { findDomainField, findWalletDomain, formatFieldFormat, isRootDomainName, listDomainFields, listWalletLocks, } from "../wallet/read/index.js";
3
+ import { loadBalanceArtText } from "./art.js";
2
4
  import { formatMiningSummaryLine } from "./mining-format.js";
3
- import { getBootstrapSyncNextStep } from "./workflow-hints.js";
4
- function formatCogAmount(value) {
5
+ import { formatNextStepLines, getBootstrapSyncNextStep, getFundingQuickstartGuidance, } from "./workflow-hints.js";
6
+ const BALANCE_QUICKSTART_THRESHOLD_SATS = 150000n;
7
+ const BALANCE_BUY_ROOT_THRESHOLD_SATS = 100000n;
8
+ const BALANCE_MINING_THRESHOLD_SATS = 10000n;
9
+ function formatUnitAmount(value, unit) {
5
10
  const sign = value < 0n ? "-" : "";
6
11
  const absolute = value < 0n ? -value : value;
7
12
  const whole = absolute / 100000000n;
8
13
  const fraction = absolute % 100000000n;
9
- return `${sign}${whole.toString()}.${fraction.toString().padStart(8, "0")} COG`;
14
+ return `${sign}${whole.toString()}.${fraction.toString().padStart(8, "0")} ${unit}`;
15
+ }
16
+ function formatCogAmount(value) {
17
+ return formatUnitAmount(value, "COG");
18
+ }
19
+ function formatBitcoinAmount(value) {
20
+ return value === null ? "unavailable BTC" : formatUnitAmount(value, "BTC");
10
21
  }
11
22
  function formatServiceHealth(health) {
12
23
  return health.replaceAll("-", " ");
@@ -26,12 +37,6 @@ function formatIndexerTruthSource(source) {
26
37
  return "none";
27
38
  }
28
39
  }
29
- function formatUnlockExpiry(unlockUntilUnixMs) {
30
- if (unlockUntilUnixMs === null) {
31
- return "locked";
32
- }
33
- return `unlocked until ${new Date(unlockUntilUnixMs).toISOString()}`;
34
- }
35
40
  function isReputationMutation(mutation) {
36
41
  return (mutation.kind === "rep-give" || mutation.kind === "rep-revoke")
37
42
  && mutation.recipientDomainName !== undefined
@@ -75,6 +80,13 @@ function formatPendingMutationDomainLabel(mutation) {
75
80
  return kind;
76
81
  }
77
82
  export function getRepairRecommendation(context) {
83
+ if (context.localState.clientPasswordReadiness === "setup-required"
84
+ || context.localState.clientPasswordReadiness === "migration-required") {
85
+ return "Run `cogcoin init` to configure the client password and migrate local wallet secrets.";
86
+ }
87
+ if (context.localState.unlockRequired) {
88
+ return null;
89
+ }
78
90
  if (context.localState.availability === "uninitialized") {
79
91
  return "Run `cogcoin init` to create a new local wallet root.";
80
92
  }
@@ -96,32 +108,18 @@ export function getRepairRecommendation(context) {
96
108
  return "Run `cogcoin repair` to recover the managed indexer daemon and local indexer artifacts.";
97
109
  }
98
110
  if (context.localState.state?.miningState.state === "repair-required"
99
- || context.localState.state?.proactiveFamilies.some((family) => family.status === "repair-required")
100
- || context.localState.state?.domains.some((domain) => domain.localAnchorIntent === "repair-required")
101
111
  || (context.localState.state?.pendingMutations ?? []).some((mutation) => mutation.status === "repair-required")) {
102
112
  return "Run `cogcoin repair` before relying on local wallet state.";
103
113
  }
104
114
  return null;
105
115
  }
106
- export function getMutationRecommendation(context) {
107
- const clearableAnchorFamily = (context.localState.state?.proactiveFamilies ?? []).find((family) => family.type === "anchor"
108
- && family.status === "draft"
109
- && family.currentStep === "reserved");
110
- if (clearableAnchorFamily?.domainName != null) {
111
- return `Run \`cogcoin anchor clear ${clearableAnchorFamily.domainName}\` to cancel the local pending anchor reservation, or rerun \`cogcoin anchor ${clearableAnchorFamily.domainName}\` to continue anchoring.`;
112
- }
113
- const unresolvedFamily = (context.localState.state?.proactiveFamilies ?? []).find((family) => (family.type === "anchor" || family.type === "field")
114
- && (family.status === "broadcast-unknown" || family.status === "repair-required"));
115
- if (unresolvedFamily !== undefined) {
116
- if (unresolvedFamily.status === "repair-required") {
117
- return unresolvedFamily.type === "field"
118
- ? "Run `cogcoin repair` before starting another field family."
119
- : "Run `cogcoin repair` before starting another anchor family.";
120
- }
121
- return unresolvedFamily.type === "field"
122
- ? `Rerun \`cogcoin field create ${unresolvedFamily.domainName} ${unresolvedFamily.fieldName} ...\` to reconcile the pending field family, or run \`cogcoin repair\` if it remains unresolved.`
123
- : `Rerun \`cogcoin anchor ${unresolvedFamily.domainName}\` to reconcile the pending anchor family, or run \`cogcoin repair\` if it remains unresolved.`;
116
+ export function getClientUnlockRecommendation(context) {
117
+ if (context.localState.unlockRequired) {
118
+ return "Run `cogcoin client unlock` to temporarily unlock wallet-local secrets.";
124
119
  }
120
+ return null;
121
+ }
122
+ export function getMutationRecommendation(context) {
125
123
  const pendingMutations = context.localState.state?.pendingMutations ?? [];
126
124
  const unresolved = pendingMutations.find((mutation) => mutation.status === "broadcast-unknown" || mutation.status === "repair-required");
127
125
  if (unresolved === undefined) {
@@ -133,6 +131,9 @@ export function getMutationRecommendation(context) {
133
131
  if (unresolved.kind === "register") {
134
132
  return `Rerun \`cogcoin register ${unresolved.domainName}\` to reconcile the pending registration, or run \`cogcoin repair\` if it remains unresolved.`;
135
133
  }
134
+ if (unresolved.kind === "anchor") {
135
+ return `Rerun \`cogcoin anchor ${unresolved.domainName}\` to reconcile the pending anchor, or run \`cogcoin repair\` if it remains unresolved.`;
136
+ }
136
137
  if (unresolved.kind === "transfer") {
137
138
  return `Rerun \`cogcoin transfer ${unresolved.domainName}\` with the same target to reconcile the pending transfer, or run \`cogcoin repair\` if it remains unresolved.`;
138
139
  }
@@ -187,22 +188,12 @@ export function getMutationRecommendation(context) {
187
188
  : "Rerun the same `cogcoin claim ...` command to reconcile the pending claim, or run `cogcoin repair` if it remains unresolved.";
188
189
  }
189
190
  function appendPendingMutationSummary(lines, context) {
190
- const pendingFamilies = (context.localState.state?.proactiveFamilies ?? [])
191
- .filter((family) => (family.type === "anchor" || family.type === "field")
192
- && family.status !== "confirmed"
193
- && family.status !== "canceled");
194
191
  const pendingMutations = (context.localState.state?.pendingMutations ?? [])
195
192
  .filter((mutation) => mutation.status !== "confirmed" && mutation.status !== "canceled");
196
- if (pendingFamilies.length === 0 && pendingMutations.length === 0) {
193
+ if (pendingMutations.length === 0) {
197
194
  lines.push("Pending mutations: none");
198
195
  return;
199
196
  }
200
- for (const family of pendingFamilies) {
201
- const label = family.type === "field"
202
- ? `Pending field family: ${family.domainName ?? "unknown"}.${family.fieldName ?? "unknown"}`
203
- : `Pending anchor family: ${family.domainName ?? "unknown"}`;
204
- lines.push(`${label} ${family.status}${family.currentStep === null || family.currentStep === undefined ? "" : ` step ${family.currentStep}`}${family.reservedDedicatedIndex == null ? "" : ` index ${family.reservedDedicatedIndex}`}`);
205
- }
206
197
  for (const mutation of pendingMutations) {
207
198
  lines.push(`Pending mutation: ${formatPendingMutationSummaryLabel(mutation)} ${mutation.status} sender spk:${mutation.senderScriptPubKeyHex}${mutation.priceCogtoshi === undefined || mutation.priceCogtoshi === null ? "" : ` price ${formatCogAmount(mutation.priceCogtoshi)}`}${mutation.amountCogtoshi === undefined || mutation.amountCogtoshi === null ? "" : ` amount ${formatCogAmount(mutation.amountCogtoshi)}`}${isReputationMutation(mutation) ? "" : mutation.recipientDomainName === undefined || mutation.recipientDomainName === null ? "" : ` domain ${mutation.recipientDomainName}`}${mutation.lockId === undefined || mutation.lockId === null ? "" : ` lock ${mutation.lockId}`}${mutation.recipientScriptPubKeyHex === undefined || mutation.recipientScriptPubKeyHex === null ? "" : ` recipient spk:${mutation.recipientScriptPubKeyHex}`}${mutation.kind === "endpoint" ? (mutation.endpointValueHex === "" ? " endpoint clear" : ` endpoint-bytes ${(mutation.endpointValueHex?.length ?? 0) / 2}`) : ""}${mutation.kind === "field-create" || mutation.kind === "field-set" ? ` format ${formatFieldFormat(mutation.fieldFormat ?? 0)}` : ""}${mutation.kind === "field-clear" ? " clear" : ""}${mutation.reviewPayloadHex === undefined || mutation.reviewPayloadHex === null ? "" : " review"}`);
208
199
  }
@@ -213,6 +204,7 @@ function listPendingDomainMutations(context, domainName) {
213
204
  || mutation.kind === "transfer"
214
205
  || mutation.kind === "sell"
215
206
  || mutation.kind === "buy"
207
+ || mutation.kind === "anchor"
216
208
  || mutation.kind === "endpoint"
217
209
  || mutation.kind === "delegate"
218
210
  || mutation.kind === "miner"
@@ -224,26 +216,13 @@ function listPendingDomainMutations(context, domainName) {
224
216
  && mutation.status !== "confirmed"
225
217
  && mutation.status !== "canceled");
226
218
  }
227
- function listPendingAnchorFamilies(context, domainName) {
228
- return (context.localState.state?.proactiveFamilies ?? [])
229
- .filter((family) => family.type === "anchor"
230
- && family.domainName === domainName
231
- && family.status !== "confirmed"
232
- && family.status !== "canceled");
233
- }
234
- function listPendingFieldFamilies(context, domainName) {
235
- return (context.localState.state?.proactiveFamilies ?? [])
236
- .filter((family) => family.type === "field"
237
- && family.domainName === domainName
238
- && family.status !== "confirmed"
239
- && family.status !== "canceled");
240
- }
241
219
  function listPendingDomainShowMutations(context, domainName) {
242
220
  return (context.localState.state?.pendingMutations ?? [])
243
221
  .filter((mutation) => (mutation.kind === "register"
244
222
  || mutation.kind === "transfer"
245
223
  || mutation.kind === "sell"
246
224
  || mutation.kind === "buy"
225
+ || mutation.kind === "anchor"
247
226
  || mutation.kind === "endpoint"
248
227
  || mutation.kind === "delegate"
249
228
  || mutation.kind === "miner"
@@ -308,7 +287,6 @@ function appendServiceSummary(lines, context) {
308
287
  function appendWalletAvailability(lines, context) {
309
288
  lines.push(`Wallet state: ${context.localState.availability}`);
310
289
  lines.push(`Wallet root: ${context.model?.walletRootId ?? context.localState.walletRootId ?? context.nodeStatus?.walletRootId ?? "none"}`);
311
- lines.push(`Wallet unlock: ${formatUnlockExpiry(context.localState.unlockUntilUnixMs)}`);
312
290
  if (context.localState.message !== null) {
313
291
  lines.push(`Wallet note: ${context.localState.message}`);
314
292
  }
@@ -325,8 +303,11 @@ function appendWalletAvailability(lines, context) {
325
303
  lines.push(`Recommended next step: ${repairRecommendation}`);
326
304
  }
327
305
  else {
328
- const bootstrapSync = getBootstrapSyncNextStep(context);
329
- if (bootstrapSync !== null) {
306
+ const clientUnlockRecommendation = getClientUnlockRecommendation(context);
307
+ if (clientUnlockRecommendation !== null) {
308
+ lines.push(`Recommended next step: ${clientUnlockRecommendation}`);
309
+ }
310
+ else if (getBootstrapSyncNextStep(context) !== null) {
330
311
  lines.push("Recommended next step: Run `cogcoin sync` to bootstrap assumeutxo and the managed Bitcoin/indexer state.");
331
312
  }
332
313
  }
@@ -347,7 +328,7 @@ function isMiningOverviewOk(mining) {
347
328
  && mining.runtime.indexerHealth === "synced"
348
329
  && mining.runtime.miningState !== "repair-required"
349
330
  && mining.runtime.miningState !== "paused-stale"
350
- && !(mining.runtime.miningState === "paused" && mining.runtime.liveMiningFamilyInMempool === true);
331
+ && !(mining.runtime.miningState === "paused" && mining.runtime.livePublishInMempool === true);
351
332
  }
352
333
  function buildOverviewPathsSection(context) {
353
334
  return [
@@ -360,7 +341,6 @@ function buildOverviewWalletSection(context) {
360
341
  const lines = [
361
342
  overviewEntry(`State: ${context.localState.availability}`, context.localState.availability === "ready"),
362
343
  overviewEntry(`Root: ${walletRoot}`, walletRoot !== "none"),
363
- overviewEntry(`Unlock: ${formatUnlockExpiry(context.localState.unlockUntilUnixMs)}`, context.localState.unlockUntilUnixMs !== null),
364
344
  ];
365
345
  if (context.localState.message !== null) {
366
346
  lines.push(overviewEntry(`Note: ${context.localState.message}`, false));
@@ -422,28 +402,17 @@ function buildOverviewLocalInventorySection(context) {
422
402
  return [overviewEntry("Status: Wallet-derived sections unavailable", false)];
423
403
  }
424
404
  return [
425
- overviewEntry(`Local identities: ${context.model.identities.length}`, true),
405
+ overviewEntry("Local wallet address: 1", true),
426
406
  overviewEntry(`Locally related domains: ${context.model.domains.length}`, true),
427
- overviewEntry(`Read-only identities: ${context.model.readOnlyIdentityCount}`, true),
428
407
  ];
429
408
  }
430
409
  function buildOverviewPendingWorkSection(context) {
431
- const pendingFamilies = (context.localState.state?.proactiveFamilies ?? [])
432
- .filter((family) => (family.type === "anchor" || family.type === "field")
433
- && family.status !== "confirmed"
434
- && family.status !== "canceled");
435
410
  const pendingMutations = (context.localState.state?.pendingMutations ?? [])
436
411
  .filter((mutation) => mutation.status !== "confirmed" && mutation.status !== "canceled");
437
- if (pendingFamilies.length === 0 && pendingMutations.length === 0) {
412
+ if (pendingMutations.length === 0) {
438
413
  return [overviewEntry("Status: none", true)];
439
414
  }
440
415
  const lines = [];
441
- for (const family of pendingFamilies) {
442
- const label = family.type === "field"
443
- ? `Field family: ${family.domainName ?? "unknown"}.${family.fieldName ?? "unknown"}`
444
- : `Anchor family: ${family.domainName ?? "unknown"}`;
445
- lines.push(overviewEntry(`${label} ${family.status}${family.currentStep === null || family.currentStep === undefined ? "" : ` step ${family.currentStep}`}${family.reservedDedicatedIndex == null ? "" : ` index ${family.reservedDedicatedIndex}`}`, false));
446
- }
447
416
  for (const mutation of pendingMutations) {
448
417
  lines.push(overviewEntry(`Mutation: ${formatPendingMutationSummaryLabel(mutation)} ${mutation.status} sender spk:${mutation.senderScriptPubKeyHex}${mutation.priceCogtoshi === undefined || mutation.priceCogtoshi === null ? "" : ` price ${formatCogAmount(mutation.priceCogtoshi)}`}${mutation.amountCogtoshi === undefined || mutation.amountCogtoshi === null ? "" : ` amount ${formatCogAmount(mutation.amountCogtoshi)}`}${isReputationMutation(mutation) ? "" : mutation.recipientDomainName === undefined || mutation.recipientDomainName === null ? "" : ` domain ${mutation.recipientDomainName}`}${mutation.lockId === undefined || mutation.lockId === null ? "" : ` lock ${mutation.lockId}`}${mutation.recipientScriptPubKeyHex === undefined || mutation.recipientScriptPubKeyHex === null ? "" : ` recipient spk:${mutation.recipientScriptPubKeyHex}`}${mutation.kind === "endpoint" ? (mutation.endpointValueHex === "" ? " endpoint clear" : ` endpoint-bytes ${(mutation.endpointValueHex?.length ?? 0) / 2}`) : ""}${mutation.kind === "field-create" || mutation.kind === "field-set" ? ` format ${formatFieldFormat(mutation.fieldFormat ?? 0)}` : ""}${mutation.kind === "field-clear" ? " clear" : ""}${mutation.reviewPayloadHex === undefined || mutation.reviewPayloadHex === null ? "" : " review"}`, false));
449
418
  }
@@ -454,6 +423,10 @@ function getOverviewNextStep(context) {
454
423
  if (repairRecommendation !== null) {
455
424
  return repairRecommendation;
456
425
  }
426
+ const clientUnlockRecommendation = getClientUnlockRecommendation(context);
427
+ if (clientUnlockRecommendation !== null) {
428
+ return clientUnlockRecommendation;
429
+ }
457
430
  if (getBootstrapSyncNextStep(context) !== null) {
458
431
  return "Run `cogcoin sync` to bootstrap assumeutxo and the managed Bitcoin/indexer state.";
459
432
  }
@@ -482,46 +455,175 @@ export function formatDetailedWalletStatusReport(context) {
482
455
  lines.push("Wallet details are unavailable until the encrypted wallet state can be read.");
483
456
  return lines.join("\n");
484
457
  }
485
- lines.push(`Funding identity: ${context.model.fundingIdentity?.selectors[0] ?? "unavailable"}`);
486
- lines.push(`Funding address: ${context.model.fundingIdentity?.address ?? "unavailable"}`);
487
- lines.push(`Controlled identities: ${context.model.identities.length}`);
458
+ lines.push(`Wallet address: ${context.model.walletAddress ?? "unavailable"}`);
459
+ lines.push(`Wallet script: spk:${context.model.walletScriptPubKeyHex ?? "unavailable"}`);
460
+ lines.push("Local wallet addresses: 1");
488
461
  lines.push(`Locally related domains: ${context.model.domains.length}`);
489
- lines.push(`Read-only identities: ${context.model.readOnlyIdentityCount}`);
490
462
  appendPendingMutationSummary(lines, context);
491
463
  return lines.join("\n");
492
464
  }
493
465
  export function formatFundingAddressReport(context) {
494
- const lines = ["BTC Funding Address"];
495
- if (context.model?.fundingIdentity === null || context.model === null) {
466
+ const lines = ["BTC Wallet Address"];
467
+ if (context.model === null) {
496
468
  appendWalletAvailability(lines, context);
497
469
  return lines.join("\n");
498
470
  }
499
- lines.push(`Selector: ${context.model.fundingIdentity.selectors[0]}`);
500
- lines.push(`Address: ${context.model.fundingIdentity.address ?? "unavailable"}`);
501
- lines.push(`ScriptPubKey: spk:${context.model.fundingIdentity.scriptPubKeyHex}`);
471
+ lines.push(`Address: ${context.model.walletAddress ?? "unavailable"}`);
472
+ lines.push(`ScriptPubKey: spk:${context.model.walletScriptPubKeyHex}`);
473
+ return lines.join("\n");
474
+ }
475
+ function renderBalanceArtLine(templateLine, label, value) {
476
+ const labelIndex = templateLine.indexOf(label);
477
+ if (labelIndex === -1) {
478
+ throw new Error(`balance_art_label_missing_${label}`);
479
+ }
480
+ const fieldStart = labelIndex + label.length;
481
+ const borderIndex = Math.max(templateLine.lastIndexOf("│"), templateLine.lastIndexOf("|"));
482
+ if (borderIndex <= fieldStart) {
483
+ throw new Error(`balance_art_field_invalid_${label}`);
484
+ }
485
+ const fieldWidth = borderIndex - fieldStart;
486
+ const fieldValue = value.slice(0, fieldWidth).padEnd(fieldWidth, " ");
487
+ const rendered = `${templateLine.slice(0, fieldStart)}${fieldValue}${templateLine.slice(borderIndex)}`;
488
+ if (rendered.length !== templateLine.length) {
489
+ throw new Error(`balance_art_render_width_invalid_${label}`);
490
+ }
491
+ return rendered;
492
+ }
493
+ function renderBalanceArtCard(context) {
494
+ const templateLines = loadBalanceArtText().split("\n");
495
+ const fundingAddress = context.model.walletAddress ?? "unavailable";
496
+ const spendableCog = getBalance(context.snapshot.state, new Uint8Array(Buffer.from(context.model.walletScriptPubKeyHex, "hex")));
497
+ return templateLines.map((line) => {
498
+ if (line.includes("Funding address:")) {
499
+ return renderBalanceArtLine(line, "Funding address:", ` ${fundingAddress}`);
500
+ }
501
+ if (line.includes("Bitcoin Balance:")) {
502
+ return renderBalanceArtLine(line, "Bitcoin Balance:", ` ${formatBitcoinAmount(context.fundingSpendableSats ?? null)}`);
503
+ }
504
+ if (line.includes("Cogcoin Balance:")) {
505
+ return renderBalanceArtLine(line, "Cogcoin Balance:", ` ${formatCogAmount(spendableCog)}`);
506
+ }
507
+ if (line.includes("mempool.space/address/")) {
508
+ return renderBalanceArtLine(line, "mempool.space/address/", fundingAddress);
509
+ }
510
+ return line;
511
+ });
512
+ }
513
+ function hasRegisteredOrAnchoredDomain(model) {
514
+ return model.domains.some((domain) => domain.localRelationship === "local"
515
+ && (domain.chainStatus === "registered-unanchored" || domain.chainStatus === "anchored"));
516
+ }
517
+ function listBalanceDomainsByStatus(model, status) {
518
+ return model.domains
519
+ .filter((domain) => domain.localRelationship === "local" && domain.chainStatus === status)
520
+ .sort((left, right) => left.name.localeCompare(right.name));
521
+ }
522
+ function shouldShowBalanceQuickstart(context) {
523
+ return context.fundingSpendableSats !== null
524
+ && context.fundingSpendableSats < BALANCE_QUICKSTART_THRESHOLD_SATS
525
+ && !hasRegisteredOrAnchoredDomain(context.model);
526
+ }
527
+ function formatBalanceDomainSection(title, icon, domains, emptyLabel) {
528
+ const domainItems = domains.map((domain) => `${icon} ${domain.name}`);
529
+ const wrappedDomainLines = [];
530
+ let currentLine = "";
531
+ for (const item of domainItems) {
532
+ const candidate = currentLine.length === 0 ? item : `${currentLine}, ${item}`;
533
+ if (candidate.length <= 80) {
534
+ currentLine = candidate;
535
+ continue;
536
+ }
537
+ if (currentLine.length > 0) {
538
+ wrappedDomainLines.push(currentLine);
539
+ }
540
+ currentLine = item;
541
+ }
542
+ if (currentLine.length > 0) {
543
+ wrappedDomainLines.push(currentLine);
544
+ }
545
+ return [
546
+ title,
547
+ ...(domains.length === 0
548
+ ? [emptyLabel]
549
+ : wrappedDomainLines),
550
+ ];
551
+ }
552
+ function getBalanceNextSteps(context) {
553
+ const anchoredDomains = listBalanceDomainsByStatus(context.model, "anchored");
554
+ const anchoredRootDomains = anchoredDomains.filter((domain) => isRootDomainName(domain.name));
555
+ const unanchoredDomains = listBalanceDomainsByStatus(context.model, "registered-unanchored");
556
+ if (anchoredRootDomains.length > 0) {
557
+ if (context.fundingSpendableSats !== null && context.fundingSpendableSats < BALANCE_MINING_THRESHOLD_SATS) {
558
+ return [`Transfer BTC to ${context.model.walletAddress ?? "this wallet address"} so your anchored root domain can keep mining.`];
559
+ }
560
+ if (context.fundingSpendableSats !== null && context.fundingSpendableSats > BALANCE_MINING_THRESHOLD_SATS) {
561
+ return ["Run `cogcoin mine` to start mining with your anchored root domain."];
562
+ }
563
+ return [];
564
+ }
565
+ if (unanchoredDomains.length > 0) {
566
+ return [`Run \`cogcoin anchor ${unanchoredDomains[0].name}\` to anchor your unanchored domain.`];
567
+ }
568
+ if (context.fundingSpendableSats !== null && context.fundingSpendableSats > BALANCE_BUY_ROOT_THRESHOLD_SATS) {
569
+ return ["Buy a 6+ character root domain with `cogcoin register <root>`."];
570
+ }
571
+ return [];
572
+ }
573
+ function listPendingBalanceLines(context) {
574
+ const lines = [];
575
+ for (const mutation of (context.localState.state?.pendingMutations ?? [])
576
+ .filter((entry) => (entry.kind === "send" || entry.kind === "lock" || entry.kind === "claim")
577
+ && entry.status !== "confirmed"
578
+ && entry.status !== "canceled")) {
579
+ const label = mutation.kind === "claim" && mutation.preimageHex === "0000000000000000000000000000000000000000000000000000000000000000"
580
+ ? "reclaim"
581
+ : mutation.kind;
582
+ lines.push(`Pending: ${label} ${mutation.status}${mutation.amountCogtoshi === null || mutation.amountCogtoshi === undefined ? "" : ` ${formatCogAmount(mutation.amountCogtoshi)}`}`);
583
+ }
584
+ return lines;
585
+ }
586
+ function formatReadyBalanceReport(context) {
587
+ const anchoredDomains = listBalanceDomainsByStatus(context.model, "anchored");
588
+ const unanchoredDomains = listBalanceDomainsByStatus(context.model, "registered-unanchored");
589
+ const nextStepLines = formatNextStepLines(getBalanceNextSteps(context));
590
+ const lines = [
591
+ "",
592
+ ...renderBalanceArtCard(context),
593
+ "",
594
+ ...formatBalanceDomainSection("Anchored Domains", "⌂", anchoredDomains, "--- No anchored domains ---"),
595
+ "",
596
+ ...formatBalanceDomainSection("Unanchored Domains", "~", unanchoredDomains, "--- No unanchored domains ---"),
597
+ ];
598
+ if (shouldShowBalanceQuickstart(context)) {
599
+ lines.push("");
600
+ lines.push(`Quickstart: ${getFundingQuickstartGuidance()}`);
601
+ }
602
+ if (nextStepLines.length > 0) {
603
+ lines.push("");
604
+ lines.push(...nextStepLines);
605
+ }
606
+ const pendingLines = listPendingBalanceLines(context);
607
+ if (pendingLines.length > 0) {
608
+ lines.push("");
609
+ lines.push(...pendingLines);
610
+ }
502
611
  return lines.join("\n");
503
612
  }
504
613
  export function formatIdentityListReport(context, options = {}) {
505
- const lines = ["Wallet Identities"];
614
+ const lines = ["Wallet Address"];
506
615
  if (context.model === null) {
507
616
  appendWalletAvailability(lines, context);
508
617
  return lines.join("\n");
509
618
  }
510
- const identities = context.model.identities;
511
- if (identities.length === 0) {
512
- lines.push("No local identities are recorded yet.");
513
- return lines.join("\n");
514
- }
515
- const limit = options.all ? null : options.limit ?? null;
516
- const renderedIdentities = limit === null ? identities : identities.slice(0, limit);
517
- for (const identity of renderedIdentities) {
518
- const domains = identity.ownedDomainNames.length === 0 ? "none" : identity.ownedDomainNames.join(", ");
519
- const balance = identity.observedCogBalance === null ? "unavailable" : formatCogAmount(identity.observedCogBalance);
520
- lines.push(`${identity.selectors[0]} ${identity.effectiveStatus} ${identity.address ?? `spk:${identity.scriptPubKeyHex}`} balance ${balance} domains ${domains} selectors ${identity.selectors.join(", ")}`);
521
- }
522
- if (limit !== null && identities.length > limit) {
523
- lines.push(`Showing first ${renderedIdentities.length} of ${identities.length}. Use --limit <n> or --all for more.`);
524
- }
619
+ const domains = context.model.domains
620
+ .filter((domain) => domain.localRelationship === "local")
621
+ .map((domain) => domain.name)
622
+ .sort();
623
+ const balance = context.snapshot === null
624
+ ? null
625
+ : getBalance(context.snapshot.state, new Uint8Array(Buffer.from(context.model.walletScriptPubKeyHex, "hex")));
626
+ lines.push(`${context.model.walletAddress ?? `spk:${context.model.walletScriptPubKeyHex}`} balance ${balance === null ? "unavailable" : formatCogAmount(balance)} domains ${domains.length === 0 ? "none" : domains.join(", ")}`);
525
627
  return lines.join("\n");
526
628
  }
527
629
  export function formatBalanceReport(context) {
@@ -534,23 +636,7 @@ export function formatBalanceReport(context) {
534
636
  lines.push(`Indexer-backed balances are unavailable while the indexer is ${formatServiceHealth(context.indexer.health)}.`);
535
637
  return lines.join("\n");
536
638
  }
537
- const spendableTotal = context.model.identities.reduce((sum, identity) => identity.readOnly || identity.observedCogBalance === null
538
- ? sum
539
- : sum + identity.observedCogBalance, 0n);
540
- lines.push(`Spendable total: ${formatCogAmount(spendableTotal)}`);
541
- for (const identity of context.model.identities) {
542
- lines.push(`${identity.selectors[0]} ${identity.address ?? `spk:${identity.scriptPubKeyHex}`} ${formatCogAmount(identity.observedCogBalance ?? 0n)}${identity.readOnly ? " read-only" : ""}`);
543
- }
544
- for (const mutation of (context.localState.state?.pendingMutations ?? [])
545
- .filter((entry) => (entry.kind === "send" || entry.kind === "lock" || entry.kind === "claim")
546
- && entry.status !== "confirmed"
547
- && entry.status !== "canceled")) {
548
- const label = mutation.kind === "claim" && mutation.preimageHex === "0000000000000000000000000000000000000000000000000000000000000000"
549
- ? "reclaim"
550
- : mutation.kind;
551
- lines.push(`Pending: ${label} ${mutation.status}${mutation.amountCogtoshi === null || mutation.amountCogtoshi === undefined ? "" : ` ${formatCogAmount(mutation.amountCogtoshi)}`}`);
552
- }
553
- return lines.join("\n");
639
+ return formatReadyBalanceReport(context);
554
640
  }
555
641
  export function formatLocksReport(context, options = {}) {
556
642
  const lines = ["COG Locks"];
@@ -621,8 +707,6 @@ export function formatDomainsReport(context, options = {}) {
621
707
  : visibleDomains.slice(0, options.limit);
622
708
  for (const domain of renderedDomains) {
623
709
  const pending = listPendingDomainMutations(context, domain.name);
624
- const pendingAnchors = listPendingAnchorFamilies(context, domain.name);
625
- const pendingFieldFamilies = listPendingFieldFamilies(context, domain.name);
626
710
  const pendingFieldMutations = listPendingFieldMutations(context, domain.name);
627
711
  const pendingText = pending.length === 0
628
712
  ? ""
@@ -635,18 +719,10 @@ export function formatDomainsReport(context, options = {}) {
635
719
  : mutation.kind === "miner" && mutation.recipientScriptPubKeyHex === null
636
720
  ? `miner-clear:${mutation.status}`
637
721
  : `${mutation.kind}:${mutation.status}`).join(",")}`;
638
- const pendingFieldsText = pendingFieldMutations.length === 0 && pendingFieldFamilies.length === 0
639
- ? ""
640
- : ` field-pending ${[
641
- ...pendingFieldMutations.map((mutation) => `${mutation.fieldName}:${mutation.kind}:${mutation.status}`),
642
- ...pendingFieldFamilies.map((family) => `${family.fieldName}:family:${family.status}${family.currentStep == null ? "" : `:${family.currentStep}`}`),
643
- ].join(",")}`;
644
- const anchorText = pendingAnchors.length === 0 && (domain.localAnchorIntent === null || domain.localAnchorIntent === "none")
722
+ const pendingFieldsText = pendingFieldMutations.length === 0
645
723
  ? ""
646
- : ` anchor ${(domain.localAnchorIntent === null || domain.localAnchorIntent === "none")
647
- ? pendingAnchors.map((family) => `${family.currentStep ?? "reserved"}:${family.status}`).join(",")
648
- : domain.localAnchorIntent}`;
649
- lines.push(`${domain.name} ${domain.chainStatus} ${domain.localRelationship} owner ${domain.ownerLocalIndex === null ? (domain.ownerAddress ?? domain.ownerScriptPubKeyHex ?? "unknown") : `id:${domain.ownerLocalIndex}`} fields ${formatMaybe(domain.fieldCount)}${domain.readOnly ? " read-only" : ""}${anchorText}${pendingText}${pendingFieldsText}`);
724
+ : ` field-pending ${pendingFieldMutations.map((mutation) => `${mutation.fieldName}:${mutation.kind}:${mutation.status}`).join(",")}`;
725
+ lines.push(`${domain.name} ${domain.chainStatus} ${domain.localRelationship} owner ${domain.ownerAddress ?? domain.ownerScriptPubKeyHex ?? "unknown"} fields ${formatMaybe(domain.fieldCount)}${pendingText}${pendingFieldsText}`);
650
726
  }
651
727
  if (!options.all && options.limit !== null && options.limit !== undefined && visibleDomains.length > options.limit) {
652
728
  lines.push(`Showing first ${renderedDomains.length} of ${visibleDomains.length}. Use --limit <n> or --all for more.`);
@@ -666,7 +742,7 @@ export function formatDomainReport(context, domainName) {
666
742
  }
667
743
  lines.push(`Domain ID: ${formatMaybe(view.domain.domainId)}`);
668
744
  lines.push(`Anchored: ${view.domain.anchored === null ? "unknown" : (view.domain.anchored ? "yes" : "no")}`);
669
- lines.push(`Owner: ${view.domain.ownerLocalIndex === null ? (view.domain.ownerAddress ?? view.domain.ownerScriptPubKeyHex ?? "unknown") : `id:${view.domain.ownerLocalIndex}`}`);
745
+ lines.push(`Owner: ${view.domain.ownerAddress ?? view.domain.ownerScriptPubKeyHex ?? "unknown"}`);
670
746
  lines.push(`Local relationship: ${view.localRelationship}`);
671
747
  lines.push(`Listing price: ${view.domain.listingPriceCogtoshi === null ? "none" : formatCogAmount(view.domain.listingPriceCogtoshi)}`);
672
748
  lines.push(`Field count: ${formatMaybe(view.domain.fieldCount)}`);
@@ -679,17 +755,10 @@ export function formatDomainReport(context, domainName) {
679
755
  lines.push(`Reputation total supported: ${view.domain.totalSupportedCogtoshi === null ? "unavailable" : formatCogAmount(view.domain.totalSupportedCogtoshi)}`);
680
756
  lines.push(`Reputation total revoked: ${view.domain.totalRevokedCogtoshi === null ? "unavailable" : formatCogAmount(view.domain.totalRevokedCogtoshi)}`);
681
757
  }
682
- lines.push(`Local anchor intent: ${view.domain.localAnchorIntent ?? "none"}`);
683
758
  lines.push(`Delegate: ${view.domain.delegateScriptPubKeyHex ?? "none"}`);
684
759
  lines.push(`Designated miner: ${view.domain.minerScriptPubKeyHex ?? "none"}`);
685
760
  lines.push(`Endpoint: ${view.domain.endpointText ?? "none"}`);
686
761
  lines.push(`Founding message: ${view.domain.foundingMessageText ?? "none"}`);
687
- for (const family of listPendingAnchorFamilies(context, domainName)) {
688
- lines.push(`Pending anchor family: ${family.status}${family.currentStep == null ? "" : ` step ${family.currentStep}`}${family.reservedDedicatedIndex == null ? "" : ` index ${family.reservedDedicatedIndex}`}`);
689
- }
690
- for (const family of listPendingFieldFamilies(context, domainName)) {
691
- lines.push(`Pending field family: ${family.fieldName ?? "unknown"} ${family.status}${family.currentStep == null ? "" : ` step ${family.currentStep}`}`);
692
- }
693
762
  for (const mutation of listPendingDomainShowMutations(context, domainName)) {
694
763
  lines.push(`Pending mutation: ${formatPendingMutationDomainLabel(mutation)} ${mutation.status}`);
695
764
  }
@@ -726,9 +795,6 @@ export function formatFieldsReport(context, domainName, options = {}) {
726
795
  for (const mutation of listPendingFieldMutations(context, domainName)) {
727
796
  lines.push(`Pending field mutation: ${mutation.fieldName ?? "unknown"} ${mutation.kind} ${mutation.status}`);
728
797
  }
729
- for (const family of listPendingFieldFamilies(context, domainName)) {
730
- lines.push(`Pending field family: ${family.fieldName ?? "unknown"} ${family.status}${family.currentStep == null ? "" : ` step ${family.currentStep}`}`);
731
- }
732
798
  if (!options.all && options.limit !== null && options.limit !== undefined && fields.length > options.limit) {
733
799
  lines.push(`Showing first ${renderedFields.length} of ${fields.length}. Use --limit <n> or --all for more.`);
734
800
  }
@@ -742,8 +808,6 @@ export function formatFieldReport(context, domainName, fieldName) {
742
808
  }
743
809
  const field = findDomainField(context, domainName, fieldName);
744
810
  const pendingMutations = listPendingFieldMutations(context, domainName, fieldName);
745
- const pendingFamilies = listPendingFieldFamilies(context, domainName)
746
- .filter((family) => family.fieldName === fieldName);
747
811
  if (field === null) {
748
812
  lines.push("Field not found.");
749
813
  }
@@ -759,8 +823,5 @@ export function formatFieldReport(context, domainName, fieldName) {
759
823
  for (const mutation of pendingMutations) {
760
824
  lines.push(`Pending field mutation: ${mutation.kind} ${mutation.status}`);
761
825
  }
762
- for (const family of pendingFamilies) {
763
- lines.push(`Pending field family: ${family.status}${family.currentStep == null ? "" : ` step ${family.currentStep}`}`);
764
- }
765
826
  return lines.join("\n");
766
827
  }
@@ -1,14 +1,14 @@
1
- import type { WalletIdentityView, WalletLockView, WalletReadContext } from "../wallet/read/index.js";
1
+ import type { WalletLockView, WalletReadContext } from "../wallet/read/index.js";
2
2
  export declare function formatNextStepLines(nextSteps: readonly string[]): string[];
3
3
  export declare function getFundingQuickstartGuidance(): string;
4
4
  export declare function getInitNextSteps(): string[];
5
5
  export declare function getRestoreNextSteps(): string[];
6
+ export declare function getSetupUnlockGuidanceLines(unlockSeconds: number): string[];
6
7
  export declare function getBootstrapSyncNextStep(context: Pick<WalletReadContext, "bitcoind" | "indexer" | "nodeHealth">): string | null;
7
8
  export declare function getRegisterNextSteps(domainName: string, registerKind: "root" | "subdomain"): string[];
8
9
  export declare function getAnchorNextSteps(domainName: string): string[];
9
- export declare function getHooksEnableMiningNextSteps(): string[];
10
10
  export declare function getMineSetupNextSteps(): string[];
11
11
  export declare function getMineStopNextSteps(): string[];
12
12
  export declare function getAddressNextSteps(context: Pick<WalletReadContext, "bitcoind" | "indexer" | "nodeHealth">, address: string | null | undefined): string[];
13
- export declare function getIdsNextSteps(identities: readonly WalletIdentityView[] | null | undefined): string[];
13
+ export declare function getIdsNextSteps(walletAddress: string | null | undefined): string[];
14
14
  export declare function getLocksNextSteps(locks: readonly WalletLockView[] | null | undefined): string[];
@@ -13,6 +13,12 @@ export function getInitNextSteps() {
13
13
  export function getRestoreNextSteps() {
14
14
  return ["cogcoin sync", "cogcoin address"];
15
15
  }
16
+ export function getSetupUnlockGuidanceLines(unlockSeconds) {
17
+ return [
18
+ `Client unlock: active for ${unlockSeconds} seconds.`,
19
+ "Use `cogcoin client unlock` to lengthen this unlock window, or `cogcoin client lock` to lock immediately.",
20
+ ];
21
+ }
16
22
  function blocksSyncBootstrap(context) {
17
23
  return context.bitcoind.health === "service-version-mismatch"
18
24
  || context.bitcoind.health === "wallet-root-mismatch"
@@ -50,9 +56,6 @@ export function getAnchorNextSteps(domainName) {
50
56
  }
51
57
  return nextSteps;
52
58
  }
53
- export function getHooksEnableMiningNextSteps() {
54
- return ["cogcoin mine", "cogcoin mine start"];
55
- }
56
59
  export function getMineSetupNextSteps() {
57
60
  return ["cogcoin mine", "cogcoin mine start"];
58
61
  }
@@ -71,13 +74,13 @@ export function getAddressNextSteps(context, address) {
71
74
  nextSteps.push("fund this wallet, then run cogcoin status");
72
75
  return nextSteps;
73
76
  }
74
- export function getIdsNextSteps(identities) {
75
- return identities === null || identities === undefined || identities.length === 0
77
+ export function getIdsNextSteps(walletAddress) {
78
+ return walletAddress === null || walletAddress === undefined || walletAddress.length === 0
76
79
  ? []
77
80
  : [
78
- "cogcoin register <root> --from <selector>",
79
- "cogcoin send ... --from <selector>",
80
- "cogcoin cog lock ... --from <selector>",
81
+ "cogcoin register <root>",
82
+ "cogcoin send ...",
83
+ "cogcoin cog lock ...",
81
84
  ];
82
85
  }
83
86
  export function getLocksNextSteps(locks) {
@@ -1,5 +1,5 @@
1
1
  import type { BitcoinBlock, GenesisParameters, IndexerState } from "@cogcoin/indexer/types";
2
- import type { ApplyBlockResult, Client, ClientStoreAdapter, ClientTip } from "../types.js";
2
+ import type { ApplyBlockResult, Client, ClientCheckpoint, ClientStoreAdapter, ClientTip } from "../types.js";
3
3
  export declare class DefaultClient implements Client {
4
4
  #private;
5
5
  constructor(store: ClientStoreAdapter, genesisParameters: GenesisParameters, state: IndexerState, tip: ClientTip | null, snapshotInterval: number, blockRecordRetention: number);
@@ -7,5 +7,7 @@ export declare class DefaultClient implements Client {
7
7
  getState(): Promise<IndexerState>;
8
8
  applyBlock(block: BitcoinBlock): Promise<ApplyBlockResult>;
9
9
  rewindToHeight(height: number): Promise<ClientTip | null>;
10
+ restoreCheckpoint(checkpoint: ClientCheckpoint): Promise<ClientTip>;
11
+ resetToInitialState(): Promise<null>;
10
12
  close(): Promise<void>;
11
13
  }