darkmesh-node 0.1.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/CHANGELOG.md +12 -0
- package/README.md +89 -0
- package/assets/darksol-banner.png +0 -0
- package/package.json +35 -0
- package/src/cli.js +366 -0
- package/src/client.js +565 -0
- package/src/config.js +64 -0
- package/src/identity.js +26 -0
- package/src/index.js +400 -0
- package/src/operator.js +113 -0
- package/src/providers.js +19 -0
- package/src/service.js +148 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this package are documented in this file.
|
|
4
|
+
|
|
5
|
+
## 0.1.0 - 2026-06-01
|
|
6
|
+
|
|
7
|
+
- initial public operator package for DarkMesh prototype
|
|
8
|
+
- add local operator account identity + persistence
|
|
9
|
+
- add operator-backed node registration and binding auth
|
|
10
|
+
- add operator CLI for status, jobs, earnings, service control, balance, ledger, and payout claims
|
|
11
|
+
- add foreground/background worker controls
|
|
12
|
+
- add internal credits and escrow-style payout claim flow
|
package/README.md
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+

|
|
2
|
+
|
|
3
|
+
# darkmesh-node
|
|
4
|
+
|
|
5
|
+
Built by DARKSOL 🌑
|
|
6
|
+
|
|
7
|
+
[](https://www.npmjs.com/package/darkmesh-node)
|
|
8
|
+
[](./package.json)
|
|
9
|
+
[](https://nodejs.org)
|
|
10
|
+
|
|
11
|
+
Operator node CLI and daemon for the DarkMesh prototype network.
|
|
12
|
+
|
|
13
|
+
`darkmesh-node` gives operators a local install surface for:
|
|
14
|
+
- node identity generation
|
|
15
|
+
- operator account key generation
|
|
16
|
+
- coordinator registration/connect flow
|
|
17
|
+
- local background service control
|
|
18
|
+
- status, jobs, earnings, balance, ledger, and payout-claim commands
|
|
19
|
+
|
|
20
|
+
## Status
|
|
21
|
+
|
|
22
|
+
This package is a **working prototype operator surface**.
|
|
23
|
+
|
|
24
|
+
What is real today:
|
|
25
|
+
- local operator + node identity persistence
|
|
26
|
+
- operator-backed node registration
|
|
27
|
+
- outbound node connectivity to a coordinator
|
|
28
|
+
- routed text-job handling
|
|
29
|
+
- internal credits / ledger / payout-claim flow
|
|
30
|
+
- foreground + background service controls
|
|
31
|
+
|
|
32
|
+
What is not real yet:
|
|
33
|
+
- production coordinator hosting
|
|
34
|
+
- wallet settlement
|
|
35
|
+
- payout approval backend
|
|
36
|
+
- full operator dashboard/admin UX
|
|
37
|
+
- final verification/audit pipeline
|
|
38
|
+
|
|
39
|
+
## Install
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
npm install -g darkmesh-node
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Quick Start
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
darkmesh init \
|
|
49
|
+
--coordinator-url http://127.0.0.1:8787 \
|
|
50
|
+
--operator-id meta \
|
|
51
|
+
--label my-node \
|
|
52
|
+
--provider memory
|
|
53
|
+
|
|
54
|
+
# register / connect the node
|
|
55
|
+
darkmesh connect
|
|
56
|
+
|
|
57
|
+
# inspect local/operator/node state
|
|
58
|
+
darkmesh whoami
|
|
59
|
+
darkmesh status --pretty
|
|
60
|
+
|
|
61
|
+
# run foreground worker
|
|
62
|
+
darkmesh run
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Core commands
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
darkmesh init
|
|
69
|
+
darkmesh whoami
|
|
70
|
+
darkmesh connect
|
|
71
|
+
darkmesh disconnect
|
|
72
|
+
darkmesh status --pretty
|
|
73
|
+
darkmesh jobs
|
|
74
|
+
darkmesh earnings
|
|
75
|
+
darkmesh balance
|
|
76
|
+
darkmesh ledger
|
|
77
|
+
darkmesh payout --amount 1 --destination wallet:demo
|
|
78
|
+
darkmesh service start
|
|
79
|
+
darkmesh service status
|
|
80
|
+
darkmesh service stop
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Notes
|
|
84
|
+
|
|
85
|
+
- This package is the **operator-side install surface** only.
|
|
86
|
+
- The coordinator / control plane is a separate service lane.
|
|
87
|
+
- Current economics are **internal credits only**.
|
|
88
|
+
|
|
89
|
+
Built with teeth. 🌑
|
|
Binary file
|
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "darkmesh-node",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"description": "Operator node CLI and daemon for the DarkMesh prototype network.",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "DARKSOL",
|
|
8
|
+
"type": "module",
|
|
9
|
+
"main": "src/index.js",
|
|
10
|
+
"bin": {
|
|
11
|
+
"darkmesh": "src/cli.js"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"src",
|
|
15
|
+
"README.md",
|
|
16
|
+
"CHANGELOG.md",
|
|
17
|
+
"assets"
|
|
18
|
+
],
|
|
19
|
+
"engines": {
|
|
20
|
+
"node": ">=20"
|
|
21
|
+
},
|
|
22
|
+
"keywords": [
|
|
23
|
+
"darkmesh",
|
|
24
|
+
"cli",
|
|
25
|
+
"operator",
|
|
26
|
+
"inference",
|
|
27
|
+
"ollama",
|
|
28
|
+
"ai"
|
|
29
|
+
],
|
|
30
|
+
"scripts": {
|
|
31
|
+
"cli": "node src/cli.js",
|
|
32
|
+
"dev": "node src/index.js",
|
|
33
|
+
"start": "node src/index.js"
|
|
34
|
+
}
|
|
35
|
+
}
|
package/src/cli.js
ADDED
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from 'node:fs/promises';
|
|
3
|
+
import { spawn } from 'node:child_process';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import { getDarkMeshHome } from './config.js';
|
|
6
|
+
import { getServiceLogPath, openServiceLogFd } from './service.js';
|
|
7
|
+
import { initNodeClient, whoAmI, fetchNodeStatus, connectNodeClient, fetchNodeJobs, fetchNodeEarnings, fetchNodeBalance, fetchNodeLedgerEvents, fetchNodeClaims, requestNodePayout, runNodeClient, disconnectNodeClient, getServiceStatus, getServiceLogs, startNodeService, stopNodeService, restartNodeService, settleNodeServiceStopped, waitForServiceStopRequest } from './client.js';
|
|
8
|
+
import { saveServiceState } from './service.js';
|
|
9
|
+
|
|
10
|
+
function parseArgs(argv) {
|
|
11
|
+
const args = argv.slice(2);
|
|
12
|
+
const command = args[0] || 'help';
|
|
13
|
+
const options = {};
|
|
14
|
+
|
|
15
|
+
for (let i = 1; i < args.length; i += 1) {
|
|
16
|
+
const token = args[i];
|
|
17
|
+
if (!token.startsWith('--')) continue;
|
|
18
|
+
const key = token.slice(2);
|
|
19
|
+
const next = args[i + 1];
|
|
20
|
+
if (!next || next.startsWith('--')) {
|
|
21
|
+
options[key] = true;
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
options[key] = next;
|
|
25
|
+
i += 1;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return { command, options };
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function print(value) {
|
|
32
|
+
process.stdout.write(`${JSON.stringify(value)}\n`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function printText(value = '') {
|
|
36
|
+
process.stdout.write(String(value));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function getHome(options) {
|
|
40
|
+
return getDarkMeshHome(options.home);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const selfPath = fileURLToPath(import.meta.url);
|
|
44
|
+
|
|
45
|
+
function spawnServiceWorker(home) {
|
|
46
|
+
const logFd = openServiceLogFd(home);
|
|
47
|
+
const child = spawn(process.execPath, [selfPath, 'run', '--home', home, '--service-mode'], {
|
|
48
|
+
detached: true,
|
|
49
|
+
stdio: ['ignore', logFd, logFd],
|
|
50
|
+
windowsHide: true,
|
|
51
|
+
cwd: process.cwd(),
|
|
52
|
+
env: { ...process.env, DARKMESH_SERVICE_MODE: '1' }
|
|
53
|
+
});
|
|
54
|
+
child.unref();
|
|
55
|
+
return child.pid;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function formatNodeStatusPretty(status) {
|
|
59
|
+
const lines = [
|
|
60
|
+
`DarkMesh node: ${status.label || 'unnamed-node'}`,
|
|
61
|
+
`operator: ${status.operatorId || 'unknown'}`,
|
|
62
|
+
`coordinator: ${status.coordinatorUrl}`,
|
|
63
|
+
`registration: ${status.registrationState}`,
|
|
64
|
+
`connectivity: ${status.connectivity}`,
|
|
65
|
+
`nodeId: ${status.nodeId || 'none'}`,
|
|
66
|
+
`privacy: ${status.privacyClass}`,
|
|
67
|
+
`models: ${(status.models || []).join(', ') || 'none'}`,
|
|
68
|
+
`verified models: ${(status.verifiedModels || []).join(', ') || 'none'}`,
|
|
69
|
+
`verification: ${status.verificationStatus || 'pending'}${status.verificationReason ? ` (${status.verificationReason})` : ''}`,
|
|
70
|
+
`service: ${status.runtime?.serviceStatus || 'stopped'}${status.runtime?.servicePid ? ` (pid ${status.runtime.servicePid})` : ''}`,
|
|
71
|
+
`credits: available ${status.availableCredits || 0} | lifetime ${status.lifetimeEarnedCredits || 0}`
|
|
72
|
+
];
|
|
73
|
+
|
|
74
|
+
if (status.health) lines.push(`health: ${status.health}`);
|
|
75
|
+
if (status.activeJobId) lines.push(`active job: ${status.activeJobId}`);
|
|
76
|
+
if (status.recentJobs?.length) lines.push(`recent jobs: ${status.recentJobs.length}`);
|
|
77
|
+
return `${lines.join('\n')}\n`;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async function followServiceLogs(home, options = {}) {
|
|
81
|
+
const logPath = getServiceLogPath(home);
|
|
82
|
+
const tailLines = Math.max(1, Number(options.tailLines || 50));
|
|
83
|
+
const pollMs = Math.max(50, Number(options.pollMs || 250));
|
|
84
|
+
let offset = 0;
|
|
85
|
+
|
|
86
|
+
const initial = await getServiceLogs(home, { tailLines });
|
|
87
|
+
if (initial.text) {
|
|
88
|
+
printText(`${initial.text}${initial.text.endsWith('\n') ? '' : '\n'}`);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
try {
|
|
92
|
+
const raw = await fs.readFile(logPath, 'utf8');
|
|
93
|
+
offset = Buffer.byteLength(raw, 'utf8');
|
|
94
|
+
} catch (error) {
|
|
95
|
+
if (error?.code !== 'ENOENT') throw error;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
let stopping = false;
|
|
99
|
+
const stop = () => {
|
|
100
|
+
stopping = true;
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
process.on('SIGINT', stop);
|
|
104
|
+
process.on('SIGTERM', stop);
|
|
105
|
+
|
|
106
|
+
while (!stopping) {
|
|
107
|
+
try {
|
|
108
|
+
const raw = await fs.readFile(logPath, 'utf8');
|
|
109
|
+
const size = Buffer.byteLength(raw, 'utf8');
|
|
110
|
+
if (size < offset) {
|
|
111
|
+
offset = 0;
|
|
112
|
+
}
|
|
113
|
+
if (size > offset) {
|
|
114
|
+
const next = Buffer.from(raw, 'utf8').subarray(offset).toString('utf8');
|
|
115
|
+
printText(next);
|
|
116
|
+
offset = size;
|
|
117
|
+
}
|
|
118
|
+
} catch (error) {
|
|
119
|
+
if (error?.code !== 'ENOENT') throw error;
|
|
120
|
+
}
|
|
121
|
+
await new Promise(resolve => setTimeout(resolve, pollMs));
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
async function main() {
|
|
126
|
+
const { command, options } = parseArgs(process.argv);
|
|
127
|
+
const home = getHome(options);
|
|
128
|
+
|
|
129
|
+
if (command === 'init') {
|
|
130
|
+
const result = await initNodeClient(home, {
|
|
131
|
+
coordinatorUrl: options['coordinator-url'],
|
|
132
|
+
operatorId: options['operator-id'],
|
|
133
|
+
label: options.label,
|
|
134
|
+
privacyClass: options['privacy-class'],
|
|
135
|
+
provider: {
|
|
136
|
+
type: options.provider,
|
|
137
|
+
baseUrl: options['provider-url']
|
|
138
|
+
},
|
|
139
|
+
models: options.models ? String(options.models).split(',').map(v => v.trim()).filter(Boolean) : undefined,
|
|
140
|
+
privacySecret: options['privacy-secret'] || undefined
|
|
141
|
+
});
|
|
142
|
+
print({ ok: true, command, ...result });
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (command === 'whoami') {
|
|
147
|
+
print({ ok: true, command, ...(await whoAmI(home)) });
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (command === 'status') {
|
|
152
|
+
const result = { ok: true, command, ...(await fetchNodeStatus(home)) };
|
|
153
|
+
if (options.pretty || options.human) {
|
|
154
|
+
printText(formatNodeStatusPretty(result));
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
print(result);
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (command === 'connect') {
|
|
162
|
+
const { info, config } = await connectNodeClient(home);
|
|
163
|
+
print({
|
|
164
|
+
ok: true,
|
|
165
|
+
command,
|
|
166
|
+
nodeId: info.nodeId,
|
|
167
|
+
models: info.models,
|
|
168
|
+
label: config.label,
|
|
169
|
+
operatorId: config.operatorId,
|
|
170
|
+
coordinatorUrl: config.coordinatorUrl,
|
|
171
|
+
registered: true,
|
|
172
|
+
connected: false,
|
|
173
|
+
wsPath: info.wsPath
|
|
174
|
+
});
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (command === 'jobs') {
|
|
179
|
+
print({ ok: true, command, ...(await fetchNodeJobs(home)) });
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (command === 'earnings') {
|
|
184
|
+
print({ ok: true, command, ...(await fetchNodeEarnings(home)) });
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (command === 'balance') {
|
|
189
|
+
print({ ok: true, command, ...(await fetchNodeBalance(home)) });
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (command === 'ledger') {
|
|
194
|
+
print({ ok: true, command, ...(await fetchNodeLedgerEvents(home)) });
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (command === 'claims') {
|
|
199
|
+
print({ ok: true, command, ...(await fetchNodeClaims(home, { status: options.status })) });
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (command === 'payout') {
|
|
204
|
+
const amountCredits = Number(options.amount || options.credits);
|
|
205
|
+
print({
|
|
206
|
+
ok: true,
|
|
207
|
+
command,
|
|
208
|
+
...(await requestNodePayout(home, {
|
|
209
|
+
amountCredits,
|
|
210
|
+
destination: options.destination,
|
|
211
|
+
requesterId: options['requester-id']
|
|
212
|
+
}))
|
|
213
|
+
});
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (command === 'disconnect') {
|
|
218
|
+
print({ ok: true, command, ...(await disconnectNodeClient(home)) });
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if (command === 'service') {
|
|
223
|
+
const action = options.action || options._action || process.argv[3] || 'status';
|
|
224
|
+
|
|
225
|
+
if (action === 'status') {
|
|
226
|
+
print({ ok: true, command, action, service: await getServiceStatus(home) });
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (action === 'start') {
|
|
231
|
+
const current = await getServiceStatus(home);
|
|
232
|
+
if (current.running) {
|
|
233
|
+
print({ ok: true, command, action, alreadyRunning: true, service: current });
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const pid = spawnServiceWorker(home);
|
|
238
|
+
const result = await startNodeService(home, { pid, status: 'starting' });
|
|
239
|
+
print({
|
|
240
|
+
ok: true,
|
|
241
|
+
command,
|
|
242
|
+
action,
|
|
243
|
+
alreadyRunning: false,
|
|
244
|
+
pid,
|
|
245
|
+
logPath: getServiceLogPath(home),
|
|
246
|
+
service: result.service
|
|
247
|
+
});
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
if (action === 'restart') {
|
|
252
|
+
const result = await restartNodeService(home, {
|
|
253
|
+
status: 'starting',
|
|
254
|
+
spawn: () => spawnServiceWorker(home)
|
|
255
|
+
});
|
|
256
|
+
print({
|
|
257
|
+
ok: true,
|
|
258
|
+
command,
|
|
259
|
+
action,
|
|
260
|
+
restarted: true,
|
|
261
|
+
alreadyRunning: false,
|
|
262
|
+
pid: result.service.pid,
|
|
263
|
+
logPath: getServiceLogPath(home),
|
|
264
|
+
service: result.service,
|
|
265
|
+
previouslyRunning: result.previouslyRunning
|
|
266
|
+
});
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
if (action === 'logs') {
|
|
271
|
+
const tailLines = Number(options.tail || options.lines || 50);
|
|
272
|
+
if (options.follow || options.f) {
|
|
273
|
+
await followServiceLogs(home, { tailLines, pollMs: options['poll-ms'] || 250 });
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
print({ ok: true, command, action, ...(await getServiceLogs(home, { tailLines })) });
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
if (action === 'stop') {
|
|
281
|
+
print({ ok: true, command, action, ...(await stopNodeService(home)) });
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
throw new Error(`service_action_unknown_${action}`);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
if (command === 'run') {
|
|
289
|
+
const { node, info, config } = await runNodeClient(home);
|
|
290
|
+
let shuttingDown = false;
|
|
291
|
+
let keepAliveResolve;
|
|
292
|
+
const keepAlive = new Promise(resolve => {
|
|
293
|
+
keepAliveResolve = resolve;
|
|
294
|
+
});
|
|
295
|
+
const shutdown = async (signal = 'shutdown') => {
|
|
296
|
+
if (shuttingDown) return;
|
|
297
|
+
shuttingDown = true;
|
|
298
|
+
try {
|
|
299
|
+
await node.close();
|
|
300
|
+
if (process.env.DARKMESH_SERVICE_MODE === '1' || options['service-mode']) {
|
|
301
|
+
await settleNodeServiceStopped(home, { signal, nodeId: info.nodeId });
|
|
302
|
+
}
|
|
303
|
+
} finally {
|
|
304
|
+
keepAliveResolve?.();
|
|
305
|
+
print({ ok: true, command, nodeId: info.nodeId, signal, stopped: true });
|
|
306
|
+
}
|
|
307
|
+
};
|
|
308
|
+
|
|
309
|
+
process.on('SIGINT', () => { shutdown('SIGINT').catch(() => process.exit(1)); });
|
|
310
|
+
process.on('SIGTERM', () => { shutdown('SIGTERM').catch(() => process.exit(1)); });
|
|
311
|
+
if (process.env.DARKMESH_SERVICE_MODE === '1' || options['service-mode']) {
|
|
312
|
+
waitForServiceStopRequest(home, shutdown).catch(() => process.exit(1));
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
if (process.env.DARKMESH_SERVICE_MODE === '1' || options['service-mode']) {
|
|
316
|
+
await saveServiceState(home, {
|
|
317
|
+
...(await getServiceStatus(home)),
|
|
318
|
+
pid: process.pid,
|
|
319
|
+
status: 'running',
|
|
320
|
+
startedAt: new Date().toISOString(),
|
|
321
|
+
stoppedAt: null,
|
|
322
|
+
lastNodeId: info.nodeId
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
print({
|
|
327
|
+
ok: true,
|
|
328
|
+
command,
|
|
329
|
+
nodeId: info.nodeId,
|
|
330
|
+
models: info.models,
|
|
331
|
+
label: config.label,
|
|
332
|
+
operatorId: config.operatorId,
|
|
333
|
+
coordinatorUrl: config.coordinatorUrl,
|
|
334
|
+
connected: true,
|
|
335
|
+
running: true
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
await keepAlive;
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
print({
|
|
343
|
+
ok: true,
|
|
344
|
+
commands: ['init', 'whoami', 'status', 'connect', 'disconnect', 'jobs', 'earnings', 'balance', 'ledger', 'claims', 'payout', 'run', 'service'],
|
|
345
|
+
usage: {
|
|
346
|
+
init: 'darkmesh init [--home <path>] [--coordinator-url <url>] [--operator-id <id>] [--label <name>] [--provider <type>] [--provider-url <url>] [--models <csv>] [--privacy-class <class>] [--privacy-secret <secret>]',
|
|
347
|
+
whoami: 'darkmesh whoami [--home <path>]',
|
|
348
|
+
status: 'darkmesh status [--home <path>] [--pretty]',
|
|
349
|
+
connect: 'darkmesh connect [--home <path>]',
|
|
350
|
+
disconnect: 'darkmesh disconnect [--home <path>]',
|
|
351
|
+
jobs: 'darkmesh jobs [--home <path>]',
|
|
352
|
+
earnings: 'darkmesh earnings [--home <path>]',
|
|
353
|
+
balance: 'darkmesh balance [--home <path>]',
|
|
354
|
+
ledger: 'darkmesh ledger [--home <path>]',
|
|
355
|
+
claims: 'darkmesh claims [--home <path>] [--status <pending_review|approved|rejected>]',
|
|
356
|
+
payout: 'darkmesh payout --amount <credits> [--destination <wallet-or-handle>] [--home <path>]',
|
|
357
|
+
run: 'darkmesh run [--home <path>] [--service-mode]',
|
|
358
|
+
service: 'darkmesh service <status|start|stop|restart|logs> [--home <path>] [--tail <lines>] [--follow]'
|
|
359
|
+
}
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
main().catch(error => {
|
|
364
|
+
process.stderr.write(`${JSON.stringify({ ok: false, error: error.message })}\n`);
|
|
365
|
+
process.exit(1);
|
|
366
|
+
});
|