@cogcoin/client 0.5.2 → 0.5.4

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 (58) hide show
  1. package/README.md +14 -3
  2. package/dist/app-paths.d.ts +1 -0
  3. package/dist/app-paths.js +2 -0
  4. package/dist/art/wallet.txt +10 -0
  5. package/dist/bitcoind/indexer-daemon.d.ts +9 -0
  6. package/dist/bitcoind/indexer-daemon.js +51 -14
  7. package/dist/bitcoind/service.d.ts +9 -0
  8. package/dist/bitcoind/service.js +65 -24
  9. package/dist/bitcoind/testing.d.ts +2 -2
  10. package/dist/bitcoind/testing.js +2 -2
  11. package/dist/cli/commands/service-runtime.d.ts +2 -0
  12. package/dist/cli/commands/service-runtime.js +432 -0
  13. package/dist/cli/commands/wallet-admin.js +227 -132
  14. package/dist/cli/commands/wallet-mutation.js +597 -580
  15. package/dist/cli/context.js +23 -1
  16. package/dist/cli/mutation-json.d.ts +17 -1
  17. package/dist/cli/mutation-json.js +42 -0
  18. package/dist/cli/output.js +113 -2
  19. package/dist/cli/parse.d.ts +1 -1
  20. package/dist/cli/parse.js +69 -4
  21. package/dist/cli/preview-json.d.ts +19 -1
  22. package/dist/cli/preview-json.js +31 -0
  23. package/dist/cli/prompt.js +40 -12
  24. package/dist/cli/runner.js +12 -0
  25. package/dist/cli/signals.d.ts +1 -0
  26. package/dist/cli/signals.js +44 -0
  27. package/dist/cli/types.d.ts +24 -2
  28. package/dist/cli/types.js +6 -0
  29. package/dist/cli/wallet-format.js +3 -0
  30. package/dist/cli/workflow-hints.d.ts +1 -0
  31. package/dist/cli/workflow-hints.js +3 -0
  32. package/dist/wallet/fs/lock.d.ts +2 -0
  33. package/dist/wallet/fs/lock.js +32 -0
  34. package/dist/wallet/lifecycle.d.ts +30 -1
  35. package/dist/wallet/lifecycle.js +394 -40
  36. package/dist/wallet/material.d.ts +2 -0
  37. package/dist/wallet/material.js +8 -1
  38. package/dist/wallet/mining/control.js +4 -4
  39. package/dist/wallet/mining/runner.js +2 -2
  40. package/dist/wallet/mnemonic-art.d.ts +2 -0
  41. package/dist/wallet/mnemonic-art.js +54 -0
  42. package/dist/wallet/read/context.d.ts +2 -0
  43. package/dist/wallet/read/context.js +64 -17
  44. package/dist/wallet/reset.d.ts +61 -0
  45. package/dist/wallet/reset.js +781 -0
  46. package/dist/wallet/runtime.d.ts +1 -0
  47. package/dist/wallet/runtime.js +1 -0
  48. package/dist/wallet/state/explicit-lock.d.ts +4 -0
  49. package/dist/wallet/state/explicit-lock.js +19 -0
  50. package/dist/wallet/tx/anchor.js +1 -0
  51. package/dist/wallet/tx/cog.js +3 -0
  52. package/dist/wallet/tx/domain-admin.js +1 -0
  53. package/dist/wallet/tx/domain-market.js +3 -0
  54. package/dist/wallet/tx/field.js +2 -0
  55. package/dist/wallet/tx/register.js +1 -0
  56. package/dist/wallet/tx/reputation.js +1 -0
  57. package/dist/wallet/types.d.ts +5 -0
  58. package/package.json +3 -3
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # `@cogcoin/client`
2
2
 
3
- `@cogcoin/client@0.5.2` is the store-backed Cogcoin client package for applications that want a local wallet, durable SQLite-backed state, and a managed Bitcoin Core integration around `@cogcoin/indexer`. It publishes the reusable client APIs, the SQLite adapter, the managed `bitcoind` integration, and the first-party `cogcoin` CLI in one package.
3
+ `@cogcoin/client@0.5.4` is the store-backed Cogcoin client package for applications that want a local wallet, durable SQLite-backed state, and a managed Bitcoin Core integration around `@cogcoin/indexer`. It publishes the reusable client APIs, the SQLite adapter, the managed `bitcoind` integration, and the first-party `cogcoin` CLI in one package.
4
4
 
5
5
  Use Node 22 or newer.
6
6
 
@@ -32,6 +32,8 @@ npx cogcoin sync
32
32
 
33
33
  Verify the installed genesis artifacts before using the client in a production implementation.
34
34
  The installed package provides the `cogcoin` command for local wallet setup, sync, reads, writes, and mining workflows.
35
+ Provider-backed local wallets unlock on demand by default; `cogcoin wallet lock` suppresses that behavior until `cogcoin unlock` is run again.
36
+ Passphrase-wrapped wallet-state flows still require explicit passphrase-based access.
35
37
 
36
38
  ## Dependency Surface
37
39
 
@@ -72,13 +74,19 @@ Managed node subpath:
72
74
 
73
75
  The installed `cogcoin` command covers the first-party local wallet and node workflow:
74
76
 
75
- - wallet lifecycle commands such as `init`, `unlock`, `lock`, `repair`, `export`, and `import`
76
- - sync and service commands such as `status`, `sync`, and `follow`
77
+ - wallet lifecycle commands such as `init`, `restore`, `unlock`, `lock`, `repair`, `export`, and `import`
78
+ - sync and service commands such as `status`, `sync`, `follow`, `bitcoin start`, `bitcoin stop`, `bitcoin status`, `indexer start`, `indexer stop`, and `indexer status`
77
79
  - domain and field commands such as `register`, `anchor`, `show`, `domains`, `fields`, `buy`, `sell`, and `transfer`
78
80
  - COG and reputation commands such as `send`, `cog lock`, `claim`, `reclaim`, `rep give`, and `rep revoke`
79
81
  - mining and hook commands such as `mine`, `mine start`, `mine stop`, `mine status`, `mine log`, `mine setup`, and `hooks status`
80
82
 
81
83
  The CLI also supports stable `--output json` and `--output preview-json` envelopes on the commands that advertise machine-readable output.
84
+ Ordinary `sync`, `follow`, and wallet-aware read/status flows detach from the managed Bitcoin and indexer services on exit instead of stopping them.
85
+ Use the explicit `bitcoin ...` and `indexer ...` commands when you want direct service inspection or start/stop control.
86
+ For provider-backed local wallets, normal reads, mutations, export, and mining setup flows auto-materialize a local unlock session when the wallet is not explicitly locked.
87
+ `cogcoin restore` and `cogcoin wallet restore` rebuild a fresh local wallet from a 24-word English BIP39 mnemonic and recreate the managed Core wallet replica.
88
+ Run `cogcoin sync` afterward to bootstrap the managed Bitcoin/indexer state.
89
+ `cogcoin wallet import <path>` remains the richer encrypted-archive restore path that preserves more local continuity metadata than mnemonic-only restore.
82
90
 
83
91
  ## SQLite Store
84
92
 
@@ -119,6 +127,9 @@ The managed `bitcoind` client also exposes:
119
127
  - `onProgress(event)` for structured bootstrap/sync progress updates
120
128
  - `progressOutput: "auto" | "tty" | "none"` for the built-in scroll-train terminal progress UI
121
129
 
130
+ At the CLI layer, managed services are persistent until explicitly stopped.
131
+ `cogcoin bitcoin start` starts managed `bitcoind`, `cogcoin bitcoin stop` stops managed `bitcoind` and the paired indexer, `cogcoin indexer start` starts the managed indexer and auto-starts `bitcoind` first when needed, and `cogcoin indexer stop` stops only the indexer.
132
+
122
133
  The default TTY progress renderer ships with the package and uses the bundled scroll, train, and quote assets from `dist/art/*` and `dist/writing_quotes.json`.
123
134
 
124
135
  ## Published Contents
@@ -18,6 +18,7 @@ export interface CogcoinResolvedPaths {
18
18
  walletStatePath: string;
19
19
  walletStateBackupPath: string;
20
20
  walletUnlockSessionPath: string;
21
+ walletExplicitLockPath: string;
21
22
  walletControlLockPath: string;
22
23
  bitcoindLockPath: string;
23
24
  bitcoindStatusPath: string;
package/dist/app-paths.js CHANGED
@@ -64,6 +64,7 @@ export function resolveCogcoinPathsForTesting(resolution = {}) {
64
64
  const walletStatePath = joinForPlatform(platform, walletStateDirectory, "wallet-state.enc");
65
65
  const walletStateBackupPath = joinForPlatform(platform, walletStateDirectory, "wallet-state.enc.bak");
66
66
  const walletUnlockSessionPath = joinForPlatform(platform, runtimeRoot, "wallet-unlock-session.enc");
67
+ const walletExplicitLockPath = joinForPlatform(platform, runtimeRoot, "wallet-explicit-lock.json");
67
68
  const walletControlLockPath = joinForPlatform(platform, runtimeRoot, "wallet-control.lock");
68
69
  const bitcoindLockPath = joinForPlatform(platform, runtimeRoot, "bitcoind.lock");
69
70
  const bitcoindStatusPath = joinForPlatform(platform, runtimeRoot, "bitcoind-status.json");
@@ -91,6 +92,7 @@ export function resolveCogcoinPathsForTesting(resolution = {}) {
91
92
  walletStatePath,
92
93
  walletStateBackupPath,
93
94
  walletUnlockSessionPath,
95
+ walletExplicitLockPath,
94
96
  walletControlLockPath,
95
97
  bitcoindLockPath,
96
98
  bitcoindStatusPath,
@@ -0,0 +1,10 @@
1
+ ⛭ Write this down. Keep it secret, keep it safe. ⛭
2
+ ▐▀▀▀▀▀▀▚ ╔──────────────────────────────────────────────────────────────────╗
3
+ ▛▞▀▀▀▀▀▀▚ │ │
4
+ ▌▝▀▀▀▀▀▀▀▌ │ 1.achieved 6.achieved 11.achieved 16.achieved 21.achieved │
5
+ ▌ ▗▙▙ ▌ │ 2.achieved 7.achieved 12.achieved 17.achieved 22.achieved │
6
+ ▌ ▐ ▌ ▌ │ 3.achieved 8.achieved 13.achieved 18.achieved 23.achieved │
7
+ ▌ ▐▀▀▚ ▌ │ 4.achieved 9.achieved 14.achieved 19.achieved 24.achieved │
8
+ ▌ ▐▄▄▞ ▌ │ 5.achieved 10.achieved 15.achieved 20.achieved │
9
+ ▌ ▘▘ ▌ │ │
10
+ ▝▀▀▀▀▀▀▀▀▘ ╚──────────────────────────────────────────────────────────────────╝
@@ -73,6 +73,10 @@ export interface IndexerDaemonProbeResult {
73
73
  client: IndexerDaemonClient | null;
74
74
  error: string | null;
75
75
  }
76
+ export interface IndexerDaemonStopResult {
77
+ status: "stopped" | "not-running";
78
+ walletRootId: string;
79
+ }
76
80
  export interface CoherentIndexerSnapshotLease {
77
81
  payload: IndexerSnapshotPayload;
78
82
  status: ManagedIndexerDaemonStatus;
@@ -92,6 +96,11 @@ export declare function attachOrStartIndexerDaemon(options: {
92
96
  walletRootId?: string;
93
97
  startupTimeoutMs?: number;
94
98
  }): Promise<IndexerDaemonClient>;
99
+ export declare function stopIndexerDaemonService(options: {
100
+ dataDir: string;
101
+ walletRootId?: string;
102
+ shutdownTimeoutMs?: number;
103
+ }): Promise<IndexerDaemonStopResult>;
95
104
  export declare function shutdownIndexerDaemonForTesting(options: {
96
105
  dataDir: string;
97
106
  walletRootId?: string;
@@ -39,6 +39,20 @@ function sleep(ms) {
39
39
  setTimeout(resolve, ms);
40
40
  });
41
41
  }
42
+ async function waitForProcessExit(pid, timeoutMs, errorCode) {
43
+ const deadline = Date.now() + timeoutMs;
44
+ while (Date.now() < deadline) {
45
+ if (!await isProcessAlive(pid)) {
46
+ return;
47
+ }
48
+ await sleep(50);
49
+ }
50
+ throw new Error(errorCode);
51
+ }
52
+ async function clearIndexerDaemonRuntimeArtifacts(paths) {
53
+ await rm(paths.indexerDaemonStatusPath, { force: true }).catch(() => undefined);
54
+ await rm(paths.indexerDaemonSocketPath, { force: true }).catch(() => undefined);
55
+ }
42
56
  function createIndexerDaemonClient(socketPath) {
43
57
  async function sendRequest(request) {
44
58
  return new Promise((resolve, reject) => {
@@ -357,26 +371,49 @@ export async function attachOrStartIndexerDaemon(options) {
357
371
  throw error;
358
372
  }
359
373
  }
360
- export async function shutdownIndexerDaemonForTesting(options) {
374
+ export async function stopIndexerDaemonService(options) {
361
375
  const walletRootId = options.walletRootId ?? UNINITIALIZED_WALLET_ROOT_ID;
362
376
  const paths = resolveManagedServicePaths(options.dataDir, walletRootId);
363
- const status = await readJsonFile(paths.indexerDaemonStatusPath);
364
- if (status?.processId !== null && status?.processId !== undefined) {
377
+ const lock = await acquireFileLock(paths.indexerDaemonLockPath, {
378
+ purpose: "indexer-daemon-stop",
379
+ walletRootId,
380
+ dataDir: options.dataDir,
381
+ });
382
+ try {
383
+ const status = await readJsonFile(paths.indexerDaemonStatusPath);
384
+ const processId = status?.processId ?? null;
385
+ if (status === null || processId === null || !await isProcessAlive(processId)) {
386
+ await clearIndexerDaemonRuntimeArtifacts(paths);
387
+ return {
388
+ status: "not-running",
389
+ walletRootId,
390
+ };
391
+ }
365
392
  try {
366
- process.kill(status.processId, "SIGTERM");
367
- const deadline = Date.now() + 5_000;
368
- while (Date.now() < deadline) {
369
- if (!await isProcessAlive(status.processId)) {
370
- break;
371
- }
372
- await sleep(50);
373
- }
393
+ process.kill(processId, "SIGTERM");
374
394
  }
375
- catch {
376
- // ignore stale pid cleanup failures
395
+ catch (error) {
396
+ if (!(error instanceof Error && "code" in error && error.code === "ESRCH")) {
397
+ throw error;
398
+ }
377
399
  }
400
+ await waitForProcessExit(processId, options.shutdownTimeoutMs ?? 5_000, "indexer_daemon_stop_timeout");
401
+ await clearIndexerDaemonRuntimeArtifacts(paths);
402
+ return {
403
+ status: "stopped",
404
+ walletRootId,
405
+ };
378
406
  }
379
- await rm(paths.indexerDaemonSocketPath, { force: true }).catch(() => undefined);
407
+ finally {
408
+ await lock.release();
409
+ }
410
+ }
411
+ export async function shutdownIndexerDaemonForTesting(options) {
412
+ await stopIndexerDaemonService(options).catch(async () => {
413
+ const walletRootId = options.walletRootId ?? UNINITIALIZED_WALLET_ROOT_ID;
414
+ const paths = resolveManagedServicePaths(options.dataDir, walletRootId);
415
+ await rm(paths.indexerDaemonSocketPath, { force: true }).catch(() => undefined);
416
+ });
380
417
  }
381
418
  export async function readIndexerDaemonStatusForTesting(options) {
382
419
  const walletRootId = options.walletRootId ?? UNINITIALIZED_WALLET_ROOT_ID;
@@ -25,11 +25,20 @@ export interface ManagedBitcoindServiceProbeResult {
25
25
  status: ManagedBitcoindObservedStatus | null;
26
26
  error: string | null;
27
27
  }
28
+ export interface ManagedBitcoindServiceStopResult {
29
+ status: "stopped" | "not-running";
30
+ walletRootId: string;
31
+ }
28
32
  export declare function createManagedWalletReplica(rpc: ManagedWalletReplicaRpc, walletRootId: string, options?: {
29
33
  managedWalletPassphrase?: string;
30
34
  }): Promise<ManagedCoreWalletReplicaStatus>;
31
35
  export declare function probeManagedBitcoindService(options: ManagedBitcoindServiceOptions): Promise<ManagedBitcoindServiceProbeResult>;
32
36
  export declare function attachOrStartManagedBitcoindService(options: ManagedBitcoindServiceOptions): Promise<ManagedBitcoindNodeHandle>;
37
+ export declare function stopManagedBitcoindService(options: {
38
+ dataDir: string;
39
+ walletRootId?: string;
40
+ shutdownTimeoutMs?: number;
41
+ }): Promise<ManagedBitcoindServiceStopResult>;
33
42
  export declare function readManagedBitcoindServiceStatusForTesting(dataDir: string, walletRootId?: string): Promise<ManagedBitcoindObservedStatus | null>;
34
43
  export declare function shutdownManagedBitcoindServiceForTesting(options: {
35
44
  dataDir: string;
@@ -21,6 +21,16 @@ function sleep(ms) {
21
21
  setTimeout(resolve, ms);
22
22
  });
23
23
  }
24
+ async function waitForProcessExit(pid, timeoutMs, errorCode) {
25
+ const deadline = Date.now() + timeoutMs;
26
+ while (Date.now() < deadline) {
27
+ if (!await isProcessAlive(pid)) {
28
+ return;
29
+ }
30
+ await sleep(250);
31
+ }
32
+ throw new Error(errorCode);
33
+ }
24
34
  function getWalletReplicaName(walletRootId) {
25
35
  return `cogcoin-${walletRootId}`.replace(/[^a-zA-Z0-9._-]+/g, "-").slice(0, 63);
26
36
  }
@@ -488,6 +498,12 @@ async function writeBitcoindStatus(paths, status) {
488
498
  p2pPort: status.p2pPort,
489
499
  });
490
500
  }
501
+ async function clearManagedBitcoindRuntimeArtifacts(paths) {
502
+ await rm(paths.bitcoindStatusPath, { force: true }).catch(() => undefined);
503
+ await rm(paths.bitcoindPidPath, { force: true }).catch(() => undefined);
504
+ await rm(paths.bitcoindReadyPath, { force: true }).catch(() => undefined);
505
+ await rm(paths.bitcoindWalletStatusPath, { force: true }).catch(() => undefined);
506
+ }
491
507
  async function refreshManagedBitcoindStatus(status, paths, options) {
492
508
  const nowUnixMs = Date.now();
493
509
  const rpc = createRpcClient(status.rpc);
@@ -699,37 +715,62 @@ export async function attachOrStartManagedBitcoindService(options) {
699
715
  throw error;
700
716
  }
701
717
  }
702
- export async function readManagedBitcoindServiceStatusForTesting(dataDir, walletRootId = UNINITIALIZED_WALLET_ROOT_ID) {
703
- const paths = resolveManagedServicePaths(dataDir, walletRootId);
704
- return readJsonFile(paths.bitcoindStatusPath);
705
- }
706
- export async function shutdownManagedBitcoindServiceForTesting(options) {
718
+ export async function stopManagedBitcoindService(options) {
707
719
  const walletRootId = options.walletRootId ?? UNINITIALIZED_WALLET_ROOT_ID;
708
720
  const paths = resolveManagedServicePaths(options.dataDir, walletRootId);
709
- const status = await readJsonFile(paths.bitcoindStatusPath);
710
- if (status === null) {
711
- return;
712
- }
713
- const rpc = createRpcClient(status.rpc);
721
+ const lock = await acquireFileLock(paths.bitcoindLockPath, {
722
+ purpose: "managed-bitcoind-stop",
723
+ walletRootId,
724
+ dataDir: options.dataDir,
725
+ });
714
726
  try {
715
- await rpc.stop();
716
- }
717
- catch {
718
- if (status.processId !== null) {
727
+ const status = await readJsonFile(paths.bitcoindStatusPath);
728
+ const processId = status?.processId ?? null;
729
+ if (status === null || processId === null || !await isProcessAlive(processId)) {
730
+ await clearManagedBitcoindRuntimeArtifacts(paths);
731
+ return {
732
+ status: "not-running",
733
+ walletRootId,
734
+ };
735
+ }
736
+ const rpc = createRpcClient(status.rpc);
737
+ try {
738
+ await rpc.stop();
739
+ }
740
+ catch {
719
741
  try {
720
- process.kill(status.processId, "SIGTERM");
742
+ process.kill(processId, "SIGTERM");
721
743
  }
722
- catch {
723
- // ignore
744
+ catch (error) {
745
+ if (!(error instanceof Error && "code" in error && error.code === "ESRCH")) {
746
+ throw error;
747
+ }
724
748
  }
725
749
  }
750
+ await waitForProcessExit(processId, options.shutdownTimeoutMs ?? DEFAULT_SHUTDOWN_TIMEOUT_MS, "managed_bitcoind_service_stop_timeout");
751
+ await clearManagedBitcoindRuntimeArtifacts(paths);
752
+ return {
753
+ status: "stopped",
754
+ walletRootId,
755
+ };
726
756
  }
727
- const deadline = Date.now() + (options.shutdownTimeoutMs ?? DEFAULT_SHUTDOWN_TIMEOUT_MS);
728
- while (Date.now() < deadline) {
729
- if (!await isProcessAlive(status.processId)) {
730
- break;
731
- }
732
- await sleep(250);
757
+ finally {
758
+ await lock.release();
733
759
  }
734
- await rm(paths.bitcoindReadyPath, { force: true }).catch(() => undefined);
760
+ }
761
+ export async function readManagedBitcoindServiceStatusForTesting(dataDir, walletRootId = UNINITIALIZED_WALLET_ROOT_ID) {
762
+ const paths = resolveManagedServicePaths(dataDir, walletRootId);
763
+ return readJsonFile(paths.bitcoindStatusPath);
764
+ }
765
+ export async function shutdownManagedBitcoindServiceForTesting(options) {
766
+ await stopManagedBitcoindService({
767
+ dataDir: options.dataDir,
768
+ walletRootId: options.walletRootId,
769
+ shutdownTimeoutMs: options.shutdownTimeoutMs,
770
+ }).catch(async (error) => {
771
+ const walletRootId = options.walletRootId ?? UNINITIALIZED_WALLET_ROOT_ID;
772
+ const paths = resolveManagedServicePaths(options.dataDir, walletRootId);
773
+ await rm(paths.bitcoindReadyPath, { force: true }).catch(() => undefined);
774
+ throw error;
775
+ });
735
776
  }
@@ -1,8 +1,8 @@
1
1
  export { openManagedBitcoindClientInternal } from "./client.js";
2
- export { attachOrStartIndexerDaemon, readIndexerDaemonStatusForTesting, shutdownIndexerDaemonForTesting, } from "./indexer-daemon.js";
2
+ export { attachOrStartIndexerDaemon, readIndexerDaemonStatusForTesting, stopIndexerDaemonService, shutdownIndexerDaemonForTesting, } from "./indexer-daemon.js";
3
3
  export { normalizeRpcBlock } from "./normalize.js";
4
4
  export { BitcoinRpcClient } from "./rpc.js";
5
- export { attachOrStartManagedBitcoindService, readManagedBitcoindServiceStatusForTesting, shutdownManagedBitcoindServiceForTesting, } from "./service.js";
5
+ export { attachOrStartManagedBitcoindService, readManagedBitcoindServiceStatusForTesting, stopManagedBitcoindService, shutdownManagedBitcoindServiceForTesting, } from "./service.js";
6
6
  export { AssumeUtxoBootstrapController, DEFAULT_SNAPSHOT_METADATA, createBootstrapStateForTesting, downloadSnapshotFileForTesting, loadBootstrapStateForTesting, resolveBootstrapPathsForTesting, saveBootstrapStateForTesting, validateSnapshotFileForTesting, waitForHeadersForTesting, } from "./bootstrap.js";
7
7
  export { buildBitcoindArgsForTesting, createRpcClient, launchManagedBitcoindNode, resolveDefaultBitcoindDataDirForTesting, validateNodeConfigForTesting, } from "./node.js";
8
8
  export { ManagedProgressController, TtyProgressRenderer, advanceFollowSceneStateForTesting, createFollowSceneStateForTesting, createBootstrapProgressForTesting, formatCompactFollowAgeLabelForTesting, loadBannerArtForTesting, loadScrollArtForTesting, loadTrainCarArtForTesting, loadTrainArtForTesting, loadTrainSmokeArtForTesting, formatProgressLineForTesting, formatQuoteLineForTesting, renderArtFrameForTesting, renderCompletionFrameForTesting, renderFollowFrameForTesting, renderIntroFrameForTesting, resolveCompletionMessageForTesting, resolveIntroMessageForTesting, resolveStatusFieldTextForTesting, setFollowBlockTimeForTesting, setFollowBlockTimesForTesting, syncFollowSceneStateForTesting, } from "./progress.js";
@@ -1,8 +1,8 @@
1
1
  export { openManagedBitcoindClientInternal } from "./client.js";
2
- export { attachOrStartIndexerDaemon, readIndexerDaemonStatusForTesting, shutdownIndexerDaemonForTesting, } from "./indexer-daemon.js";
2
+ export { attachOrStartIndexerDaemon, readIndexerDaemonStatusForTesting, stopIndexerDaemonService, shutdownIndexerDaemonForTesting, } from "./indexer-daemon.js";
3
3
  export { normalizeRpcBlock } from "./normalize.js";
4
4
  export { BitcoinRpcClient } from "./rpc.js";
5
- export { attachOrStartManagedBitcoindService, readManagedBitcoindServiceStatusForTesting, shutdownManagedBitcoindServiceForTesting, } from "./service.js";
5
+ export { attachOrStartManagedBitcoindService, readManagedBitcoindServiceStatusForTesting, stopManagedBitcoindService, shutdownManagedBitcoindServiceForTesting, } from "./service.js";
6
6
  export { AssumeUtxoBootstrapController, DEFAULT_SNAPSHOT_METADATA, createBootstrapStateForTesting, downloadSnapshotFileForTesting, loadBootstrapStateForTesting, resolveBootstrapPathsForTesting, saveBootstrapStateForTesting, validateSnapshotFileForTesting, waitForHeadersForTesting, } from "./bootstrap.js";
7
7
  export { buildBitcoindArgsForTesting, createRpcClient, launchManagedBitcoindNode, resolveDefaultBitcoindDataDirForTesting, validateNodeConfigForTesting, } from "./node.js";
8
8
  export { ManagedProgressController, TtyProgressRenderer, advanceFollowSceneStateForTesting, createFollowSceneStateForTesting, createBootstrapProgressForTesting, formatCompactFollowAgeLabelForTesting, loadBannerArtForTesting, loadScrollArtForTesting, loadTrainCarArtForTesting, loadTrainArtForTesting, loadTrainSmokeArtForTesting, formatProgressLineForTesting, formatQuoteLineForTesting, renderArtFrameForTesting, renderCompletionFrameForTesting, renderFollowFrameForTesting, renderIntroFrameForTesting, resolveCompletionMessageForTesting, resolveIntroMessageForTesting, resolveStatusFieldTextForTesting, setFollowBlockTimeForTesting, setFollowBlockTimesForTesting, syncFollowSceneStateForTesting, } from "./progress.js";
@@ -0,0 +1,2 @@
1
+ import type { ParsedCliArgs, RequiredCliRunnerContext } from "../types.js";
2
+ export declare function runServiceRuntimeCommand(parsed: ParsedCliArgs, context: RequiredCliRunnerContext): Promise<number>;