@toon-protocol/client-mcp 0.10.7 → 0.10.8
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/dist/app/index.html +65 -60
- package/dist/{chunk-XYR3ACYX.js → chunk-3ZBC2HUB.js} +35 -2
- package/dist/{chunk-XYR3ACYX.js.map → chunk-3ZBC2HUB.js.map} +1 -1
- package/dist/{chunk-NDIIPZB4.js → chunk-ADBNZA5O.js} +2 -2
- package/dist/{chunk-CF4X4QPI.js → chunk-XFRMAETF.js} +2 -2
- package/dist/daemon.js +15 -3
- package/dist/daemon.js.map +1 -1
- package/dist/index.d.ts +8 -0
- package/dist/index.js +3 -3
- package/dist/mcp.js +2 -2
- package/package.json +3 -3
- /package/dist/{chunk-NDIIPZB4.js.map → chunk-ADBNZA5O.js.map} +0 -0
- /package/dist/{chunk-CF4X4QPI.js.map → chunk-XFRMAETF.js.map} +0 -0
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
isEventExpired,
|
|
16
16
|
parseIlpPeerInfo,
|
|
17
17
|
readConfigFile
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-3ZBC2HUB.js";
|
|
19
19
|
import {
|
|
20
20
|
__require
|
|
21
21
|
} from "./chunk-F22GNSF6.js";
|
|
@@ -2662,4 +2662,4 @@ export {
|
|
|
2662
2662
|
PublishRejectedError,
|
|
2663
2663
|
registerRoutes
|
|
2664
2664
|
};
|
|
2665
|
-
//# sourceMappingURL=chunk-
|
|
2665
|
+
//# sourceMappingURL=chunk-ADBNZA5O.js.map
|
|
@@ -2,7 +2,7 @@ import { createRequire as __cr } from 'module'; const require = __cr(import.meta
|
|
|
2
2
|
import {
|
|
3
3
|
ControlApiError,
|
|
4
4
|
DaemonUnreachableError
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-3ZBC2HUB.js";
|
|
6
6
|
|
|
7
7
|
// ../views/dist/tool-names.js
|
|
8
8
|
var PUBLISH_TOOL = "toon_publish_unsigned";
|
|
@@ -1301,4 +1301,4 @@ export {
|
|
|
1301
1301
|
TOOL_DEFINITIONS,
|
|
1302
1302
|
dispatchTool
|
|
1303
1303
|
};
|
|
1304
|
-
//# sourceMappingURL=chunk-
|
|
1304
|
+
//# sourceMappingURL=chunk-XFRMAETF.js.map
|
package/dist/daemon.js
CHANGED
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
ClientRunner,
|
|
5
5
|
registerRoutes,
|
|
6
6
|
scaffoldFirstRun
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-ADBNZA5O.js";
|
|
8
8
|
import {
|
|
9
9
|
ControlClient,
|
|
10
10
|
ToonClient,
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
resolveConfig,
|
|
18
18
|
spawnDaemonDetached,
|
|
19
19
|
waitForReady
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-3ZBC2HUB.js";
|
|
21
21
|
import "./chunk-32QD72IL.js";
|
|
22
22
|
import "./chunk-DLYE6U2Z.js";
|
|
23
23
|
import "./chunk-LR7W2ISE.js";
|
|
@@ -42,7 +42,19 @@ async function runForeground() {
|
|
|
42
42
|
createClient: (clientConfig) => new ToonClient(clientConfig),
|
|
43
43
|
logger: log
|
|
44
44
|
});
|
|
45
|
-
const app = Fastify({
|
|
45
|
+
const app = Fastify({
|
|
46
|
+
logger: false,
|
|
47
|
+
// Keep idle keep-alive sockets open longer than the MCP-side undici client
|
|
48
|
+
// would ever pool one (its keepAliveMaxTimeout default is 600s). The client
|
|
49
|
+
// calls this localhost control plane infrequently, so with Node's default
|
|
50
|
+
// 5s keep-alive the daemon was reaping sockets the client still held —
|
|
51
|
+
// causing the next request to fail with ECONNRESET ("daemon not reachable")
|
|
52
|
+
// until a retry opened a fresh socket (toon-client#186). Outliving the
|
|
53
|
+
// client's pool removes that race for non-retried (POST) requests too; the
|
|
54
|
+
// client-side retry covers the residual. Localhost-only listener, so a
|
|
55
|
+
// long-lived idle socket is harmless.
|
|
56
|
+
keepAliveTimeout: 65e4
|
|
57
|
+
});
|
|
46
58
|
registerRoutes(app, runner);
|
|
47
59
|
runner.start();
|
|
48
60
|
await app.listen({ host: "127.0.0.1", port: config.httpPort });
|
package/dist/daemon.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/daemon.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * `toon-clientd` — the always-on, detached TOON client daemon. It owns the two\n * long-lived connections that cannot live in an ephemeral agent session:\n * • a BTP session to the apex/connector (paid writes), and\n * • a persistent town-relay Nostr-WS subscription (free reads),\n * plus the payment channels (with a persisted nonce watermark) and the signer.\n *\n * Subcommands:\n * toon-clientd run Run the daemon in the foreground (used internally by\n * the detached spawn; logs to stdout).\n * toon-clientd start Spawn the daemon detached and wait until reachable.\n * toon-clientd stop Stop a running daemon (SIGTERM the locked PID).\n * toon-clientd status Print the daemon status as JSON.\n */\n\nimport Fastify from 'fastify';\nimport { ToonClient } from '@toon-protocol/client';\nimport {\n defaultConfigPath,\n readConfigFile,\n resolveConfig,\n type ResolvedDaemonConfig,\n} from './daemon/config.js';\nimport { scaffoldFirstRun } from './daemon/first-run.js';\nimport { ClientRunner, type ToonClientLike } from './daemon/client-runner.js';\nimport { registerRoutes } from './daemon/routes.js';\nimport {\n acquireLock,\n isProcessAlive,\n readPid,\n releaseLock,\n spawnDaemonDetached,\n waitForReady,\n} from './daemon/lifecycle.js';\nimport { ControlClient } from './control-client.js';\n\nfunction baseUrl(config: ResolvedDaemonConfig): string {\n return `http://127.0.0.1:${config.httpPort}`;\n}\n\nfunction loadResolvedConfig(): ResolvedDaemonConfig {\n const path = process.env['TOON_CLIENT_CONFIG'] ?? defaultConfigPath();\n return resolveConfig(readConfigFile(path));\n}\n\n/** Run the daemon in the foreground (the detached child's actual work). */\nasync function runForeground(): Promise<void> {\n acquireLock();\n const config = loadResolvedConfig();\n const log = (msg: string): void => console.error(msg);\n\n const runner = new ClientRunner({\n config,\n createClient: (clientConfig) =>\n new ToonClient(clientConfig) as unknown as ToonClientLike,\n logger: log,\n });\n\n const app = Fastify({
|
|
1
|
+
{"version":3,"sources":["../src/daemon.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * `toon-clientd` — the always-on, detached TOON client daemon. It owns the two\n * long-lived connections that cannot live in an ephemeral agent session:\n * • a BTP session to the apex/connector (paid writes), and\n * • a persistent town-relay Nostr-WS subscription (free reads),\n * plus the payment channels (with a persisted nonce watermark) and the signer.\n *\n * Subcommands:\n * toon-clientd run Run the daemon in the foreground (used internally by\n * the detached spawn; logs to stdout).\n * toon-clientd start Spawn the daemon detached and wait until reachable.\n * toon-clientd stop Stop a running daemon (SIGTERM the locked PID).\n * toon-clientd status Print the daemon status as JSON.\n */\n\nimport Fastify from 'fastify';\nimport { ToonClient } from '@toon-protocol/client';\nimport {\n defaultConfigPath,\n readConfigFile,\n resolveConfig,\n type ResolvedDaemonConfig,\n} from './daemon/config.js';\nimport { scaffoldFirstRun } from './daemon/first-run.js';\nimport { ClientRunner, type ToonClientLike } from './daemon/client-runner.js';\nimport { registerRoutes } from './daemon/routes.js';\nimport {\n acquireLock,\n isProcessAlive,\n readPid,\n releaseLock,\n spawnDaemonDetached,\n waitForReady,\n} from './daemon/lifecycle.js';\nimport { ControlClient } from './control-client.js';\n\nfunction baseUrl(config: ResolvedDaemonConfig): string {\n return `http://127.0.0.1:${config.httpPort}`;\n}\n\nfunction loadResolvedConfig(): ResolvedDaemonConfig {\n const path = process.env['TOON_CLIENT_CONFIG'] ?? defaultConfigPath();\n return resolveConfig(readConfigFile(path));\n}\n\n/** Run the daemon in the foreground (the detached child's actual work). */\nasync function runForeground(): Promise<void> {\n acquireLock();\n const config = loadResolvedConfig();\n const log = (msg: string): void => console.error(msg);\n\n const runner = new ClientRunner({\n config,\n createClient: (clientConfig) =>\n new ToonClient(clientConfig) as unknown as ToonClientLike,\n logger: log,\n });\n\n const app = Fastify({\n logger: false,\n // Keep idle keep-alive sockets open longer than the MCP-side undici client\n // would ever pool one (its keepAliveMaxTimeout default is 600s). The client\n // calls this localhost control plane infrequently, so with Node's default\n // 5s keep-alive the daemon was reaping sockets the client still held —\n // causing the next request to fail with ECONNRESET (\"daemon not reachable\")\n // until a retry opened a fresh socket (toon-client#186). Outliving the\n // client's pool removes that race for non-retried (POST) requests too; the\n // client-side retry covers the residual. Localhost-only listener, so a\n // long-lived idle socket is harmless.\n keepAliveTimeout: 650_000,\n });\n registerRoutes(app, runner);\n\n // Begin bootstrap (non-blocking) before listening so /status is immediately\n // reachable and reports `bootstrapping: true` while anon/BTP come up.\n runner.start();\n\n await app.listen({ host: '127.0.0.1', port: config.httpPort });\n log(`[toon-clientd] listening on ${baseUrl(config)}`);\n\n let shuttingDown = false;\n const shutdown = async (signal: string): Promise<void> => {\n if (shuttingDown) return;\n shuttingDown = true;\n log(`[toon-clientd] received ${signal}, shutting down`);\n try {\n await app.close();\n } catch {\n /* ignore */\n }\n await runner.stop();\n releaseLock();\n setTimeout(() => process.exit(0), 500).unref();\n };\n process.on('SIGTERM', () => void shutdown('SIGTERM'));\n process.on('SIGINT', () => void shutdown('SIGINT'));\n}\n\n/** Spawn the daemon detached and wait until the control plane responds. */\nasync function start(): Promise<void> {\n const config = loadResolvedConfig();\n const url = baseUrl(config);\n const existing = readPid();\n if (existing !== null && isProcessAlive(existing)) {\n console.log(`toon-clientd already running (pid ${existing}) at ${url}`);\n return;\n }\n const pid = spawnDaemonDetached();\n const ok = await waitForReady(url, 20_000);\n if (ok) {\n console.log(`toon-clientd started (pid ${pid}) at ${url}`);\n } else {\n console.error(\n `toon-clientd spawned (pid ${pid}) but did not become reachable at ${url} in time. ` +\n `Check the daemon log.`\n );\n process.exitCode = 1;\n }\n}\n\n/** Stop a running daemon via SIGTERM on the locked PID. */\nasync function stop(): Promise<void> {\n const pid = readPid();\n if (pid === null || !isProcessAlive(pid)) {\n console.log('toon-clientd is not running');\n releaseLock();\n return;\n }\n process.kill(pid, 'SIGTERM');\n // Wait briefly for the process to exit.\n for (let i = 0; i < 40; i++) {\n if (!isProcessAlive(pid)) break;\n await new Promise((r) => setTimeout(r, 100));\n }\n console.log(`toon-clientd stopped (pid ${pid})`);\n}\n\n/** Print the daemon status JSON. */\nasync function status(): Promise<void> {\n const config = loadResolvedConfig();\n const client = new ControlClient({ baseUrl: baseUrl(config) });\n try {\n const s = await client.status();\n console.log(JSON.stringify(s, null, 2));\n } catch {\n console.log(JSON.stringify({ running: false }, null, 2));\n process.exitCode = 1;\n }\n}\n\nasync function main(): Promise<void> {\n const cmd = process.argv[2] ?? 'run';\n switch (cmd) {\n case 'run':\n // First-run onboarding (#251): mint + persist an identity and scaffold\n // the transport config so a fresh install starts with no manual setup.\n await scaffoldFirstRun();\n await runForeground();\n break;\n case 'start':\n await scaffoldFirstRun();\n await start();\n break;\n case 'stop':\n await stop();\n break;\n case 'status':\n await status();\n break;\n default:\n console.error(\n `Unknown command \"${cmd}\". Usage: toon-clientd <run|start|stop|status>`\n );\n process.exitCode = 1;\n }\n}\n\nmain().catch((err) => {\n console.error(\n err instanceof Error ? (err.stack ?? err.message) : String(err)\n );\n process.exitCode = 1;\n});\n"],"mappings":"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","names":[]}
|
package/dist/index.d.ts
CHANGED
|
@@ -543,7 +543,15 @@ declare class ControlClient {
|
|
|
543
543
|
addApex(body: AddApexRequest): Promise<AddApexResponse>;
|
|
544
544
|
removeApex(body: RemoveApexRequest): Promise<TargetsResponse>;
|
|
545
545
|
fundWallet(body?: FundWalletRequest): Promise<FundWalletResponse>;
|
|
546
|
+
/**
|
|
547
|
+
* Whether an HTTP method is safe to transparently retry. Idempotent reads
|
|
548
|
+
* (GET) and deletes can be replayed verbatim; a mutating POST cannot — the
|
|
549
|
+
* daemon may have already applied it before the socket failed, so retrying
|
|
550
|
+
* risks a double publish/fund/deposit.
|
|
551
|
+
*/
|
|
552
|
+
private static isIdempotent;
|
|
546
553
|
private request;
|
|
554
|
+
private attemptOnce;
|
|
547
555
|
}
|
|
548
556
|
|
|
549
557
|
/**
|
package/dist/index.js
CHANGED
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
hasConfiguredIdentity,
|
|
9
9
|
registerRoutes,
|
|
10
10
|
scaffoldFirstRun
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-ADBNZA5O.js";
|
|
12
12
|
import {
|
|
13
13
|
PUBLISH_TOOL,
|
|
14
14
|
TOOL_DEFINITIONS,
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
buildFollowListFilter,
|
|
19
19
|
buildProfileFilter,
|
|
20
20
|
dispatchTool
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-XFRMAETF.js";
|
|
22
22
|
import {
|
|
23
23
|
ControlApiError,
|
|
24
24
|
ControlClient,
|
|
@@ -36,7 +36,7 @@ import {
|
|
|
36
36
|
resolveMnemonic,
|
|
37
37
|
spawnDaemonDetached,
|
|
38
38
|
waitForReady
|
|
39
|
-
} from "./chunk-
|
|
39
|
+
} from "./chunk-3ZBC2HUB.js";
|
|
40
40
|
import "./chunk-32QD72IL.js";
|
|
41
41
|
import "./chunk-DLYE6U2Z.js";
|
|
42
42
|
import "./chunk-LR7W2ISE.js";
|
package/dist/mcp.js
CHANGED
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
APP_RESOURCE_URI,
|
|
5
5
|
TOOL_DEFINITIONS,
|
|
6
6
|
dispatchTool
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-XFRMAETF.js";
|
|
8
8
|
import {
|
|
9
9
|
ARWEAVE_GATEWAYS,
|
|
10
10
|
ControlClient,
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
readConfigFile,
|
|
14
14
|
spawnDaemonDetached,
|
|
15
15
|
waitForReady
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-3ZBC2HUB.js";
|
|
17
17
|
import "./chunk-32QD72IL.js";
|
|
18
18
|
import "./chunk-DLYE6U2Z.js";
|
|
19
19
|
import "./chunk-LR7W2ISE.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@toon-protocol/client-mcp",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.8",
|
|
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 swaps.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Jonathan Green",
|
|
@@ -48,9 +48,9 @@
|
|
|
48
48
|
"tsx": "^4.19.2",
|
|
49
49
|
"typescript": "^5.3.0",
|
|
50
50
|
"vitest": "^1.0.0",
|
|
51
|
+
"@toon-protocol/arweave": "0.1.1",
|
|
51
52
|
"@toon-protocol/client": "0.14.8",
|
|
52
|
-
"@toon-protocol/views": "0.10.
|
|
53
|
-
"@toon-protocol/arweave": "0.1.1"
|
|
53
|
+
"@toon-protocol/views": "0.10.8"
|
|
54
54
|
},
|
|
55
55
|
"engines": {
|
|
56
56
|
"node": ">=20"
|
|
File without changes
|
|
File without changes
|