paralith-mcp 0.2.0 → 0.3.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 CHANGED
@@ -9,7 +9,13 @@ Solana and Sui. Public docs: `products/orderbook/app/src/docs/pages/ai/mcp.md`
9
9
 
10
10
  Read-only, no install: connect your MCP client to `https://mcp.paralithmarkets.com/mcp`.
11
11
 
12
- To play, trade and bridge, run it locally with a phrase made for the agent (Node 20+):
12
+ To play, trade and bridge, connect every agent app on this machine (Claude Code, Claude Desktop, Codex, Grok), each with its own new wallet:
13
+
14
+ ```bash
15
+ npx -y paralith-mcp@latest setup
16
+ ```
17
+
18
+ Or by hand, with a phrase made for the agent (Node 20+):
13
19
 
14
20
  ```bash
15
21
  claude mcp add paralith --env PARALITH_MNEMONIC_FILE=/path/to/agent-phrase.txt -- npx -y paralith-mcp@latest
@@ -30,7 +36,9 @@ PARALITH_MNEMONIC_FILE=phrase.txt node scripts/call.mjs wallet '{}' # call one
30
36
  npm test # also fails if dist/ or the tool reference is stale
31
37
  ```
32
38
 
33
- - `src/server.mjs`: stdio entry. No phrase means read-only.
39
+ - `src/server.mjs`: stdio entry. No phrase means read-only. `setup` runs `src/setup.mjs` instead.
40
+ - `src/setup.mjs`: one wallet per agent app, written into each app's MCP config; `src/agents.mjs` records their public addresses.
41
+ - `src/progress.mjs`: the `progress` tool, one read across game, venues, vaults, bridge and gas, for one agent or all.
34
42
  - `src/http.mjs`: hosted read-only endpoint, `POST /mcp`, `GET /health`.
35
43
  - `src/build.mjs`: `buildServer()` and the account tools.
36
44
  - `src/keys.mjs`: phrase to AO/Base/Solana/Sui signers.
package/dist/chains.json CHANGED
@@ -4,11 +4,11 @@
4
4
  "chainId": 8453,
5
5
  "rpc": "https://mainnet.base.org",
6
6
  "explorer": "https://basescan.org",
7
- "bridge": "0xCE13574d0Ca4A0dE9c5E5039fD2E9F6ec2593409",
8
- "deployBlock": 52295541,
7
+ "bridge": "0x871ae9cd37B76F9216076d775928C733687596e6",
8
+ "deployBlock": 52429067,
9
9
  "tokens": [
10
10
  {
11
- "address": "0x405c70597266BefB0504389E333F10785B7919a9",
11
+ "address": "0xce2ED346Ff3E537E2D99B47F5162b0A07431d9a4",
12
12
  "symbol": "TEST-USDC",
13
13
  "decimals": 6,
14
14
  "faucet": true
@@ -19,95 +19,132 @@
19
19
  "cluster": "mainnet-beta",
20
20
  "rpc": "https://api.mainnet-beta.solana.com",
21
21
  "explorer": "https://solscan.io",
22
- "programId": "thXGuX413NPvD7zPrSv658UmVEwdki2Tu3zhbU6LoiM",
22
+ "programId": "41aBnUWVghxSWboMKY2F1MhtAYhPMU83igKbfvtjVjcr",
23
23
  "deployed": true,
24
24
  "tokens": [
25
25
  {
26
- "mint": "2oJf5PQxWYjLfPQ5yTBt5XE34F1zoP1fHCeFwoPcrdDn",
26
+ "mint": "4CjGDd6atsPPe7YPukt3aaHAuXUfhsA9KPkgbgVrcGyq",
27
27
  "symbol": "TEST-USDC",
28
28
  "decimals": 6,
29
29
  "tokenProgram": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb",
30
30
  "faucet": true
31
31
  }
32
32
  ],
33
- "programIndex": 4
33
+ "programIndex": 5
34
34
  },
35
35
  "sui": {
36
36
  "network": "mainnet",
37
37
  "rpc": "https://fullnode.mainnet.sui.io:443",
38
38
  "graphql": "https://graphql.mainnet.sui.io/graphql",
39
39
  "explorer": "https://suivision.xyz",
40
- "package": "0x43e8e6eea948b92358e799d9f27042ce9d77cf160ad2736ab0f5fd852d1ffa24",
41
- "originalPackage": "0x43e8e6eea948b92358e799d9f27042ce9d77cf160ad2736ab0f5fd852d1ffa24",
42
- "bridge": "0x63e9050c72530fb577379f6b9d979aba3b84afeb83833cbe47a6972443fcd300",
43
- "faucet": "0x24cdc90a23c129fe3afcc2bbb5c8bd0a63f10dad06ca6c04e03c41eb1e955ac3",
40
+ "package": "0x647f58c931f3f9c48ada70a3f91bc554f8945bcad16967e02a0bd49fffe9aed6",
41
+ "originalPackage": "0x647f58c931f3f9c48ada70a3f91bc554f8945bcad16967e02a0bd49fffe9aed6",
42
+ "bridge": "0x270b73af9e6543d196ba7a3bc160f87aabdc662e8601af46ceb0d465ae103337",
43
+ "faucet": "0x4c549789110006fadc343790b770fffa314269bcbeafd4f48853c3bf3d9639ef",
44
44
  "tokens": [
45
45
  {
46
- "type": "0x43e8e6eea948b92358e799d9f27042ce9d77cf160ad2736ab0f5fd852d1ffa24::test_usdc::TEST_USDC",
46
+ "type": "0x647f58c931f3f9c48ada70a3f91bc554f8945bcad16967e02a0bd49fffe9aed6::test_usdc::TEST_USDC",
47
47
  "symbol": "TEST-USDC",
48
48
  "decimals": 6,
49
49
  "faucet": true
50
50
  }
51
51
  ],
52
- "adminCap": "0xbfade5103b48bde0bdb5dcc0b016bb9571a93f79895de542e8853f522166d404",
52
+ "adminCap": "0xdd6abffeb51098b05be212f89fe44e78cbef062edfeec6078b225f9e75267570",
53
53
  "deployed": true,
54
54
  "upgradeCap": "0xa1fb1dc179dcdc0579dca5b50a8d1162c1a3c40f531fb723f21de206c1ca78cd"
55
55
  },
56
- "relayers": {
57
- "base": "0xDaaefC6Fe9C820DB57E9be7C0b566800de11ac22",
58
- "solana": "9eVvxEPKgpQ4Y2BZV8BWVAeRHWWfSEJy3vrM2AFNzdQ2",
59
- "sui": "0x46bd8f40263f6e056262f82f13c61d0849d813a030cde4c5bd6a8dd768144e9f",
60
- "ao": "z2OMYtbWHqNZY01ehkN0tsepznlrZQW-6dXPQO5lxDM"
61
- },
62
56
  "deploy": {
63
57
  "sui": {
64
- "id": "0x43e8e6eea948b92358e799d9f27042ce9d77cf160ad2736ab0f5fd852d1ffa24",
65
- "version": "sha256:a1fa3e2c74ded1733922a0055ed98b964223253daa25386a1adcec5e84e1b280",
66
- "localHash": "sha256:a1fa3e2c74ded1733922a0055ed98b964223253daa25386a1adcec5e84e1b280",
67
- "deployedAt": "2026-10-07T13:59:55.943Z",
68
- "tx": "2ENtda5acLVU3RyTfTC4U9n56C9F4wNJfhPK8fZq7FtB",
58
+ "id": "0x647f58c931f3f9c48ada70a3f91bc554f8945bcad16967e02a0bd49fffe9aed6",
59
+ "version": "sha256:d8675a23dc00cfe0d9e73f128ed5948d05e9a708afc1a68829906bec0aaeb432",
60
+ "localHash": "sha256:d8675a23dc00cfe0d9e73f128ed5948d05e9a708afc1a68829906bec0aaeb432",
61
+ "deployedAt": "2026-10-10T16:08:52.325Z",
62
+ "tx": "7CjZL9MGDVXUgSeGCNmT69HWtksnNyJaacFDTrAGahhu",
69
63
  "action": "FRESH"
70
64
  },
71
65
  "pusd": {
72
- "id": "sXuny0tvUizug41AHbbvWfDcjkqK0MEjrWSBTQwp3ac",
73
- "version": "sha256:4371b32bcc00fd14e85e740ac0f09d41bb6192509bee171d83594c901185eabc",
74
- "localHash": "sha256:4371b32bcc00fd14e85e740ac0f09d41bb6192509bee171d83594c901185eabc",
75
- "deployedAt": "2026-10-09T21:40:48.119Z",
76
- "tx": "sXuny0tvUizug41AHbbvWfDcjkqK0MEjrWSBTQwp3ac",
66
+ "id": "xhYkQ8qm7zssDC2nrOfzkk2Xy8rPVvlEMWestfrAvK8",
67
+ "version": "sha256:5c7aee2fad4dd8c558bbbcc4cf1dd19da28c5faf834bf4a801cf82969c0225c8",
68
+ "localHash": "sha256:5c7aee2fad4dd8c558bbbcc4cf1dd19da28c5faf834bf4a801cf82969c0225c8",
69
+ "deployedAt": "2026-10-10T15:51:14.512Z",
70
+ "tx": "xhYkQ8qm7zssDC2nrOfzkk2Xy8rPVvlEMWestfrAvK8",
77
71
  "action": "FRESH"
78
72
  },
79
73
  "base": {
80
- "id": "0xCE13574d0Ca4A0dE9c5E5039fD2E9F6ec2593409",
81
- "version": "0x85ba7d3498f2cf2c87849ee1d4966867465431d233837f1158964dece0af9028",
82
- "localHash": "0x85ba7d3498f2cf2c87849ee1d4966867465431d233837f1158964dece0af9028",
83
- "deployedAt": "2026-10-07T13:41:12.236Z",
84
- "tx": "0xb07dcc2967c1f803f7177ce99359f235319771fa0037982d983d1fd586bfdfef",
85
- "action": "FRESH"
74
+ "id": "0x871ae9cd37B76F9216076d775928C733687596e6",
75
+ "version": "0xe9e86188e3c0aa76ab1148c6cdee756045799152b0d796c2c74138ffae8ad03b",
76
+ "localHash": "0xe9e86188e3c0aa76ab1148c6cdee756045799152b0d796c2c74138ffae8ad03b",
77
+ "baselined": false,
78
+ "recordedAt": "2026-10-10T16:09:39.076Z",
79
+ "deployedAt": null
86
80
  },
87
81
  "solana": {
88
- "id": "thXGuX413NPvD7zPrSv658UmVEwdki2Tu3zhbU6LoiM",
89
- "version": "sha256:3ab07b185fa24f3da2a57352b9e2eed5f37475752cb2258d182d8a61afab7d2b",
90
- "localHash": "sha256:3ab07b185fa24f3da2a57352b9e2eed5f37475752cb2258d182d8a61afab7d2b",
91
- "deployedAt": "2026-10-07T13:59:36.619Z",
92
- "tx": "4gzQJeXcj6WZyhTP1djC95LVAsEiH78gVcNBk57KESYkwzWqRNDkkGgotQwENYEXfzqZpfRFcmysrBoHh44TMxz1",
82
+ "id": "41aBnUWVghxSWboMKY2F1MhtAYhPMU83igKbfvtjVjcr",
83
+ "version": "sha256:4279831e73a9247928ad5c4490bb203bc498d834da24f6da0ff20562898ec47e",
84
+ "localHash": "sha256:4279831e73a9247928ad5c4490bb203bc498d834da24f6da0ff20562898ec47e",
85
+ "deployedAt": "2026-10-10T16:08:35.744Z",
86
+ "tx": "J8trVshLfVhCxSJHnXXLhxdbkmkWLEhpE9FEjTHDK8qTkYY7izhX2zAtVscsztaTn7nMDnLhT88BHBw9MsVmbVC",
93
87
  "action": "FRESH"
94
88
  },
95
89
  "lastRun": {
96
- "at": "2026-10-09T21:41:00.279Z",
97
- "startedAt": "2026-10-09T19:17:15.931Z",
90
+ "at": "2026-10-10T16:09:39.077Z",
91
+ "startedAt": "2026-10-10T15:51:02.462Z",
98
92
  "steps": [
99
93
  {
100
94
  "component": "pusd",
101
95
  "action": "FRESH",
102
96
  "status": "done",
103
- "tx": "sXuny0tvUizug41AHbbvWfDcjkqK0MEjrWSBTQwp3ac"
97
+ "tx": "xhYkQ8qm7zssDC2nrOfzkk2Xy8rPVvlEMWestfrAvK8"
98
+ },
99
+ {
100
+ "component": "base",
101
+ "action": "FRESH",
102
+ "status": "done"
103
+ },
104
+ {
105
+ "component": "solana",
106
+ "action": "FRESH",
107
+ "status": "done",
108
+ "tx": "J8trVshLfVhCxSJHnXXLhxdbkmkWLEhpE9FEjTHDK8qTkYY7izhX2zAtVscsztaTn7nMDnLhT88BHBw9MsVmbVC"
109
+ },
110
+ {
111
+ "component": "sui",
112
+ "action": "FRESH",
113
+ "status": "done",
114
+ "tx": "7CjZL9MGDVXUgSeGCNmT69HWtksnNyJaacFDTrAGahhu"
104
115
  },
105
116
  {
106
117
  "component": "tokens",
107
118
  "action": "CONFIGURE",
108
119
  "status": "done"
120
+ },
121
+ {
122
+ "component": "graph",
123
+ "action": "CONFIGURE",
124
+ "status": "done"
125
+ },
126
+ {
127
+ "component": "site",
128
+ "action": "CONFIGURE",
129
+ "status": "done"
109
130
  }
110
131
  ]
111
132
  }
133
+ },
134
+ "attestors": [
135
+ {
136
+ "ao": "tkqULqMDeHKXCN79Cm_bDIV560JxXl6pBSmdPgxqwSw",
137
+ "operator": "efH9MDGEFZqQ4nTTRNxl8WXJi2NbZvd2xVgCWmG5EeM",
138
+ "base": "0xcefcaae4d5077eda2b126e9b315b5d7c4dd2ff38",
139
+ "solana": "BBuQ11wQE6K5bj6Cx7X5VpVDB9CG83nbeDdDSinavUz",
140
+ "sui": "0x397c399eb2f7e24e8f5d1988f71284baac48149b9e8cdcd741b353c771118ebc",
141
+ "epoch": 0
142
+ }
143
+ ],
144
+ "retiredRelayers": {
145
+ "base": "0xDaaefC6Fe9C820DB57E9be7C0b566800de11ac22",
146
+ "solana": "9eVvxEPKgpQ4Y2BZV8BWVAeRHWWfSEJy3vrM2AFNzdQ2",
147
+ "sui": "0x46bd8f40263f6e056262f82f13c61d0849d813a030cde4c5bd6a8dd768144e9f",
148
+ "ao": "z2OMYtbWHqNZY01ehkN0tsepznlrZQW-6dXPQO5lxDM"
112
149
  }
113
150
  }
package/dist/client.mjs CHANGED
@@ -401,7 +401,7 @@ var init_slot_settle = __esm({
401
401
  var graph_default;
402
402
  var init_graph = __esm({
403
403
  "runerealm-graph:C:\\REPO\\paralith-mono\\products\\runerealm-ui\\src\\lib\\graph.json"() {
404
- graph_default = { node: "https://hyperbeam.tylerw.ai", owner: "DA9qhP25ZPz6MHIhO-7aNHDN3LsTAL7yCKYIkqr13Z8", deployedAt: "", processes: { game: "bqkZT1qY8Qpea7QsKZEk8q7m0yUE8-G3Miq8EFXnRJg", rune: "0j4rkkEqUO25aXI8LoDuou2Ibr0GSMGsXrFRxwrSfY8", pusd: "sXuny0tvUizug41AHbbvWfDcjkqK0MEjrWSBTQwp3ac", dao: "YAPgWNxRQksjYn_zfUw-h-JkwpmJDtPL1K9yifR5S_Q", elements: { earth: "3CS-LPEfD4YJwpuh1kuPGOv3lGwIlOAWOT15ATGIbPg", air: "y51gmVYD1GoJWtMxAtePMnvMCR0aT-jSfnsMKjFeU70", fire: "os6EKVQGuukvgTFmaZbGj23Xt3frHB3cb8ljquCdJ18", water: "P9OPPoVw9MxpIz8QghA6TcYUhXrYG3Ro09KM8shX5QM" }, internalVenue: "pxw-Y9Hl8CNQlPGLr-2Ez_9BVjjEP6wisxrZhe-AyxU", externalVenue: "D3SUysjoweBXtoGFm4zoq1dKSt7Dc5b_V9x_weLJV7Y", hunt: "4iABQxFjL3LtMGgfZQuwsH5WHKKjjSu7b7XfxEN_j40", huntWorkers: ["4iABQxFjL3LtMGgfZQuwsH5WHKKjjSu7b7XfxEN_j40", "2RBkmldqPdij2PopnEPuStLl6Pb6OcIrpilfK64Q1m8", "EATa5vTV53J1c711CEjiuks2Kllq3Gi-kVSXFqe7O7M", "SHXyU87725eI8i6qSET70Pwovf744DJqEfajTZI4N4M", "iesbJSITvqtDXMHxhGeOOXUXofnD-nh1qro9PH5IHNQ"], battleWorkers: ["Xk8XXWY2QY-UCd1Y_yqx6SHlVt5bNUbQnwzngMgxbzc", "IPjes-iFyMZH_JCx1z-4c-7JEdJgd3RGgbglgl3_u2s", "-m-6qgUsU6ybjOpMMlPHvG1bIlHypFMORKw4blCpRnU", "mSzalVGuEgxAG_tCEhVivSPMhSvmp5ePMHRIW0-gASM", "PkPEU-yZpgn9LwXWYPahUKOPe-Hw2sHB0DPBNPoxQeA"] }, huntNode: "https://hyperbeam.tylerw.ai", marketNode: "https://hyperbeam.tylerw.ai", venueNode: "https://hyperbeam.tylerw.ai" };
404
+ graph_default = { node: "https://hyperbeam.tylerw.ai", owner: "DA9qhP25ZPz6MHIhO-7aNHDN3LsTAL7yCKYIkqr13Z8", deployedAt: "", processes: { game: "bqkZT1qY8Qpea7QsKZEk8q7m0yUE8-G3Miq8EFXnRJg", rune: "0j4rkkEqUO25aXI8LoDuou2Ibr0GSMGsXrFRxwrSfY8", pusd: "xhYkQ8qm7zssDC2nrOfzkk2Xy8rPVvlEMWestfrAvK8", dao: "YAPgWNxRQksjYn_zfUw-h-JkwpmJDtPL1K9yifR5S_Q", elements: { earth: "3CS-LPEfD4YJwpuh1kuPGOv3lGwIlOAWOT15ATGIbPg", air: "y51gmVYD1GoJWtMxAtePMnvMCR0aT-jSfnsMKjFeU70", fire: "os6EKVQGuukvgTFmaZbGj23Xt3frHB3cb8ljquCdJ18", water: "P9OPPoVw9MxpIz8QghA6TcYUhXrYG3Ro09KM8shX5QM" }, internalVenue: "pxw-Y9Hl8CNQlPGLr-2Ez_9BVjjEP6wisxrZhe-AyxU", externalVenue: "D3SUysjoweBXtoGFm4zoq1dKSt7Dc5b_V9x_weLJV7Y", hunt: "4iABQxFjL3LtMGgfZQuwsH5WHKKjjSu7b7XfxEN_j40", huntWorkers: ["4iABQxFjL3LtMGgfZQuwsH5WHKKjjSu7b7XfxEN_j40", "2RBkmldqPdij2PopnEPuStLl6Pb6OcIrpilfK64Q1m8", "EATa5vTV53J1c711CEjiuks2Kllq3Gi-kVSXFqe7O7M", "SHXyU87725eI8i6qSET70Pwovf744DJqEfajTZI4N4M", "iesbJSITvqtDXMHxhGeOOXUXofnD-nh1qro9PH5IHNQ"], battleWorkers: ["Xk8XXWY2QY-UCd1Y_yqx6SHlVt5bNUbQnwzngMgxbzc", "IPjes-iFyMZH_JCx1z-4c-7JEdJgd3RGgbglgl3_u2s", "-m-6qgUsU6ybjOpMMlPHvG1bIlHypFMORKw4blCpRnU", "mSzalVGuEgxAG_tCEhVivSPMhSvmp5ePMHRIW0-gASM", "PkPEU-yZpgn9LwXWYPahUKOPe-Hw2sHB0DPBNPoxQeA"] }, huntNode: "https://hyperbeam.tylerw.ai", marketNode: "https://hyperbeam.tylerw.ai", venueNode: "https://hyperbeam.tylerw.ai" };
405
405
  }
406
406
  });
407
407
 
package/dist/graph.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "node": "https://hyperbeam.tylerw.ai",
3
3
  "owner": "DA9qhP25ZPz6MHIhO-7aNHDN3LsTAL7yCKYIkqr13Z8",
4
- "deployedAt": "2026-10-09T21:40:15.402Z",
4
+ "deployedAt": "2026-10-10T15:51:09.959Z",
5
5
  "processes": {
6
6
  "game": "bqkZT1qY8Qpea7QsKZEk8q7m0yUE8-G3Miq8EFXnRJg",
7
7
  "rune": "0j4rkkEqUO25aXI8LoDuou2Ibr0GSMGsXrFRxwrSfY8",
8
- "pusd": "sXuny0tvUizug41AHbbvWfDcjkqK0MEjrWSBTQwp3ac",
8
+ "pusd": "xhYkQ8qm7zssDC2nrOfzkk2Xy8rPVvlEMWestfrAvK8",
9
9
  "dao": "YAPgWNxRQksjYn_zfUw-h-JkwpmJDtPL1K9yifR5S_Q",
10
10
  "elements": {
11
11
  "earth": "3CS-LPEfD4YJwpuh1kuPGOv3lGwIlOAWOT15ATGIbPg",
package/dist/http.mjs CHANGED
@@ -5,8 +5,8 @@ import http2 from "node:http";
5
5
  import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
6
6
 
7
7
  // src/runtime.mjs
8
- import fs2 from "node:fs";
9
- import path2 from "node:path";
8
+ import fs3 from "node:fs";
9
+ import path3 from "node:path";
10
10
  import { fileURLToPath, pathToFileURL } from "node:url";
11
11
 
12
12
  // ../../backend/native/ans104.mjs
@@ -135,7 +135,7 @@ import { mnemonicToAccount } from "viem/accounts";
135
135
  import { Keypair } from "@solana/web3.js";
136
136
  import { Ed25519Keypair } from "@mysten/sui/keypairs/ed25519";
137
137
  import { getKeyFromMnemonic } from "arweave-mnemonic-keys";
138
- var CACHE_DIR = process.env.PARALITH_MCP_HOME || path.join(os.homedir(), ".paralith", "mcp");
138
+ var HOME = process.env.PARALITH_MCP_HOME || path.join(os.homedir(), ".paralith", "mcp");
139
139
  function readPhrase(env = process.env) {
140
140
  const raw = env.PARALITH_MNEMONIC ?? (env.PARALITH_MNEMONIC_FILE ? fs.readFileSync(env.PARALITH_MNEMONIC_FILE, "utf8") : null);
141
141
  if (!raw) {
@@ -162,25 +162,27 @@ function slip10(seed, derivation) {
162
162
  async function aoJwk(phrase, env) {
163
163
  if (env.PARALITH_AO_JWK) return JSON.parse(fs.readFileSync(env.PARALITH_AO_JWK, "utf8"));
164
164
  const id = crypto2.createHash("sha256").update(phrase).digest("hex").slice(0, 24);
165
- const file = path.join(CACHE_DIR, `ao-${id}.json`);
165
+ const file = path.join(HOME, `ao-${id}.json`);
166
166
  if (fs.existsSync(file)) return JSON.parse(fs.readFileSync(file, "utf8"));
167
167
  const jwk = await getKeyFromMnemonic(phrase);
168
- fs.mkdirSync(CACHE_DIR, { recursive: true, mode: 448 });
168
+ fs.mkdirSync(HOME, { recursive: true, mode: 448 });
169
169
  fs.writeFileSync(file, JSON.stringify(jwk), { mode: 384 });
170
170
  return jwk;
171
171
  }
172
- async function deriveWallets(phrase, env = process.env) {
172
+ function chainWallets(phrase) {
173
173
  const evm = mnemonicToAccount(phrase, { path: "m/44'/60'/0'/0/0" });
174
174
  const solana = Keypair.fromSeed(slip10(mnemonicToSeedSync(phrase), "m/44'/501'/0'/0'"));
175
175
  const sui = Ed25519Keypair.deriveKeypair(phrase, "m/44'/784'/0'/0'/0'");
176
- const jwk = await aoJwk(phrase, env);
177
176
  return {
178
- ao: { jwk, address: jwkToAddress(jwk) },
179
177
  base: { account: evm, address: evm.address },
180
178
  solana: { keypair: solana, address: solana.publicKey.toBase58() },
181
179
  sui: { keypair: sui, address: sui.getPublicKey().toSuiAddress() }
182
180
  };
183
181
  }
182
+ async function deriveWallets(phrase, env = process.env) {
183
+ const jwk = await aoJwk(phrase, env);
184
+ return { ao: { jwk, address: jwkToAddress(jwk) }, ...chainWallets(phrase) };
185
+ }
184
186
  var publicAddresses = (w) => ({
185
187
  ao: w.ao.address,
186
188
  base: w.base.address,
@@ -188,12 +190,32 @@ var publicAddresses = (w) => ({
188
190
  sui: w.sui.address
189
191
  });
190
192
 
193
+ // src/agents.mjs
194
+ import fs2 from "node:fs";
195
+ import path2 from "node:path";
196
+ var FILE = path2.join(HOME, "agents.json");
197
+ function readAgents() {
198
+ try {
199
+ return JSON.parse(fs2.readFileSync(FILE, "utf8"));
200
+ } catch {
201
+ return {};
202
+ }
203
+ }
204
+ function saveAgent(name, entry) {
205
+ const all = readAgents();
206
+ all[name] = { ...all[name], ...entry, addresses: { ...all[name]?.addresses, ...entry.addresses } };
207
+ fs2.mkdirSync(HOME, { recursive: true, mode: 448 });
208
+ fs2.writeFileSync(FILE, `${JSON.stringify(all, null, 2)}
209
+ `);
210
+ return all[name];
211
+ }
212
+
191
213
  // src/runtime.mjs
192
- var HERE = path2.dirname(fileURLToPath(import.meta.url));
193
- var DIST = fs2.existsSync(path2.join(HERE, "graph.json")) ? HERE : path2.join(HERE, "..", "dist");
194
- var graph = JSON.parse(fs2.readFileSync(path2.join(DIST, "graph.json"), "utf8"));
214
+ var HERE = path3.dirname(fileURLToPath(import.meta.url));
215
+ var DIST = fs3.existsSync(path3.join(HERE, "graph.json")) ? HERE : path3.join(HERE, "..", "dist");
216
+ var graph = JSON.parse(fs3.readFileSync(path3.join(DIST, "graph.json"), "utf8"));
195
217
  var NODE = graph.node.replace(/\/$/, "");
196
- var chains = JSON.parse(fs2.readFileSync(path2.join(DIST, "chains.json"), "utf8"));
218
+ var chains = JSON.parse(fs3.readFileSync(path3.join(DIST, "chains.json"), "utf8"));
197
219
  var PROCESS_ALIASES = {
198
220
  game: graph.processes.game,
199
221
  rune: graph.processes.rune,
@@ -215,7 +237,8 @@ var loaded = null;
215
237
  function runtime() {
216
238
  loaded ??= (async () => {
217
239
  const wallets = READ_ONLY ? null : await deriveWallets(readPhrase());
218
- const api = await import(pathToFileURL(path2.join(DIST, "client.mjs")).href);
240
+ if (wallets && process.env.PARALITH_AGENT) saveAgent(process.env.PARALITH_AGENT, { addresses: publicAddresses(wallets) });
241
+ const api = await import(pathToFileURL(path3.join(DIST, "client.mjs")).href);
219
242
  if (wallets) api.swarmWalletSlot.wallet = walletShim(wallets.ao.jwk);
220
243
  return { api, wallets };
221
244
  })();
@@ -277,7 +300,7 @@ async function until(what, read, done, timeoutMs = 6e5, everyMs = 3e3) {
277
300
 
278
301
  // src/build.mjs
279
302
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
280
- import { z as z8 } from "zod";
303
+ import { z as z9 } from "zod";
281
304
 
282
305
  // src/tool.mjs
283
306
  import { z } from "zod";
@@ -1153,6 +1176,19 @@ function suiChain(w) {
1153
1176
  }
1154
1177
  };
1155
1178
  }
1179
+ async function gasOf(name, address) {
1180
+ if (name === "base") {
1181
+ const rpc = process.env.PARALITH_BASE_RPC || chains.base.rpc;
1182
+ const pub = createPublicClient({ chain: { ...base, id: chains.base.chainId }, transport: http(rpc) });
1183
+ return `${formatEther(await pub.getBalance({ address }))} ETH`;
1184
+ }
1185
+ if (name === "solana") {
1186
+ const conn = new Connection(process.env.PARALITH_SOLANA_RPC || chains.solana.rpc, "confirmed");
1187
+ return `${await conn.getBalance(new PublicKey(address)) / 1e9} SOL`;
1188
+ }
1189
+ const client = new SuiGrpcClient({ network: chains.sui.network, baseUrl: process.env.PARALITH_SUI_RPC || chains.sui.rpc });
1190
+ return `${Number((await client.getBalance({ owner: address })).balance.balance) / 1e9} SUI`;
1191
+ }
1156
1192
  async function chainFor(name) {
1157
1193
  const { wallets } = await runtime();
1158
1194
  return { base: baseChain, solana: solanaChain, sui: suiChain }[name](wallets);
@@ -1627,18 +1663,18 @@ function registerVaults(server) {
1627
1663
  }
1628
1664
 
1629
1665
  // src/show.mjs
1630
- import fs3 from "node:fs";
1631
- import path3 from "node:path";
1666
+ import fs4 from "node:fs";
1667
+ import path4 from "node:path";
1632
1668
  import { fileURLToPath as fileURLToPath2 } from "node:url";
1633
1669
  import { z as z7 } from "zod";
1634
1670
  import { registerAppResource, registerAppTool, RESOURCE_MIME_TYPE } from "@modelcontextprotocol/ext-apps/server";
1635
1671
  var GAME = (process.env.PARALITH_GAME_URL || "https://game.paralithmarkets.com").replace(/\/$/, "");
1636
1672
  var TRADE = (process.env.PARALITH_TRADE_URL || "https://trade.paralithmarkets.com").replace(/\/$/, "");
1637
1673
  var URI = "ui://paralith/view";
1638
- var HERE2 = path3.dirname(fileURLToPath2(import.meta.url));
1674
+ var HERE2 = path4.dirname(fileURLToPath2(import.meta.url));
1639
1675
  function viewHtml() {
1640
- for (const file of [path3.join(HERE2, "view.html"), path3.join(HERE2, "..", "dist", "view.html")]) {
1641
- if (fs3.existsSync(file)) return fs3.readFileSync(file, "utf8");
1676
+ for (const file of [path4.join(HERE2, "view.html"), path4.join(HERE2, "..", "dist", "view.html")]) {
1677
+ if (fs4.existsSync(file)) return fs4.readFileSync(file, "utf8");
1642
1678
  }
1643
1679
  throw new Error("view.html is missing: run npm run build");
1644
1680
  }
@@ -1699,6 +1735,102 @@ function registerShow(server) {
1699
1735
  });
1700
1736
  }
1701
1737
 
1738
+ // src/progress.mjs
1739
+ import { z as z8 } from "zod";
1740
+ var VENUES = { game: graph.processes.internalVenue, token: graph.processes.externalVenue };
1741
+ var count = (x) => Array.isArray(x) ? x.length : Object.values(x ?? {}).reduce((n, v) => n + Number(v || 0), 0);
1742
+ async function targets(who) {
1743
+ const { wallets } = await runtime();
1744
+ const agents = readAgents();
1745
+ const self = wallets && { name: process.env.PARALITH_AGENT ?? "you", addresses: publicAddresses(wallets) };
1746
+ if (!who || who === "me") {
1747
+ if (!self) throw new Error("This server has no wallet; pass who: an AO address.");
1748
+ return [self];
1749
+ }
1750
+ if (who === "all") {
1751
+ const list = Object.entries(agents).map(([name, a]) => ({ name, addresses: a.addresses }));
1752
+ if (self && !list.some((t) => t.name === self.name)) list.unshift(self);
1753
+ if (!list.length) throw new Error("No agents are set up here. Run: npx -y paralith-mcp@latest setup");
1754
+ return list;
1755
+ }
1756
+ if (agents[who]) return [{ name: who, addresses: agents[who].addresses }];
1757
+ if (ID.test(who)) return [{ name: who, addresses: { ao: who } }];
1758
+ throw new Error(`"${who}" is not an agent here (${Object.keys(agents).join(", ") || "none"}) or an AO address.`);
1759
+ }
1760
+ async function report({ name, addresses: a }) {
1761
+ const { api } = await runtime();
1762
+ const out = { agent: name, addresses: a };
1763
+ const todo = [];
1764
+ const gas = Object.fromEntries(await Promise.all(["base", "solana", "sui"].filter((c) => a[c]).map(async (c) => [c, await gasOf(c, a[c]).catch(() => "unreadable")])));
1765
+ if (Object.keys(gas).length) out.gas = gas;
1766
+ if (!a.ao) {
1767
+ out.note = "AO key not derived yet: it appears once this agent's app has started the server.";
1768
+ return out;
1769
+ }
1770
+ const [p, tokens, venues, redemptions] = await Promise.all([
1771
+ api.readPlayer(a.ao).catch(() => null),
1772
+ Promise.all(Object.entries({ rune: graph.processes.rune, pusd: graph.processes.pusd, ...graph.processes.elements }).map(async ([t, id]) => [t, await readAtoms(id, `balance-${a.ao}`).catch(() => 0n)])),
1773
+ Promise.all(Object.entries(VENUES).map(async ([v, pid]) => [
1774
+ v,
1775
+ await api.readVenuePosition(pid, a.ao).catch(() => null),
1776
+ await api.readVenueVaultPositions(pid, a.ao).catch(() => null)
1777
+ ])),
1778
+ readKey("pusd", "withdrawals").catch(() => null)
1779
+ ]);
1780
+ if (!p) {
1781
+ out.game = { joined: false };
1782
+ todo.push("Join the game (game_join).");
1783
+ } else {
1784
+ const raw = p.monsters?.[p.activeId] ?? p.collection?.[p.activeId];
1785
+ const c = companion(raw);
1786
+ out.game = {
1787
+ faction: p.faction,
1788
+ gold: p.gold,
1789
+ rune: p.inventory?.rune ?? 0,
1790
+ companion: c && { name: c.name, level: c.level, exp: c.exp, energy: c.energy, happiness: c.happiness },
1791
+ arena: { wins: p.wins ?? 0, losses: p.losses ?? 0, rating: p.rating, sessionBattlesLeft: p.battlesRemaining ?? 0 },
1792
+ ...p.battleFleet ? { inBattle: p.battleFleet.battleId } : {},
1793
+ ...p.hunt ? { onHunt: p.hunt.runId } : {}
1794
+ };
1795
+ if (!p.dailyReadyAt || Number(p.dailyReadyAt) <= Date.now()) todo.push("Daily crate is ready (game_daily).");
1796
+ if (count(p.lootboxes)) todo.push(`${count(p.lootboxes)} loot box(es) to open (game_lootbox).`);
1797
+ if (raw && Number(raw.exp ?? 0) >= Number(raw.nextLevelExp ?? Infinity)) todo.push("Companion can level up (game_level_up).");
1798
+ if (c && (c.energy < 25 || c.happiness < 25)) todo.push("Companion is below the arena's 25 energy/happiness: feed or play.");
1799
+ }
1800
+ const held = Object.fromEntries(tokens.filter(([, v]) => v > 0n).map(([t, v]) => [t, formatAtoms(v)]));
1801
+ if (Object.keys(held).length) out.tokens = held;
1802
+ const trading = {};
1803
+ for (const [v, pos, vaults] of venues) {
1804
+ const row = {};
1805
+ if (pos?.orders?.length) row.openOrders = pos.orders.length;
1806
+ if (pos?.fills?.length) row.recentFills = pos.fills.length;
1807
+ const shares = Object.entries(vaults ?? {}).flatMap(([m, r]) => Object.entries(r).filter(([, x]) => BigInt(x?.shares ?? 0) > 0n).map(([s]) => `${m} ${s}`));
1808
+ if (shares.length) row.vaults = shares;
1809
+ if (Object.keys(row).length) trading[v] = row;
1810
+ }
1811
+ if (Object.keys(trading).length) out.trading = trading;
1812
+ const pending = (redemptions ?? []).filter((w) => w.account === a.ao && w.status !== "released");
1813
+ if (pending.length) out.bridge = { pendingRedemptions: pending.length };
1814
+ if (Object.keys(gas).length && Object.values(gas).every((g) => /^0 /.test(g))) {
1815
+ todo.push("No chain gas yet: fund an address above to bridge.");
1816
+ }
1817
+ if (todo.length) out.todo = todo;
1818
+ return out;
1819
+ }
1820
+ function registerProgress(server) {
1821
+ tool(
1822
+ server,
1823
+ "progress",
1824
+ 'How an agent is doing, in one free read: game (companion, Gold, Rune, arena record, live battle or hunt), tokens, open orders and vault shares on both venues, pending bridge redemptions, chain gas, and what needs doing next. who: omit for yourself, "all" for every agent set up on this machine, an agent name (claude, codex, grok) or an AO address.',
1825
+ { who: z8.string().optional() },
1826
+ async ({ who }) => {
1827
+ const list = await Promise.all((await targets(who)).map(report));
1828
+ return list.length === 1 ? list[0] : list;
1829
+ },
1830
+ READ
1831
+ );
1832
+ }
1833
+
1702
1834
  // src/build.mjs
1703
1835
  var DOCS = process.env.PARALITH_DOCS_URL || "https://docs.paralithmarkets.com";
1704
1836
  var INSTRUCTIONS = `Paralith on AO (HyperBEAM): Rune Realm (a companion game), two order books, and the PUSD bridge.
@@ -1715,6 +1847,8 @@ Vaults (pooled liquidity, one amm/active/grid per market): vault_list, vault_pos
1715
1847
  Rune: rune_move withdraw (game -> token) / deposit (token -> game). Bridge: bridge_balances, bridge_faucet, bridge_deposit, bridge_redeem.
1716
1848
  DAO (stake TEST-RUNE; a passed proposal may send one attached message): dao_info, dao_proposals, dao_stake stake/unstake/withdraw, dao_propose, dao_vote.
1717
1849
 
1850
+ To report how you (or every agent set up on this machine) are doing, call progress (who: "all" for every agent); it also lists what needs doing next.
1851
+
1718
1852
  To let the user SEE something (an arena fight as it happens, a companion, a hunt, a market's book and chart, a vault, a position, bridge transfers), call show: it returns a live link and displays inline where the client supports it.
1719
1853
 
1720
1854
  Rules: if a tool says a write WAS accepted but unconfirmed, never resend it; re-read state instead.
@@ -1723,7 +1857,7 @@ var READ_ONLY_NOTE = `This endpoint is READ-ONLY: it explains the protocol and r
1723
1857
  To play, trade or bridge, run the local server with a wallet phrase: ${DOCS}/ai/mcp`;
1724
1858
  function buildServer() {
1725
1859
  const server = new McpServer(
1726
- { name: "paralith", version: "0.2.0" },
1860
+ { name: "paralith", version: "0.3.0" },
1727
1861
  { instructions: READ_ONLY ? `${READ_ONLY_NOTE}
1728
1862
 
1729
1863
  ${INSTRUCTIONS}` : INSTRUCTIONS }
@@ -1754,7 +1888,7 @@ ${INSTRUCTIONS}` : INSTRUCTIONS }
1754
1888
  server,
1755
1889
  "read_state",
1756
1890
  `Read any published key of any process, free: /<process>~process@1.0/now/<key>. process is an id or an alias (${Object.keys(PROCESS_ALIASES).join(", ")}). Returns null when absent.`,
1757
- { process: z8.string(), key: z8.string() },
1891
+ { process: z9.string(), key: z9.string() },
1758
1892
  async ({ process: process2, key }) => readKey(process2, key),
1759
1893
  READ
1760
1894
  );
@@ -1763,10 +1897,10 @@ ${INSTRUCTIONS}` : INSTRUCTIONS }
1763
1897
  "send_message",
1764
1898
  "Escape hatch: sign and send a raw message to any process and return its reply. Prefer the specific tools; use this only for an action they do not cover. Tag values must be strings; never use a tag named Target.",
1765
1899
  {
1766
- process: z8.string(),
1767
- tags: z8.record(z8.string(), z8.string()).describe('e.g. {"Action": "Pass.Info"}'),
1768
- data: z8.string().optional(),
1769
- push_outbox: z8.boolean().optional().describe("Deliver the messages this one emits to other processes (e.g. a Transfer to a process).")
1900
+ process: z9.string(),
1901
+ tags: z9.record(z9.string(), z9.string()).describe('e.g. {"Action": "Pass.Info"}'),
1902
+ data: z9.string().optional(),
1903
+ push_outbox: z9.boolean().optional().describe("Deliver the messages this one emits to other processes (e.g. a Transfer to a process).")
1770
1904
  },
1771
1905
  async ({ process: process2, tags: tags2, data, push_outbox }) => {
1772
1906
  if (Object.keys(tags2).some((k) => k.toLowerCase() === "target")) throw new Error("Target is not a usable tag name.");
@@ -1796,6 +1930,7 @@ ${INSTRUCTIONS}` : INSTRUCTIONS }
1796
1930
  registerDao(server);
1797
1931
  registerVaults(server);
1798
1932
  registerShow(server);
1933
+ registerProgress(server);
1799
1934
  return server;
1800
1935
  }
1801
1936