@cogcoin/client 0.5.15 → 1.0.1

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 (174) 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 +142 -5
  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 +49 -92
  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 +5 -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/sync-progress.d.ts +6 -0
  75. package/dist/cli/sync-progress.js +91 -0
  76. package/dist/cli/types.d.ts +9 -17
  77. package/dist/cli/types.js +0 -2
  78. package/dist/cli/wallet-format.d.ts +1 -0
  79. package/dist/cli/wallet-format.js +208 -144
  80. package/dist/cli/workflow-hints.d.ts +3 -3
  81. package/dist/cli/workflow-hints.js +11 -8
  82. package/dist/client/default-client.d.ts +3 -1
  83. package/dist/client/default-client.js +45 -2
  84. package/dist/client/factory.js +1 -1
  85. package/dist/client/initialization.js +23 -0
  86. package/dist/client/persistence.js +5 -5
  87. package/dist/client/store-adapter.js +1 -0
  88. package/dist/sqlite/checkpoints.d.ts +1 -0
  89. package/dist/sqlite/checkpoints.js +7 -0
  90. package/dist/sqlite/store.js +14 -1
  91. package/dist/types.d.ts +1 -0
  92. package/dist/wallet/coin-control.d.ts +41 -12
  93. package/dist/wallet/coin-control.js +100 -428
  94. package/dist/wallet/descriptor-normalization.d.ts +1 -3
  95. package/dist/wallet/descriptor-normalization.js +0 -16
  96. package/dist/wallet/lifecycle.d.ts +7 -99
  97. package/dist/wallet/lifecycle.js +513 -968
  98. package/dist/wallet/managed-core-wallet.d.ts +13 -0
  99. package/dist/wallet/managed-core-wallet.js +20 -0
  100. package/dist/wallet/mining/constants.d.ts +5 -12
  101. package/dist/wallet/mining/constants.js +5 -12
  102. package/dist/wallet/mining/control.d.ts +1 -13
  103. package/dist/wallet/mining/control.js +45 -349
  104. package/dist/wallet/mining/index.d.ts +4 -5
  105. package/dist/wallet/mining/index.js +2 -3
  106. package/dist/wallet/mining/runner.d.ts +123 -13
  107. package/dist/wallet/mining/runner.js +899 -511
  108. package/dist/wallet/mining/runtime-artifacts.js +23 -3
  109. package/dist/wallet/mining/sentence-protocol.d.ts +44 -0
  110. package/dist/wallet/mining/sentence-protocol.js +123 -0
  111. package/dist/wallet/mining/sentences.d.ts +4 -8
  112. package/dist/wallet/mining/sentences.js +3 -52
  113. package/dist/wallet/mining/state.d.ts +11 -6
  114. package/dist/wallet/mining/state.js +7 -6
  115. package/dist/wallet/mining/types.d.ts +2 -30
  116. package/dist/wallet/mining/visualizer.d.ts +31 -3
  117. package/dist/wallet/mining/visualizer.js +135 -13
  118. package/dist/wallet/read/context.d.ts +0 -2
  119. package/dist/wallet/read/context.js +119 -140
  120. package/dist/wallet/read/filter.js +2 -11
  121. package/dist/wallet/read/index.d.ts +1 -1
  122. package/dist/wallet/read/project.js +24 -77
  123. package/dist/wallet/read/types.d.ts +10 -25
  124. package/dist/wallet/reset.d.ts +0 -1
  125. package/dist/wallet/reset.js +60 -138
  126. package/dist/wallet/root-resolution.d.ts +1 -5
  127. package/dist/wallet/root-resolution.js +0 -18
  128. package/dist/wallet/runtime.d.ts +0 -6
  129. package/dist/wallet/runtime.js +0 -8
  130. package/dist/wallet/state/client-password-agent.js +208 -0
  131. package/dist/wallet/state/client-password.d.ts +65 -0
  132. package/dist/wallet/state/client-password.js +952 -0
  133. package/dist/wallet/state/crypto.d.ts +1 -20
  134. package/dist/wallet/state/crypto.js +0 -63
  135. package/dist/wallet/state/provider.d.ts +23 -11
  136. package/dist/wallet/state/provider.js +248 -290
  137. package/dist/wallet/state/storage.d.ts +2 -2
  138. package/dist/wallet/state/storage.js +48 -16
  139. package/dist/wallet/tx/anchor.d.ts +3 -28
  140. package/dist/wallet/tx/anchor.js +349 -1250
  141. package/dist/wallet/tx/bitcoin-transfer.d.ts +35 -0
  142. package/dist/wallet/tx/bitcoin-transfer.js +200 -0
  143. package/dist/wallet/tx/cog.d.ts +5 -1
  144. package/dist/wallet/tx/cog.js +149 -185
  145. package/dist/wallet/tx/common.d.ts +61 -8
  146. package/dist/wallet/tx/common.js +266 -146
  147. package/dist/wallet/tx/domain-admin.d.ts +3 -1
  148. package/dist/wallet/tx/domain-admin.js +61 -99
  149. package/dist/wallet/tx/domain-market.d.ts +5 -1
  150. package/dist/wallet/tx/domain-market.js +221 -228
  151. package/dist/wallet/tx/field.d.ts +4 -10
  152. package/dist/wallet/tx/field.js +83 -924
  153. package/dist/wallet/tx/identity-selector.d.ts +9 -3
  154. package/dist/wallet/tx/identity-selector.js +17 -35
  155. package/dist/wallet/tx/index.d.ts +3 -1
  156. package/dist/wallet/tx/index.js +2 -1
  157. package/dist/wallet/tx/register.d.ts +3 -1
  158. package/dist/wallet/tx/register.js +62 -220
  159. package/dist/wallet/tx/reputation.d.ts +3 -1
  160. package/dist/wallet/tx/reputation.js +58 -95
  161. package/dist/wallet/types.d.ts +8 -122
  162. package/package.json +5 -5
  163. package/dist/wallet/archive.d.ts +0 -4
  164. package/dist/wallet/archive.js +0 -41
  165. package/dist/wallet/mining/hook-protocol.d.ts +0 -47
  166. package/dist/wallet/mining/hook-protocol.js +0 -161
  167. package/dist/wallet/mining/hook-runner.js +0 -52
  168. package/dist/wallet/mining/hooks.d.ts +0 -38
  169. package/dist/wallet/mining/hooks.js +0 -520
  170. package/dist/wallet/state/explicit-lock.d.ts +0 -4
  171. package/dist/wallet/state/explicit-lock.js +0 -19
  172. package/dist/wallet/state/session.d.ts +0 -12
  173. package/dist/wallet/state/session.js +0 -23
  174. /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,178 @@ 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
+ if (context.mining?.provider.status === "missing") {
562
+ return ["Run `cogcoin mine setup` to configure your mining provider."];
563
+ }
564
+ return ["Run `cogcoin mine` to start mining with your anchored root domain."];
565
+ }
566
+ return [];
567
+ }
568
+ if (unanchoredDomains.length > 0) {
569
+ return [`Run \`cogcoin anchor ${unanchoredDomains[0].name}\` to anchor your unanchored domain.`];
570
+ }
571
+ if (context.fundingSpendableSats !== null && context.fundingSpendableSats > BALANCE_BUY_ROOT_THRESHOLD_SATS) {
572
+ return ["Buy a 6+ character root domain with `cogcoin register <root>`."];
573
+ }
574
+ return [];
575
+ }
576
+ function listPendingBalanceLines(context) {
577
+ const lines = [];
578
+ for (const mutation of (context.localState.state?.pendingMutations ?? [])
579
+ .filter((entry) => (entry.kind === "send" || entry.kind === "lock" || entry.kind === "claim")
580
+ && entry.status !== "confirmed"
581
+ && entry.status !== "canceled")) {
582
+ const label = mutation.kind === "claim" && mutation.preimageHex === "0000000000000000000000000000000000000000000000000000000000000000"
583
+ ? "reclaim"
584
+ : mutation.kind;
585
+ lines.push(`Pending: ${label} ${mutation.status}${mutation.amountCogtoshi === null || mutation.amountCogtoshi === undefined ? "" : ` ${formatCogAmount(mutation.amountCogtoshi)}`}`);
586
+ }
587
+ return lines;
588
+ }
589
+ function formatReadyBalanceReport(context) {
590
+ const anchoredDomains = listBalanceDomainsByStatus(context.model, "anchored");
591
+ const unanchoredDomains = listBalanceDomainsByStatus(context.model, "registered-unanchored");
592
+ const nextStepLines = formatNextStepLines(getBalanceNextSteps(context));
593
+ const lines = [
594
+ "",
595
+ ...renderBalanceArtCard(context),
596
+ "",
597
+ ...formatBalanceDomainSection("Anchored Domains", "⌂", anchoredDomains, "--- No anchored domains ---"),
598
+ "",
599
+ ...formatBalanceDomainSection("Unanchored Domains", "~", unanchoredDomains, "--- No unanchored domains ---"),
600
+ ];
601
+ if (shouldShowBalanceQuickstart(context)) {
602
+ lines.push("");
603
+ lines.push(`Quickstart: ${getFundingQuickstartGuidance()}`);
604
+ }
605
+ if (nextStepLines.length > 0) {
606
+ lines.push("");
607
+ lines.push(...nextStepLines);
608
+ }
609
+ const pendingLines = listPendingBalanceLines(context);
610
+ if (pendingLines.length > 0) {
611
+ lines.push("");
612
+ lines.push(...pendingLines);
613
+ }
502
614
  return lines.join("\n");
503
615
  }
504
616
  export function formatIdentityListReport(context, options = {}) {
505
- const lines = ["Wallet Identities"];
617
+ const lines = ["Wallet Address"];
506
618
  if (context.model === null) {
507
619
  appendWalletAvailability(lines, context);
508
620
  return lines.join("\n");
509
621
  }
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
- }
622
+ const domains = context.model.domains
623
+ .filter((domain) => domain.localRelationship === "local")
624
+ .map((domain) => domain.name)
625
+ .sort();
626
+ const balance = context.snapshot === null
627
+ ? null
628
+ : getBalance(context.snapshot.state, new Uint8Array(Buffer.from(context.model.walletScriptPubKeyHex, "hex")));
629
+ lines.push(`${context.model.walletAddress ?? `spk:${context.model.walletScriptPubKeyHex}`} balance ${balance === null ? "unavailable" : formatCogAmount(balance)} domains ${domains.length === 0 ? "none" : domains.join(", ")}`);
525
630
  return lines.join("\n");
526
631
  }
527
632
  export function formatBalanceReport(context) {
@@ -534,23 +639,7 @@ export function formatBalanceReport(context) {
534
639
  lines.push(`Indexer-backed balances are unavailable while the indexer is ${formatServiceHealth(context.indexer.health)}.`);
535
640
  return lines.join("\n");
536
641
  }
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");
642
+ return formatReadyBalanceReport(context);
554
643
  }
555
644
  export function formatLocksReport(context, options = {}) {
556
645
  const lines = ["COG Locks"];
@@ -621,8 +710,6 @@ export function formatDomainsReport(context, options = {}) {
621
710
  : visibleDomains.slice(0, options.limit);
622
711
  for (const domain of renderedDomains) {
623
712
  const pending = listPendingDomainMutations(context, domain.name);
624
- const pendingAnchors = listPendingAnchorFamilies(context, domain.name);
625
- const pendingFieldFamilies = listPendingFieldFamilies(context, domain.name);
626
713
  const pendingFieldMutations = listPendingFieldMutations(context, domain.name);
627
714
  const pendingText = pending.length === 0
628
715
  ? ""
@@ -635,18 +722,10 @@ export function formatDomainsReport(context, options = {}) {
635
722
  : mutation.kind === "miner" && mutation.recipientScriptPubKeyHex === null
636
723
  ? `miner-clear:${mutation.status}`
637
724
  : `${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")
725
+ const pendingFieldsText = pendingFieldMutations.length === 0
645
726
  ? ""
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}`);
727
+ : ` field-pending ${pendingFieldMutations.map((mutation) => `${mutation.fieldName}:${mutation.kind}:${mutation.status}`).join(",")}`;
728
+ lines.push(`${domain.name} ${domain.chainStatus} ${domain.localRelationship} owner ${domain.ownerAddress ?? domain.ownerScriptPubKeyHex ?? "unknown"} fields ${formatMaybe(domain.fieldCount)}${pendingText}${pendingFieldsText}`);
650
729
  }
651
730
  if (!options.all && options.limit !== null && options.limit !== undefined && visibleDomains.length > options.limit) {
652
731
  lines.push(`Showing first ${renderedDomains.length} of ${visibleDomains.length}. Use --limit <n> or --all for more.`);
@@ -666,7 +745,7 @@ export function formatDomainReport(context, domainName) {
666
745
  }
667
746
  lines.push(`Domain ID: ${formatMaybe(view.domain.domainId)}`);
668
747
  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}`}`);
748
+ lines.push(`Owner: ${view.domain.ownerAddress ?? view.domain.ownerScriptPubKeyHex ?? "unknown"}`);
670
749
  lines.push(`Local relationship: ${view.localRelationship}`);
671
750
  lines.push(`Listing price: ${view.domain.listingPriceCogtoshi === null ? "none" : formatCogAmount(view.domain.listingPriceCogtoshi)}`);
672
751
  lines.push(`Field count: ${formatMaybe(view.domain.fieldCount)}`);
@@ -679,17 +758,10 @@ export function formatDomainReport(context, domainName) {
679
758
  lines.push(`Reputation total supported: ${view.domain.totalSupportedCogtoshi === null ? "unavailable" : formatCogAmount(view.domain.totalSupportedCogtoshi)}`);
680
759
  lines.push(`Reputation total revoked: ${view.domain.totalRevokedCogtoshi === null ? "unavailable" : formatCogAmount(view.domain.totalRevokedCogtoshi)}`);
681
760
  }
682
- lines.push(`Local anchor intent: ${view.domain.localAnchorIntent ?? "none"}`);
683
761
  lines.push(`Delegate: ${view.domain.delegateScriptPubKeyHex ?? "none"}`);
684
762
  lines.push(`Designated miner: ${view.domain.minerScriptPubKeyHex ?? "none"}`);
685
763
  lines.push(`Endpoint: ${view.domain.endpointText ?? "none"}`);
686
764
  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
765
  for (const mutation of listPendingDomainShowMutations(context, domainName)) {
694
766
  lines.push(`Pending mutation: ${formatPendingMutationDomainLabel(mutation)} ${mutation.status}`);
695
767
  }
@@ -726,9 +798,6 @@ export function formatFieldsReport(context, domainName, options = {}) {
726
798
  for (const mutation of listPendingFieldMutations(context, domainName)) {
727
799
  lines.push(`Pending field mutation: ${mutation.fieldName ?? "unknown"} ${mutation.kind} ${mutation.status}`);
728
800
  }
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
801
  if (!options.all && options.limit !== null && options.limit !== undefined && fields.length > options.limit) {
733
802
  lines.push(`Showing first ${renderedFields.length} of ${fields.length}. Use --limit <n> or --all for more.`);
734
803
  }
@@ -742,8 +811,6 @@ export function formatFieldReport(context, domainName, fieldName) {
742
811
  }
743
812
  const field = findDomainField(context, domainName, fieldName);
744
813
  const pendingMutations = listPendingFieldMutations(context, domainName, fieldName);
745
- const pendingFamilies = listPendingFieldFamilies(context, domainName)
746
- .filter((family) => family.fieldName === fieldName);
747
814
  if (field === null) {
748
815
  lines.push("Field not found.");
749
816
  }
@@ -759,8 +826,5 @@ export function formatFieldReport(context, domainName, fieldName) {
759
826
  for (const mutation of pendingMutations) {
760
827
  lines.push(`Pending field mutation: ${mutation.kind} ${mutation.status}`);
761
828
  }
762
- for (const family of pendingFamilies) {
763
- lines.push(`Pending field family: ${family.status}${family.currentStep == null ? "" : ` step ${family.currentStep}`}`);
764
- }
765
829
  return lines.join("\n");
766
830
  }
@@ -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
  }