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.
Files changed (73) hide show
  1. package/bin/chainlesschain.js +0 -0
  2. package/package.json +1 -1
  3. package/src/assets/web-panel/.build-hash +1 -1
  4. package/src/assets/web-panel/assets/{AppLayout-6SPt_8Y_.js → AppLayout-Rvi759IS.js} +1 -1
  5. package/src/assets/web-panel/assets/Dashboard-BS-tzGNj.css +1 -0
  6. package/src/assets/web-panel/assets/{Dashboard-Br7kCwKJ.js → Dashboard-DBhFxXYQ.js} +2 -2
  7. package/src/assets/web-panel/assets/{index-tN-8TosE.js → index-uL0cZ8N_.js} +2 -2
  8. package/src/assets/web-panel/index.html +2 -2
  9. package/src/commands/codegen.js +303 -0
  10. package/src/commands/collab.js +482 -0
  11. package/src/commands/crosschain.js +382 -0
  12. package/src/commands/dbevo.js +388 -0
  13. package/src/commands/dev.js +411 -0
  14. package/src/commands/federation.js +427 -0
  15. package/src/commands/fusion.js +332 -0
  16. package/src/commands/governance.js +505 -0
  17. package/src/commands/hardening.js +110 -0
  18. package/src/commands/incentive.js +373 -0
  19. package/src/commands/inference.js +304 -0
  20. package/src/commands/infra.js +361 -0
  21. package/src/commands/ipfs.js +392 -0
  22. package/src/commands/kg.js +371 -0
  23. package/src/commands/marketplace.js +326 -0
  24. package/src/commands/mcp.js +97 -18
  25. package/src/commands/multimodal.js +404 -0
  26. package/src/commands/nlprog.js +329 -0
  27. package/src/commands/ops.js +408 -0
  28. package/src/commands/perception.js +385 -0
  29. package/src/commands/pqc.js +34 -0
  30. package/src/commands/privacy.js +345 -0
  31. package/src/commands/quantization.js +280 -0
  32. package/src/commands/recommend.js +336 -0
  33. package/src/commands/reputation.js +349 -0
  34. package/src/commands/runtime.js +500 -0
  35. package/src/commands/sla.js +352 -0
  36. package/src/commands/stress.js +252 -0
  37. package/src/commands/tech.js +268 -0
  38. package/src/commands/tenant.js +576 -0
  39. package/src/commands/trust.js +366 -0
  40. package/src/harness/mcp-client.js +330 -54
  41. package/src/index.js +118 -0
  42. package/src/lib/aiops.js +523 -0
  43. package/src/lib/autonomous-developer.js +524 -0
  44. package/src/lib/code-agent.js +442 -0
  45. package/src/lib/collaboration-governance.js +556 -0
  46. package/src/lib/community-governance.js +649 -0
  47. package/src/lib/content-recommendation.js +600 -0
  48. package/src/lib/cross-chain.js +669 -0
  49. package/src/lib/dbevo.js +669 -0
  50. package/src/lib/decentral-infra.js +445 -0
  51. package/src/lib/federation-hardening.js +587 -0
  52. package/src/lib/hardening-manager.js +409 -0
  53. package/src/lib/inference-network.js +407 -0
  54. package/src/lib/ipfs-storage.js +575 -0
  55. package/src/lib/knowledge-graph.js +530 -0
  56. package/src/lib/mcp-client.js +3 -0
  57. package/src/lib/multimodal.js +725 -0
  58. package/src/lib/nl-programming.js +595 -0
  59. package/src/lib/perception.js +500 -0
  60. package/src/lib/pqc-manager.js +141 -9
  61. package/src/lib/privacy-computing.js +575 -0
  62. package/src/lib/protocol-fusion.js +535 -0
  63. package/src/lib/quantization.js +362 -0
  64. package/src/lib/reputation-optimizer.js +509 -0
  65. package/src/lib/skill-marketplace.js +397 -0
  66. package/src/lib/sla-manager.js +484 -0
  67. package/src/lib/stress-tester.js +383 -0
  68. package/src/lib/tech-learning-engine.js +651 -0
  69. package/src/lib/tenant-saas.js +831 -0
  70. package/src/lib/token-incentive.js +513 -0
  71. package/src/lib/trust-security.js +473 -0
  72. package/src/lib/universal-runtime.js +771 -0
  73. 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
+ }