chainlesschain 0.47.9 → 0.51.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/bin/chainlesschain.js +0 -0
- package/package.json +1 -1
- package/src/assets/web-panel/.build-hash +1 -1
- package/src/assets/web-panel/assets/{AppLayout-6SPt_8Y_.js → AppLayout-Rvi759IS.js} +1 -1
- package/src/assets/web-panel/assets/Dashboard-BS-tzGNj.css +1 -0
- package/src/assets/web-panel/assets/{Dashboard-Br7kCwKJ.js → Dashboard-DBhFxXYQ.js} +2 -2
- package/src/assets/web-panel/assets/{index-tN-8TosE.js → index-uL0cZ8N_.js} +2 -2
- package/src/assets/web-panel/index.html +2 -2
- package/src/commands/codegen.js +303 -0
- package/src/commands/collab.js +482 -0
- package/src/commands/crosschain.js +382 -0
- package/src/commands/dbevo.js +388 -0
- package/src/commands/dev.js +411 -0
- package/src/commands/federation.js +427 -0
- package/src/commands/fusion.js +332 -0
- package/src/commands/governance.js +505 -0
- package/src/commands/hardening.js +110 -0
- package/src/commands/incentive.js +373 -0
- package/src/commands/inference.js +304 -0
- package/src/commands/infra.js +361 -0
- package/src/commands/ipfs.js +392 -0
- package/src/commands/kg.js +371 -0
- package/src/commands/marketplace.js +326 -0
- package/src/commands/mcp.js +97 -18
- package/src/commands/multimodal.js +404 -0
- package/src/commands/nlprog.js +329 -0
- package/src/commands/ops.js +408 -0
- package/src/commands/perception.js +385 -0
- package/src/commands/pqc.js +34 -0
- package/src/commands/privacy.js +345 -0
- package/src/commands/quantization.js +280 -0
- package/src/commands/recommend.js +336 -0
- package/src/commands/reputation.js +349 -0
- package/src/commands/runtime.js +500 -0
- package/src/commands/sla.js +352 -0
- package/src/commands/stress.js +252 -0
- package/src/commands/tech.js +268 -0
- package/src/commands/tenant.js +576 -0
- package/src/commands/trust.js +366 -0
- package/src/harness/mcp-client.js +330 -54
- package/src/index.js +118 -0
- package/src/lib/aiops.js +523 -0
- package/src/lib/autonomous-developer.js +524 -0
- package/src/lib/code-agent.js +442 -0
- package/src/lib/collaboration-governance.js +556 -0
- package/src/lib/community-governance.js +649 -0
- package/src/lib/content-recommendation.js +600 -0
- package/src/lib/cross-chain.js +669 -0
- package/src/lib/dbevo.js +669 -0
- package/src/lib/decentral-infra.js +445 -0
- package/src/lib/federation-hardening.js +587 -0
- package/src/lib/hardening-manager.js +409 -0
- package/src/lib/inference-network.js +407 -0
- package/src/lib/ipfs-storage.js +575 -0
- package/src/lib/knowledge-graph.js +530 -0
- package/src/lib/mcp-client.js +3 -0
- package/src/lib/multimodal.js +725 -0
- package/src/lib/nl-programming.js +595 -0
- package/src/lib/perception.js +500 -0
- package/src/lib/pqc-manager.js +141 -9
- package/src/lib/privacy-computing.js +575 -0
- package/src/lib/protocol-fusion.js +535 -0
- package/src/lib/quantization.js +362 -0
- package/src/lib/reputation-optimizer.js +509 -0
- package/src/lib/skill-marketplace.js +397 -0
- package/src/lib/sla-manager.js +484 -0
- package/src/lib/stress-tester.js +383 -0
- package/src/lib/tech-learning-engine.js +651 -0
- package/src/lib/tenant-saas.js +831 -0
- package/src/lib/token-incentive.js +513 -0
- package/src/lib/trust-security.js +473 -0
- package/src/lib/universal-runtime.js +771 -0
- package/src/assets/web-panel/assets/Dashboard-CKeMmCoT.css +0 -1
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token Incentive commands (Phase 66)
|
|
3
|
+
* chainlesschain incentive contribution-types|tx-types|balance|accounts|transfer|
|
|
4
|
+
* mint|history|contribute|reward|contributions|leaderboard
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import chalk from "chalk";
|
|
8
|
+
import { logger } from "../lib/logger.js";
|
|
9
|
+
import { bootstrap, shutdown } from "../runtime/bootstrap.js";
|
|
10
|
+
import {
|
|
11
|
+
ensureTokenTables,
|
|
12
|
+
listContributionTypes,
|
|
13
|
+
listTxTypes,
|
|
14
|
+
getBalance,
|
|
15
|
+
listAccounts,
|
|
16
|
+
transfer,
|
|
17
|
+
mint,
|
|
18
|
+
getTransactionHistory,
|
|
19
|
+
recordContribution,
|
|
20
|
+
rewardContribution,
|
|
21
|
+
getContributions,
|
|
22
|
+
getLeaderboard,
|
|
23
|
+
} from "../lib/token-incentive.js";
|
|
24
|
+
|
|
25
|
+
function _dbFromCtx(ctx) {
|
|
26
|
+
if (!ctx.db) {
|
|
27
|
+
logger.error("Database not available");
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
const db = ctx.db.getDatabase();
|
|
31
|
+
ensureTokenTables(db);
|
|
32
|
+
return db;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function _printAccount(a) {
|
|
36
|
+
logger.log(` ${chalk.bold("Account:")} ${chalk.cyan(a.accountId)}`);
|
|
37
|
+
logger.log(` ${chalk.bold("Balance:")} ${a.balance}`);
|
|
38
|
+
logger.log(` ${chalk.bold("Total Earned:")} ${a.totalEarned}`);
|
|
39
|
+
logger.log(` ${chalk.bold("Total Spent:")} ${a.totalSpent}`);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function registerIncentiveCommand(program) {
|
|
43
|
+
const inc = program
|
|
44
|
+
.command("incentive")
|
|
45
|
+
.description(
|
|
46
|
+
"Token incentive — ledger accounts, transfers, contributions, leaderboard",
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
inc
|
|
50
|
+
.command("contribution-types")
|
|
51
|
+
.description("List known contribution types and their base rewards")
|
|
52
|
+
.option("--json", "Output as JSON")
|
|
53
|
+
.action((options) => {
|
|
54
|
+
const types = listContributionTypes();
|
|
55
|
+
if (options.json) {
|
|
56
|
+
console.log(JSON.stringify(types, null, 2));
|
|
57
|
+
} else {
|
|
58
|
+
for (const t of types) {
|
|
59
|
+
logger.log(
|
|
60
|
+
` ${chalk.cyan(t.name.padEnd(22))} base=${String(t.baseReward).padStart(6)} ${t.description}`,
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
inc
|
|
67
|
+
.command("tx-types")
|
|
68
|
+
.description("List known transaction types")
|
|
69
|
+
.option("--json", "Output as JSON")
|
|
70
|
+
.action((options) => {
|
|
71
|
+
const types = listTxTypes();
|
|
72
|
+
if (options.json) {
|
|
73
|
+
console.log(JSON.stringify(types, null, 2));
|
|
74
|
+
} else {
|
|
75
|
+
for (const t of types) logger.log(` ${chalk.cyan(t)}`);
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
inc
|
|
80
|
+
.command("balance <account-id>")
|
|
81
|
+
.description("Query token balance for an account")
|
|
82
|
+
.option("--json", "Output as JSON")
|
|
83
|
+
.action(async (accountId, options) => {
|
|
84
|
+
try {
|
|
85
|
+
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
86
|
+
_dbFromCtx(ctx);
|
|
87
|
+
const account = getBalance(accountId);
|
|
88
|
+
if (!account) {
|
|
89
|
+
logger.info(`No account: ${accountId} (balance 0)`);
|
|
90
|
+
} else if (options.json) {
|
|
91
|
+
console.log(JSON.stringify(account, null, 2));
|
|
92
|
+
} else {
|
|
93
|
+
_printAccount(account);
|
|
94
|
+
}
|
|
95
|
+
await shutdown();
|
|
96
|
+
} catch (err) {
|
|
97
|
+
logger.error(`Failed: ${err.message}`);
|
|
98
|
+
process.exit(1);
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
inc
|
|
103
|
+
.command("accounts")
|
|
104
|
+
.description("List accounts (sorted by balance DESC)")
|
|
105
|
+
.option("--limit <n>", "Maximum entries", parseInt, 50)
|
|
106
|
+
.option("--json", "Output as JSON")
|
|
107
|
+
.action(async (options) => {
|
|
108
|
+
try {
|
|
109
|
+
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
110
|
+
_dbFromCtx(ctx);
|
|
111
|
+
const rows = listAccounts({ limit: options.limit });
|
|
112
|
+
if (options.json) {
|
|
113
|
+
console.log(JSON.stringify(rows, null, 2));
|
|
114
|
+
} else if (rows.length === 0) {
|
|
115
|
+
logger.info("No accounts.");
|
|
116
|
+
} else {
|
|
117
|
+
for (const a of rows) {
|
|
118
|
+
logger.log(
|
|
119
|
+
` ${chalk.cyan(a.accountId.padEnd(24))} balance=${String(a.balance).padStart(10)} earned=${a.totalEarned} spent=${a.totalSpent}`,
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
await shutdown();
|
|
124
|
+
} catch (err) {
|
|
125
|
+
logger.error(`Failed: ${err.message}`);
|
|
126
|
+
process.exit(1);
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
inc
|
|
131
|
+
.command("mint <to> <amount>")
|
|
132
|
+
.description("Mint tokens into an account (admin op)")
|
|
133
|
+
.option("-r, --reason <text>", "Reason (e.g. initial grant)")
|
|
134
|
+
.option("--json", "Output as JSON")
|
|
135
|
+
.action(async (to, amountStr, options) => {
|
|
136
|
+
try {
|
|
137
|
+
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
138
|
+
const db = _dbFromCtx(ctx);
|
|
139
|
+
const tx = mint(db, {
|
|
140
|
+
to,
|
|
141
|
+
amount: Number(amountStr),
|
|
142
|
+
reason: options.reason,
|
|
143
|
+
});
|
|
144
|
+
if (options.json) {
|
|
145
|
+
console.log(JSON.stringify(tx, null, 2));
|
|
146
|
+
} else {
|
|
147
|
+
logger.success(`Minted ${tx.amount} → ${tx.toAccount}`);
|
|
148
|
+
logger.log(
|
|
149
|
+
` ${chalk.bold("Tx:")} ${chalk.cyan(tx.id.slice(0, 8))}`,
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
await shutdown();
|
|
153
|
+
} catch (err) {
|
|
154
|
+
logger.error(`Failed: ${err.message}`);
|
|
155
|
+
process.exit(1);
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
inc
|
|
160
|
+
.command("transfer <from> <to> <amount>")
|
|
161
|
+
.description("Transfer tokens between accounts")
|
|
162
|
+
.option("-r, --reason <text>", "Reason for transfer")
|
|
163
|
+
.option("--json", "Output as JSON")
|
|
164
|
+
.action(async (from, to, amountStr, options) => {
|
|
165
|
+
try {
|
|
166
|
+
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
167
|
+
const db = _dbFromCtx(ctx);
|
|
168
|
+
const tx = transfer(db, {
|
|
169
|
+
from,
|
|
170
|
+
to,
|
|
171
|
+
amount: Number(amountStr),
|
|
172
|
+
reason: options.reason,
|
|
173
|
+
});
|
|
174
|
+
if (options.json) {
|
|
175
|
+
console.log(JSON.stringify(tx, null, 2));
|
|
176
|
+
} else {
|
|
177
|
+
logger.success(`Transferred ${tx.amount} from ${from} → ${to}`);
|
|
178
|
+
logger.log(
|
|
179
|
+
` ${chalk.bold("Tx:")} ${chalk.cyan(tx.id.slice(0, 8))}`,
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
await shutdown();
|
|
183
|
+
} catch (err) {
|
|
184
|
+
logger.error(`Failed: ${err.message}`);
|
|
185
|
+
process.exit(1);
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
inc
|
|
190
|
+
.command("history")
|
|
191
|
+
.description("Show transaction history")
|
|
192
|
+
.option("-a, --account <id>", "Filter by account (from OR to)")
|
|
193
|
+
.option("-t, --type <t>", "Filter by tx type (transfer|reward|mint|burn)")
|
|
194
|
+
.option("--limit <n>", "Maximum entries", parseInt, 50)
|
|
195
|
+
.option("--json", "Output as JSON")
|
|
196
|
+
.action(async (options) => {
|
|
197
|
+
try {
|
|
198
|
+
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
199
|
+
_dbFromCtx(ctx);
|
|
200
|
+
const rows = getTransactionHistory({
|
|
201
|
+
accountId: options.account,
|
|
202
|
+
type: options.type,
|
|
203
|
+
limit: options.limit,
|
|
204
|
+
});
|
|
205
|
+
if (options.json) {
|
|
206
|
+
console.log(JSON.stringify(rows, null, 2));
|
|
207
|
+
} else if (rows.length === 0) {
|
|
208
|
+
logger.info("No transactions.");
|
|
209
|
+
} else {
|
|
210
|
+
for (const tx of rows) {
|
|
211
|
+
const from = tx.fromAccount || "(system)";
|
|
212
|
+
const to = tx.toAccount || "(burn)";
|
|
213
|
+
logger.log(
|
|
214
|
+
` ${chalk.cyan(tx.id.slice(0, 8))} [${tx.type.padEnd(8)}] ${String(tx.amount).padStart(10)} ${from} → ${to}${tx.reason ? ` (${tx.reason})` : ""}`,
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
await shutdown();
|
|
219
|
+
} catch (err) {
|
|
220
|
+
logger.error(`Failed: ${err.message}`);
|
|
221
|
+
process.exit(1);
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
inc
|
|
226
|
+
.command("contribute <user-id> <type> [value]")
|
|
227
|
+
.description(
|
|
228
|
+
"Record a contribution (type: skill_publication|invocation_provided|skill_review|bug_report|code_contribution|documentation|community_support)",
|
|
229
|
+
)
|
|
230
|
+
.option("-m, --metadata <json>", "Metadata JSON")
|
|
231
|
+
.option("-a, --auto-reward", "Auto-reward this contribution")
|
|
232
|
+
.option(
|
|
233
|
+
"-M, --multiplier <n>",
|
|
234
|
+
"Reward multiplier (requires --auto-reward)",
|
|
235
|
+
parseFloat,
|
|
236
|
+
1.0,
|
|
237
|
+
)
|
|
238
|
+
.option("--json", "Output as JSON")
|
|
239
|
+
.action(async (userId, type, valueStr, options) => {
|
|
240
|
+
try {
|
|
241
|
+
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
242
|
+
const db = _dbFromCtx(ctx);
|
|
243
|
+
const metadata = options.metadata ? JSON.parse(options.metadata) : null;
|
|
244
|
+
const contribution = recordContribution(db, {
|
|
245
|
+
userId,
|
|
246
|
+
type,
|
|
247
|
+
value: valueStr != null ? Number(valueStr) : 1,
|
|
248
|
+
metadata,
|
|
249
|
+
autoReward: options.autoReward,
|
|
250
|
+
multiplier: options.multiplier,
|
|
251
|
+
});
|
|
252
|
+
if (options.json) {
|
|
253
|
+
console.log(JSON.stringify(contribution, null, 2));
|
|
254
|
+
} else {
|
|
255
|
+
logger.success(
|
|
256
|
+
`Contribution recorded: ${userId} → ${type} (value=${contribution.value})`,
|
|
257
|
+
);
|
|
258
|
+
logger.log(
|
|
259
|
+
` ${chalk.bold("ID:")} ${chalk.cyan(contribution.id.slice(0, 8))}`,
|
|
260
|
+
);
|
|
261
|
+
if (contribution.rewarded) {
|
|
262
|
+
logger.log(
|
|
263
|
+
` ${chalk.bold("Rewarded:")} ${contribution.rewardAmount} tokens`,
|
|
264
|
+
);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
await shutdown();
|
|
268
|
+
} catch (err) {
|
|
269
|
+
logger.error(`Failed: ${err.message}`);
|
|
270
|
+
process.exit(1);
|
|
271
|
+
}
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
inc
|
|
275
|
+
.command("reward <contribution-id>")
|
|
276
|
+
.description("Reward a previously-recorded contribution")
|
|
277
|
+
.option("-M, --multiplier <n>", "Reward multiplier", parseFloat, 1.0)
|
|
278
|
+
.option("--json", "Output as JSON")
|
|
279
|
+
.action(async (contributionId, options) => {
|
|
280
|
+
try {
|
|
281
|
+
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
282
|
+
const db = _dbFromCtx(ctx);
|
|
283
|
+
const result = rewardContribution(db, contributionId, {
|
|
284
|
+
multiplier: options.multiplier,
|
|
285
|
+
});
|
|
286
|
+
if (options.json) {
|
|
287
|
+
console.log(JSON.stringify(result, null, 2));
|
|
288
|
+
} else if (result.tx) {
|
|
289
|
+
logger.success(
|
|
290
|
+
`Rewarded ${result.tx.amount} tokens → ${result.tx.toAccount}`,
|
|
291
|
+
);
|
|
292
|
+
logger.log(
|
|
293
|
+
` ${chalk.bold("Tx:")} ${chalk.cyan(result.tx.id.slice(0, 8))}`,
|
|
294
|
+
);
|
|
295
|
+
} else {
|
|
296
|
+
logger.info("No reward (amount was 0).");
|
|
297
|
+
}
|
|
298
|
+
await shutdown();
|
|
299
|
+
} catch (err) {
|
|
300
|
+
logger.error(`Failed: ${err.message}`);
|
|
301
|
+
process.exit(1);
|
|
302
|
+
}
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
inc
|
|
306
|
+
.command("contributions")
|
|
307
|
+
.description("List contributions")
|
|
308
|
+
.option("-u, --user <id>", "Filter by user")
|
|
309
|
+
.option("-t, --type <t>", "Filter by contribution type")
|
|
310
|
+
.option("--rewarded", "Only rewarded contributions")
|
|
311
|
+
.option("--unrewarded", "Only unrewarded contributions")
|
|
312
|
+
.option("--limit <n>", "Maximum entries", parseInt, 50)
|
|
313
|
+
.option("--json", "Output as JSON")
|
|
314
|
+
.action(async (options) => {
|
|
315
|
+
try {
|
|
316
|
+
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
317
|
+
_dbFromCtx(ctx);
|
|
318
|
+
let rewardedFilter;
|
|
319
|
+
if (options.rewarded) rewardedFilter = true;
|
|
320
|
+
if (options.unrewarded) rewardedFilter = false;
|
|
321
|
+
const rows = getContributions({
|
|
322
|
+
userId: options.user,
|
|
323
|
+
type: options.type,
|
|
324
|
+
rewarded: rewardedFilter,
|
|
325
|
+
limit: options.limit,
|
|
326
|
+
});
|
|
327
|
+
if (options.json) {
|
|
328
|
+
console.log(JSON.stringify(rows, null, 2));
|
|
329
|
+
} else if (rows.length === 0) {
|
|
330
|
+
logger.info("No contributions.");
|
|
331
|
+
} else {
|
|
332
|
+
for (const c of rows) {
|
|
333
|
+
const flag = c.rewarded ? chalk.green("✓") : chalk.yellow("…");
|
|
334
|
+
logger.log(
|
|
335
|
+
` ${flag} ${chalk.cyan(c.id.slice(0, 8))} ${c.userId.padEnd(16)} ${c.type.padEnd(22)} value=${c.value} reward=${c.rewardAmount}`,
|
|
336
|
+
);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
await shutdown();
|
|
340
|
+
} catch (err) {
|
|
341
|
+
logger.error(`Failed: ${err.message}`);
|
|
342
|
+
process.exit(1);
|
|
343
|
+
}
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
inc
|
|
347
|
+
.command("leaderboard")
|
|
348
|
+
.description("Top contributors by total reward earned")
|
|
349
|
+
.option("--limit <n>", "Maximum entries", parseInt, 10)
|
|
350
|
+
.option("--json", "Output as JSON")
|
|
351
|
+
.action(async (options) => {
|
|
352
|
+
try {
|
|
353
|
+
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
354
|
+
_dbFromCtx(ctx);
|
|
355
|
+
const rows = getLeaderboard({ limit: options.limit });
|
|
356
|
+
if (options.json) {
|
|
357
|
+
console.log(JSON.stringify(rows, null, 2));
|
|
358
|
+
} else if (rows.length === 0) {
|
|
359
|
+
logger.info("No contributions yet.");
|
|
360
|
+
} else {
|
|
361
|
+
rows.forEach((r, i) => {
|
|
362
|
+
logger.log(
|
|
363
|
+
` ${chalk.bold(`#${i + 1}`.padStart(3))} ${chalk.cyan(r.userId.padEnd(20))} reward=${String(r.totalReward).padStart(10)} value=${r.totalValue} count=${r.contributions}`,
|
|
364
|
+
);
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
await shutdown();
|
|
368
|
+
} catch (err) {
|
|
369
|
+
logger.error(`Failed: ${err.message}`);
|
|
370
|
+
process.exit(1);
|
|
371
|
+
}
|
|
372
|
+
});
|
|
373
|
+
}
|
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `cc inference` — CLI surface for Phase 67 Decentralized Inference Network.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { Command } from "commander";
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
NODE_STATUS,
|
|
9
|
+
TASK_STATUS,
|
|
10
|
+
PRIVACY_MODE,
|
|
11
|
+
DEFAULT_CONFIG,
|
|
12
|
+
ensureInferenceTables,
|
|
13
|
+
registerNode,
|
|
14
|
+
unregisterNode,
|
|
15
|
+
heartbeat,
|
|
16
|
+
updateNodeStatus,
|
|
17
|
+
getNode,
|
|
18
|
+
listNodes,
|
|
19
|
+
submitTask,
|
|
20
|
+
completeTask,
|
|
21
|
+
failTask,
|
|
22
|
+
getTask,
|
|
23
|
+
listTasks,
|
|
24
|
+
getSchedulerStats,
|
|
25
|
+
} from "../lib/inference-network.js";
|
|
26
|
+
|
|
27
|
+
function _dbFromCtx(cmd) {
|
|
28
|
+
const root = cmd?.parent?.parent ?? cmd?.parent;
|
|
29
|
+
return root?._db;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function registerInferenceCommand(program) {
|
|
33
|
+
const inf = new Command("inference")
|
|
34
|
+
.description("Decentralized inference network (Phase 67)")
|
|
35
|
+
.hook("preAction", (thisCmd) => {
|
|
36
|
+
const db = _dbFromCtx(thisCmd);
|
|
37
|
+
if (db) ensureInferenceTables(db);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
/* ── Catalogs ────────────────────────────────────── */
|
|
41
|
+
|
|
42
|
+
inf
|
|
43
|
+
.command("node-statuses")
|
|
44
|
+
.description("List node statuses")
|
|
45
|
+
.option("--json", "JSON output")
|
|
46
|
+
.action((opts) => {
|
|
47
|
+
const statuses = Object.values(NODE_STATUS);
|
|
48
|
+
if (opts.json) return console.log(JSON.stringify(statuses, null, 2));
|
|
49
|
+
for (const s of statuses) console.log(` ${s}`);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
inf
|
|
53
|
+
.command("task-statuses")
|
|
54
|
+
.description("List task statuses")
|
|
55
|
+
.option("--json", "JSON output")
|
|
56
|
+
.action((opts) => {
|
|
57
|
+
const statuses = Object.values(TASK_STATUS);
|
|
58
|
+
if (opts.json) return console.log(JSON.stringify(statuses, null, 2));
|
|
59
|
+
for (const s of statuses) console.log(` ${s}`);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
inf
|
|
63
|
+
.command("privacy-modes")
|
|
64
|
+
.description("List privacy modes")
|
|
65
|
+
.option("--json", "JSON output")
|
|
66
|
+
.action((opts) => {
|
|
67
|
+
const modes = Object.values(PRIVACY_MODE);
|
|
68
|
+
if (opts.json) return console.log(JSON.stringify(modes, null, 2));
|
|
69
|
+
for (const m of modes) console.log(` ${m}`);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
/* ── Node Registry ───────────────────────────────── */
|
|
73
|
+
|
|
74
|
+
inf
|
|
75
|
+
.command("register <node-id>")
|
|
76
|
+
.description("Register inference node")
|
|
77
|
+
.option("-e, --endpoint <url>", "Node endpoint URL")
|
|
78
|
+
.option("-c, --capabilities <list>", "Comma-separated capabilities")
|
|
79
|
+
.option("-g, --gpu <mb>", "GPU memory in MB", parseInt)
|
|
80
|
+
.option("--json", "JSON output")
|
|
81
|
+
.action((nodeId, opts) => {
|
|
82
|
+
const db = _dbFromCtx(inf);
|
|
83
|
+
const caps = opts.capabilities ? opts.capabilities.split(",") : [];
|
|
84
|
+
const result = registerNode(db, nodeId, {
|
|
85
|
+
endpoint: opts.endpoint,
|
|
86
|
+
capabilities: caps,
|
|
87
|
+
gpuMemory: opts.gpu,
|
|
88
|
+
});
|
|
89
|
+
if (opts.json) return console.log(JSON.stringify(result, null, 2));
|
|
90
|
+
if (result.nodeId) console.log(`Node registered: ${result.nodeId}`);
|
|
91
|
+
else console.log(`Failed: ${result.reason}`);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
inf
|
|
95
|
+
.command("unregister <id>")
|
|
96
|
+
.description("Unregister inference node")
|
|
97
|
+
.option("--json", "JSON output")
|
|
98
|
+
.action((id, opts) => {
|
|
99
|
+
const db = _dbFromCtx(inf);
|
|
100
|
+
const result = unregisterNode(db, id);
|
|
101
|
+
if (opts.json) return console.log(JSON.stringify(result, null, 2));
|
|
102
|
+
console.log(
|
|
103
|
+
result.removed ? "Node unregistered." : `Failed: ${result.reason}`,
|
|
104
|
+
);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
inf
|
|
108
|
+
.command("heartbeat <id>")
|
|
109
|
+
.description("Send node heartbeat")
|
|
110
|
+
.option("--json", "JSON output")
|
|
111
|
+
.action((id, opts) => {
|
|
112
|
+
const db = _dbFromCtx(inf);
|
|
113
|
+
const result = heartbeat(db, id);
|
|
114
|
+
if (opts.json) return console.log(JSON.stringify(result, null, 2));
|
|
115
|
+
console.log(
|
|
116
|
+
result.updated
|
|
117
|
+
? `Heartbeat OK (status=${result.status})`
|
|
118
|
+
: `Failed: ${result.reason}`,
|
|
119
|
+
);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
inf
|
|
123
|
+
.command("node-status <id> <status>")
|
|
124
|
+
.description("Update node status")
|
|
125
|
+
.option("--json", "JSON output")
|
|
126
|
+
.action((id, status, opts) => {
|
|
127
|
+
const db = _dbFromCtx(inf);
|
|
128
|
+
const result = updateNodeStatus(db, id, status);
|
|
129
|
+
if (opts.json) return console.log(JSON.stringify(result, null, 2));
|
|
130
|
+
console.log(
|
|
131
|
+
result.updated ? "Node status updated." : `Failed: ${result.reason}`,
|
|
132
|
+
);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
inf
|
|
136
|
+
.command("show-node <id>")
|
|
137
|
+
.description("Show node details")
|
|
138
|
+
.option("--json", "JSON output")
|
|
139
|
+
.action((id, opts) => {
|
|
140
|
+
const db = _dbFromCtx(inf);
|
|
141
|
+
const n = getNode(db, id);
|
|
142
|
+
if (!n) return console.log("Node not found.");
|
|
143
|
+
if (opts.json) return console.log(JSON.stringify(n, null, 2));
|
|
144
|
+
console.log(`ID: ${n.id}`);
|
|
145
|
+
console.log(`Node ID: ${n.node_id}`);
|
|
146
|
+
console.log(`Status: ${n.status}`);
|
|
147
|
+
if (n.endpoint) console.log(`Endpoint: ${n.endpoint}`);
|
|
148
|
+
console.log(`GPU: ${n.gpu_memory_mb} MB`);
|
|
149
|
+
console.log(`Tasks: ${n.task_count}`);
|
|
150
|
+
console.log(
|
|
151
|
+
`Capabilities: ${Array.isArray(n.capabilities) ? n.capabilities.join(", ") : "none"}`,
|
|
152
|
+
);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
inf
|
|
156
|
+
.command("nodes")
|
|
157
|
+
.description("List inference nodes")
|
|
158
|
+
.option("-s, --status <status>", "Filter by status")
|
|
159
|
+
.option("-c, --capability <cap>", "Filter by capability")
|
|
160
|
+
.option("--limit <n>", "Max results", parseInt)
|
|
161
|
+
.option("--json", "JSON output")
|
|
162
|
+
.action((opts) => {
|
|
163
|
+
const db = _dbFromCtx(inf);
|
|
164
|
+
const nodes = listNodes(db, {
|
|
165
|
+
status: opts.status,
|
|
166
|
+
capability: opts.capability,
|
|
167
|
+
limit: opts.limit,
|
|
168
|
+
});
|
|
169
|
+
if (opts.json) return console.log(JSON.stringify(nodes, null, 2));
|
|
170
|
+
if (nodes.length === 0) return console.log("No nodes.");
|
|
171
|
+
for (const n of nodes) {
|
|
172
|
+
console.log(
|
|
173
|
+
` ${n.status.padEnd(10)} ${n.node_id.padEnd(20)} gpu=${n.gpu_memory_mb}MB tasks=${n.task_count} ${n.id.slice(0, 8)}`,
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
/* ── Task Scheduler ──────────────────────────────── */
|
|
179
|
+
|
|
180
|
+
inf
|
|
181
|
+
.command("submit <model>")
|
|
182
|
+
.description("Submit inference task")
|
|
183
|
+
.option("-i, --input <text>", "Input data")
|
|
184
|
+
.option("-p, --priority <n>", "Priority (1-10)", parseInt)
|
|
185
|
+
.option("-m, --mode <mode>", "Privacy mode (standard/encrypted/federated)")
|
|
186
|
+
.option("--json", "JSON output")
|
|
187
|
+
.action((model, opts) => {
|
|
188
|
+
const db = _dbFromCtx(inf);
|
|
189
|
+
const result = submitTask(db, model, {
|
|
190
|
+
input: opts.input,
|
|
191
|
+
privacyMode: opts.mode,
|
|
192
|
+
priority: opts.priority,
|
|
193
|
+
});
|
|
194
|
+
if (opts.json) return console.log(JSON.stringify(result, null, 2));
|
|
195
|
+
if (result.taskId) {
|
|
196
|
+
console.log(`Task submitted: ${result.taskId}`);
|
|
197
|
+
console.log(`Status: ${result.status}`);
|
|
198
|
+
if (result.assignedNode)
|
|
199
|
+
console.log(`Assigned: ${result.assignedNode}`);
|
|
200
|
+
} else console.log(`Failed: ${result.reason}`);
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
inf
|
|
204
|
+
.command("complete <task-id>")
|
|
205
|
+
.description("Mark task as complete")
|
|
206
|
+
.option("-o, --output <text>", "Task output")
|
|
207
|
+
.option("-d, --duration <ms>", "Duration in ms", parseInt)
|
|
208
|
+
.option("--json", "JSON output")
|
|
209
|
+
.action((taskId, opts) => {
|
|
210
|
+
const db = _dbFromCtx(inf);
|
|
211
|
+
const result = completeTask(db, taskId, {
|
|
212
|
+
output: opts.output,
|
|
213
|
+
durationMs: opts.duration,
|
|
214
|
+
});
|
|
215
|
+
if (opts.json) return console.log(JSON.stringify(result, null, 2));
|
|
216
|
+
console.log(
|
|
217
|
+
result.completed
|
|
218
|
+
? `Task completed (${result.durationMs}ms)`
|
|
219
|
+
: `Failed: ${result.reason}`,
|
|
220
|
+
);
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
inf
|
|
224
|
+
.command("fail-task <task-id>")
|
|
225
|
+
.description("Mark task as failed")
|
|
226
|
+
.option("-e, --error <text>", "Error message")
|
|
227
|
+
.option("--json", "JSON output")
|
|
228
|
+
.action((taskId, opts) => {
|
|
229
|
+
const db = _dbFromCtx(inf);
|
|
230
|
+
const result = failTask(db, taskId, { error: opts.error });
|
|
231
|
+
if (opts.json) return console.log(JSON.stringify(result, null, 2));
|
|
232
|
+
console.log(
|
|
233
|
+
result.failed ? "Task marked as failed." : `Failed: ${result.reason}`,
|
|
234
|
+
);
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
inf
|
|
238
|
+
.command("show-task <task-id>")
|
|
239
|
+
.description("Show task details")
|
|
240
|
+
.option("--json", "JSON output")
|
|
241
|
+
.action((taskId, opts) => {
|
|
242
|
+
const db = _dbFromCtx(inf);
|
|
243
|
+
const t = getTask(db, taskId);
|
|
244
|
+
if (!t) return console.log("Task not found.");
|
|
245
|
+
if (opts.json) return console.log(JSON.stringify(t, null, 2));
|
|
246
|
+
console.log(`ID: ${t.id}`);
|
|
247
|
+
console.log(`Model: ${t.model}`);
|
|
248
|
+
console.log(`Status: ${t.status}`);
|
|
249
|
+
console.log(`Priority: ${t.priority}`);
|
|
250
|
+
console.log(`Privacy: ${t.privacy_mode}`);
|
|
251
|
+
if (t.assigned_node) console.log(`Node: ${t.assigned_node}`);
|
|
252
|
+
if (t.input) console.log(`Input: ${t.input}`);
|
|
253
|
+
if (t.output) console.log(`Output: ${t.output}`);
|
|
254
|
+
if (t.duration_ms) console.log(`Duration: ${t.duration_ms}ms`);
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
inf
|
|
258
|
+
.command("tasks")
|
|
259
|
+
.description("List inference tasks")
|
|
260
|
+
.option("-s, --status <status>", "Filter by status")
|
|
261
|
+
.option("-m, --model <model>", "Filter by model")
|
|
262
|
+
.option("-p, --privacy <mode>", "Filter by privacy mode")
|
|
263
|
+
.option("--limit <n>", "Max results", parseInt)
|
|
264
|
+
.option("--json", "JSON output")
|
|
265
|
+
.action((opts) => {
|
|
266
|
+
const db = _dbFromCtx(inf);
|
|
267
|
+
const tasks = listTasks(db, {
|
|
268
|
+
status: opts.status,
|
|
269
|
+
model: opts.model,
|
|
270
|
+
privacyMode: opts.privacy,
|
|
271
|
+
limit: opts.limit,
|
|
272
|
+
});
|
|
273
|
+
if (opts.json) return console.log(JSON.stringify(tasks, null, 2));
|
|
274
|
+
if (tasks.length === 0) return console.log("No tasks.");
|
|
275
|
+
for (const t of tasks) {
|
|
276
|
+
console.log(
|
|
277
|
+
` ${t.status.padEnd(12)} ${t.model.padEnd(16)} prio=${t.priority} ${t.privacy_mode.padEnd(10)} ${t.id.slice(0, 8)}`,
|
|
278
|
+
);
|
|
279
|
+
}
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
/* ── Stats ───────────────────────────────────────── */
|
|
283
|
+
|
|
284
|
+
inf
|
|
285
|
+
.command("stats")
|
|
286
|
+
.description("Inference network statistics")
|
|
287
|
+
.option("--json", "JSON output")
|
|
288
|
+
.action((opts) => {
|
|
289
|
+
const db = _dbFromCtx(inf);
|
|
290
|
+
const stats = getSchedulerStats(db);
|
|
291
|
+
if (opts.json) return console.log(JSON.stringify(stats, null, 2));
|
|
292
|
+
const n = stats.nodes;
|
|
293
|
+
console.log(
|
|
294
|
+
`Nodes: ${n.total} total (${n.online} online, ${n.offline} offline, ${n.busy} busy)`,
|
|
295
|
+
);
|
|
296
|
+
const t = stats.tasks;
|
|
297
|
+
console.log(
|
|
298
|
+
`Tasks: ${t.total} total (${t.queued} queued, ${t.completed} completed, ${t.failed} failed)`,
|
|
299
|
+
);
|
|
300
|
+
if (t.avgDurationMs > 0) console.log(`Avg latency: ${t.avgDurationMs}ms`);
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
program.addCommand(inf);
|
|
304
|
+
}
|