@cogcoin/client 1.0.2 → 1.1.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.
- package/README.md +3 -2
- package/dist/bitcoind/client/factory.d.ts +0 -8
- package/dist/bitcoind/client/factory.js +1 -59
- package/dist/bitcoind/client/managed-client.d.ts +1 -3
- package/dist/bitcoind/client/managed-client.js +3 -47
- package/dist/bitcoind/indexer-daemon-main.js +173 -28
- package/dist/bitcoind/indexer-daemon.d.ts +11 -3
- package/dist/bitcoind/indexer-daemon.js +123 -57
- package/dist/bitcoind/indexer-monitor.d.ts +12 -0
- package/dist/bitcoind/indexer-monitor.js +89 -0
- package/dist/bitcoind/progress/follow-scene.d.ts +7 -1
- package/dist/bitcoind/progress/follow-scene.js +87 -4
- package/dist/bitcoind/progress/tty-renderer.d.ts +2 -0
- package/dist/bitcoind/progress/tty-renderer.js +2 -0
- package/dist/bitcoind/testing.d.ts +0 -1
- package/dist/bitcoind/testing.js +0 -1
- package/dist/bitcoind/types.d.ts +5 -2
- package/dist/cli/commands/follow.js +44 -49
- package/dist/cli/commands/mining-admin.js +56 -2
- package/dist/cli/commands/mining-read.js +43 -3
- package/dist/cli/commands/mining-runtime.js +91 -73
- package/dist/cli/commands/service-runtime.js +42 -2
- package/dist/cli/commands/status.js +3 -1
- package/dist/cli/commands/sync.js +50 -90
- package/dist/cli/commands/wallet-admin.js +21 -3
- package/dist/cli/commands/wallet-read.js +2 -0
- package/dist/cli/context.js +5 -1
- package/dist/cli/managed-indexer-observer.d.ts +33 -0
- package/dist/cli/managed-indexer-observer.js +163 -0
- package/dist/cli/mining-format.d.ts +3 -1
- package/dist/cli/mining-format.js +35 -0
- package/dist/cli/mining-json.d.ts +11 -1
- package/dist/cli/mining-json.js +9 -0
- package/dist/cli/output.js +24 -0
- package/dist/cli/parse.d.ts +1 -1
- package/dist/cli/parse.js +23 -0
- package/dist/cli/read-json.d.ts +13 -1
- package/dist/cli/read-json.js +31 -0
- package/dist/cli/runner.js +4 -2
- package/dist/cli/signals.d.ts +12 -0
- package/dist/cli/signals.js +31 -13
- package/dist/cli/types.d.ts +8 -4
- package/dist/cli/update-service.d.ts +2 -12
- package/dist/cli/update-service.js +2 -68
- package/dist/semver.d.ts +12 -0
- package/dist/semver.js +68 -0
- package/dist/wallet/lifecycle.js +0 -6
- package/dist/wallet/mining/config.js +54 -3
- package/dist/wallet/mining/control.d.ts +5 -2
- package/dist/wallet/mining/control.js +153 -34
- package/dist/wallet/mining/domain-prompts.d.ts +17 -0
- package/dist/wallet/mining/domain-prompts.js +130 -0
- package/dist/wallet/mining/index.d.ts +2 -1
- package/dist/wallet/mining/index.js +1 -0
- package/dist/wallet/mining/runner.d.ts +58 -2
- package/dist/wallet/mining/runner.js +553 -331
- package/dist/wallet/mining/sentence-protocol.d.ts +1 -0
- package/dist/wallet/mining/sentences.js +7 -4
- package/dist/wallet/mining/types.d.ts +26 -0
- package/dist/wallet/mining/visualizer.d.ts +3 -0
- package/dist/wallet/mining/visualizer.js +106 -12
- package/dist/wallet/read/context.d.ts +1 -0
- package/dist/wallet/read/context.js +15 -10
- package/dist/wallet/reset.js +0 -1
- package/dist/wallet/state/client-password-agent.js +4 -1
- package/dist/wallet/state/client-password.js +15 -8
- package/dist/wallet/tx/anchor.js +0 -1
- package/dist/wallet/tx/bitcoin-transfer.js +0 -1
- package/dist/wallet/tx/cog.js +0 -3
- package/dist/wallet/tx/common.js +1 -1
- package/dist/wallet/tx/domain-admin.js +0 -1
- package/dist/wallet/tx/domain-market.js +0 -3
- package/dist/wallet/tx/field.js +0 -1
- package/dist/wallet/tx/register.js +0 -1
- package/dist/wallet/tx/reputation.js +0 -1
- package/package.json +1 -1
|
@@ -2,20 +2,66 @@ import { readFile } from "node:fs/promises";
|
|
|
2
2
|
import { writeJsonFileAtomic } from "../fs/atomic.js";
|
|
3
3
|
import { decryptJsonWithSecretProvider, encryptJsonWithSecretProvider } from "../state/crypto.js";
|
|
4
4
|
import { normalizeMiningProviderConfigRecord } from "./provider-model.js";
|
|
5
|
+
const MINING_PROVIDER_KINDS = ["openai", "anthropic"];
|
|
6
|
+
function normalizeDomainExtraPrompts(raw) {
|
|
7
|
+
if (raw === null || typeof raw !== "object") {
|
|
8
|
+
return {};
|
|
9
|
+
}
|
|
10
|
+
const normalized = new Map();
|
|
11
|
+
for (const [rawDomainName, rawPrompt] of Object.entries(raw)) {
|
|
12
|
+
if (typeof rawPrompt !== "string") {
|
|
13
|
+
continue;
|
|
14
|
+
}
|
|
15
|
+
const domainName = rawDomainName.trim().toLowerCase();
|
|
16
|
+
const prompt = rawPrompt.trim();
|
|
17
|
+
if (domainName.length === 0 || prompt.length === 0) {
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
normalized.set(domainName, prompt);
|
|
21
|
+
}
|
|
22
|
+
return Object.fromEntries([...normalized.entries()].sort(([left], [right]) => left.localeCompare(right)));
|
|
23
|
+
}
|
|
5
24
|
function createEmptyClientConfig() {
|
|
6
25
|
return {
|
|
7
26
|
schemaVersion: 1,
|
|
8
27
|
mining: {
|
|
9
28
|
builtIn: null,
|
|
29
|
+
domainExtraPrompts: {},
|
|
10
30
|
},
|
|
11
31
|
};
|
|
12
32
|
}
|
|
33
|
+
function normalizeBuiltInProviderConfigMap(raw) {
|
|
34
|
+
if (raw === null || typeof raw !== "object") {
|
|
35
|
+
return {};
|
|
36
|
+
}
|
|
37
|
+
const normalized = {};
|
|
38
|
+
const entries = raw;
|
|
39
|
+
for (const provider of MINING_PROVIDER_KINDS) {
|
|
40
|
+
const config = entries[provider];
|
|
41
|
+
if (config == null) {
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
normalized[provider] = normalizeMiningProviderConfigRecord({
|
|
45
|
+
...config,
|
|
46
|
+
provider,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
return normalized;
|
|
50
|
+
}
|
|
13
51
|
function normalizeClientConfig(config) {
|
|
52
|
+
const mining = config.mining ?? createEmptyClientConfig().mining;
|
|
53
|
+
const builtIn = mining.builtIn === null ? null : normalizeMiningProviderConfigRecord(mining.builtIn);
|
|
54
|
+
const builtInByProvider = normalizeBuiltInProviderConfigMap(mining.builtInByProvider);
|
|
55
|
+
if (builtIn !== null) {
|
|
56
|
+
builtInByProvider[builtIn.provider] = builtIn;
|
|
57
|
+
}
|
|
14
58
|
return {
|
|
15
59
|
...config,
|
|
16
60
|
mining: {
|
|
17
|
-
...
|
|
18
|
-
builtIn
|
|
61
|
+
...mining,
|
|
62
|
+
builtIn,
|
|
63
|
+
...(Object.keys(builtInByProvider).length === 0 ? {} : { builtInByProvider }),
|
|
64
|
+
domainExtraPrompts: normalizeDomainExtraPrompts(mining.domainExtraPrompts),
|
|
19
65
|
},
|
|
20
66
|
};
|
|
21
67
|
}
|
|
@@ -43,7 +89,12 @@ export async function saveBuiltInMiningProviderConfig(options) {
|
|
|
43
89
|
provider: options.provider,
|
|
44
90
|
}).catch(() => null);
|
|
45
91
|
const nextConfig = existing ?? createEmptyClientConfig();
|
|
46
|
-
|
|
92
|
+
const normalizedConfig = normalizeMiningProviderConfigRecord(options.config);
|
|
93
|
+
nextConfig.mining.builtIn = normalizedConfig;
|
|
94
|
+
nextConfig.mining.builtInByProvider = {
|
|
95
|
+
...(nextConfig.mining.builtInByProvider ?? {}),
|
|
96
|
+
[normalizedConfig.provider]: normalizedConfig,
|
|
97
|
+
};
|
|
47
98
|
await saveClientConfig({
|
|
48
99
|
path: options.path,
|
|
49
100
|
provider: options.provider,
|
|
@@ -2,7 +2,7 @@ import type { WalletPrompter } from "../lifecycle.js";
|
|
|
2
2
|
import { type WalletRuntimePaths } from "../runtime.js";
|
|
3
3
|
import { type WalletSecretProvider } from "../state/provider.js";
|
|
4
4
|
import type { WalletBitcoindStatus, WalletIndexerStatus, WalletLocalStateStatus, WalletNodeStatus } from "../read/types.js";
|
|
5
|
-
import type { MiningControlPlaneView, MiningEventRecord, MiningProviderConfigRecord, MiningRuntimeStatusV1 } from "./types.js";
|
|
5
|
+
import type { MiningControlPlaneView, MiningEventRecord, MiningProviderConfigByProvider, MiningProviderConfigRecord, MiningRuntimeStatusV1 } from "./types.js";
|
|
6
6
|
export declare function inspectMiningControlPlane(options: {
|
|
7
7
|
provider?: WalletSecretProvider;
|
|
8
8
|
localState: WalletLocalStateStatus;
|
|
@@ -23,7 +23,10 @@ export declare function refreshMiningRuntimeStatus(options: {
|
|
|
23
23
|
nowUnixMs?: number;
|
|
24
24
|
paths?: WalletRuntimePaths;
|
|
25
25
|
}): Promise<MiningControlPlaneView>;
|
|
26
|
-
export declare function promptForMiningProviderConfigForTesting(prompter: WalletPrompter, eligibleRootCount: number
|
|
26
|
+
export declare function promptForMiningProviderConfigForTesting(prompter: WalletPrompter, eligibleRootCount: number, options?: {
|
|
27
|
+
currentConfig?: MiningProviderConfigRecord | null;
|
|
28
|
+
rememberedConfigs?: MiningProviderConfigByProvider;
|
|
29
|
+
}): Promise<MiningProviderConfigRecord>;
|
|
27
30
|
export declare function setupBuiltInMining(options: {
|
|
28
31
|
provider?: WalletSecretProvider;
|
|
29
32
|
prompter: WalletPrompter;
|
|
@@ -9,6 +9,7 @@ import { normalizeMiningPublishState, normalizeMiningStateRecord } from "./state
|
|
|
9
9
|
import { loadClientConfig, saveBuiltInMiningProviderConfig } from "./config.js";
|
|
10
10
|
import { MINING_WORKER_API_VERSION, MINING_WORKER_HEARTBEAT_STALE_MS, } from "./constants.js";
|
|
11
11
|
import { estimateBuiltInModelDailyCost, getBuiltInProviderModelCatalog, getRecommendedBuiltInProviderModel, MINING_MODEL_DAILY_COST_ESTIMATE_ASSUMPTION, resolveBuiltInProviderSelection, } from "./provider-model.js";
|
|
12
|
+
const KEEP_CURRENT_MODEL_SELECTION = "__keep_current__";
|
|
12
13
|
function createMiningEvent(kind, message, options = {}) {
|
|
13
14
|
return {
|
|
14
15
|
schemaVersion: 1,
|
|
@@ -414,59 +415,170 @@ async function promptForMiningProviderModelSelectionFallback(prompter, options)
|
|
|
414
415
|
prompter.writeLine(`Enter a number from 1 to ${options.options.length}, or q to cancel.`);
|
|
415
416
|
}
|
|
416
417
|
}
|
|
417
|
-
|
|
418
|
+
function formatMiningProviderDisplayName(provider) {
|
|
419
|
+
return provider === "openai" ? "OpenAI" : "Anthropic";
|
|
420
|
+
}
|
|
421
|
+
async function promptMiningSetupYesNo(prompter, message, defaultAnswer) {
|
|
422
|
+
const prompt = `${message}${defaultAnswer ? " [Y/n]: " : " [y/N]: "}`;
|
|
423
|
+
while (true) {
|
|
424
|
+
const answer = (await prompter.prompt(prompt)).trim().toLowerCase();
|
|
425
|
+
if (answer.length === 0) {
|
|
426
|
+
return defaultAnswer;
|
|
427
|
+
}
|
|
428
|
+
if (answer === "y" || answer === "yes") {
|
|
429
|
+
return true;
|
|
430
|
+
}
|
|
431
|
+
if (answer === "n" || answer === "no") {
|
|
432
|
+
return false;
|
|
433
|
+
}
|
|
434
|
+
if (answer === "q" || answer === "quit" || answer === "esc" || answer === "escape") {
|
|
435
|
+
throw new Error("mining_setup_canceled");
|
|
436
|
+
}
|
|
437
|
+
prompter.writeLine("Enter y or n, or q to cancel.");
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
function buildMiningProviderModelSelectorOptions(provider, eligibleRootCount, currentConfig) {
|
|
441
|
+
const catalogOptions = getBuiltInProviderModelCatalog(provider).map((entry) => {
|
|
442
|
+
const estimate = estimateBuiltInModelDailyCost(provider, entry.modelId, eligibleRootCount);
|
|
443
|
+
return {
|
|
444
|
+
label: entry.label,
|
|
445
|
+
description: `${entry.modelId} - ${estimate?.estimatedDailyCostDisplay ?? "n/a"}`,
|
|
446
|
+
value: entry.modelId,
|
|
447
|
+
};
|
|
448
|
+
});
|
|
449
|
+
const selection = currentConfig === null ? null : resolveBuiltInProviderSelection(currentConfig);
|
|
450
|
+
const options = [...catalogOptions];
|
|
451
|
+
let initialValue = getRecommendedBuiltInProviderModel(provider);
|
|
452
|
+
if (selection !== null) {
|
|
453
|
+
if (selection.modelSelectionSource === "custom" || selection.modelSelectionSource === "legacy-custom") {
|
|
454
|
+
initialValue = "custom";
|
|
455
|
+
}
|
|
456
|
+
else if (catalogOptions.some((entry) => entry.value === selection.modelId)) {
|
|
457
|
+
initialValue = selection.modelId;
|
|
458
|
+
}
|
|
459
|
+
else {
|
|
460
|
+
options.push({
|
|
461
|
+
label: "Current configured model",
|
|
462
|
+
description: `${selection.modelId} - current saved setting`,
|
|
463
|
+
value: KEEP_CURRENT_MODEL_SELECTION,
|
|
464
|
+
});
|
|
465
|
+
initialValue = KEEP_CURRENT_MODEL_SELECTION;
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
options.push({
|
|
469
|
+
label: "Custom model ID...",
|
|
470
|
+
description: "",
|
|
471
|
+
value: "custom",
|
|
472
|
+
});
|
|
473
|
+
return {
|
|
474
|
+
initialValue,
|
|
475
|
+
options,
|
|
476
|
+
};
|
|
477
|
+
}
|
|
478
|
+
async function promptForMiningProviderConfig(prompter, eligibleRootCount, options = {}) {
|
|
418
479
|
writeBuiltInMiningProviderDisclosure(prompter);
|
|
419
|
-
const
|
|
420
|
-
const
|
|
421
|
-
|
|
422
|
-
|
|
480
|
+
const currentConfig = options.currentConfig ?? null;
|
|
481
|
+
const rememberedConfigs = options.rememberedConfigs ?? {};
|
|
482
|
+
let provider;
|
|
483
|
+
let rememberedConfig = currentConfig;
|
|
484
|
+
let reuseSavedApiKey = false;
|
|
485
|
+
if (currentConfig !== null) {
|
|
486
|
+
const useDifferentProviderOrApiKey = await promptMiningSetupYesNo(prompter, "Use a different provider or API key?", false);
|
|
487
|
+
if (!useDifferentProviderOrApiKey) {
|
|
488
|
+
provider = currentConfig.provider;
|
|
489
|
+
reuseSavedApiKey = true;
|
|
490
|
+
}
|
|
491
|
+
else {
|
|
492
|
+
const providerInput = await prompter.prompt("Provider (openai/anthropic): ");
|
|
493
|
+
const selectedProvider = normalizeProviderChoice(providerInput);
|
|
494
|
+
if (selectedProvider === null) {
|
|
495
|
+
throw new Error("mining_setup_invalid_provider");
|
|
496
|
+
}
|
|
497
|
+
provider = selectedProvider;
|
|
498
|
+
rememberedConfig = rememberedConfigs[provider] ?? null;
|
|
499
|
+
if (rememberedConfig !== null) {
|
|
500
|
+
reuseSavedApiKey = await promptMiningSetupYesNo(prompter, `Use saved ${formatMiningProviderDisplayName(provider)} API key?`, true);
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
else {
|
|
505
|
+
const providerInput = await prompter.prompt("Provider (openai/anthropic): ");
|
|
506
|
+
const selectedProvider = normalizeProviderChoice(providerInput);
|
|
507
|
+
if (selectedProvider === null) {
|
|
508
|
+
throw new Error("mining_setup_invalid_provider");
|
|
509
|
+
}
|
|
510
|
+
provider = selectedProvider;
|
|
511
|
+
rememberedConfig = rememberedConfigs[provider] ?? null;
|
|
512
|
+
if (rememberedConfig !== null) {
|
|
513
|
+
reuseSavedApiKey = await promptMiningSetupYesNo(prompter, `Use saved ${formatMiningProviderDisplayName(provider)} API key?`, true);
|
|
514
|
+
}
|
|
423
515
|
}
|
|
516
|
+
const selectorModelOptions = buildMiningProviderModelSelectorOptions(provider, eligibleRootCount, rememberedConfig);
|
|
424
517
|
const selectorOptions = {
|
|
425
518
|
message: "Choose the mining model:",
|
|
426
|
-
options:
|
|
427
|
-
|
|
428
|
-
const estimate = estimateBuiltInModelDailyCost(provider, entry.modelId, eligibleRootCount);
|
|
429
|
-
return {
|
|
430
|
-
label: entry.label,
|
|
431
|
-
description: `${entry.modelId} - ${estimate?.estimatedDailyCostDisplay ?? "n/a"}`,
|
|
432
|
-
value: entry.modelId,
|
|
433
|
-
};
|
|
434
|
-
}),
|
|
435
|
-
{
|
|
436
|
-
label: "Custom model ID...",
|
|
437
|
-
description: null,
|
|
438
|
-
value: "custom",
|
|
439
|
-
},
|
|
440
|
-
],
|
|
441
|
-
initialValue: getRecommendedBuiltInProviderModel(provider),
|
|
519
|
+
options: selectorModelOptions.options,
|
|
520
|
+
initialValue: selectorModelOptions.initialValue,
|
|
442
521
|
footer: MINING_MODEL_DAILY_COST_ESTIMATE_ASSUMPTION,
|
|
443
522
|
};
|
|
444
523
|
const selectedModelId = prompter.selectOption == null
|
|
445
524
|
? await promptForMiningProviderModelSelectionFallback(prompter, selectorOptions)
|
|
446
525
|
: await prompter.selectOption(selectorOptions);
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
526
|
+
let modelSelectionSource;
|
|
527
|
+
let modelOverride;
|
|
528
|
+
if (selectedModelId === KEEP_CURRENT_MODEL_SELECTION) {
|
|
529
|
+
if (rememberedConfig === null) {
|
|
530
|
+
throw new Error("mining_setup_missing_model_id");
|
|
531
|
+
}
|
|
532
|
+
modelSelectionSource = rememberedConfig.modelSelectionSource;
|
|
533
|
+
modelOverride = rememberedConfig.modelOverride;
|
|
534
|
+
}
|
|
535
|
+
else if (selectedModelId === "custom") {
|
|
536
|
+
const currentCustomModel = rememberedConfig !== null
|
|
537
|
+
&& (rememberedConfig.modelSelectionSource === "custom" || rememberedConfig.modelSelectionSource === "legacy-custom")
|
|
538
|
+
? rememberedConfig.modelOverride
|
|
539
|
+
: null;
|
|
540
|
+
const customModelId = (await prompter.prompt(currentCustomModel === null
|
|
541
|
+
? "Custom model ID: "
|
|
542
|
+
: `Custom model ID (blank to keep current: ${currentCustomModel}): `)).trim();
|
|
543
|
+
if (customModelId.length === 0) {
|
|
544
|
+
if (currentCustomModel === null) {
|
|
545
|
+
throw new Error("mining_setup_missing_model_id");
|
|
546
|
+
}
|
|
547
|
+
modelSelectionSource = rememberedConfig?.modelSelectionSource ?? "custom";
|
|
548
|
+
modelOverride = currentCustomModel;
|
|
549
|
+
}
|
|
550
|
+
else {
|
|
551
|
+
modelSelectionSource = "custom";
|
|
552
|
+
modelOverride = customModelId;
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
else {
|
|
556
|
+
modelSelectionSource = "catalog";
|
|
557
|
+
modelOverride = selectedModelId;
|
|
558
|
+
}
|
|
559
|
+
const apiKey = reuseSavedApiKey && rememberedConfig !== null
|
|
560
|
+
? rememberedConfig.apiKey
|
|
561
|
+
: (await prompter.prompt("API key: ")).trim();
|
|
455
562
|
if (apiKey.length === 0) {
|
|
456
563
|
throw new Error("mining_setup_missing_api_key");
|
|
457
564
|
}
|
|
458
|
-
const
|
|
565
|
+
const extraPromptInput = (await prompter.prompt(rememberedConfig === null
|
|
566
|
+
? "Extra prompt (optional, blank for none): "
|
|
567
|
+
: `Extra prompt (optional, blank to keep current: ${rememberedConfig.extraPrompt ?? "none"}): `)).trim();
|
|
568
|
+
const extraPrompt = extraPromptInput.length === 0
|
|
569
|
+
? rememberedConfig?.extraPrompt ?? null
|
|
570
|
+
: extraPromptInput;
|
|
459
571
|
return {
|
|
460
572
|
provider,
|
|
461
573
|
apiKey,
|
|
462
|
-
extraPrompt: extraPrompt.length === 0 ? null : extraPrompt,
|
|
574
|
+
extraPrompt: extraPrompt === null || extraPrompt.length === 0 ? null : extraPrompt,
|
|
463
575
|
modelOverride,
|
|
464
576
|
modelSelectionSource,
|
|
465
577
|
updatedAtUnixMs: Date.now(),
|
|
466
578
|
};
|
|
467
579
|
}
|
|
468
|
-
export async function promptForMiningProviderConfigForTesting(prompter, eligibleRootCount) {
|
|
469
|
-
return await promptForMiningProviderConfig(prompter, eligibleRootCount);
|
|
580
|
+
export async function promptForMiningProviderConfigForTesting(prompter, eligibleRootCount, options = {}) {
|
|
581
|
+
return await promptForMiningProviderConfig(prompter, eligibleRootCount, options);
|
|
470
582
|
}
|
|
471
583
|
export async function setupBuiltInMining(options) {
|
|
472
584
|
if (!options.prompter.isInteractive) {
|
|
@@ -502,9 +614,16 @@ export async function setupBuiltInMining(options) {
|
|
|
502
614
|
message: null,
|
|
503
615
|
};
|
|
504
616
|
const eligibleRootCount = countEligibleAnchoredRoots(localState) ?? 0;
|
|
617
|
+
const clientConfig = await loadClientConfig({
|
|
618
|
+
path: paths.clientConfigPath,
|
|
619
|
+
provider,
|
|
620
|
+
}).catch(() => null);
|
|
505
621
|
await appendMiningEvent(paths.miningEventsPath, createMiningEvent("mine-setup-started", "Started built-in mining provider setup.", { timestampUnixMs: nowUnixMs }));
|
|
506
622
|
try {
|
|
507
|
-
const config = await promptForMiningProviderConfig(options.prompter, eligibleRootCount
|
|
623
|
+
const config = await promptForMiningProviderConfig(options.prompter, eligibleRootCount, {
|
|
624
|
+
currentConfig: clientConfig?.mining.builtIn ?? null,
|
|
625
|
+
rememberedConfigs: clientConfig?.mining.builtInByProvider ?? {},
|
|
626
|
+
});
|
|
508
627
|
config.updatedAtUnixMs = nowUnixMs;
|
|
509
628
|
await saveBuiltInMiningProviderConfig({
|
|
510
629
|
path: paths.clientConfigPath,
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { WalletReadContext } from "../read/index.js";
|
|
2
|
+
import { type WalletSecretProvider } from "../state/provider.js";
|
|
3
|
+
import type { WalletRuntimePaths } from "../runtime.js";
|
|
4
|
+
import type { MiningDomainPromptListResult, MiningDomainPromptMutationResult } from "./types.js";
|
|
5
|
+
export declare function canonicalizeMiningDomainPromptName(domainName: string): string;
|
|
6
|
+
export declare function inspectMiningDomainPromptState(options: {
|
|
7
|
+
paths: WalletRuntimePaths;
|
|
8
|
+
provider: WalletSecretProvider;
|
|
9
|
+
readContext: WalletReadContext;
|
|
10
|
+
}): Promise<MiningDomainPromptListResult>;
|
|
11
|
+
export declare function updateMiningDomainPrompt(options: {
|
|
12
|
+
paths: WalletRuntimePaths;
|
|
13
|
+
provider: WalletSecretProvider;
|
|
14
|
+
readContext: WalletReadContext;
|
|
15
|
+
domainName: string;
|
|
16
|
+
prompt: string | null;
|
|
17
|
+
}): Promise<MiningDomainPromptMutationResult>;
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { findWalletDomain, isMineableWalletDomain } from "../read/index.js";
|
|
2
|
+
import { createWalletSecretReference } from "../state/provider.js";
|
|
3
|
+
import { loadClientConfig, saveClientConfig } from "./config.js";
|
|
4
|
+
function createEmptyClientConfig() {
|
|
5
|
+
return {
|
|
6
|
+
schemaVersion: 1,
|
|
7
|
+
mining: {
|
|
8
|
+
builtIn: null,
|
|
9
|
+
domainExtraPrompts: {},
|
|
10
|
+
},
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export function canonicalizeMiningDomainPromptName(domainName) {
|
|
14
|
+
return domainName.trim().toLowerCase();
|
|
15
|
+
}
|
|
16
|
+
function fallbackPromptConfigured(config) {
|
|
17
|
+
const extraPrompt = config?.mining.builtIn?.extraPrompt ?? null;
|
|
18
|
+
return extraPrompt !== null && extraPrompt.length > 0;
|
|
19
|
+
}
|
|
20
|
+
function listMineableDomains(readContext) {
|
|
21
|
+
const domains = new Map();
|
|
22
|
+
for (const domain of readContext.model?.domains ?? []) {
|
|
23
|
+
if (!isMineableWalletDomain(readContext, domain)) {
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
domains.set(canonicalizeMiningDomainPromptName(domain.name), {
|
|
27
|
+
name: domain.name,
|
|
28
|
+
domainId: domain.domainId,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
return domains;
|
|
32
|
+
}
|
|
33
|
+
function buildPromptEntries(options) {
|
|
34
|
+
const entries = new Map();
|
|
35
|
+
const mineableDomains = listMineableDomains(options.readContext);
|
|
36
|
+
for (const domain of mineableDomains.values()) {
|
|
37
|
+
const canonicalDomainName = canonicalizeMiningDomainPromptName(domain.name);
|
|
38
|
+
const prompt = options.domainExtraPrompts[canonicalDomainName] ?? null;
|
|
39
|
+
entries.set(canonicalDomainName, {
|
|
40
|
+
domain,
|
|
41
|
+
mineable: true,
|
|
42
|
+
prompt,
|
|
43
|
+
effectivePromptSource: prompt !== null
|
|
44
|
+
? "domain"
|
|
45
|
+
: options.fallbackPromptConfigured
|
|
46
|
+
? "global-fallback"
|
|
47
|
+
: "none",
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
for (const [domainName, prompt] of Object.entries(options.domainExtraPrompts)) {
|
|
51
|
+
if (entries.has(domainName)) {
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
const found = findWalletDomain(options.readContext, domainName);
|
|
55
|
+
entries.set(domainName, {
|
|
56
|
+
domain: {
|
|
57
|
+
name: domainName,
|
|
58
|
+
domainId: found?.domain.domainId ?? null,
|
|
59
|
+
},
|
|
60
|
+
mineable: false,
|
|
61
|
+
prompt,
|
|
62
|
+
effectivePromptSource: "domain",
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
return [...entries.values()].sort((left, right) => left.domain.name.localeCompare(right.domain.name));
|
|
66
|
+
}
|
|
67
|
+
function isMineableTarget(readContext, domainName) {
|
|
68
|
+
const domain = readContext.model?.domains.find((entry) => canonicalizeMiningDomainPromptName(entry.name) === domainName);
|
|
69
|
+
return domain === undefined ? false : isMineableWalletDomain(readContext, domain);
|
|
70
|
+
}
|
|
71
|
+
export async function inspectMiningDomainPromptState(options) {
|
|
72
|
+
const config = await loadClientConfig({
|
|
73
|
+
path: options.paths.clientConfigPath,
|
|
74
|
+
provider: options.provider,
|
|
75
|
+
});
|
|
76
|
+
return {
|
|
77
|
+
fallbackPromptConfigured: fallbackPromptConfigured(config),
|
|
78
|
+
prompts: buildPromptEntries({
|
|
79
|
+
readContext: options.readContext,
|
|
80
|
+
domainExtraPrompts: config?.mining.domainExtraPrompts ?? {},
|
|
81
|
+
fallbackPromptConfigured: fallbackPromptConfigured(config),
|
|
82
|
+
}),
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
export async function updateMiningDomainPrompt(options) {
|
|
86
|
+
const canonicalDomainName = canonicalizeMiningDomainPromptName(options.domainName);
|
|
87
|
+
const config = await loadClientConfig({
|
|
88
|
+
path: options.paths.clientConfigPath,
|
|
89
|
+
provider: options.provider,
|
|
90
|
+
});
|
|
91
|
+
const currentPrompts = {
|
|
92
|
+
...(config?.mining.domainExtraPrompts ?? {}),
|
|
93
|
+
};
|
|
94
|
+
const existingPrompt = currentPrompts[canonicalDomainName] ?? null;
|
|
95
|
+
const mineable = isMineableTarget(options.readContext, canonicalDomainName);
|
|
96
|
+
const found = findWalletDomain(options.readContext, canonicalDomainName);
|
|
97
|
+
const nextPrompt = options.prompt === null || options.prompt.trim().length === 0
|
|
98
|
+
? null
|
|
99
|
+
: options.prompt.trim();
|
|
100
|
+
if (!mineable && existingPrompt === null) {
|
|
101
|
+
throw new Error("mine_prompt_domain_not_mineable");
|
|
102
|
+
}
|
|
103
|
+
if (options.readContext.localState.walletRootId === null) {
|
|
104
|
+
throw new Error("wallet_uninitialized");
|
|
105
|
+
}
|
|
106
|
+
if (nextPrompt === null) {
|
|
107
|
+
delete currentPrompts[canonicalDomainName];
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
currentPrompts[canonicalDomainName] = nextPrompt;
|
|
111
|
+
}
|
|
112
|
+
const nextConfig = config ?? createEmptyClientConfig();
|
|
113
|
+
nextConfig.mining.domainExtraPrompts = currentPrompts;
|
|
114
|
+
await saveClientConfig({
|
|
115
|
+
path: options.paths.clientConfigPath,
|
|
116
|
+
provider: options.provider,
|
|
117
|
+
secretReference: createWalletSecretReference(options.readContext.localState.walletRootId),
|
|
118
|
+
config: nextConfig,
|
|
119
|
+
});
|
|
120
|
+
return {
|
|
121
|
+
domain: {
|
|
122
|
+
name: canonicalDomainName,
|
|
123
|
+
domainId: found?.domain.domainId ?? null,
|
|
124
|
+
},
|
|
125
|
+
previousPrompt: existingPrompt,
|
|
126
|
+
prompt: nextPrompt,
|
|
127
|
+
status: nextPrompt === null ? "cleared" : "updated",
|
|
128
|
+
fallbackPromptConfigured: fallbackPromptConfigured(config),
|
|
129
|
+
};
|
|
130
|
+
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
export { isMiningGenerationAbortRequested, markMiningGenerationActive, markMiningGenerationInactive, readMiningGenerationActivity, readMiningPreemptionRequest, requestMiningGenerationPreemption, } from "./coordination.js";
|
|
2
|
+
export { canonicalizeMiningDomainPromptName, inspectMiningDomainPromptState, updateMiningDomainPrompt, } from "./domain-prompts.js";
|
|
2
3
|
export { followMiningLog, inspectMiningControlPlane, readMiningLog, refreshMiningRuntimeStatus, setupBuiltInMining, } from "./control.js";
|
|
3
4
|
export { ensureBuiltInMiningSetupIfNeeded, runBackgroundMiningWorker, runForegroundMining, startBackgroundMining, stopBackgroundMining, type MiningStartResult, } from "./runner.js";
|
|
4
5
|
export { appendMiningEvent, loadMiningRuntimeStatus, readMiningEvents, resolveRotatedMiningEventsPath, saveMiningRuntimeStatus, } from "./runtime-artifacts.js";
|
|
5
6
|
export type { MiningSentenceCandidateV1, MiningSentenceGenerationRequestV1, MiningSentenceGenerationResponseV1, } from "./sentence-protocol.js";
|
|
6
7
|
export { loadClientConfig, saveBuiltInMiningProviderConfig, saveClientConfig, } from "./config.js";
|
|
7
|
-
export type { ClientConfigV1, MiningControlPlaneView, MiningEventRecord, MiningModelSelectionSource, MiningProviderConfigRecord, MiningProviderInspection, MiningRuntimeStatusV1, MiningServiceHealth, } from "./types.js";
|
|
8
|
+
export type { ClientConfigV1, MiningControlPlaneView, MiningDomainPromptEntry, MiningDomainPromptListResult, MiningDomainPromptMutationResult, MiningEventRecord, MiningModelSelectionSource, MiningProviderConfigRecord, MiningProviderInspection, MiningRuntimeStatusV1, MiningServiceHealth, } from "./types.js";
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { isMiningGenerationAbortRequested, markMiningGenerationActive, markMiningGenerationInactive, readMiningGenerationActivity, readMiningPreemptionRequest, requestMiningGenerationPreemption, } from "./coordination.js";
|
|
2
|
+
export { canonicalizeMiningDomainPromptName, inspectMiningDomainPromptState, updateMiningDomainPrompt, } from "./domain-prompts.js";
|
|
2
3
|
export { followMiningLog, inspectMiningControlPlane, readMiningLog, refreshMiningRuntimeStatus, setupBuiltInMining, } from "./control.js";
|
|
3
4
|
export { ensureBuiltInMiningSetupIfNeeded, runBackgroundMiningWorker, runForegroundMining, startBackgroundMining, stopBackgroundMining, } from "./runner.js";
|
|
4
5
|
export { appendMiningEvent, loadMiningRuntimeStatus, readMiningEvents, resolveRotatedMiningEventsPath, saveMiningRuntimeStatus, } from "./runtime-artifacts.js";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
|
-
import { attachOrStartManagedBitcoindService } from "../../bitcoind/service.js";
|
|
2
|
+
import { attachOrStartManagedBitcoindService, probeManagedBitcoindService, stopManagedBitcoindService } from "../../bitcoind/service.js";
|
|
3
3
|
import { createRpcClient } from "../../bitcoind/node.js";
|
|
4
4
|
import type { ProgressOutputMode } from "../../bitcoind/types.js";
|
|
5
5
|
import { type FixedWalletInput, type MutationSender, type WalletMutationRpcClient } from "../tx/common.js";
|
|
@@ -10,6 +10,7 @@ import { type WalletRuntimePaths } from "../runtime.js";
|
|
|
10
10
|
import { type WalletSecretProvider } from "../state/provider.js";
|
|
11
11
|
import type { MiningStateRecord, OutpointRecord, WalletStateV1 } from "../types.js";
|
|
12
12
|
import { requestMiningGenerationPreemption } from "./coordination.js";
|
|
13
|
+
import { type MiningSentenceGenerationRequest } from "./sentences.js";
|
|
13
14
|
import type { MiningControlPlaneView, MiningEventRecord, MiningRuntimeStatusV1 } from "./types.js";
|
|
14
15
|
import { type MiningFollowVisualizerState, type MiningSentenceBoardEntry, MiningFollowVisualizer } from "./visualizer.js";
|
|
15
16
|
type MiningRpcClient = WalletMutationRpcClient & {
|
|
@@ -94,6 +95,8 @@ interface MiningRunnerStatusOverrides {
|
|
|
94
95
|
currentAbsoluteFeeSats?: number | null;
|
|
95
96
|
currentBlockFeeSpentSats?: string;
|
|
96
97
|
lastSuspendDetectedAtUnixMs?: number | null;
|
|
98
|
+
reconnectSettledUntilUnixMs?: number | null;
|
|
99
|
+
tipSettledUntilUnixMs?: number | null;
|
|
97
100
|
providerState?: MiningRuntimeStatusV1["providerState"];
|
|
98
101
|
corePublishState?: MiningRuntimeStatusV1["corePublishState"];
|
|
99
102
|
currentPublishDecision?: string | null;
|
|
@@ -175,10 +178,19 @@ interface MiningLoopState {
|
|
|
175
178
|
selectedCandidate: MiningCandidate | null;
|
|
176
179
|
ui: MiningFollowVisualizerState;
|
|
177
180
|
waitingNote: string | null;
|
|
181
|
+
bitcoinRecoveryFirstFailureAtUnixMs: number | null;
|
|
182
|
+
bitcoinRecoveryFirstUnreachableAtUnixMs: number | null;
|
|
183
|
+
bitcoinRecoveryLastRestartAttemptAtUnixMs: number | null;
|
|
184
|
+
bitcoinRecoveryServiceInstanceId: string | null;
|
|
185
|
+
bitcoinRecoveryProcessId: number | null;
|
|
186
|
+
reconnectSettledUntilUnixMs: number | null;
|
|
187
|
+
tipSettledUntilUnixMs: number | null;
|
|
178
188
|
}
|
|
179
189
|
export interface RunForegroundMiningOptions extends RunnerDependencies {
|
|
180
190
|
dataDir: string;
|
|
181
191
|
databasePath: string;
|
|
192
|
+
clientVersion?: string | null;
|
|
193
|
+
updateAvailable?: boolean;
|
|
182
194
|
provider?: WalletSecretProvider;
|
|
183
195
|
prompter: WalletPrompter;
|
|
184
196
|
builtInSetupEnsured?: boolean;
|
|
@@ -224,6 +236,7 @@ export declare function resetMiningUiForTipForTesting(loopState: MiningLoopState
|
|
|
224
236
|
export declare function resolveSettledBoardForTesting(options: {
|
|
225
237
|
snapshotState: NonNullable<WalletReadContext["snapshot"]>["state"] | null | undefined;
|
|
226
238
|
snapshotTipHeight: number | null;
|
|
239
|
+
snapshotTipPreviousHashHex?: string | null;
|
|
227
240
|
nodeBestHeight: number | null;
|
|
228
241
|
}): {
|
|
229
242
|
settledBlockHeight: number | null;
|
|
@@ -273,7 +286,7 @@ export declare function createMiningPlanForTesting(options: {
|
|
|
273
286
|
referencedBlockHashInternal: Uint8Array;
|
|
274
287
|
targetBlockHeight: number;
|
|
275
288
|
};
|
|
276
|
-
conflictOutpoint: OutpointRecord;
|
|
289
|
+
conflictOutpoint: OutpointRecord | null;
|
|
277
290
|
allUtxos: Awaited<ReturnType<MiningRpcClient["listUnspent"]>>;
|
|
278
291
|
feeRateSatVb: number;
|
|
279
292
|
}): {
|
|
@@ -294,6 +307,19 @@ export declare function resolveMiningConflictOutpointForTesting(options: {
|
|
|
294
307
|
state: WalletStateV1;
|
|
295
308
|
allUtxos: Awaited<ReturnType<MiningRpcClient["listUnspent"]>>;
|
|
296
309
|
}): OutpointRecord | null;
|
|
310
|
+
export declare function buildMiningGenerationRequestForTesting(options: {
|
|
311
|
+
targetBlockHeight: number;
|
|
312
|
+
referencedBlockHashDisplay: string;
|
|
313
|
+
generatedAtUnixMs?: number;
|
|
314
|
+
requestId?: string;
|
|
315
|
+
domains: Array<{
|
|
316
|
+
domainId: number;
|
|
317
|
+
domainName: string;
|
|
318
|
+
requiredWords: [string, string, string, string, string];
|
|
319
|
+
}>;
|
|
320
|
+
domainExtraPrompts?: Record<string, string>;
|
|
321
|
+
extraPrompt?: string | null;
|
|
322
|
+
}): MiningSentenceGenerationRequest;
|
|
297
323
|
declare function publishCandidateOnce(options: {
|
|
298
324
|
readContext: WalletReadContext & {
|
|
299
325
|
localState: {
|
|
@@ -356,11 +382,15 @@ declare function runMiningLoop(options: {
|
|
|
356
382
|
fetchImpl?: typeof fetch;
|
|
357
383
|
openReadContext: typeof openWalletReadContext;
|
|
358
384
|
attachService: typeof attachOrStartManagedBitcoindService;
|
|
385
|
+
probeService?: typeof probeManagedBitcoindService;
|
|
386
|
+
stopService?: typeof stopManagedBitcoindService;
|
|
359
387
|
rpcFactory: (config: Parameters<typeof createRpcClient>[0]) => MiningRpcClient;
|
|
360
388
|
stdout?: {
|
|
361
389
|
write(chunk: string): void;
|
|
362
390
|
};
|
|
363
391
|
visualizer?: MiningFollowVisualizer;
|
|
392
|
+
nowImpl?: () => number;
|
|
393
|
+
sleepImpl?: typeof sleep;
|
|
364
394
|
}): Promise<void>;
|
|
365
395
|
declare function waitForBackgroundHealthy(paths: WalletRuntimePaths): Promise<MiningRuntimeStatusV1 | null>;
|
|
366
396
|
export declare function runForegroundMining(options: RunForegroundMiningOptions): Promise<void>;
|
|
@@ -384,6 +414,7 @@ export declare function handleDetectedMiningRuntimeResumeForTesting(options: {
|
|
|
384
414
|
detectedAtUnixMs: number;
|
|
385
415
|
openReadContext: typeof openWalletReadContext;
|
|
386
416
|
visualizer?: MiningFollowVisualizer;
|
|
417
|
+
loopState?: MiningLoopState;
|
|
387
418
|
}): Promise<void>;
|
|
388
419
|
export declare function takeOverMiningRuntimeForTesting(options: {
|
|
389
420
|
paths: WalletRuntimePaths;
|
|
@@ -406,11 +437,36 @@ export declare function performMiningCycleForTesting(options: {
|
|
|
406
437
|
fetchImpl?: typeof fetch;
|
|
407
438
|
openReadContext: typeof openWalletReadContext;
|
|
408
439
|
attachService: typeof attachOrStartManagedBitcoindService;
|
|
440
|
+
probeService?: typeof probeManagedBitcoindService;
|
|
441
|
+
stopService?: typeof stopManagedBitcoindService;
|
|
409
442
|
rpcFactory: (config: Parameters<typeof createRpcClient>[0]) => MiningRpcClient;
|
|
410
443
|
stdout?: {
|
|
411
444
|
write(chunk: string): void;
|
|
412
445
|
};
|
|
413
446
|
loopState?: MiningLoopState;
|
|
447
|
+
nowImpl?: () => number;
|
|
448
|
+
}): Promise<void>;
|
|
449
|
+
export declare function runMiningLoopForTesting(options: {
|
|
450
|
+
dataDir: string;
|
|
451
|
+
databasePath: string;
|
|
452
|
+
provider: WalletSecretProvider;
|
|
453
|
+
paths: WalletRuntimePaths;
|
|
454
|
+
runMode: "foreground" | "background";
|
|
455
|
+
backgroundWorkerPid: number | null;
|
|
456
|
+
backgroundWorkerRunId: string | null;
|
|
457
|
+
signal?: AbortSignal;
|
|
458
|
+
fetchImpl?: typeof fetch;
|
|
459
|
+
openReadContext: typeof openWalletReadContext;
|
|
460
|
+
attachService: typeof attachOrStartManagedBitcoindService;
|
|
461
|
+
probeService?: typeof probeManagedBitcoindService;
|
|
462
|
+
stopService?: typeof stopManagedBitcoindService;
|
|
463
|
+
rpcFactory: (config: Parameters<typeof createRpcClient>[0]) => MiningRpcClient;
|
|
464
|
+
stdout?: {
|
|
465
|
+
write(chunk: string): void;
|
|
466
|
+
};
|
|
467
|
+
visualizer?: MiningFollowVisualizer;
|
|
468
|
+
nowImpl?: () => number;
|
|
469
|
+
sleepImpl?: typeof sleep;
|
|
414
470
|
}): Promise<void>;
|
|
415
471
|
export declare function buildPrePublishStatusOverridesForTesting(options: {
|
|
416
472
|
state: WalletStateV1;
|