@cogcoin/client 1.0.1 → 1.0.2

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 (50) hide show
  1. package/README.md +2 -1
  2. package/dist/bitcoind/indexer-daemon.d.ts +3 -0
  3. package/dist/bitcoind/indexer-daemon.js +58 -8
  4. package/dist/bitcoind/retryable-rpc.js +3 -0
  5. package/dist/bitcoind/service.d.ts +1 -0
  6. package/dist/bitcoind/service.js +31 -9
  7. package/dist/cli/commands/mining-admin.js +9 -0
  8. package/dist/cli/commands/update.d.ts +2 -0
  9. package/dist/cli/commands/update.js +101 -0
  10. package/dist/cli/context.js +31 -0
  11. package/dist/cli/mining-format.js +28 -0
  12. package/dist/cli/mining-json.js +6 -0
  13. package/dist/cli/output.js +50 -2
  14. package/dist/cli/parse.d.ts +1 -1
  15. package/dist/cli/parse.js +5 -0
  16. package/dist/cli/prompt.js +109 -0
  17. package/dist/cli/read-json.d.ts +13 -0
  18. package/dist/cli/read-json.js +17 -0
  19. package/dist/cli/runner.js +4 -0
  20. package/dist/cli/types.d.ts +6 -1
  21. package/dist/cli/update-notifier.js +7 -222
  22. package/dist/cli/update-service.d.ts +44 -0
  23. package/dist/cli/update-service.js +218 -0
  24. package/dist/client/initialization.js +5 -0
  25. package/dist/wallet/lifecycle.d.ts +10 -0
  26. package/dist/wallet/lifecycle.js +6 -0
  27. package/dist/wallet/mining/config.js +13 -3
  28. package/dist/wallet/mining/control.d.ts +2 -1
  29. package/dist/wallet/mining/control.js +143 -19
  30. package/dist/wallet/mining/index.d.ts +1 -1
  31. package/dist/wallet/mining/provider-model.d.ts +30 -0
  32. package/dist/wallet/mining/provider-model.js +134 -0
  33. package/dist/wallet/mining/runner.d.ts +98 -3
  34. package/dist/wallet/mining/runner.js +493 -95
  35. package/dist/wallet/mining/runtime-artifacts.js +1 -0
  36. package/dist/wallet/mining/sentences.d.ts +2 -2
  37. package/dist/wallet/mining/sentences.js +25 -2
  38. package/dist/wallet/mining/types.d.ts +9 -1
  39. package/dist/wallet/mining/visualizer.js +28 -5
  40. package/dist/wallet/read/context.js +3 -0
  41. package/dist/wallet/reset.js +1 -0
  42. package/dist/wallet/tx/anchor.js +1 -0
  43. package/dist/wallet/tx/bitcoin-transfer.js +1 -0
  44. package/dist/wallet/tx/cog.js +3 -0
  45. package/dist/wallet/tx/domain-admin.js +1 -0
  46. package/dist/wallet/tx/domain-market.js +3 -0
  47. package/dist/wallet/tx/field.js +1 -0
  48. package/dist/wallet/tx/register.js +1 -0
  49. package/dist/wallet/tx/reputation.js +1 -0
  50. package/package.json +3 -2
@@ -18,6 +18,7 @@ function normalizeLegacyMiningProviderState(raw) {
18
18
  case "unavailable":
19
19
  case "rate-limited":
20
20
  case "auth-error":
21
+ case "not-found":
21
22
  return raw;
22
23
  case "hook-error":
23
24
  case "n/a":
@@ -10,8 +10,8 @@ export interface MiningSentenceSourceOptions {
10
10
  fetchImpl?: typeof fetch;
11
11
  }
12
12
  declare class MiningProviderRequestError extends Error {
13
- readonly providerState: "unavailable" | "rate-limited" | "auth-error";
14
- constructor(providerState: "unavailable" | "rate-limited" | "auth-error", message: string);
13
+ readonly providerState: "unavailable" | "rate-limited" | "auth-error" | "not-found";
14
+ constructor(providerState: "unavailable" | "rate-limited" | "auth-error" | "not-found", message: string);
15
15
  }
16
16
  export declare function generateMiningSentences(request: MiningSentenceGenerationRequest, options: MiningSentenceSourceOptions): Promise<{
17
17
  candidates: MiningSentenceCandidateV1[];
@@ -1,6 +1,7 @@
1
1
  import { loadClientConfig } from "./config.js";
2
2
  import { MINING_BUILTIN_TIMEOUT_MS, } from "./constants.js";
3
3
  import { normalizeMiningSentenceResponse, parseStrictJsonValue, stripMarkdownCodeFence, } from "./sentence-protocol.js";
4
+ import { resolveBuiltInProviderModel } from "./provider-model.js";
4
5
  class MiningProviderRequestError extends Error {
5
6
  providerState;
6
7
  constructor(providerState, message) {
@@ -9,6 +10,14 @@ class MiningProviderRequestError extends Error {
9
10
  this.providerState = providerState;
10
11
  }
11
12
  }
13
+ function createBuiltInProviderNotFoundError(options) {
14
+ const providerName = options.provider === "anthropic" ? "Anthropic" : "OpenAI";
15
+ const providerLabel = `The built-in ${providerName} mining provider`;
16
+ const message = options.usingDefaultModel
17
+ ? `${providerLabel} returned HTTP 404 for default model "${options.model}". ${providerName} may no longer serve that model. Rerun \`cogcoin mine setup\` to choose a valid override.`
18
+ : `${providerLabel} returned HTTP 404 for model "${options.model}". The configured model override may be invalid. Rerun \`cogcoin mine setup\` to clear or correct it.`;
19
+ return new MiningProviderRequestError("not-found", message);
20
+ }
12
21
  function buildSystemPrompt(extraPrompt) {
13
22
  const lines = [
14
23
  "You are helping generate candidate Cogcoin mining sentences.",
@@ -65,7 +74,7 @@ async function requestBuiltInSentences(options) {
65
74
  const providerSignal = createProviderSignal(options.signal, Math.min(MINING_BUILTIN_TIMEOUT_MS, options.request.limits.timeoutMs));
66
75
  try {
67
76
  if (options.provider === "openai") {
68
- const model = options.modelOverride ?? "gpt-5.4-mini";
77
+ const { effectiveModel: model, usingDefaultModel } = resolveBuiltInProviderModel(options.provider, options.modelOverride);
69
78
  const response = await fetchImpl("https://api.openai.com/v1/responses", {
70
79
  method: "POST",
71
80
  headers: {
@@ -93,6 +102,13 @@ async function requestBuiltInSentences(options) {
93
102
  if (response.status === 429) {
94
103
  throw new MiningProviderRequestError("rate-limited", "The built-in OpenAI mining provider is rate limited.");
95
104
  }
105
+ if (response.status === 404) {
106
+ throw createBuiltInProviderNotFoundError({
107
+ provider: options.provider,
108
+ model,
109
+ usingDefaultModel,
110
+ });
111
+ }
96
112
  if (!response.ok) {
97
113
  throw new MiningProviderRequestError("unavailable", `The built-in OpenAI mining provider returned HTTP ${response.status}.`);
98
114
  }
@@ -106,7 +122,7 @@ async function requestBuiltInSentences(options) {
106
122
  model,
107
123
  });
108
124
  }
109
- const model = options.modelOverride ?? "claude-sonnet-4-20250514";
125
+ const { effectiveModel: model, usingDefaultModel } = resolveBuiltInProviderModel(options.provider, options.modelOverride);
110
126
  const response = await fetchImpl("https://api.anthropic.com/v1/messages", {
111
127
  method: "POST",
112
128
  headers: {
@@ -133,6 +149,13 @@ async function requestBuiltInSentences(options) {
133
149
  if (response.status === 429) {
134
150
  throw new MiningProviderRequestError("rate-limited", "The built-in Anthropic mining provider is rate limited.");
135
151
  }
152
+ if (response.status === 404) {
153
+ throw createBuiltInProviderNotFoundError({
154
+ provider: options.provider,
155
+ model,
156
+ usingDefaultModel,
157
+ });
158
+ }
136
159
  if (!response.ok) {
137
160
  throw new MiningProviderRequestError("unavailable", `The built-in Anthropic mining provider returned HTTP ${response.status}.`);
138
161
  }
@@ -1,11 +1,13 @@
1
1
  import type { ManagedBitcoindHealth, ManagedIndexerTruthSource } from "../../bitcoind/types.js";
2
2
  export type MiningServiceHealth = "synced" | "catching-up" | "reorging" | "starting" | "stale-heartbeat" | "failed" | "schema-mismatch" | "service-version-mismatch" | "wallet-root-mismatch" | "unavailable";
3
3
  export type MiningProviderKind = "openai" | "anthropic";
4
+ export type MiningModelSelectionSource = "catalog" | "custom" | "legacy-default" | "legacy-custom";
4
5
  export interface MiningProviderConfigRecord {
5
6
  provider: MiningProviderKind;
6
7
  apiKey: string;
7
8
  extraPrompt: string | null;
8
9
  modelOverride: string | null;
10
+ modelSelectionSource: MiningModelSelectionSource;
9
11
  updatedAtUnixMs: number;
10
12
  }
11
13
  export interface ClientConfigV1 {
@@ -56,7 +58,7 @@ export interface MiningRuntimeStatusV1 {
56
58
  indexerReorgDepth: number | null;
57
59
  indexerTipAligned: boolean | null;
58
60
  corePublishState: "unknown" | "network-inactive" | "no-outbound-peers" | "ibd" | "mempool-loading" | "healthy" | null;
59
- providerState: "ready" | "backoff" | "unavailable" | "rate-limited" | "auth-error" | null;
61
+ providerState: "ready" | "backoff" | "unavailable" | "rate-limited" | "auth-error" | "not-found" | null;
60
62
  lastSuspendDetectedAtUnixMs: number | null;
61
63
  reconnectSettledUntilUnixMs: number | null;
62
64
  tipSettledUntilUnixMs: number | null;
@@ -103,8 +105,14 @@ export interface MiningProviderInspection {
103
105
  provider: MiningProviderKind | null;
104
106
  status: "ready" | "missing" | "error";
105
107
  message: string | null;
108
+ modelId: string | null;
109
+ effectiveModel: string | null;
106
110
  modelOverride: string | null;
111
+ modelSelectionSource: MiningModelSelectionSource | null;
112
+ usingDefaultModel: boolean | null;
107
113
  extraPromptConfigured: boolean;
114
+ estimatedDailyCostUsd: number | null;
115
+ estimatedDailyCostDisplay: string | null;
108
116
  }
109
117
  export interface MiningControlPlaneView {
110
118
  runtime: MiningRuntimeStatusV1;
@@ -82,6 +82,29 @@ export function createEmptyMiningFollowVisualizerState() {
82
82
  recentWin: null,
83
83
  };
84
84
  }
85
+ function cloneMiningRuntimeSnapshot(snapshot) {
86
+ return {
87
+ ...snapshot,
88
+ };
89
+ }
90
+ function cloneMiningFollowVisualizerState(state) {
91
+ return {
92
+ ...state,
93
+ visibleBlockTimesByHeight: { ...state.visibleBlockTimesByHeight },
94
+ settledBoardEntries: state.settledBoardEntries.map((entry) => ({
95
+ ...entry,
96
+ })),
97
+ provisionalRequiredWords: [...state.provisionalRequiredWords],
98
+ provisionalEntry: {
99
+ ...state.provisionalEntry,
100
+ },
101
+ recentWin: state.recentWin === null
102
+ ? null
103
+ : {
104
+ ...state.recentWin,
105
+ },
106
+ };
107
+ }
85
108
  const VISUALIZER_PROGRESS_SNAPSHOT = {
86
109
  url: "",
87
110
  filename: "mining-follow-visualizer",
@@ -208,13 +231,13 @@ export class MiningFollowVisualizer {
208
231
  if (this.#renderer === null) {
209
232
  return;
210
233
  }
211
- this.#latestSnapshot = snapshot;
234
+ this.#latestSnapshot = cloneMiningRuntimeSnapshot(snapshot);
212
235
  if (uiState !== undefined) {
213
- this.#latestUiState = uiState;
236
+ this.#latestUiState = cloneMiningFollowVisualizerState(uiState);
214
237
  }
215
238
  replaceFollowBlockTimes(this.#scene, this.#latestUiState.visibleBlockTimesByHeight);
216
- const indexedHeight = snapshot.indexerTipHeight ?? snapshot.coreBestHeight ?? null;
217
- const nodeHeight = snapshot.coreBestHeight ?? indexedHeight;
239
+ const indexedHeight = this.#latestSnapshot.indexerTipHeight ?? this.#latestSnapshot.coreBestHeight ?? null;
240
+ const nodeHeight = this.#latestSnapshot.coreBestHeight ?? indexedHeight;
218
241
  syncFollowSceneState(this.#scene, {
219
242
  indexedHeight,
220
243
  nodeHeight,
@@ -256,7 +279,7 @@ export class MiningFollowVisualizer {
256
279
  artworkCogText: formatCompactCogBalanceText(uiState.balanceCogtoshi),
257
280
  artworkSatText: formatCompactSatBalanceText(uiState.balanceSats),
258
281
  extraLines: [
259
- `✎ Block #${uiState.settledBlockHeight ?? "-----"} Sentences ✎`,
282
+ `✎ Indexed Block #${uiState.settledBlockHeight ?? "-----"} Sentences ✎`,
260
283
  "",
261
284
  ...Array.from({ length: MINING_SENTENCE_BOARD_SIZE }, (_value, index) => {
262
285
  const entry = uiState.settledBoardEntries[index];
@@ -76,6 +76,7 @@ async function normalizeLoadedWalletStateForRead(options) {
76
76
  dataDir: options.dataDir,
77
77
  chain: "main",
78
78
  startHeight: 0,
79
+ serviceLifetime: "ephemeral",
79
80
  walletRootId: options.loaded.state.walletRootId,
80
81
  });
81
82
  try {
@@ -435,6 +436,7 @@ async function attachNodeStatus(options) {
435
436
  dataDir: options.dataDir,
436
437
  chain: "main",
437
438
  startHeight: resolveCogcoinProcessingStartHeight(genesis),
439
+ serviceLifetime: "ephemeral",
438
440
  walletRootId: options.walletRootId,
439
441
  startupTimeoutMs: options.startupTimeoutMs,
440
442
  });
@@ -541,6 +543,7 @@ export async function openWalletReadContext(options) {
541
543
  daemonClient = await attachOrStartIndexerDaemon({
542
544
  dataDir: options.dataDir,
543
545
  databasePath: options.databasePath,
546
+ serviceLifetime: "ephemeral",
544
547
  walletRootId,
545
548
  startupTimeoutMs,
546
549
  });
@@ -232,6 +232,7 @@ async function recreateManagedCoreWalletReplicaForReset(options) {
232
232
  dataDir: options.dataDir,
233
233
  chain: "main",
234
234
  startHeight: 0,
235
+ serviceLifetime: "ephemeral",
235
236
  walletRootId: options.state.walletRootId,
236
237
  managedWalletPassphrase: options.state.managedCoreWallet.internalPassphrase,
237
238
  });
@@ -394,6 +394,7 @@ export async function anchorDomain(options) {
394
394
  dataDir: options.dataDir,
395
395
  chain: "main",
396
396
  startHeight: 0,
397
+ serviceLifetime: "ephemeral",
397
398
  walletRootId: state.walletRootId,
398
399
  });
399
400
  const rpc = (options.rpcFactory ?? createRpcClient)(node.rpc);
@@ -131,6 +131,7 @@ export async function transferBitcoin(options) {
131
131
  dataDir: options.dataDir,
132
132
  chain: "main",
133
133
  startHeight: 0,
134
+ serviceLifetime: "ephemeral",
134
135
  walletRootId: state.walletRootId,
135
136
  });
136
137
  const rpc = (options.rpcFactory ?? createRpcClient)(node.rpc);
@@ -534,6 +534,7 @@ export async function sendCog(options) {
534
534
  dataDir: options.dataDir,
535
535
  chain: "main",
536
536
  startHeight: 0,
537
+ serviceLifetime: "ephemeral",
537
538
  walletRootId: operation.state.walletRootId,
538
539
  });
539
540
  const rpc = (options.rpcFactory ?? createRpcClient)(node.rpc);
@@ -716,6 +717,7 @@ export async function lockCogToDomain(options) {
716
717
  dataDir: options.dataDir,
717
718
  chain: "main",
718
719
  startHeight: 0,
720
+ serviceLifetime: "ephemeral",
719
721
  walletRootId: operation.state.walletRootId,
720
722
  });
721
723
  const rpc = (options.rpcFactory ?? createRpcClient)(node.rpc);
@@ -875,6 +877,7 @@ async function runClaimLikeMutation(options, reclaim) {
875
877
  dataDir: options.dataDir,
876
878
  chain: "main",
877
879
  startHeight: 0,
880
+ serviceLifetime: "ephemeral",
878
881
  walletRootId: operation.state.walletRootId,
879
882
  });
880
883
  const rpc = (options.rpcFactory ?? createRpcClient)(node.rpc);
@@ -518,6 +518,7 @@ async function submitDomainAdminMutation(options) {
518
518
  dataDir: options.dataDir,
519
519
  chain: "main",
520
520
  startHeight: 0,
521
+ serviceLifetime: "ephemeral",
521
522
  walletRootId: operation.state.walletRootId,
522
523
  });
523
524
  const rpc = (options.rpcFactory ?? createRpcClient)(node.rpc);
@@ -609,6 +609,7 @@ export async function transferDomain(options) {
609
609
  dataDir: options.dataDir,
610
610
  chain: "main",
611
611
  startHeight: 0,
612
+ serviceLifetime: "ephemeral",
612
613
  walletRootId: operation.state.walletRootId,
613
614
  });
614
615
  const rpc = (options.rpcFactory ?? createRpcClient)(node.rpc);
@@ -867,6 +868,7 @@ async function runSellMutation(options) {
867
868
  dataDir: options.dataDir,
868
869
  chain: "main",
869
870
  startHeight: 0,
871
+ serviceLifetime: "ephemeral",
870
872
  walletRootId: operation.state.walletRootId,
871
873
  });
872
874
  const rpc = (options.rpcFactory ?? createRpcClient)(node.rpc);
@@ -1136,6 +1138,7 @@ export async function buyDomain(options) {
1136
1138
  dataDir: options.dataDir,
1137
1139
  chain: "main",
1138
1140
  startHeight: 0,
1141
+ serviceLifetime: "ephemeral",
1139
1142
  walletRootId: operation.state.walletRootId,
1140
1143
  });
1141
1144
  const rpc = (options.rpcFactory ?? createRpcClient)(node.rpc);
@@ -686,6 +686,7 @@ async function submitStandaloneFieldMutation(options) {
686
686
  dataDir: options.dataDir,
687
687
  chain: "main",
688
688
  startHeight: 0,
689
+ serviceLifetime: "ephemeral",
689
690
  walletRootId: operation.state.walletRootId,
690
691
  });
691
692
  const rpc = (options.rpcFactory ?? createRpcClient)(node.rpc);
@@ -532,6 +532,7 @@ export async function registerDomain(options) {
532
532
  dataDir: options.dataDir,
533
533
  chain: "main",
534
534
  startHeight: 0,
535
+ serviceLifetime: "ephemeral",
535
536
  walletRootId: state.walletRootId,
536
537
  });
537
538
  const rpc = (options.rpcFactory ?? createRpcClient)(node.rpc);
@@ -513,6 +513,7 @@ async function submitReputationMutation(options) {
513
513
  dataDir: options.dataDir,
514
514
  chain: "main",
515
515
  startHeight: 0,
516
+ serviceLifetime: "ephemeral",
516
517
  walletRootId: operation.state.walletRootId,
517
518
  });
518
519
  const rpc = (options.rpcFactory ?? createRpcClient)(node.rpc);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cogcoin/client",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "Store-backed Cogcoin client with wallet flows, SQLite persistence, and managed Bitcoin Core integration.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -59,7 +59,8 @@
59
59
  "build": "rm -rf dist && node ./node_modules/typescript/bin/tsc -p tsconfig.json && node ./scripts/copy-static-assets.mjs build",
60
60
  "generate:default-snapshot-chunk-manifest": "node scripts/generate-default-snapshot-chunk-manifest.mjs",
61
61
  "verify:default-snapshot-chunk-manifest": "node scripts/generate-default-snapshot-chunk-manifest.mjs --check",
62
- "test": "rm -rf .test-dist && node ./node_modules/typescript/bin/tsc -p tsconfig.test.json && node ./scripts/copy-static-assets.mjs test && node --test .test-dist/test/*.test.js"
62
+ "test": "rm -rf .test-dist && node ./node_modules/typescript/bin/tsc -p tsconfig.test.json && node ./scripts/copy-static-assets.mjs test && node --test .test-dist/test/*.test.js",
63
+ "test:mining": "rm -rf .test-dist && node ./node_modules/typescript/bin/tsc -p tsconfig.test-mining.json && node ./scripts/copy-static-assets.mjs test && node --test .test-dist/test/mining*.test.js"
63
64
  },
64
65
  "dependencies": {
65
66
  "@cogcoin/bitcoin": "30.2.0",