@darksol/terminal 0.14.1 → 0.14.2
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/package.json +1 -1
- package/src/cli.js +9 -0
- package/src/services/health.js +131 -0
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -26,6 +26,7 @@ import { casinoBet, casinoTables, casinoStats, casinoReceipt, casinoHealth, casi
|
|
|
26
26
|
import { pokerNewGame, pokerAction, pokerStatus, pokerHistory } from './services/poker.js';
|
|
27
27
|
import { cardsCatalog, cardsOrder, cardsStatus } from './services/cards.js';
|
|
28
28
|
import { facilitatorHealth, facilitatorVerify, facilitatorSettle } from './services/facilitator.js';
|
|
29
|
+
import { healthCommand } from './services/health.js';
|
|
29
30
|
import { buildersLeaderboard, buildersLookup, buildersFeed } from './services/builders.js';
|
|
30
31
|
import { createScript, listScripts, runScript, showScript, editScript, deleteScript, cloneScript, listTemplates } from './scripts/engine.js';
|
|
31
32
|
import {
|
|
@@ -1712,6 +1713,14 @@ export function cli(argv) {
|
|
|
1712
1713
|
}
|
|
1713
1714
|
});
|
|
1714
1715
|
|
|
1716
|
+
// ═══════════════════════════════════════
|
|
1717
|
+
// HEALTH CHECK
|
|
1718
|
+
// ═══════════════════════════════════════
|
|
1719
|
+
program
|
|
1720
|
+
.command('health')
|
|
1721
|
+
.description('Check status of all DARKSOL services')
|
|
1722
|
+
.action(() => healthCommand());
|
|
1723
|
+
|
|
1715
1724
|
program
|
|
1716
1725
|
.command('dash')
|
|
1717
1726
|
.description('Launch the live terminal dashboard')
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import fetch from 'node-fetch';
|
|
2
|
+
import { getServiceURL } from '../config/store.js';
|
|
3
|
+
import { theme } from '../ui/theme.js';
|
|
4
|
+
import { spinner, kvDisplay, success, error, info, table } from '../ui/components.js';
|
|
5
|
+
import { showSection } from '../ui/banner.js';
|
|
6
|
+
|
|
7
|
+
// Service definitions — each has a name, URL resolver, and endpoint to ping
|
|
8
|
+
const SERVICES = [
|
|
9
|
+
{
|
|
10
|
+
name: 'Facilitator',
|
|
11
|
+
url: () => (getServiceURL('facilitator') || 'https://facilitator.darksol.net') + '/',
|
|
12
|
+
desc: 'x402 payment facilitator',
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
name: 'Casino',
|
|
16
|
+
url: () => (getServiceURL('casino') || 'https://casino.darksol.net') + '/api/stats',
|
|
17
|
+
desc: 'On-chain casino',
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
name: 'Oracle',
|
|
21
|
+
url: () => (getServiceURL('oracle') || 'https://acp.darksol.net/api/oracle') + '/health',
|
|
22
|
+
desc: 'Random oracle (x402)',
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
name: 'Cards',
|
|
26
|
+
url: () => (getServiceURL('cards') || 'https://acp.darksol.net') + '/api/cards/catalog',
|
|
27
|
+
desc: 'Prepaid crypto cards',
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
name: 'LI.FI',
|
|
31
|
+
url: () => 'https://li.quest/v1/status',
|
|
32
|
+
desc: 'Cross-chain swaps & bridges',
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
name: 'Agent Signer',
|
|
36
|
+
url: () => 'http://127.0.0.1:18790/status',
|
|
37
|
+
desc: 'Local signing proxy',
|
|
38
|
+
},
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
const TIMEOUT_MS = 5000;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Ping a single service endpoint.
|
|
45
|
+
* Returns { name, url, status: 'up'|'down'|'timeout', responseMs, error? }
|
|
46
|
+
*/
|
|
47
|
+
async function pingService(service) {
|
|
48
|
+
const url = service.url();
|
|
49
|
+
const start = Date.now();
|
|
50
|
+
|
|
51
|
+
try {
|
|
52
|
+
const controller = new AbortController();
|
|
53
|
+
const timer = setTimeout(() => controller.abort(), TIMEOUT_MS);
|
|
54
|
+
|
|
55
|
+
const resp = await fetch(url, { signal: controller.signal });
|
|
56
|
+
clearTimeout(timer);
|
|
57
|
+
|
|
58
|
+
const responseMs = Date.now() - start;
|
|
59
|
+
|
|
60
|
+
if (resp.ok || resp.status < 500) {
|
|
61
|
+
return { name: service.name, url, status: 'up', responseMs, desc: service.desc };
|
|
62
|
+
}
|
|
63
|
+
return { name: service.name, url, status: 'down', responseMs, desc: service.desc, error: `HTTP ${resp.status}` };
|
|
64
|
+
} catch (err) {
|
|
65
|
+
const responseMs = Date.now() - start;
|
|
66
|
+
if (err.name === 'AbortError') {
|
|
67
|
+
return { name: service.name, url, status: 'timeout', responseMs, desc: service.desc, error: 'Timed out' };
|
|
68
|
+
}
|
|
69
|
+
// Connection refused, DNS failure, etc.
|
|
70
|
+
const msg = err.code === 'ECONNREFUSED' ? 'Connection refused' : (err.message || 'Unknown error');
|
|
71
|
+
return { name: service.name, url, status: 'down', responseMs, desc: service.desc, error: msg };
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Check health of all configured services.
|
|
77
|
+
* Returns array of results.
|
|
78
|
+
*/
|
|
79
|
+
export async function checkHealth() {
|
|
80
|
+
return Promise.all(SERVICES.map(s => pingService(s)));
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* CLI handler — check all services and display results.
|
|
85
|
+
*/
|
|
86
|
+
export async function healthCommand() {
|
|
87
|
+
showSection('SERVICE HEALTH CHECK 🏥');
|
|
88
|
+
const spin = spinner('Checking all services...').start();
|
|
89
|
+
|
|
90
|
+
const results = await checkHealth();
|
|
91
|
+
spin.stop();
|
|
92
|
+
|
|
93
|
+
// Status indicators
|
|
94
|
+
const statusIcon = (s) => {
|
|
95
|
+
if (s === 'up') return theme.success('● UP');
|
|
96
|
+
if (s === 'timeout') return theme.warning('◐ TIMEOUT');
|
|
97
|
+
return theme.error('○ DOWN');
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
const latencyColor = (ms) => {
|
|
101
|
+
if (ms < 300) return theme.success(`${ms}ms`);
|
|
102
|
+
if (ms < 1000) return theme.warning(`${ms}ms`);
|
|
103
|
+
return theme.error(`${ms}ms`);
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
// Display table
|
|
107
|
+
const headers = ['Service', 'Status', 'Latency', 'Details'];
|
|
108
|
+
const rows = results.map(r => [
|
|
109
|
+
theme.bright(r.name),
|
|
110
|
+
statusIcon(r.status),
|
|
111
|
+
latencyColor(r.responseMs),
|
|
112
|
+
r.status === 'up' ? theme.dim(r.desc) : theme.error(r.error || ''),
|
|
113
|
+
]);
|
|
114
|
+
|
|
115
|
+
console.log('');
|
|
116
|
+
table(headers, rows);
|
|
117
|
+
|
|
118
|
+
// Summary
|
|
119
|
+
const healthy = results.filter(r => r.status === 'up').length;
|
|
120
|
+
const total = results.length;
|
|
121
|
+
console.log('');
|
|
122
|
+
|
|
123
|
+
if (healthy === total) {
|
|
124
|
+
success(`${healthy}/${total} services healthy`);
|
|
125
|
+
} else if (healthy > 0) {
|
|
126
|
+
info(`${healthy}/${total} services healthy`);
|
|
127
|
+
} else {
|
|
128
|
+
error(`${healthy}/${total} services healthy`);
|
|
129
|
+
}
|
|
130
|
+
console.log('');
|
|
131
|
+
}
|