@aaronbassett/midnight-local-devnet 0.1.2 → 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 +34 -5
- package/dist/cli/commands/dashboard.d.ts +3 -0
- package/dist/cli/commands/dashboard.js +59 -0
- package/dist/cli/commands/dashboard.js.map +1 -0
- package/dist/cli/commands/interactive.d.ts +3 -0
- package/dist/cli/commands/interactive.js +16 -0
- package/dist/cli/commands/interactive.js.map +1 -0
- package/dist/cli/dashboard/html.d.ts +3 -0
- package/dist/cli/dashboard/html.js +1095 -0
- package/dist/cli/dashboard/html.js.map +1 -0
- package/dist/cli/dashboard/lib/log-parser.d.ts +15 -0
- package/dist/cli/dashboard/lib/log-parser.js +44 -0
- package/dist/cli/dashboard/lib/log-parser.js.map +1 -0
- package/dist/cli/dashboard/lib/proof-server-api.d.ts +15 -0
- package/dist/cli/dashboard/lib/proof-server-api.js +48 -0
- package/dist/cli/dashboard/lib/proof-server-api.js.map +1 -0
- package/dist/cli/dashboard/lib/substrate-rpc.d.ts +16 -0
- package/dist/cli/dashboard/lib/substrate-rpc.js +39 -0
- package/dist/cli/dashboard/lib/substrate-rpc.js.map +1 -0
- package/dist/cli/dashboard/server.d.ts +17 -0
- package/dist/cli/dashboard/server.js +133 -0
- package/dist/cli/dashboard/server.js.map +1 -0
- package/dist/cli/dashboard/state-collector.d.ts +67 -0
- package/dist/cli/dashboard/state-collector.js +121 -0
- package/dist/cli/dashboard/state-collector.js.map +1 -0
- package/dist/cli.js +18 -18
- package/dist/cli.js.map +1 -1
- package/package.json +5 -2
package/README.md
CHANGED
|
@@ -13,16 +13,16 @@ A CLI and MCP (Model Context Protocol) server for managing a local Docker-based
|
|
|
13
13
|
|
|
14
14
|
### CLI
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
Start the network:
|
|
17
17
|
|
|
18
18
|
```bash
|
|
19
|
-
npx @aaronbassett/midnight-local-devnet
|
|
19
|
+
npx @aaronbassett/midnight-local-devnet start
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
Open the dashboard in your browser to monitor your devnet:
|
|
23
23
|
|
|
24
24
|
```bash
|
|
25
|
-
npx @aaronbassett/midnight-local-devnet
|
|
25
|
+
npx @aaronbassett/midnight-local-devnet dashboard
|
|
26
26
|
```
|
|
27
27
|
|
|
28
28
|
### MCP Server
|
|
@@ -58,9 +58,38 @@ All commands can be run via `npx @aaronbassett/midnight-local-devnet <command>`.
|
|
|
58
58
|
| `fund <address>` | Fund a Bech32 address with NIGHT tokens | `--amount <n>` Amount in NIGHT (default: 50,000) |
|
|
59
59
|
| `fund-file <path>` | Fund all accounts from an accounts.json file | |
|
|
60
60
|
| `generate-accounts` | Generate random test accounts | `--count <n>`, `--format <mnemonic\|privateKey>`, `--output <path>`, `--fund`, `--register-dust` |
|
|
61
|
+
| `dashboard` | Open browser dashboard | `--port <n>` (default: 31780), `--no-open` Suppress auto-open |
|
|
61
62
|
| `interactive` | Start interactive menu mode | |
|
|
62
63
|
|
|
63
|
-
Running with no arguments
|
|
64
|
+
Running with no arguments displays help.
|
|
65
|
+
|
|
66
|
+
## Dashboard
|
|
67
|
+
|
|
68
|
+
The `dashboard` command starts a local server and opens a browser-based dashboard that displays the state of all local devnet services in real time.
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
npx @aaronbassett/midnight-local-devnet dashboard
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
This starts a server on `http://localhost:31780` and opens your default browser. Press Ctrl+C in the terminal to stop.
|
|
75
|
+
|
|
76
|
+
Options:
|
|
77
|
+
|
|
78
|
+
- `--port <n>` -- Use a specific port (default: 31780, auto-increments if in use)
|
|
79
|
+
- `--no-open` -- Start the server without opening the browser
|
|
80
|
+
|
|
81
|
+
The dashboard shows:
|
|
82
|
+
|
|
83
|
+
- **Node** -- Block height, average block time, chain, peers, sync status, version
|
|
84
|
+
- **Indexer** -- Ready status, response time
|
|
85
|
+
- **Proof Server** -- Version, proof versions, job processing/pending/capacity gauge
|
|
86
|
+
- **Wallet** -- Master wallet NIGHT (unshielded + shielded) and DUST balances
|
|
87
|
+
- **Response Times** -- SVG sparkline charts of per-service response times
|
|
88
|
+
- **Logs** -- Combined color-coded log stream from all services, filterable by service, level, or text search
|
|
89
|
+
|
|
90
|
+
The dashboard connects to the server via WebSocket for live updates. If the connection drops, it auto-reconnects. You can start and stop the network directly from the dashboard using the action buttons.
|
|
91
|
+
|
|
92
|
+
The layout is responsive and adapts to your browser window width.
|
|
64
93
|
|
|
65
94
|
## MCP Tool Reference
|
|
66
95
|
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { createServer } from 'node:net';
|
|
2
|
+
async function findOpenPort(start, maxAttempts = 10) {
|
|
3
|
+
for (let i = 0; i < maxAttempts; i++) {
|
|
4
|
+
const port = start + i;
|
|
5
|
+
const available = await new Promise((resolve) => {
|
|
6
|
+
const server = createServer();
|
|
7
|
+
server.once('error', () => resolve(false));
|
|
8
|
+
server.once('listening', () => {
|
|
9
|
+
server.close(() => resolve(true));
|
|
10
|
+
});
|
|
11
|
+
server.listen(port, '127.0.0.1');
|
|
12
|
+
});
|
|
13
|
+
if (available)
|
|
14
|
+
return port;
|
|
15
|
+
}
|
|
16
|
+
throw new Error(`No open port found in range ${start}-${start + maxAttempts - 1}`);
|
|
17
|
+
}
|
|
18
|
+
export function registerDashboardCommand(program, manager) {
|
|
19
|
+
program
|
|
20
|
+
.command('dashboard')
|
|
21
|
+
.description('Open browser dashboard for the local devnet')
|
|
22
|
+
.option('--port <port>', 'Port to serve dashboard on', '31780')
|
|
23
|
+
.option('--no-open', 'Do not auto-open the browser')
|
|
24
|
+
.action(async (opts) => {
|
|
25
|
+
const { createDashboardApp } = await import('../dashboard/server.js');
|
|
26
|
+
const { serve } = await import('@hono/node-server');
|
|
27
|
+
const open = (await import('open')).default;
|
|
28
|
+
const preferredPort = parseInt(opts.port, 10);
|
|
29
|
+
const port = await findOpenPort(preferredPort);
|
|
30
|
+
const { app, setupWebSocket, startPolling, shutdown } = createDashboardApp({
|
|
31
|
+
config: manager.config,
|
|
32
|
+
manager,
|
|
33
|
+
port,
|
|
34
|
+
});
|
|
35
|
+
const server = serve({ fetch: app.fetch, port, hostname: '127.0.0.1' }, (info) => {
|
|
36
|
+
const url = `http://localhost:${info.port}`;
|
|
37
|
+
console.log(`Dashboard running at ${url}`);
|
|
38
|
+
console.log('Press Ctrl+C to stop\n');
|
|
39
|
+
if (opts.open !== false) {
|
|
40
|
+
open(url).catch(() => {
|
|
41
|
+
// Ignore browser open errors
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
const wss = setupWebSocket(server);
|
|
46
|
+
startPolling();
|
|
47
|
+
const gracefulShutdown = async () => {
|
|
48
|
+
console.log('\nShutting down dashboard...');
|
|
49
|
+
shutdown();
|
|
50
|
+
wss.close();
|
|
51
|
+
await new Promise((resolve) => server.close(() => resolve()));
|
|
52
|
+
await manager.shutdown();
|
|
53
|
+
process.exit(0);
|
|
54
|
+
};
|
|
55
|
+
process.on('SIGINT', gracefulShutdown);
|
|
56
|
+
process.on('SIGTERM', gracefulShutdown);
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=dashboard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboard.js","sourceRoot":"","sources":["../../../src/cli/commands/dashboard.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { startInteractiveMode } from '../interactive.js';
|
|
2
|
+
export function registerInteractiveCommand(program, manager) {
|
|
3
|
+
program
|
|
4
|
+
.command('interactive')
|
|
5
|
+
.description('Start interactive menu mode')
|
|
6
|
+
.action(async () => {
|
|
7
|
+
try {
|
|
8
|
+
await startInteractiveMode(manager);
|
|
9
|
+
}
|
|
10
|
+
catch (error) {
|
|
11
|
+
console.error('Interactive mode error:', error instanceof Error ? error.message : error);
|
|
12
|
+
process.exit(1);
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=interactive.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interactive.js","sourceRoot":"","sources":["../../../src/cli/commands/interactive.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAEzD,MAAM,UAAU,0BAA0B,CAAC,OAAgB,EAAE,OAAuB;IAClF,OAAO;SACJ,OAAO,CAAC,aAAa,CAAC;SACtB,WAAW,CAAC,6BAA6B,CAAC;SAC1C,MAAM,CAAC,KAAK,IAAI,EAAE;QACjB,IAAI,CAAC;YACH,MAAM,oBAAoB,CAAC,OAAO,CAAC,CAAC;QACtC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,yBAAyB,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;YACzF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
|