@toon-protocol/client-mcp 0.31.1 → 0.32.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 +48 -7
- package/dist/{chunk-MI2IWKHX.js → chunk-ALMTQYYJ.js} +104 -4
- package/dist/{chunk-MI2IWKHX.js.map → chunk-ALMTQYYJ.js.map} +1 -1
- package/dist/{chunk-SECSBCDA.js → chunk-AYZWVPNQ.js} +853 -187
- package/dist/chunk-AYZWVPNQ.js.map +1 -0
- package/dist/{chunk-JOGMX4IT.js → chunk-CPVOJ7FE.js} +130 -5
- package/dist/chunk-CPVOJ7FE.js.map +1 -0
- package/dist/daemon.js +7 -4
- package/dist/daemon.js.map +1 -1
- package/dist/index.d.ts +309 -72
- package/dist/index.js +12 -4
- package/dist/mcp.js +2 -2
- package/package.json +3 -3
- package/dist/chunk-JOGMX4IT.js.map +0 -1
- package/dist/chunk-SECSBCDA.js.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -53,6 +53,13 @@ interface StatusResponse {
|
|
|
53
53
|
buffered: number;
|
|
54
54
|
/** Active subscription ids. */
|
|
55
55
|
subscriptions: string[];
|
|
56
|
+
/**
|
|
57
|
+
* Error from the daemon-managed read proxy, if any. Set only in the
|
|
58
|
+
* btp-direct + relay-`.anyone` case where the daemon starts its own `anon`
|
|
59
|
+
* proxy for reads; a failure here means hidden-service reads are down while
|
|
60
|
+
* direct paid writes are unaffected.
|
|
61
|
+
*/
|
|
62
|
+
proxyError?: string;
|
|
56
63
|
};
|
|
57
64
|
/** Per-chain settlement status when a named `network` tier is configured. */
|
|
58
65
|
network?: ChainStatus[];
|
|
@@ -67,6 +74,12 @@ interface PublishRequest {
|
|
|
67
74
|
destination?: string;
|
|
68
75
|
/** Fee override in base units. Defaults to the daemon's configured fee. */
|
|
69
76
|
fee?: string;
|
|
77
|
+
/**
|
|
78
|
+
* Which apex (BTP write target) to publish through. Defaults to the
|
|
79
|
+
* config-seeded apex. Writes always go through BTP — never to a relay
|
|
80
|
+
* directly — so this selects among the registered apexes, not relays.
|
|
81
|
+
*/
|
|
82
|
+
btpUrl?: string;
|
|
70
83
|
}
|
|
71
84
|
interface PublishResponse {
|
|
72
85
|
eventId: string;
|
|
@@ -83,9 +96,17 @@ interface SubscribeRequest {
|
|
|
83
96
|
filters: NostrFilter | NostrFilter[];
|
|
84
97
|
/** Optional caller-supplied subscription id (else one is generated). */
|
|
85
98
|
subId?: string;
|
|
99
|
+
/**
|
|
100
|
+
* Restrict the subscription to a single relay. Omit to FAN OUT across every
|
|
101
|
+
* registered relay (the same subId is registered on each); reads merge into
|
|
102
|
+
* one ordered stream.
|
|
103
|
+
*/
|
|
104
|
+
relayUrl?: string;
|
|
86
105
|
}
|
|
87
106
|
interface SubscribeResponse {
|
|
88
107
|
subId: string;
|
|
108
|
+
/** The relays the subscription was registered on. */
|
|
109
|
+
relays: string[];
|
|
89
110
|
}
|
|
90
111
|
/** `GET /events` — drain buffered events for a subscription (free read). */
|
|
91
112
|
interface EventsQuery {
|
|
@@ -95,6 +116,8 @@ interface EventsQuery {
|
|
|
95
116
|
cursor?: number;
|
|
96
117
|
/** Max events to return (default 200). */
|
|
97
118
|
limit?: number;
|
|
119
|
+
/** Restrict the drain to events received from a single relay. */
|
|
120
|
+
relayUrl?: string;
|
|
98
121
|
}
|
|
99
122
|
interface EventsResponse {
|
|
100
123
|
events: NostrEvent[];
|
|
@@ -143,6 +166,11 @@ interface SwapRequest {
|
|
|
143
166
|
chainRecipient: string;
|
|
144
167
|
/** Split the swap into N equal packets (default 1). */
|
|
145
168
|
packetCount?: number;
|
|
169
|
+
/**
|
|
170
|
+
* Which apex to settle the source-asset claim through (default: the
|
|
171
|
+
* config-seeded apex). The mill must be a child peer of this apex.
|
|
172
|
+
*/
|
|
173
|
+
btpUrl?: string;
|
|
146
174
|
}
|
|
147
175
|
/** One accumulated, decrypted claim harvested from a single swap packet. */
|
|
148
176
|
interface SwapClaim {
|
|
@@ -183,6 +211,74 @@ interface SwapResponse {
|
|
|
183
211
|
/** First rejection message, if any. */
|
|
184
212
|
message?: string;
|
|
185
213
|
}
|
|
214
|
+
/** `POST /relays` — add a relay READ target (fans into all fan-out reads). */
|
|
215
|
+
interface AddRelayRequest {
|
|
216
|
+
/** Relay WS URL, e.g. `ws://host:7100` or a `.anyone` hidden service. */
|
|
217
|
+
relayUrl: string;
|
|
218
|
+
}
|
|
219
|
+
/** `DELETE /relays` — remove a relay read target. */
|
|
220
|
+
interface RemoveRelayRequest {
|
|
221
|
+
relayUrl: string;
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* `POST /apex` — add an apex WRITE target. Settlement params are DISCOVERED by
|
|
225
|
+
* reading the apex's `kind:10032` announcement off a relay, so the caller never
|
|
226
|
+
* hand-supplies chain/settlement details.
|
|
227
|
+
*/
|
|
228
|
+
interface AddApexRequest {
|
|
229
|
+
/** ILP address of the apex to add (e.g. `g.townhouse.town`). */
|
|
230
|
+
ilpAddress: string;
|
|
231
|
+
/**
|
|
232
|
+
* Relay to discover the apex's `kind:10032` on. If it isn't already a read
|
|
233
|
+
* target it is added (and persisted) first.
|
|
234
|
+
*/
|
|
235
|
+
relayUrl: string;
|
|
236
|
+
/** Optional apex Nostr pubkey to narrow the discovery filter (64-char hex). */
|
|
237
|
+
pubkey?: string;
|
|
238
|
+
/** Preferred settlement chain family; defaults to the apex's first chain. */
|
|
239
|
+
chain?: SettlementChain;
|
|
240
|
+
/** Child peers reached via this apex's channel (e.g. `["dvm","mill"]`). */
|
|
241
|
+
childPeers?: string[];
|
|
242
|
+
/** Per-write fee override (base units) for this apex. */
|
|
243
|
+
feePerEvent?: string;
|
|
244
|
+
}
|
|
245
|
+
interface AddApexResponse {
|
|
246
|
+
btpUrl: string;
|
|
247
|
+
destination: string;
|
|
248
|
+
chain: SettlementChain;
|
|
249
|
+
/** Whether the apex bootstrapped + opened a channel by the time we replied. */
|
|
250
|
+
ready: boolean;
|
|
251
|
+
}
|
|
252
|
+
/** `DELETE /apex` — remove an apex write target by its BTP URL. */
|
|
253
|
+
interface RemoveApexRequest {
|
|
254
|
+
btpUrl: string;
|
|
255
|
+
}
|
|
256
|
+
/** Status of one registered relay read target. */
|
|
257
|
+
interface RelayTargetStatus {
|
|
258
|
+
relayUrl: string;
|
|
259
|
+
connected: boolean;
|
|
260
|
+
buffered: number;
|
|
261
|
+
subscriptions: string[];
|
|
262
|
+
/** True for the permanent config-seeded relay (not removable). */
|
|
263
|
+
isDefault: boolean;
|
|
264
|
+
}
|
|
265
|
+
/** Status of one registered apex write target. */
|
|
266
|
+
interface ApexTargetStatus {
|
|
267
|
+
btpUrl: string;
|
|
268
|
+
destination: string;
|
|
269
|
+
chain: SettlementChain;
|
|
270
|
+
ready: boolean;
|
|
271
|
+
bootstrapping: boolean;
|
|
272
|
+
channelId?: string;
|
|
273
|
+
lastError?: string;
|
|
274
|
+
/** True for the permanent config-seeded apex (not removable). */
|
|
275
|
+
isDefault: boolean;
|
|
276
|
+
}
|
|
277
|
+
/** `GET /targets` — list every registered relay + apex target. */
|
|
278
|
+
interface TargetsResponse {
|
|
279
|
+
relays: RelayTargetStatus[];
|
|
280
|
+
apexes: ApexTargetStatus[];
|
|
281
|
+
}
|
|
186
282
|
/** Uniform error envelope returned with non-2xx responses. */
|
|
187
283
|
interface ErrorResponse {
|
|
188
284
|
error: string;
|
|
@@ -248,6 +344,11 @@ declare class ControlClient {
|
|
|
248
344
|
}>;
|
|
249
345
|
channels(): Promise<ChannelsResponse>;
|
|
250
346
|
swap(body: SwapRequest): Promise<SwapResponse>;
|
|
347
|
+
targets(): Promise<TargetsResponse>;
|
|
348
|
+
addRelay(body: AddRelayRequest): Promise<TargetsResponse>;
|
|
349
|
+
removeRelay(body: RemoveRelayRequest): Promise<TargetsResponse>;
|
|
350
|
+
addApex(body: AddApexRequest): Promise<AddApexResponse>;
|
|
351
|
+
removeApex(body: RemoveApexRequest): Promise<TargetsResponse>;
|
|
251
352
|
private request;
|
|
252
353
|
}
|
|
253
354
|
|
|
@@ -296,6 +397,14 @@ interface RelaySubscriptionOptions {
|
|
|
296
397
|
* object it is used directly and this is not called.
|
|
297
398
|
*/
|
|
298
399
|
decodeEvent?: (raw: string) => NostrEvent;
|
|
400
|
+
/**
|
|
401
|
+
* Invoked once per newly-buffered (de-duplicated) event. The daemon uses this
|
|
402
|
+
* to feed a runner-level MERGED buffer across many relays — so a fan-out read
|
|
403
|
+
* (`toon_read` with no relayUrl) draws from one ordered stream with a single
|
|
404
|
+
* scalar cursor. The relay still keeps its own buffer for `bufferedCount` /
|
|
405
|
+
* single-relay drains.
|
|
406
|
+
*/
|
|
407
|
+
onEvent?: (subId: string, event: NostrEvent) => void;
|
|
299
408
|
/** Optional logger. */
|
|
300
409
|
logger?: (msg: string) => void;
|
|
301
410
|
}
|
|
@@ -314,6 +423,7 @@ declare class RelaySubscription {
|
|
|
314
423
|
private readonly log;
|
|
315
424
|
private readonly wsFactory;
|
|
316
425
|
private readonly decodeEvent?;
|
|
426
|
+
private readonly onEvent?;
|
|
317
427
|
/** Active subscriptions: subId -> filters (re-sent on every (re)connect). */
|
|
318
428
|
private readonly subscriptions;
|
|
319
429
|
/** Ring buffer of received events, ordered by ascending `seq`. */
|
|
@@ -406,6 +516,15 @@ interface DaemonConfigFile {
|
|
|
406
516
|
mnemonic?: string;
|
|
407
517
|
mnemonicAccountIndex?: number;
|
|
408
518
|
keystorePath?: string;
|
|
519
|
+
/**
|
|
520
|
+
* Set when the daemon auto-generated the keystore (#251 first-run onboarding).
|
|
521
|
+
* Such a keystore is encrypted with a default password so the identity reloads
|
|
522
|
+
* across restarts without `TOON_CLIENT_KEYSTORE_PASSWORD`. A user-imported
|
|
523
|
+
* keystore leaves this unset and still requires the env password.
|
|
524
|
+
*/
|
|
525
|
+
keystoreAutoPassword?: boolean;
|
|
526
|
+
/** Human-facing onboarding notes written by first-run scaffolding (ignored at runtime). */
|
|
527
|
+
_help?: Record<string, string>;
|
|
409
528
|
/** BTP WebSocket URL of the apex/connector. */
|
|
410
529
|
btpUrl?: string;
|
|
411
530
|
/** Transport: `direct` or a `socks5h://` proxy for `.anyone` hosts. */
|
|
@@ -462,6 +581,15 @@ interface ResolvedDaemonConfig {
|
|
|
462
581
|
httpPort: number;
|
|
463
582
|
relayUrl: string;
|
|
464
583
|
socksProxy?: string;
|
|
584
|
+
/**
|
|
585
|
+
* When true the daemon must start its OWN managed `anon` proxy for free reads
|
|
586
|
+
* — the btp-direct + relay-`.anyone` case the ToonClient does not cover (it
|
|
587
|
+
* only auto-starts a proxy for a `.anyone` btpUrl). `readProxySocksPort` is the
|
|
588
|
+
* loopback port to bind; `socksProxy` already points the relay at it.
|
|
589
|
+
*/
|
|
590
|
+
manageReadProxy: boolean;
|
|
591
|
+
/** Loopback SOCKS port for the daemon-managed read proxy (when `manageReadProxy`). */
|
|
592
|
+
readProxySocksPort?: number;
|
|
465
593
|
destination: string;
|
|
466
594
|
feePerEvent: bigint;
|
|
467
595
|
apex?: ApexNegotiationConfig;
|
|
@@ -475,6 +603,14 @@ interface ResolvedDaemonConfig {
|
|
|
475
603
|
toonClientConfig: ToonClientConfig;
|
|
476
604
|
network?: string;
|
|
477
605
|
}
|
|
606
|
+
/**
|
|
607
|
+
* Password used to encrypt an auto-generated keystore (#251 first-run
|
|
608
|
+
* onboarding) when `TOON_CLIENT_KEYSTORE_PASSWORD` is unset. At-rest
|
|
609
|
+
* obfuscation only — its purpose is letting the daemon reload the identity
|
|
610
|
+
* across restarts with no env var. Users wanting a real password re-import the
|
|
611
|
+
* keystore and set the env var.
|
|
612
|
+
*/
|
|
613
|
+
declare const DEFAULT_KEYSTORE_PASSWORD = "toon-client-default";
|
|
478
614
|
/** Default config directory: `~/.toon-client`. Overridable via env. */
|
|
479
615
|
declare function configDir(): string;
|
|
480
616
|
/** Default config file path. */
|
|
@@ -492,18 +628,23 @@ declare function resolveMnemonic(file: DaemonConfigFile): string;
|
|
|
492
628
|
declare function resolveConfig(file: DaemonConfigFile): ResolvedDaemonConfig;
|
|
493
629
|
|
|
494
630
|
/**
|
|
495
|
-
* ClientRunner — the daemon's connection owner.
|
|
496
|
-
*
|
|
497
|
-
*
|
|
498
|
-
* HTTP routes map onto.
|
|
631
|
+
* ClientRunner — the daemon's connection owner. The TOON client is 1-to-MANY:
|
|
632
|
+
* it can write through several apexes (each a `ToonClient` + BTP session +
|
|
633
|
+
* payment channel) and read from several relays (each a `RelaySubscription`).
|
|
499
634
|
*
|
|
500
|
-
*
|
|
501
|
-
*
|
|
502
|
-
*
|
|
503
|
-
*
|
|
635
|
+
* • Writes go through BTP, never to a relay directly — `publish`/`swap` select
|
|
636
|
+
* an apex (default: the config-seeded one).
|
|
637
|
+
* • Reads FAN OUT — `subscribe`/`getEvents` apply across every relay and merge
|
|
638
|
+
* into one ordered stream with a single scalar cursor (the runner owns the
|
|
639
|
+
* merged buffer; each `RelaySubscription` mirrors new events into it).
|
|
504
640
|
*
|
|
505
|
-
*
|
|
506
|
-
*
|
|
641
|
+
* Targets are added at runtime (`addRelay`/`addApex`), persisted to
|
|
642
|
+
* `targets.json`, replayed on the next boot, and removable. The config-seeded
|
|
643
|
+
* relay + apex are the permanent DEFAULT targets and cannot be removed.
|
|
644
|
+
*
|
|
645
|
+
* Each apex bootstraps asynchronously and non-blocking: the connection comes up
|
|
646
|
+
* in the background (the managed anon proxy alone can take 30–90s). Until ready,
|
|
647
|
+
* writes against it report `bootstrapping` so tools surface "retry".
|
|
507
648
|
*/
|
|
508
649
|
|
|
509
650
|
/** The subset of `ToonClient` the runner depends on. */
|
|
@@ -549,98 +690,151 @@ interface ToonClientLike {
|
|
|
549
690
|
message?: string;
|
|
550
691
|
}>;
|
|
551
692
|
}
|
|
693
|
+
/** A started managed proxy: just the teardown handle the runner needs. */
|
|
694
|
+
interface ManagedProxyHandle {
|
|
695
|
+
stop(): Promise<void>;
|
|
696
|
+
}
|
|
697
|
+
/** Starts a managed `anon` read proxy on a loopback SOCKS port. */
|
|
698
|
+
type StartReadProxy = (opts: {
|
|
699
|
+
socksPort: number;
|
|
700
|
+
log?: (msg: string) => void;
|
|
701
|
+
}) => Promise<ManagedProxyHandle>;
|
|
702
|
+
/** Builds a `ToonClient` (or a fake) for a given resolved client config. */
|
|
703
|
+
type CreateClient = (config: ToonClientConfig) => ToonClientLike;
|
|
704
|
+
/** Builds a `RelaySubscription` for a given relay URL + optional read proxy. */
|
|
705
|
+
type CreateRelay = (opts: {
|
|
706
|
+
relayUrl: string;
|
|
707
|
+
socksProxy?: string;
|
|
708
|
+
onEvent: (subId: string, event: NostrEvent) => void;
|
|
709
|
+
logger?: (msg: string) => void;
|
|
710
|
+
}) => RelaySubscription;
|
|
552
711
|
interface ClientRunnerDeps {
|
|
553
712
|
config: ResolvedDaemonConfig;
|
|
554
|
-
/** Factory producing the (real or fake) ToonClient. */
|
|
555
|
-
createClient:
|
|
556
|
-
/** Factory producing
|
|
557
|
-
createRelay?:
|
|
713
|
+
/** Factory producing the (real or fake) ToonClient for a client config. */
|
|
714
|
+
createClient: CreateClient;
|
|
715
|
+
/** Factory producing a relay subscription (defaults to the real one). */
|
|
716
|
+
createRelay?: CreateRelay;
|
|
717
|
+
/**
|
|
718
|
+
* Starts the daemon-managed read proxy (defaults to the real
|
|
719
|
+
* `startManagedAnonProxy`). Injected so tests avoid the anon download/spawn.
|
|
720
|
+
*/
|
|
721
|
+
startReadProxy?: StartReadProxy;
|
|
558
722
|
logger?: (msg: string) => void;
|
|
723
|
+
/** Path to the dynamic-targets store (tests override). */
|
|
724
|
+
targetsPath?: string;
|
|
559
725
|
}
|
|
560
726
|
declare class ClientRunner {
|
|
561
727
|
private readonly config;
|
|
562
|
-
private readonly
|
|
563
|
-
private readonly
|
|
728
|
+
private readonly createClient;
|
|
729
|
+
private readonly createRelay;
|
|
730
|
+
private readonly startReadProxy;
|
|
564
731
|
private readonly log;
|
|
732
|
+
private readonly targetsPath?;
|
|
565
733
|
private readonly startedAt;
|
|
566
|
-
|
|
567
|
-
private
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
734
|
+
/** Apex write targets, keyed by btpUrl. */
|
|
735
|
+
private readonly apexes;
|
|
736
|
+
/** Relay read targets, keyed by relayUrl. */
|
|
737
|
+
private readonly relays;
|
|
738
|
+
/** Runner-level merged read buffer across all relays (de-duped by event.id). */
|
|
739
|
+
private merged;
|
|
740
|
+
private readonly mergedSeen;
|
|
741
|
+
private mergedSeq;
|
|
742
|
+
/**
|
|
743
|
+
* Fan-out subscriptions (no relayUrl restriction): replayed onto relays added
|
|
744
|
+
* later so a new relay immediately participates in existing reads.
|
|
745
|
+
*/
|
|
746
|
+
private readonly fanoutSubs;
|
|
747
|
+
private subIdCounter;
|
|
748
|
+
private readonly defaultBtpUrl;
|
|
749
|
+
private readonly defaultRelayUrl;
|
|
750
|
+
/** Teardown for the daemon-managed read proxy (btp-direct + relay-`.anyone`). */
|
|
751
|
+
private stopReadProxy;
|
|
752
|
+
private readProxyError;
|
|
571
753
|
private stopped;
|
|
754
|
+
private started;
|
|
572
755
|
constructor(deps: ClientRunnerDeps);
|
|
573
756
|
/**
|
|
574
|
-
*
|
|
575
|
-
*
|
|
576
|
-
*
|
|
757
|
+
* Start the live connections: the shared read proxy, every relay socket, the
|
|
758
|
+
* default apex bootstrap (non-blocking), then replay persisted dynamic
|
|
759
|
+
* targets. Returns immediately; apexes become ready asynchronously.
|
|
577
760
|
*/
|
|
578
761
|
start(): void;
|
|
579
|
-
/**
|
|
762
|
+
/** Await the default apex's bootstrap (kicking it off if not already running). */
|
|
580
763
|
bootstrap(): Promise<void>;
|
|
581
764
|
/**
|
|
582
|
-
*
|
|
583
|
-
*
|
|
584
|
-
*
|
|
585
|
-
* peer→channelId mapping, so a naive `openChannel()` after restart re-deposits
|
|
586
|
-
* into a fresh channel and reverts on-chain. We persist the channelId here and,
|
|
587
|
-
* when present, `trackChannel()` the live channel (which rehydrates the nonce
|
|
588
|
-
* from the channel store) — no on-chain write, watermark continues.
|
|
765
|
+
* Build + register a relay (idempotent by URL), wiring its events into the
|
|
766
|
+
* merged buffer and replaying active fan-out subscriptions. Does NOT start the
|
|
767
|
+
* socket — callers start it (so construction stays side-effect-free for tests).
|
|
589
768
|
*/
|
|
590
|
-
private
|
|
769
|
+
private registerRelay;
|
|
591
770
|
/**
|
|
592
|
-
*
|
|
593
|
-
*
|
|
594
|
-
* peers (no relay-based discovery). Mirrors the docker entrypoint's approach.
|
|
771
|
+
* Add a relay read target at runtime. `.anyone` relays reuse the managed read
|
|
772
|
+
* proxy (started here if needed). Persisted unless `persist` is false.
|
|
595
773
|
*/
|
|
596
|
-
|
|
774
|
+
addRelay(relayUrl: string, persist?: boolean): Promise<void>;
|
|
775
|
+
/** Remove a relay read target. The config-seeded default cannot be removed. */
|
|
776
|
+
removeRelay(relayUrl: string): void;
|
|
777
|
+
/** Mirror a newly-buffered relay event into the merged cross-relay buffer. */
|
|
778
|
+
private pushMerged;
|
|
779
|
+
/**
|
|
780
|
+
* Register a free-read subscription. With no `relayUrl` it FANS OUT across
|
|
781
|
+
* every relay (and onto relays added later); with one it targets that relay.
|
|
782
|
+
*/
|
|
783
|
+
subscribe(req: SubscribeRequest): SubscribeResponse;
|
|
784
|
+
/** Drain merged events newer than the cursor (free read), optionally scoped. */
|
|
785
|
+
getEvents(query: EventsQuery): EventsResponse;
|
|
786
|
+
private makeApex;
|
|
597
787
|
/**
|
|
598
|
-
*
|
|
599
|
-
*
|
|
600
|
-
*
|
|
601
|
-
* child the ILP destination addresses; but `ToonClient.resolvePeerId` keys off
|
|
602
|
-
* the destination's last segment (`town`/`dvm`/`mill`), so without this each
|
|
603
|
-
* child would (a) fail the "no negotiation for peer" guard and (b) try to open
|
|
604
|
-
* a SECOND on-chain channel to the same apex receive (which reverts —
|
|
605
|
-
* channel-exists). So: inject the same apex negotiation under each child peer
|
|
606
|
-
* AND pre-map its peer→channel to the already-open apex channel so
|
|
607
|
-
* `ensureChannel` reuses it (no second open; one shared nonce sequence).
|
|
788
|
+
* Bootstrap one apex (memoized): start, inject negotiation, open/resume the
|
|
789
|
+
* channel, route child peers. Concurrent callers await the same in-flight
|
|
790
|
+
* work rather than re-running it.
|
|
608
791
|
*/
|
|
792
|
+
private bootstrapApex;
|
|
793
|
+
private doBootstrapApex;
|
|
794
|
+
/**
|
|
795
|
+
* Add an apex write target. Settlement params are discovered by reading the
|
|
796
|
+
* apex's kind:10032 off the given relay (added first if unknown). Persisted.
|
|
797
|
+
*/
|
|
798
|
+
addApex(req: AddApexRequest): Promise<AddApexResponse>;
|
|
799
|
+
/** Build + register + bootstrap an apex from a (persisted) target record. */
|
|
800
|
+
private instantiateApex;
|
|
801
|
+
/** Remove an apex write target. The config-seeded default cannot be removed. */
|
|
802
|
+
removeApex(btpUrl: string): Promise<void>;
|
|
803
|
+
/** Derive a per-apex ToonClientConfig from the default (shared identity/transport). */
|
|
804
|
+
private deriveApexClientConfig;
|
|
805
|
+
private apexChannelStorePathFor;
|
|
806
|
+
private replayPersistedTargets;
|
|
807
|
+
private ensureReadProxy;
|
|
808
|
+
private bringUpReadProxy;
|
|
809
|
+
/** Open the apex channel — or, on a restart, RESUME the existing one. */
|
|
810
|
+
private openOrResumeApexChannel;
|
|
811
|
+
/** Inject the apex settlement negotiation directly into its ToonClient. */
|
|
812
|
+
private injectApexNegotiation;
|
|
813
|
+
/** Route apex CHILD peers (dvm/mill) through the SAME apex payment channel. */
|
|
609
814
|
private routeChildPeersThroughApexChannel;
|
|
815
|
+
private defaultApex;
|
|
816
|
+
/** Whether any apex has finished bootstrapping. */
|
|
610
817
|
isReady(): boolean;
|
|
611
818
|
isBootstrapping(): boolean;
|
|
612
819
|
getStatus(): StatusResponse;
|
|
613
|
-
/**
|
|
820
|
+
/** Full registry of relay + apex targets with per-target status. */
|
|
821
|
+
getTargets(): TargetsResponse;
|
|
822
|
+
/** Pay-to-write a single event through the selected (or default) apex. */
|
|
614
823
|
publish(req: PublishRequest): Promise<PublishResponse>;
|
|
615
|
-
/**
|
|
616
|
-
|
|
617
|
-
/** Drain buffered events newer than the cursor (free read). */
|
|
618
|
-
getEvents(query: EventsQuery): EventsResponse;
|
|
619
|
-
/** Open (or return) a payment channel for a destination. */
|
|
620
|
-
openChannel(destination?: string): Promise<{
|
|
824
|
+
/** Open (or return) a payment channel on the selected (or default) apex. */
|
|
825
|
+
openChannel(destination?: string, btpUrl?: string): Promise<{
|
|
621
826
|
channelId: string;
|
|
622
827
|
}>;
|
|
623
|
-
/** List tracked channels with
|
|
828
|
+
/** List tracked channels across ALL apexes with nonce + cumulative amount. */
|
|
624
829
|
getChannels(): ChannelsResponse;
|
|
625
|
-
/**
|
|
626
|
-
* Swap source asset → target asset against a mill peer.
|
|
627
|
-
*
|
|
628
|
-
* Uses SDK `streamSwap`, which builds a NIP-59 gift-wrapped kind:20032 swap
|
|
629
|
-
* rumor per packet and sends it over the open BTP session. The source-asset
|
|
630
|
-
* balance proof is signed by the ToonClient's ChannelManager against the apex
|
|
631
|
-
* channel — so the mill peer MUST be routed via `apexChildPeers` (otherwise
|
|
632
|
-
* there is no channel to sign against and the mill rejects with F99).
|
|
633
|
-
*
|
|
634
|
-
* A fresh ephemeral gift-wrap key is generated per swap (used for sealing the
|
|
635
|
-
* rumor AND decrypting the FULFILL claims) — independent of the daemon's
|
|
636
|
-
* settlement identity, so callers never need to expose a key.
|
|
637
|
-
*/
|
|
830
|
+
/** Swap source→target asset against a mill peer via the selected apex. */
|
|
638
831
|
swap(req: SwapRequest): Promise<SwapResponse>;
|
|
639
|
-
/** Graceful teardown
|
|
832
|
+
/** Graceful teardown: close every relay + stop every apex client + read proxy. */
|
|
640
833
|
stop(): Promise<void>;
|
|
641
|
-
private
|
|
834
|
+
private selectApex;
|
|
835
|
+
private assertApexReady;
|
|
642
836
|
}
|
|
643
|
-
/** Thrown by paid-write operations while the
|
|
837
|
+
/** Thrown by paid-write operations while the target apex is not yet ready. */
|
|
644
838
|
declare class NotReadyError extends Error {
|
|
645
839
|
readonly retryable = true;
|
|
646
840
|
constructor(message: string);
|
|
@@ -650,6 +844,49 @@ declare class PublishRejectedError extends Error {
|
|
|
650
844
|
constructor(message: string);
|
|
651
845
|
}
|
|
652
846
|
|
|
847
|
+
/**
|
|
848
|
+
* First-run onboarding for `toon-clientd`.
|
|
849
|
+
*
|
|
850
|
+
* A brand-new user (`npx`/plugin install) has no identity and no config file.
|
|
851
|
+
* Before the daemon resolves its config it calls {@link scaffoldFirstRun},
|
|
852
|
+
* which makes a fresh install start with zero manual setup:
|
|
853
|
+
*
|
|
854
|
+
* 1. **Identity** — if no mnemonic source is configured (no
|
|
855
|
+
* `TOON_CLIENT_MNEMONIC`, no `keystorePath`, no `mnemonic`), generate a
|
|
856
|
+
* fresh BIP-39 mnemonic, encrypt it to `~/.toon-client/keystore.json`, and
|
|
857
|
+
* record `keystorePath` (+ `keystoreAutoPassword`) in `config.json`. The
|
|
858
|
+
* keystore is encrypted with `TOON_CLIENT_KEYSTORE_PASSWORD` when set, else
|
|
859
|
+
* a default password so the identity survives restarts with no env var.
|
|
860
|
+
* The mnemonic + derived addresses are printed ONCE for backup.
|
|
861
|
+
* 2. **Transport scaffolding** — ensure `config.json` carries the transport
|
|
862
|
+
* knobs (`btpUrl`/`relayUrl`/`managedAnonProxy`) plus a `_help` block
|
|
863
|
+
* documenting direct-vs-`.anyone` selection, so the user can see what to
|
|
864
|
+
* point at.
|
|
865
|
+
*
|
|
866
|
+
* This is all idempotent: on later runs an identity already exists, so nothing
|
|
867
|
+
* is regenerated and the config is left untouched.
|
|
868
|
+
*/
|
|
869
|
+
|
|
870
|
+
/** Default keystore path: `~/.toon-client/keystore.json`. */
|
|
871
|
+
declare function defaultKeystorePath(): string;
|
|
872
|
+
/**
|
|
873
|
+
* True when SOME mnemonic source is already configured: the env var, a keystore
|
|
874
|
+
* path, or an inline mnemonic. When false the daemon would otherwise hard-fail
|
|
875
|
+
* with "No mnemonic configured".
|
|
876
|
+
*/
|
|
877
|
+
declare function hasConfiguredIdentity(file: DaemonConfigFile): boolean;
|
|
878
|
+
interface ScaffoldOptions {
|
|
879
|
+
/** Config file path (defaults to `TOON_CLIENT_CONFIG` / `~/.toon-client/config.json`). */
|
|
880
|
+
configPath?: string;
|
|
881
|
+
/** Log sink (defaults to stderr, since stdout may carry MCP/JSON). */
|
|
882
|
+
log?: (msg: string) => void;
|
|
883
|
+
}
|
|
884
|
+
/**
|
|
885
|
+
* Generate + persist an identity and/or scaffold transport config on first run.
|
|
886
|
+
* Safe to call on every startup — it only acts when something is missing.
|
|
887
|
+
*/
|
|
888
|
+
declare function scaffoldFirstRun(opts?: ScaffoldOptions): Promise<void>;
|
|
889
|
+
|
|
653
890
|
/**
|
|
654
891
|
* Fastify route registration for the `toon-clientd` control plane. Each route
|
|
655
892
|
* is a thin adapter: parse/validate the request, call the `ClientRunner`, map
|
|
@@ -725,4 +962,4 @@ declare const TOOL_DEFINITIONS: ToolDefinition[];
|
|
|
725
962
|
*/
|
|
726
963
|
declare function dispatchTool(client: ControlClient, name: string, args: Record<string, unknown>): Promise<ToolResult>;
|
|
727
964
|
|
|
728
|
-
export { type ApexNegotiationConfig, type ChainStatus, type ChannelInfo, type ChannelsResponse, ClientRunner, type ClientRunnerDeps, ControlApiError, ControlClient, type ControlClientOptions, type DaemonConfigFile, DaemonUnreachableError, type DrainResult, type ErrorResponse, type EventsQuery, type EventsResponse, type MinimalWebSocket, type NostrFilter, NotReadyError, type OpenChannelRequest, PublishRejectedError, type PublishRequest, type PublishResponse, RelaySubscription, type RelaySubscriptionOptions, type ResolvedDaemonConfig, type SettlementChain, type StatusResponse, type SubscribeRequest, type SubscribeResponse, type SwapClaim, type SwapRequest, type SwapResponse, TOOL_DEFINITIONS, type ToolDefinition, type ToolResult, type ToonClientLike, type WebSocketFactory, acquireLock, configDir, defaultConfigPath, dispatchTool, isDaemonRunning, isProcessAlive, readConfigFile, readPid, registerRoutes, releaseLock, resolveConfig, resolveMnemonic, spawnDaemonDetached, waitForReady };
|
|
965
|
+
export { type AddApexRequest, type AddApexResponse, type AddRelayRequest, type ApexNegotiationConfig, type ApexTargetStatus, type ChainStatus, type ChannelInfo, type ChannelsResponse, ClientRunner, type ClientRunnerDeps, ControlApiError, ControlClient, type ControlClientOptions, DEFAULT_KEYSTORE_PASSWORD, type DaemonConfigFile, DaemonUnreachableError, type DrainResult, type ErrorResponse, type EventsQuery, type EventsResponse, type MinimalWebSocket, type NostrFilter, NotReadyError, type OpenChannelRequest, PublishRejectedError, type PublishRequest, type PublishResponse, RelaySubscription, type RelaySubscriptionOptions, type RelayTargetStatus, type RemoveApexRequest, type RemoveRelayRequest, type ResolvedDaemonConfig, type SettlementChain, type StatusResponse, type SubscribeRequest, type SubscribeResponse, type SwapClaim, type SwapRequest, type SwapResponse, TOOL_DEFINITIONS, type TargetsResponse, type ToolDefinition, type ToolResult, type ToonClientLike, type WebSocketFactory, acquireLock, configDir, defaultConfigPath, defaultKeystorePath, dispatchTool, hasConfiguredIdentity, isDaemonRunning, isProcessAlive, readConfigFile, readPid, registerRoutes, releaseLock, resolveConfig, resolveMnemonic, scaffoldFirstRun, spawnDaemonDetached, waitForReady };
|
package/dist/index.js
CHANGED
|
@@ -4,15 +4,19 @@ import {
|
|
|
4
4
|
NotReadyError,
|
|
5
5
|
PublishRejectedError,
|
|
6
6
|
RelaySubscription,
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
defaultKeystorePath,
|
|
8
|
+
hasConfiguredIdentity,
|
|
9
|
+
registerRoutes,
|
|
10
|
+
scaffoldFirstRun
|
|
11
|
+
} from "./chunk-AYZWVPNQ.js";
|
|
9
12
|
import {
|
|
10
13
|
TOOL_DEFINITIONS,
|
|
11
14
|
dispatchTool
|
|
12
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-CPVOJ7FE.js";
|
|
13
16
|
import {
|
|
14
17
|
ControlApiError,
|
|
15
18
|
ControlClient,
|
|
19
|
+
DEFAULT_KEYSTORE_PASSWORD,
|
|
16
20
|
DaemonUnreachableError,
|
|
17
21
|
acquireLock,
|
|
18
22
|
configDir,
|
|
@@ -26,7 +30,7 @@ import {
|
|
|
26
30
|
resolveMnemonic,
|
|
27
31
|
spawnDaemonDetached,
|
|
28
32
|
waitForReady
|
|
29
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-ALMTQYYJ.js";
|
|
30
34
|
import "./chunk-32QD72IL.js";
|
|
31
35
|
import "./chunk-QTDCFXPF.js";
|
|
32
36
|
import "./chunk-LR7W2ISE.js";
|
|
@@ -37,6 +41,7 @@ export {
|
|
|
37
41
|
ClientRunner,
|
|
38
42
|
ControlApiError,
|
|
39
43
|
ControlClient,
|
|
44
|
+
DEFAULT_KEYSTORE_PASSWORD,
|
|
40
45
|
DaemonUnreachableError,
|
|
41
46
|
NotReadyError,
|
|
42
47
|
PublishRejectedError,
|
|
@@ -45,7 +50,9 @@ export {
|
|
|
45
50
|
acquireLock,
|
|
46
51
|
configDir,
|
|
47
52
|
defaultConfigPath,
|
|
53
|
+
defaultKeystorePath,
|
|
48
54
|
dispatchTool,
|
|
55
|
+
hasConfiguredIdentity,
|
|
49
56
|
isDaemonRunning,
|
|
50
57
|
isProcessAlive,
|
|
51
58
|
readConfigFile,
|
|
@@ -54,6 +61,7 @@ export {
|
|
|
54
61
|
releaseLock,
|
|
55
62
|
resolveConfig,
|
|
56
63
|
resolveMnemonic,
|
|
64
|
+
scaffoldFirstRun,
|
|
57
65
|
spawnDaemonDetached,
|
|
58
66
|
waitForReady
|
|
59
67
|
};
|
package/dist/mcp.js
CHANGED
|
@@ -3,7 +3,7 @@ import { createRequire as __cr } from 'module'; const require = __cr(import.meta
|
|
|
3
3
|
import {
|
|
4
4
|
TOOL_DEFINITIONS,
|
|
5
5
|
dispatchTool
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-CPVOJ7FE.js";
|
|
7
7
|
import {
|
|
8
8
|
ControlClient,
|
|
9
9
|
defaultConfigPath,
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
readConfigFile,
|
|
12
12
|
spawnDaemonDetached,
|
|
13
13
|
waitForReady
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-ALMTQYYJ.js";
|
|
15
15
|
import "./chunk-32QD72IL.js";
|
|
16
16
|
import "./chunk-QTDCFXPF.js";
|
|
17
17
|
import "./chunk-LR7W2ISE.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@toon-protocol/client-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.32.0",
|
|
4
4
|
"description": "Always-on local daemon + MCP server letting a Claude agent (Desktop or Code) act as a TOON Protocol client: pay-to-write publishing, free reads, channel/balance management, and mill swaps.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Jonathan Green",
|
|
@@ -45,8 +45,8 @@
|
|
|
45
45
|
"typescript": "^5.3.0",
|
|
46
46
|
"vitest": "^1.0.0",
|
|
47
47
|
"@toon-protocol/client": "0.9.1",
|
|
48
|
-
"@toon-protocol/
|
|
49
|
-
"@toon-protocol/
|
|
48
|
+
"@toon-protocol/core": "1.4.1",
|
|
49
|
+
"@toon-protocol/sdk": "0.5.0"
|
|
50
50
|
},
|
|
51
51
|
"engines": {
|
|
52
52
|
"node": ">=20"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/mcp-tools.ts"],"sourcesContent":["/**\n * MCP tool definitions + dispatch. The MCP server is a thin proxy: each tool\n * maps to a `toon-clientd` control-plane call. This module is the testable core\n * (no stdio / SDK transport) so the tool→HTTP mapping and the\n * \"bootstrapping — retry\" handling can be unit-tested directly.\n */\n\nimport { ControlApiError, DaemonUnreachableError } from './control-client.js';\nimport type { ControlClient } from './control-client.js';\nimport type {\n NostrFilter,\n PublishRequest,\n SwapRequest,\n} from './control-api.js';\n\n/** A JSON-Schema-described MCP tool. */\nexport interface ToolDefinition {\n name: string;\n description: string;\n inputSchema: Record<string, unknown>;\n}\n\n/** MCP tool-call result shape (subset of the SDK's CallToolResult). */\nexport interface ToolResult {\n content: { type: 'text'; text: string }[];\n isError?: boolean;\n}\n\nexport const TOOL_DEFINITIONS: ToolDefinition[] = [\n {\n name: 'toon_status',\n description:\n 'Report TOON client daemon health: bootstrapping/ready state, transport, ' +\n 'relay connection, buffered-event count, and per-chain settlement status.',\n inputSchema: {\n type: 'object',\n properties: {},\n additionalProperties: false,\n },\n },\n {\n name: 'toon_identity',\n description:\n \"Return this client's public identity (Nostr pubkey + EVM/Solana/Mina \" +\n 'addresses). Never returns private keys.',\n inputSchema: {\n type: 'object',\n properties: {},\n additionalProperties: false,\n },\n },\n {\n name: 'toon_publish',\n description:\n 'Pay-to-write: publish a fully-signed Nostr event to the TOON network. ' +\n 'Signs an off-chain payment-channel claim and forwards it over BTP. ' +\n 'Returns the event id, channel id, and the advanced channel nonce.',\n inputSchema: {\n type: 'object',\n properties: {\n event: {\n type: 'object',\n description:\n 'A fully-signed Nostr event (must include id, pubkey, sig, kind, ' +\n 'created_at, tags, content).',\n },\n destination: {\n type: 'string',\n description:\n 'Optional ILP destination override (default: the apex/town).',\n },\n fee: {\n type: 'string',\n description:\n 'Optional fee override in base units (default: daemon config).',\n },\n },\n required: ['event'],\n additionalProperties: false,\n },\n },\n {\n name: 'toon_subscribe',\n description:\n 'Free read: register a persistent town-relay subscription with NIP-01 ' +\n 'filter(s). Returns a subscription id to drain with toon_read.',\n inputSchema: {\n type: 'object',\n properties: {\n filters: {\n description: 'A NIP-01 filter object or an array of OR-ed filters.',\n },\n subId: { type: 'string', description: 'Optional caller-supplied id.' },\n },\n required: ['filters'],\n additionalProperties: false,\n },\n },\n {\n name: 'toon_read',\n description:\n 'Free read: drain buffered events newer than a cursor. Pass back the ' +\n 'returned cursor to fetch only events received since the last read.',\n inputSchema: {\n type: 'object',\n properties: {\n subId: { type: 'string', description: 'Restrict to one subscription.' },\n cursor: {\n type: 'number',\n description: 'Cursor from a prior toon_read.',\n },\n limit: {\n type: 'number',\n description: 'Max events to return (default 200).',\n },\n },\n additionalProperties: false,\n },\n },\n {\n name: 'toon_open_channel',\n description:\n 'Open (or return the existing) payment channel for a destination. ' +\n 'Channels open lazily on first publish; use this to pre-open.',\n inputSchema: {\n type: 'object',\n properties: {\n destination: {\n type: 'string',\n description: 'ILP destination (default: apex).',\n },\n },\n additionalProperties: false,\n },\n },\n {\n name: 'toon_channels',\n description:\n 'List tracked payment channels with their nonce watermark and cumulative ' +\n 'transferred amount.',\n inputSchema: {\n type: 'object',\n properties: {},\n additionalProperties: false,\n },\n },\n {\n name: 'toon_swap',\n description:\n 'Pay a mill peer (asset A) to receive asset B plus a signed target-chain ' +\n 'claim. Builds the NIP-59 gift-wrapped kind:20032 swap rumor and streams ' +\n 'it; the source-asset claim is signed against the open apex channel (the ' +\n 'mill must be routed via apexChildPeers). Returns the accumulated, ' +\n 'decrypted target-chain claim(s) and settlement metadata.',\n inputSchema: {\n type: 'object',\n properties: {\n destination: {\n type: 'string',\n description: 'Mill peer ILP destination (e.g. g.townhouse.mill).',\n },\n amount: {\n type: 'string',\n description: 'Total source-asset amount to swap, source micro-units.',\n },\n millPubkey: {\n type: 'string',\n description:\n \"Mill's 64-char lowercase hex Nostr pubkey (gift-wrap recipient).\",\n },\n pair: {\n type: 'object',\n description:\n 'The swap pair (from kind:10032 discovery or operator-supplied): ' +\n '{ from:{assetCode,assetScale,chain}, to:{...}, rate, minAmount?, maxAmount? }.',\n },\n chainRecipient: {\n type: 'string',\n description:\n \"Sender's payout address on pair.to.chain (EVM 0x-hex / Solana / Mina base58).\",\n },\n packetCount: {\n type: 'number',\n description: 'Split the swap into N equal packets (default 1).',\n },\n },\n required: [\n 'destination',\n 'amount',\n 'millPubkey',\n 'pair',\n 'chainRecipient',\n ],\n additionalProperties: false,\n },\n },\n];\n\n/**\n * Dispatch an MCP tool call to the daemon control plane. Always resolves with a\n * `ToolResult` (errors are encoded as `isError: true` text, not thrown, so the\n * agent sees a readable message). A retryable error (daemon still\n * bootstrapping) yields a clear \"retry shortly\" message.\n */\nexport async function dispatchTool(\n client: ControlClient,\n name: string,\n args: Record<string, unknown>\n): Promise<ToolResult> {\n try {\n switch (name) {\n case 'toon_status':\n return ok(await client.status());\n case 'toon_identity': {\n const s = await client.status();\n return ok({\n identity: s.identity,\n ready: s.ready,\n bootstrapping: s.bootstrapping,\n });\n }\n case 'toon_publish':\n return ok(await client.publish(args as unknown as PublishRequest));\n case 'toon_subscribe':\n return ok(\n await client.subscribe({\n filters: args['filters'] as NostrFilter | NostrFilter[],\n ...(typeof args['subId'] === 'string'\n ? { subId: args['subId'] }\n : {}),\n })\n );\n case 'toon_read':\n return ok(\n await client.events({\n ...(typeof args['subId'] === 'string'\n ? { subId: args['subId'] }\n : {}),\n ...(typeof args['cursor'] === 'number'\n ? { cursor: args['cursor'] }\n : {}),\n ...(typeof args['limit'] === 'number'\n ? { limit: args['limit'] }\n : {}),\n })\n );\n case 'toon_open_channel':\n return ok(\n await client.openChannel(\n typeof args['destination'] === 'string'\n ? { destination: args['destination'] }\n : {}\n )\n );\n case 'toon_channels':\n return ok(await client.channels());\n case 'toon_swap':\n return ok(\n await client.swap({\n destination: String(args['destination']),\n amount: String(args['amount']),\n millPubkey: String(args['millPubkey']),\n pair: args['pair'] as SwapRequest['pair'],\n chainRecipient: String(args['chainRecipient']),\n ...(typeof args['packetCount'] === 'number'\n ? { packetCount: args['packetCount'] }\n : {}),\n })\n );\n default:\n return err(`Unknown tool: ${name}`);\n }\n } catch (e) {\n if (e instanceof ControlApiError && e.retryable) {\n return err(\n `TOON client is still bootstrapping (the anon proxy / BTP session can take ` +\n `30–90s) — retry shortly. (${e.message})`\n );\n }\n if (e instanceof DaemonUnreachableError) {\n return err(\n `TOON client daemon is not reachable at ${e.baseUrl}. It may have failed ` +\n `to start — check ~/.toon-client/daemon.log.`\n );\n }\n if (e instanceof ControlApiError) {\n return err(`${e.message}${e.detail ? `: ${e.detail}` : ''}`);\n }\n return err(e instanceof Error ? e.message : String(e));\n }\n}\n\nfunction ok(data: unknown): ToolResult {\n return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };\n}\n\nfunction err(message: string): ToolResult {\n return { content: [{ type: 'text', text: message }], isError: true };\n}\n"],"mappings":"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","names":[]}
|