@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
@@ -0,0 +1,30 @@
1
+ import type { MiningModelSelectionSource, MiningProviderConfigRecord, MiningProviderKind } from "./types.js";
2
+ export interface BuiltInProviderModelCatalogEntry {
3
+ label: string;
4
+ modelId: string;
5
+ inputUsdPerMillionTokens: number;
6
+ outputUsdPerMillionTokens: number;
7
+ }
8
+ export interface BuiltInProviderSelection {
9
+ modelId: string;
10
+ effectiveModel: string;
11
+ modelSelectionSource: MiningModelSelectionSource;
12
+ usingDefaultModel: boolean;
13
+ }
14
+ export interface BuiltInModelDailyCostEstimate {
15
+ estimatedDailyCostUsd: number;
16
+ estimatedDailyCostDisplay: string;
17
+ }
18
+ export declare const MINING_MODEL_DAILY_COST_ESTIMATE_ASSUMPTION = "Approximate daily cost assumes 144 sentence-generation calls/day using your current anchored root count, standard token pricing, no caching, and no extra prompt.";
19
+ export declare function getLegacyBuiltInProviderDefaultModel(provider: MiningProviderKind): string;
20
+ export declare function getRecommendedBuiltInProviderModel(provider: MiningProviderKind): string;
21
+ export declare function getBuiltInProviderModelCatalog(provider: MiningProviderKind): readonly BuiltInProviderModelCatalogEntry[];
22
+ export declare function findBuiltInProviderModelCatalogEntry(provider: MiningProviderKind, modelId: string): BuiltInProviderModelCatalogEntry | null;
23
+ export declare function normalizeMiningModelSelectionSource(raw: unknown, modelOverride: string | null): MiningModelSelectionSource;
24
+ export declare function normalizeMiningProviderConfigRecord(config: MiningProviderConfigRecord): MiningProviderConfigRecord;
25
+ export declare function resolveBuiltInProviderModel(provider: MiningProviderKind, modelOverride: string | null): {
26
+ effectiveModel: string;
27
+ usingDefaultModel: boolean;
28
+ };
29
+ export declare function resolveBuiltInProviderSelection(config: Pick<MiningProviderConfigRecord, "provider" | "modelOverride" | "modelSelectionSource">): BuiltInProviderSelection;
30
+ export declare function estimateBuiltInModelDailyCost(provider: MiningProviderKind, modelId: string, eligibleRootCount: number): BuiltInModelDailyCostEstimate | null;
@@ -0,0 +1,134 @@
1
+ const DEFAULT_BUILT_IN_PROVIDER_MODELS = {
2
+ openai: "gpt-5.4-mini",
3
+ anthropic: "claude-sonnet-4-20250514",
4
+ };
5
+ const RECOMMENDED_BUILT_IN_PROVIDER_MODELS = {
6
+ openai: "gpt-5.4-mini",
7
+ anthropic: "claude-sonnet-4-6",
8
+ };
9
+ const BUILT_IN_PROVIDER_MODEL_CATALOG = {
10
+ openai: [
11
+ {
12
+ label: "GPT-5.4",
13
+ modelId: "gpt-5.4",
14
+ inputUsdPerMillionTokens: 2.5,
15
+ outputUsdPerMillionTokens: 15,
16
+ },
17
+ {
18
+ label: "GPT-5.4 mini",
19
+ modelId: "gpt-5.4-mini",
20
+ inputUsdPerMillionTokens: 0.75,
21
+ outputUsdPerMillionTokens: 4.5,
22
+ },
23
+ {
24
+ label: "GPT-5.4 nano",
25
+ modelId: "gpt-5.4-nano",
26
+ inputUsdPerMillionTokens: 0.2,
27
+ outputUsdPerMillionTokens: 1.25,
28
+ },
29
+ ],
30
+ anthropic: [
31
+ {
32
+ label: "Claude Opus 4.7",
33
+ modelId: "claude-opus-4-7",
34
+ inputUsdPerMillionTokens: 5,
35
+ outputUsdPerMillionTokens: 25,
36
+ },
37
+ {
38
+ label: "Claude Sonnet 4.6",
39
+ modelId: "claude-sonnet-4-6",
40
+ inputUsdPerMillionTokens: 3,
41
+ outputUsdPerMillionTokens: 15,
42
+ },
43
+ {
44
+ label: "Claude Haiku 4.5",
45
+ modelId: "claude-haiku-4-5",
46
+ inputUsdPerMillionTokens: 1,
47
+ outputUsdPerMillionTokens: 5,
48
+ },
49
+ ],
50
+ };
51
+ const DAILY_COST_ESTIMATE_CALLS_PER_DAY = 144;
52
+ const DAILY_COST_ESTIMATE_BASE_INPUT_TOKENS = 340;
53
+ const DAILY_COST_ESTIMATE_PER_ROOT_INPUT_TOKENS = 85;
54
+ const DAILY_COST_ESTIMATE_BASE_OUTPUT_TOKENS = 120;
55
+ const DAILY_COST_ESTIMATE_PER_ROOT_OUTPUT_TOKENS = 105;
56
+ export const MINING_MODEL_DAILY_COST_ESTIMATE_ASSUMPTION = "Approximate daily cost assumes 144 sentence-generation calls/day using your current anchored root count, standard token pricing, no caching, and no extra prompt.";
57
+ function normalizeModelOverride(raw) {
58
+ if (typeof raw !== "string") {
59
+ return null;
60
+ }
61
+ const trimmed = raw.trim();
62
+ return trimmed.length === 0 ? null : trimmed;
63
+ }
64
+ export function getLegacyBuiltInProviderDefaultModel(provider) {
65
+ return DEFAULT_BUILT_IN_PROVIDER_MODELS[provider];
66
+ }
67
+ export function getRecommendedBuiltInProviderModel(provider) {
68
+ return RECOMMENDED_BUILT_IN_PROVIDER_MODELS[provider];
69
+ }
70
+ export function getBuiltInProviderModelCatalog(provider) {
71
+ return BUILT_IN_PROVIDER_MODEL_CATALOG[provider];
72
+ }
73
+ export function findBuiltInProviderModelCatalogEntry(provider, modelId) {
74
+ return BUILT_IN_PROVIDER_MODEL_CATALOG[provider].find((entry) => entry.modelId === modelId) ?? null;
75
+ }
76
+ export function normalizeMiningModelSelectionSource(raw, modelOverride) {
77
+ switch (raw) {
78
+ case "catalog":
79
+ case "custom":
80
+ case "legacy-default":
81
+ case "legacy-custom":
82
+ return raw;
83
+ default:
84
+ return modelOverride === null ? "legacy-default" : "legacy-custom";
85
+ }
86
+ }
87
+ export function normalizeMiningProviderConfigRecord(config) {
88
+ const modelOverride = normalizeModelOverride(config.modelOverride);
89
+ return {
90
+ ...config,
91
+ extraPrompt: typeof config.extraPrompt === "string" && config.extraPrompt.trim().length > 0
92
+ ? config.extraPrompt
93
+ : null,
94
+ modelOverride,
95
+ modelSelectionSource: normalizeMiningModelSelectionSource(config.modelSelectionSource, modelOverride),
96
+ };
97
+ }
98
+ export function resolveBuiltInProviderModel(provider, modelOverride) {
99
+ const normalizedModelOverride = normalizeModelOverride(modelOverride);
100
+ return {
101
+ effectiveModel: normalizedModelOverride ?? DEFAULT_BUILT_IN_PROVIDER_MODELS[provider],
102
+ usingDefaultModel: normalizedModelOverride === null,
103
+ };
104
+ }
105
+ export function resolveBuiltInProviderSelection(config) {
106
+ const modelOverride = normalizeModelOverride(config.modelOverride);
107
+ const modelSelectionSource = normalizeMiningModelSelectionSource(config.modelSelectionSource, modelOverride);
108
+ const { effectiveModel, usingDefaultModel } = resolveBuiltInProviderModel(config.provider, modelOverride);
109
+ return {
110
+ modelId: effectiveModel,
111
+ effectiveModel,
112
+ modelSelectionSource,
113
+ usingDefaultModel,
114
+ };
115
+ }
116
+ export function estimateBuiltInModelDailyCost(provider, modelId, eligibleRootCount) {
117
+ const model = findBuiltInProviderModelCatalogEntry(provider, modelId);
118
+ if (model === null) {
119
+ return null;
120
+ }
121
+ const rootCount = Math.max(0, Math.trunc(eligibleRootCount));
122
+ const estimatedInputTokens = DAILY_COST_ESTIMATE_BASE_INPUT_TOKENS
123
+ + (DAILY_COST_ESTIMATE_PER_ROOT_INPUT_TOKENS * rootCount);
124
+ const estimatedOutputTokens = DAILY_COST_ESTIMATE_BASE_OUTPUT_TOKENS
125
+ + (DAILY_COST_ESTIMATE_PER_ROOT_OUTPUT_TOKENS * rootCount);
126
+ const estimatedPerCallUsd = ((estimatedInputTokens / 1_000_000) * model.inputUsdPerMillionTokens) + ((estimatedOutputTokens / 1_000_000) * model.outputUsdPerMillionTokens);
127
+ const estimatedDailyCostUsd = Number((estimatedPerCallUsd * DAILY_COST_ESTIMATE_CALLS_PER_DAY).toFixed(6));
128
+ return {
129
+ estimatedDailyCostUsd,
130
+ estimatedDailyCostDisplay: estimatedDailyCostUsd < 0.005
131
+ ? "<$0.01/day"
132
+ : `$${estimatedDailyCostUsd.toFixed(2)}/day`,
133
+ };
134
+ }
@@ -1,14 +1,17 @@
1
+ import { spawn } from "node:child_process";
1
2
  import { attachOrStartManagedBitcoindService } from "../../bitcoind/service.js";
2
3
  import { createRpcClient } from "../../bitcoind/node.js";
3
4
  import type { ProgressOutputMode } from "../../bitcoind/types.js";
4
5
  import { type FixedWalletInput, type MutationSender, type WalletMutationRpcClient } from "../tx/common.js";
6
+ import { readLockMetadata } from "../fs/lock.js";
5
7
  import type { WalletPrompter } from "../lifecycle.js";
6
8
  import { openWalletReadContext, type WalletReadContext } from "../read/index.js";
7
9
  import { type WalletRuntimePaths } from "../runtime.js";
8
10
  import { type WalletSecretProvider } from "../state/provider.js";
9
11
  import type { MiningStateRecord, OutpointRecord, WalletStateV1 } from "../types.js";
10
- import type { MiningEventRecord, MiningRuntimeStatusV1 } from "./types.js";
11
- import { type MiningFollowVisualizerState, type MiningSentenceBoardEntry } from "./visualizer.js";
12
+ import { requestMiningGenerationPreemption } from "./coordination.js";
13
+ import type { MiningControlPlaneView, MiningEventRecord, MiningRuntimeStatusV1 } from "./types.js";
14
+ import { type MiningFollowVisualizerState, type MiningSentenceBoardEntry, MiningFollowVisualizer } from "./visualizer.js";
12
15
  type MiningRpcClient = WalletMutationRpcClient & {
13
16
  getBlockchainInfo(): Promise<{
14
17
  blocks: number;
@@ -72,6 +75,39 @@ type MiningRpcClient = WalletMutationRpcClient & {
72
75
  sendRawTransaction(hex: string): Promise<string>;
73
76
  saveMempool?(): Promise<null>;
74
77
  };
78
+ interface MiningRunnerStatusOverrides {
79
+ runMode?: MiningRuntimeStatusV1["runMode"];
80
+ backgroundWorkerPid?: number | null;
81
+ backgroundWorkerRunId?: string | null;
82
+ backgroundWorkerHeartbeatAtUnixMs?: number | null;
83
+ currentPhase?: MiningRuntimeStatusV1["currentPhase"];
84
+ currentPublishState?: MiningRuntimeStatusV1["currentPublishState"];
85
+ targetBlockHeight?: number | null;
86
+ referencedBlockHashDisplay?: string | null;
87
+ currentDomainId?: number | null;
88
+ currentDomainName?: string | null;
89
+ currentSentenceDisplay?: string | null;
90
+ currentCanonicalBlend?: string | null;
91
+ currentTxid?: string | null;
92
+ currentWtxid?: string | null;
93
+ currentFeeRateSatVb?: number | null;
94
+ currentAbsoluteFeeSats?: number | null;
95
+ currentBlockFeeSpentSats?: string;
96
+ lastSuspendDetectedAtUnixMs?: number | null;
97
+ providerState?: MiningRuntimeStatusV1["providerState"];
98
+ corePublishState?: MiningRuntimeStatusV1["corePublishState"];
99
+ currentPublishDecision?: string | null;
100
+ sameDomainCompetitorSuppressed?: boolean | null;
101
+ higherRankedCompetitorDomainCount?: number | null;
102
+ dedupedCompetitorDomainCount?: number | null;
103
+ competitivenessGateIndeterminate?: boolean | null;
104
+ mempoolSequenceCacheStatus?: MiningRuntimeStatusV1["mempoolSequenceCacheStatus"];
105
+ lastMempoolSequence?: string | null;
106
+ lastCompetitivenessGateAtUnixMs?: number | null;
107
+ lastError?: string | null;
108
+ note?: string | null;
109
+ livePublishInMempool?: boolean | null;
110
+ }
75
111
  interface MiningCandidate {
76
112
  domainId: number;
77
113
  domainName: string;
@@ -97,8 +133,9 @@ type ReadyMiningReadContext = WalletReadContext & {
97
133
  interface MiningPublishSkipResult {
98
134
  state: WalletStateV1;
99
135
  txid: null;
100
- decision: "publish-skipped-stale-candidate";
136
+ decision: "publish-skipped-stale-candidate" | "publish-paused-insufficient-funds";
101
137
  note: string;
138
+ lastError?: string | null;
102
139
  skipped: true;
103
140
  retryable?: false;
104
141
  candidate: null;
@@ -123,6 +160,13 @@ interface RunnerDependencies {
123
160
  attachService?: typeof attachOrStartManagedBitcoindService;
124
161
  rpcFactory?: (config: Parameters<typeof createRpcClient>[0]) => MiningRpcClient;
125
162
  fetchImpl?: typeof fetch;
163
+ requestMiningPreemption?: typeof requestMiningGenerationPreemption;
164
+ runMiningLoopImpl?: typeof runMiningLoop;
165
+ saveStopSnapshotImpl?: typeof saveStopSnapshot;
166
+ spawnWorkerProcess?: typeof spawn;
167
+ waitForBackgroundHealthyImpl?: typeof waitForBackgroundHealthy;
168
+ shutdownGraceMs?: number;
169
+ sleepImpl?: typeof sleep;
126
170
  }
127
171
  interface MiningLoopState {
128
172
  attemptedTipKey: string | null;
@@ -168,6 +212,13 @@ export interface MiningStartResult {
168
212
  started: boolean;
169
213
  snapshot: MiningRuntimeStatusV1 | null;
170
214
  }
215
+ interface MiningRuntimeTakeoverResult {
216
+ controlLockCleared: boolean;
217
+ replaced: boolean;
218
+ snapshot: MiningRuntimeStatusV1 | null;
219
+ terminatedPids: number[];
220
+ }
221
+ declare function sleep(ms: number, signal?: AbortSignal): Promise<void>;
171
222
  export declare function createMiningLoopStateForTesting(): MiningLoopState;
172
223
  export declare function resetMiningUiForTipForTesting(loopState: MiningLoopState, targetBlockHeight: number | null): void;
173
224
  export declare function resolveSettledBoardForTesting(options: {
@@ -283,6 +334,35 @@ export declare function ensureBuiltInMiningSetupIfNeeded(options: {
283
334
  prompter: WalletPrompter;
284
335
  paths: WalletRuntimePaths;
285
336
  }): Promise<boolean>;
337
+ declare function saveStopSnapshot(options: {
338
+ dataDir: string;
339
+ databasePath: string;
340
+ provider: WalletSecretProvider;
341
+ paths: WalletRuntimePaths;
342
+ runMode: "foreground" | "background";
343
+ backgroundWorkerPid: number | null;
344
+ backgroundWorkerRunId: string | null;
345
+ note: string | null;
346
+ }): Promise<void>;
347
+ declare function runMiningLoop(options: {
348
+ dataDir: string;
349
+ databasePath: string;
350
+ provider: WalletSecretProvider;
351
+ paths: WalletRuntimePaths;
352
+ runMode: "foreground" | "background";
353
+ backgroundWorkerPid: number | null;
354
+ backgroundWorkerRunId: string | null;
355
+ signal?: AbortSignal;
356
+ fetchImpl?: typeof fetch;
357
+ openReadContext: typeof openWalletReadContext;
358
+ attachService: typeof attachOrStartManagedBitcoindService;
359
+ rpcFactory: (config: Parameters<typeof createRpcClient>[0]) => MiningRpcClient;
360
+ stdout?: {
361
+ write(chunk: string): void;
362
+ };
363
+ visualizer?: MiningFollowVisualizer;
364
+ }): Promise<void>;
365
+ declare function waitForBackgroundHealthy(paths: WalletRuntimePaths): Promise<MiningRuntimeStatusV1 | null>;
286
366
  export declare function runForegroundMining(options: RunForegroundMiningOptions): Promise<void>;
287
367
  export declare function startBackgroundMining(options: StartBackgroundMiningOptions): Promise<MiningStartResult>;
288
368
  export declare function stopBackgroundMining(options: StopBackgroundMiningOptions): Promise<MiningRuntimeStatusV1 | null>;
@@ -303,7 +383,17 @@ export declare function handleDetectedMiningRuntimeResumeForTesting(options: {
303
383
  backgroundWorkerRunId: string | null;
304
384
  detectedAtUnixMs: number;
305
385
  openReadContext: typeof openWalletReadContext;
386
+ visualizer?: MiningFollowVisualizer;
306
387
  }): Promise<void>;
388
+ export declare function takeOverMiningRuntimeForTesting(options: {
389
+ paths: WalletRuntimePaths;
390
+ reason: string;
391
+ clearControlLockFile?: boolean;
392
+ controlLockMetadata?: Awaited<ReturnType<typeof readLockMetadata>>;
393
+ requestMiningPreemption?: typeof requestMiningGenerationPreemption;
394
+ shutdownGraceMs?: number;
395
+ sleepImpl?: typeof sleep;
396
+ }): Promise<MiningRuntimeTakeoverResult>;
307
397
  export declare function performMiningCycleForTesting(options: {
308
398
  dataDir: string;
309
399
  databasePath: string;
@@ -322,6 +412,11 @@ export declare function performMiningCycleForTesting(options: {
322
412
  };
323
413
  loopState?: MiningLoopState;
324
414
  }): Promise<void>;
415
+ export declare function buildPrePublishStatusOverridesForTesting(options: {
416
+ state: WalletStateV1;
417
+ candidate: MiningCandidate;
418
+ }): MiningRunnerStatusOverrides;
419
+ export declare function buildStatusSnapshotForTesting(view: MiningControlPlaneView, overrides?: MiningRunnerStatusOverrides): MiningRuntimeStatusV1;
325
420
  export declare function shouldKeepCurrentTipLivePublishForTesting(options: {
326
421
  liveState: MiningStateRecord;
327
422
  candidate: {