chainlesschain 0.51.0 → 0.81.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/package.json +1 -1
- package/src/assets/web-panel/.build-hash +1 -1
- package/src/assets/web-panel/assets/{AppLayout-Rvi759IS.js → AppLayout-6SPt_8Y_.js} +1 -1
- package/src/assets/web-panel/assets/{Dashboard-DBhFxXYQ.js → Dashboard-Br7kCwKJ.js} +2 -2
- package/src/assets/web-panel/assets/Dashboard-CKeMmCoT.css +1 -0
- package/src/assets/web-panel/assets/{index-uL0cZ8N_.js → index-tN-8TosE.js} +2 -2
- package/src/assets/web-panel/index.html +2 -2
- package/src/commands/a2a.js +380 -0
- package/src/commands/agent-network.js +785 -0
- package/src/commands/automation.js +654 -0
- package/src/commands/bi.js +348 -0
- package/src/commands/crosschain.js +218 -0
- package/src/commands/dao.js +565 -0
- package/src/commands/did-v2.js +620 -0
- package/src/commands/dlp.js +341 -0
- package/src/commands/economy.js +578 -0
- package/src/commands/evolution.js +391 -0
- package/src/commands/evomap.js +394 -0
- package/src/commands/federation.js +283 -0
- package/src/commands/hmemory.js +442 -0
- package/src/commands/inference.js +318 -0
- package/src/commands/lowcode.js +356 -0
- package/src/commands/marketplace.js +256 -0
- package/src/commands/perf.js +433 -0
- package/src/commands/pipeline.js +449 -0
- package/src/commands/plugin-ecosystem.js +517 -0
- package/src/commands/privacy.js +321 -0
- package/src/commands/reputation.js +261 -0
- package/src/commands/sandbox.js +401 -0
- package/src/commands/siem.js +246 -0
- package/src/commands/sla.js +259 -0
- package/src/commands/social.js +311 -0
- package/src/commands/sso.js +798 -0
- package/src/commands/stress.js +230 -0
- package/src/commands/terraform.js +245 -0
- package/src/commands/workflow.js +320 -0
- package/src/commands/zkp.js +562 -1
- package/src/index.js +21 -0
- package/src/lib/a2a-protocol.js +451 -0
- package/src/lib/agent-economy.js +479 -0
- package/src/lib/agent-network.js +1121 -0
- package/src/lib/app-builder.js +239 -0
- package/src/lib/automation-engine.js +948 -0
- package/src/lib/bi-engine.js +338 -0
- package/src/lib/cross-chain.js +345 -0
- package/src/lib/dao-governance.js +569 -0
- package/src/lib/did-v2-manager.js +1127 -0
- package/src/lib/dlp-engine.js +389 -0
- package/src/lib/evolution-system.js +453 -0
- package/src/lib/evomap-federation.js +177 -0
- package/src/lib/evomap-governance.js +276 -0
- package/src/lib/federation-hardening.js +259 -0
- package/src/lib/hierarchical-memory.js +481 -0
- package/src/lib/inference-network.js +330 -0
- package/src/lib/perf-tuning.js +734 -0
- package/src/lib/pipeline-orchestrator.js +928 -0
- package/src/lib/plugin-ecosystem.js +1109 -0
- package/src/lib/privacy-computing.js +427 -0
- package/src/lib/reputation-optimizer.js +299 -0
- package/src/lib/sandbox-v2.js +306 -0
- package/src/lib/siem-exporter.js +333 -0
- package/src/lib/skill-marketplace.js +325 -0
- package/src/lib/sla-manager.js +275 -0
- package/src/lib/social-graph-analytics.js +707 -0
- package/src/lib/sso-manager.js +841 -0
- package/src/lib/stress-tester.js +330 -0
- package/src/lib/terraform-manager.js +363 -0
- package/src/lib/workflow-engine.js +454 -1
- package/src/lib/zkp-engine.js +523 -20
- package/src/assets/web-panel/assets/Dashboard-BS-tzGNj.css +0 -1
|
@@ -9,6 +9,11 @@ import {
|
|
|
9
9
|
TASK_STATUS,
|
|
10
10
|
PRIVACY_MODE,
|
|
11
11
|
DEFAULT_CONFIG,
|
|
12
|
+
NODE_STATUS_V2,
|
|
13
|
+
TASK_STATUS_V2,
|
|
14
|
+
PRIVACY_MODE_V2,
|
|
15
|
+
INFERENCE_DEFAULT_MAX_CONCURRENT_TASKS_PER_NODE,
|
|
16
|
+
INFERENCE_DEFAULT_HEARTBEAT_TIMEOUT_MS,
|
|
12
17
|
ensureInferenceTables,
|
|
13
18
|
registerNode,
|
|
14
19
|
unregisterNode,
|
|
@@ -22,6 +27,20 @@ import {
|
|
|
22
27
|
getTask,
|
|
23
28
|
listTasks,
|
|
24
29
|
getSchedulerStats,
|
|
30
|
+
setMaxConcurrentTasksPerNode,
|
|
31
|
+
getMaxConcurrentTasksPerNode,
|
|
32
|
+
setHeartbeatTimeoutMs,
|
|
33
|
+
getHeartbeatTimeoutMs,
|
|
34
|
+
getActiveTasksPerNode,
|
|
35
|
+
submitTaskV2,
|
|
36
|
+
dispatchTaskV2,
|
|
37
|
+
startTask,
|
|
38
|
+
completeTaskV2,
|
|
39
|
+
failTaskV2,
|
|
40
|
+
setTaskStatus,
|
|
41
|
+
autoMarkOfflineNodes,
|
|
42
|
+
findEligibleNodes,
|
|
43
|
+
getInferenceStatsV2,
|
|
25
44
|
} from "../lib/inference-network.js";
|
|
26
45
|
|
|
27
46
|
function _dbFromCtx(cmd) {
|
|
@@ -300,5 +319,304 @@ export function registerInferenceCommand(program) {
|
|
|
300
319
|
if (t.avgDurationMs > 0) console.log(`Avg latency: ${t.avgDurationMs}ms`);
|
|
301
320
|
});
|
|
302
321
|
|
|
322
|
+
/* ──────────────────────────────────────────────────
|
|
323
|
+
* V2 — Phase 67 surface
|
|
324
|
+
* ────────────────────────────────────────────────── */
|
|
325
|
+
|
|
326
|
+
inf
|
|
327
|
+
.command("node-statuses-v2")
|
|
328
|
+
.description("List V2 node statuses")
|
|
329
|
+
.option("--json", "JSON output")
|
|
330
|
+
.action((opts) => {
|
|
331
|
+
const v = Object.values(NODE_STATUS_V2);
|
|
332
|
+
if (opts.json) return console.log(JSON.stringify(v, null, 2));
|
|
333
|
+
for (const s of v) console.log(` ${s}`);
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
inf
|
|
337
|
+
.command("task-statuses-v2")
|
|
338
|
+
.description("List V2 task statuses")
|
|
339
|
+
.option("--json", "JSON output")
|
|
340
|
+
.action((opts) => {
|
|
341
|
+
const v = Object.values(TASK_STATUS_V2);
|
|
342
|
+
if (opts.json) return console.log(JSON.stringify(v, null, 2));
|
|
343
|
+
for (const s of v) console.log(` ${s}`);
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
inf
|
|
347
|
+
.command("privacy-modes-v2")
|
|
348
|
+
.description("List V2 privacy modes")
|
|
349
|
+
.option("--json", "JSON output")
|
|
350
|
+
.action((opts) => {
|
|
351
|
+
const v = Object.values(PRIVACY_MODE_V2);
|
|
352
|
+
if (opts.json) return console.log(JSON.stringify(v, null, 2));
|
|
353
|
+
for (const m of v) console.log(` ${m}`);
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
inf
|
|
357
|
+
.command("default-max-concurrent-tasks")
|
|
358
|
+
.description("Show default per-node concurrent task cap")
|
|
359
|
+
.option("--json", "JSON output")
|
|
360
|
+
.action((opts) => {
|
|
361
|
+
const v = INFERENCE_DEFAULT_MAX_CONCURRENT_TASKS_PER_NODE;
|
|
362
|
+
if (opts.json)
|
|
363
|
+
return console.log(JSON.stringify({ default: v }, null, 2));
|
|
364
|
+
console.log(v);
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
inf
|
|
368
|
+
.command("max-concurrent-tasks")
|
|
369
|
+
.description("Show current per-node concurrent task cap")
|
|
370
|
+
.option("--json", "JSON output")
|
|
371
|
+
.action((opts) => {
|
|
372
|
+
const v = getMaxConcurrentTasksPerNode();
|
|
373
|
+
if (opts.json) return console.log(JSON.stringify({ max: v }, null, 2));
|
|
374
|
+
console.log(v);
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
inf
|
|
378
|
+
.command("set-max-concurrent-tasks <n>")
|
|
379
|
+
.description("Set per-node concurrent task cap")
|
|
380
|
+
.option("--json", "JSON output")
|
|
381
|
+
.action((n, opts) => {
|
|
382
|
+
try {
|
|
383
|
+
setMaxConcurrentTasksPerNode(Number(n));
|
|
384
|
+
const v = getMaxConcurrentTasksPerNode();
|
|
385
|
+
if (opts.json) return console.log(JSON.stringify({ max: v }, null, 2));
|
|
386
|
+
console.log(`Max concurrent tasks per node: ${v}`);
|
|
387
|
+
} catch (e) {
|
|
388
|
+
if (opts.json)
|
|
389
|
+
return console.log(JSON.stringify({ error: e.message }, null, 2));
|
|
390
|
+
console.error(`Error: ${e.message}`);
|
|
391
|
+
process.exitCode = 1;
|
|
392
|
+
}
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
inf
|
|
396
|
+
.command("active-task-count <node-id>")
|
|
397
|
+
.description("Show current active tasks for a node")
|
|
398
|
+
.option("--json", "JSON output")
|
|
399
|
+
.action((nodeId, opts) => {
|
|
400
|
+
const v = getActiveTasksPerNode(nodeId);
|
|
401
|
+
if (opts.json)
|
|
402
|
+
return console.log(JSON.stringify({ nodeId, active: v }, null, 2));
|
|
403
|
+
console.log(v);
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
inf
|
|
407
|
+
.command("heartbeat-timeout")
|
|
408
|
+
.description("Show current heartbeat timeout (ms)")
|
|
409
|
+
.option("--json", "JSON output")
|
|
410
|
+
.action((opts) => {
|
|
411
|
+
const v = getHeartbeatTimeoutMs();
|
|
412
|
+
if (opts.json)
|
|
413
|
+
return console.log(JSON.stringify({ timeoutMs: v }, null, 2));
|
|
414
|
+
console.log(v);
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
inf
|
|
418
|
+
.command("set-heartbeat-timeout <ms>")
|
|
419
|
+
.description("Set heartbeat timeout (ms)")
|
|
420
|
+
.option("--json", "JSON output")
|
|
421
|
+
.action((ms, opts) => {
|
|
422
|
+
try {
|
|
423
|
+
setHeartbeatTimeoutMs(Number(ms));
|
|
424
|
+
const v = getHeartbeatTimeoutMs();
|
|
425
|
+
if (opts.json)
|
|
426
|
+
return console.log(JSON.stringify({ timeoutMs: v }, null, 2));
|
|
427
|
+
console.log(`Heartbeat timeout: ${v}ms`);
|
|
428
|
+
} catch (e) {
|
|
429
|
+
if (opts.json)
|
|
430
|
+
return console.log(JSON.stringify({ error: e.message }, null, 2));
|
|
431
|
+
console.error(`Error: ${e.message}`);
|
|
432
|
+
process.exitCode = 1;
|
|
433
|
+
}
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
inf
|
|
437
|
+
.command("submit-v2 <model>")
|
|
438
|
+
.description("Submit task (V2, creates queued no assignment)")
|
|
439
|
+
.option("-i, --input <text>", "Input data")
|
|
440
|
+
.option("-p, --priority <n>", "Priority (1-10)", parseInt)
|
|
441
|
+
.option("-m, --mode <mode>", "Privacy mode")
|
|
442
|
+
.option("--json", "JSON output")
|
|
443
|
+
.action((model, opts) => {
|
|
444
|
+
const db = _dbFromCtx(inf);
|
|
445
|
+
try {
|
|
446
|
+
const t = submitTaskV2(db, {
|
|
447
|
+
model,
|
|
448
|
+
input: opts.input,
|
|
449
|
+
privacyMode: opts.mode,
|
|
450
|
+
priority: opts.priority,
|
|
451
|
+
});
|
|
452
|
+
if (opts.json) return console.log(JSON.stringify(t, null, 2));
|
|
453
|
+
console.log(`Task submitted: ${t.id}`);
|
|
454
|
+
console.log(`Status: ${t.status}`);
|
|
455
|
+
} catch (e) {
|
|
456
|
+
if (opts.json)
|
|
457
|
+
return console.log(JSON.stringify({ error: e.message }, null, 2));
|
|
458
|
+
console.error(`Error: ${e.message}`);
|
|
459
|
+
process.exitCode = 1;
|
|
460
|
+
}
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
inf
|
|
464
|
+
.command("dispatch-v2 <task-id>")
|
|
465
|
+
.description("Dispatch queued task to online node")
|
|
466
|
+
.option("-n, --node <id>", "Specific node id (else least-loaded)")
|
|
467
|
+
.option("--json", "JSON output")
|
|
468
|
+
.action((taskId, opts) => {
|
|
469
|
+
const db = _dbFromCtx(inf);
|
|
470
|
+
try {
|
|
471
|
+
const t = dispatchTaskV2(db, taskId, { nodeId: opts.node });
|
|
472
|
+
if (opts.json) return console.log(JSON.stringify(t, null, 2));
|
|
473
|
+
console.log(`Dispatched ${t.id} → ${t.assigned_node}`);
|
|
474
|
+
} catch (e) {
|
|
475
|
+
if (opts.json)
|
|
476
|
+
return console.log(JSON.stringify({ error: e.message }, null, 2));
|
|
477
|
+
console.error(`Error: ${e.message}`);
|
|
478
|
+
process.exitCode = 1;
|
|
479
|
+
}
|
|
480
|
+
});
|
|
481
|
+
|
|
482
|
+
inf
|
|
483
|
+
.command("start-task <task-id>")
|
|
484
|
+
.description("Start dispatched task (dispatched → running)")
|
|
485
|
+
.option("--json", "JSON output")
|
|
486
|
+
.action((taskId, opts) => {
|
|
487
|
+
const db = _dbFromCtx(inf);
|
|
488
|
+
try {
|
|
489
|
+
const t = startTask(db, taskId);
|
|
490
|
+
if (opts.json) return console.log(JSON.stringify(t, null, 2));
|
|
491
|
+
console.log(`Task started at ${t.started_at}`);
|
|
492
|
+
} catch (e) {
|
|
493
|
+
if (opts.json)
|
|
494
|
+
return console.log(JSON.stringify({ error: e.message }, null, 2));
|
|
495
|
+
console.error(`Error: ${e.message}`);
|
|
496
|
+
process.exitCode = 1;
|
|
497
|
+
}
|
|
498
|
+
});
|
|
499
|
+
|
|
500
|
+
inf
|
|
501
|
+
.command("complete-v2 <task-id>")
|
|
502
|
+
.description("Complete running task (running → complete)")
|
|
503
|
+
.option("-o, --output <text>", "Task output")
|
|
504
|
+
.option("-d, --duration <ms>", "Duration in ms", parseInt)
|
|
505
|
+
.option("--json", "JSON output")
|
|
506
|
+
.action((taskId, opts) => {
|
|
507
|
+
const db = _dbFromCtx(inf);
|
|
508
|
+
try {
|
|
509
|
+
const t = completeTaskV2(db, taskId, {
|
|
510
|
+
output: opts.output,
|
|
511
|
+
durationMs: opts.duration,
|
|
512
|
+
});
|
|
513
|
+
if (opts.json) return console.log(JSON.stringify(t, null, 2));
|
|
514
|
+
console.log(`Completed ${t.id} (${t.duration_ms}ms)`);
|
|
515
|
+
} catch (e) {
|
|
516
|
+
if (opts.json)
|
|
517
|
+
return console.log(JSON.stringify({ error: e.message }, null, 2));
|
|
518
|
+
console.error(`Error: ${e.message}`);
|
|
519
|
+
process.exitCode = 1;
|
|
520
|
+
}
|
|
521
|
+
});
|
|
522
|
+
|
|
523
|
+
inf
|
|
524
|
+
.command("fail-v2 <task-id>")
|
|
525
|
+
.description("Fail task (any non-terminal → failed)")
|
|
526
|
+
.option("-e, --error <text>", "Error message")
|
|
527
|
+
.option("--json", "JSON output")
|
|
528
|
+
.action((taskId, opts) => {
|
|
529
|
+
const db = _dbFromCtx(inf);
|
|
530
|
+
try {
|
|
531
|
+
const t = failTaskV2(db, taskId, { error: opts.error });
|
|
532
|
+
if (opts.json) return console.log(JSON.stringify(t, null, 2));
|
|
533
|
+
console.log(`Failed ${t.id}: ${t.error_message || ""}`);
|
|
534
|
+
} catch (e) {
|
|
535
|
+
if (opts.json)
|
|
536
|
+
return console.log(JSON.stringify({ error: e.message }, null, 2));
|
|
537
|
+
console.error(`Error: ${e.message}`);
|
|
538
|
+
process.exitCode = 1;
|
|
539
|
+
}
|
|
540
|
+
});
|
|
541
|
+
|
|
542
|
+
inf
|
|
543
|
+
.command("set-task-status <task-id> <status>")
|
|
544
|
+
.description("Generic state-machine-guarded task status setter")
|
|
545
|
+
.option("-o, --output <text>", "Patch: output")
|
|
546
|
+
.option("-d, --duration <ms>", "Patch: durationMs", parseInt)
|
|
547
|
+
.option("-e, --error <text>", "Patch: errorMessage")
|
|
548
|
+
.option("--json", "JSON output")
|
|
549
|
+
.action((taskId, status, opts) => {
|
|
550
|
+
const db = _dbFromCtx(inf);
|
|
551
|
+
const patch = {};
|
|
552
|
+
if (opts.output !== undefined) patch.output = opts.output;
|
|
553
|
+
if (opts.duration !== undefined) patch.durationMs = opts.duration;
|
|
554
|
+
if (opts.error !== undefined) patch.errorMessage = opts.error;
|
|
555
|
+
try {
|
|
556
|
+
const t = setTaskStatus(db, taskId, status, patch);
|
|
557
|
+
if (opts.json) return console.log(JSON.stringify(t, null, 2));
|
|
558
|
+
console.log(`Task ${t.id} → ${t.status}`);
|
|
559
|
+
} catch (e) {
|
|
560
|
+
if (opts.json)
|
|
561
|
+
return console.log(JSON.stringify({ error: e.message }, null, 2));
|
|
562
|
+
console.error(`Error: ${e.message}`);
|
|
563
|
+
process.exitCode = 1;
|
|
564
|
+
}
|
|
565
|
+
});
|
|
566
|
+
|
|
567
|
+
inf
|
|
568
|
+
.command("auto-offline")
|
|
569
|
+
.description("Mark nodes with stale heartbeat as offline")
|
|
570
|
+
.option("--json", "JSON output")
|
|
571
|
+
.action((opts) => {
|
|
572
|
+
const db = _dbFromCtx(inf);
|
|
573
|
+
const offlined = autoMarkOfflineNodes(db);
|
|
574
|
+
if (opts.json) return console.log(JSON.stringify(offlined, null, 2));
|
|
575
|
+
if (offlined.length === 0) return console.log("No stale nodes.");
|
|
576
|
+
for (const n of offlined)
|
|
577
|
+
console.log(` ${n.node_id.padEnd(20)} → offline`);
|
|
578
|
+
});
|
|
579
|
+
|
|
580
|
+
inf
|
|
581
|
+
.command("eligible-nodes")
|
|
582
|
+
.description("List online, under-cap nodes matching capability")
|
|
583
|
+
.option("-c, --capability <cap>", "Required capability")
|
|
584
|
+
.option("-m, --mode <mode>", "Privacy mode (reserved)")
|
|
585
|
+
.option("--json", "JSON output")
|
|
586
|
+
.action((opts) => {
|
|
587
|
+
const nodes = findEligibleNodes({
|
|
588
|
+
capability: opts.capability,
|
|
589
|
+
privacyMode: opts.mode,
|
|
590
|
+
});
|
|
591
|
+
if (opts.json) return console.log(JSON.stringify(nodes, null, 2));
|
|
592
|
+
if (nodes.length === 0) return console.log("No eligible nodes.");
|
|
593
|
+
for (const n of nodes)
|
|
594
|
+
console.log(
|
|
595
|
+
` ${n.node_id.padEnd(20)} load=${getActiveTasksPerNode(n.id)} ${n.id.slice(0, 8)}`,
|
|
596
|
+
);
|
|
597
|
+
});
|
|
598
|
+
|
|
599
|
+
inf
|
|
600
|
+
.command("stats-v2")
|
|
601
|
+
.description("V2 inference statistics (all-enum-key zero init)")
|
|
602
|
+
.option("--json", "JSON output")
|
|
603
|
+
.action((opts) => {
|
|
604
|
+
const s = getInferenceStatsV2();
|
|
605
|
+
if (opts.json) return console.log(JSON.stringify(s, null, 2));
|
|
606
|
+
console.log(`Nodes: ${s.totalNodes} Tasks: ${s.totalTasks}`);
|
|
607
|
+
console.log(`Max concurrent/node: ${s.maxConcurrentTasksPerNode}`);
|
|
608
|
+
console.log(`Heartbeat timeout: ${s.heartbeatTimeoutMs}ms`);
|
|
609
|
+
console.log(`Avg duration: ${s.avgDurationMs}ms`);
|
|
610
|
+
console.log("Nodes by status:");
|
|
611
|
+
for (const [k, v] of Object.entries(s.nodesByStatus))
|
|
612
|
+
console.log(` ${k.padEnd(12)} ${v}`);
|
|
613
|
+
console.log("Tasks by status:");
|
|
614
|
+
for (const [k, v] of Object.entries(s.tasksByStatus))
|
|
615
|
+
console.log(` ${k.padEnd(12)} ${v}`);
|
|
616
|
+
console.log("Tasks by privacy:");
|
|
617
|
+
for (const [k, v] of Object.entries(s.tasksByPrivacyMode))
|
|
618
|
+
console.log(` ${k.padEnd(12)} ${v}`);
|
|
619
|
+
});
|
|
620
|
+
|
|
303
621
|
program.addCommand(inf);
|
|
304
622
|
}
|
package/src/commands/lowcode.js
CHANGED
|
@@ -20,7 +20,22 @@ import {
|
|
|
20
20
|
exportApp,
|
|
21
21
|
listApps,
|
|
22
22
|
deployApp,
|
|
23
|
+
// Phase 93 V2 surface
|
|
24
|
+
COMPONENT_CATEGORY,
|
|
25
|
+
DATASOURCE_TYPE,
|
|
26
|
+
APP_STATUS,
|
|
27
|
+
listComponentsV2,
|
|
28
|
+
registerDataSourceV2,
|
|
29
|
+
testDataSourceConnection,
|
|
30
|
+
updateAppStatus,
|
|
31
|
+
archiveApp,
|
|
32
|
+
getStatusHistory,
|
|
33
|
+
cloneApp,
|
|
34
|
+
exportAppJSON,
|
|
35
|
+
importAppJSON,
|
|
36
|
+
getLowcodeStatsV2,
|
|
23
37
|
} from "../lib/app-builder.js";
|
|
38
|
+
import fs from "fs";
|
|
24
39
|
|
|
25
40
|
export function registerLowcodeCommand(program) {
|
|
26
41
|
const lowcode = program
|
|
@@ -305,6 +320,347 @@ export function registerLowcodeCommand(program) {
|
|
|
305
320
|
}
|
|
306
321
|
});
|
|
307
322
|
|
|
323
|
+
// ─── Phase 93 V2 subcommands ────────────────────────────────
|
|
324
|
+
|
|
325
|
+
// lowcode categories
|
|
326
|
+
lowcode
|
|
327
|
+
.command("categories")
|
|
328
|
+
.description("List component categories (V2)")
|
|
329
|
+
.option("--json", "Output as JSON")
|
|
330
|
+
.action((options) => {
|
|
331
|
+
const categories = Object.values(COMPONENT_CATEGORY);
|
|
332
|
+
if (options.json) {
|
|
333
|
+
console.log(JSON.stringify(categories, null, 2));
|
|
334
|
+
} else {
|
|
335
|
+
logger.log(chalk.bold("Component Categories:"));
|
|
336
|
+
for (const c of categories) logger.log(` ${chalk.cyan(c)}`);
|
|
337
|
+
}
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
// lowcode datasource-types
|
|
341
|
+
lowcode
|
|
342
|
+
.command("datasource-types")
|
|
343
|
+
.description("List supported data source types (V2)")
|
|
344
|
+
.option("--json", "Output as JSON")
|
|
345
|
+
.action((options) => {
|
|
346
|
+
const types = Object.values(DATASOURCE_TYPE);
|
|
347
|
+
if (options.json) {
|
|
348
|
+
console.log(JSON.stringify(types, null, 2));
|
|
349
|
+
} else {
|
|
350
|
+
logger.log(chalk.bold("Data Source Types:"));
|
|
351
|
+
for (const t of types) logger.log(` ${chalk.cyan(t)}`);
|
|
352
|
+
}
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
// lowcode statuses
|
|
356
|
+
lowcode
|
|
357
|
+
.command("statuses")
|
|
358
|
+
.description("List canonical app statuses (V2)")
|
|
359
|
+
.option("--json", "Output as JSON")
|
|
360
|
+
.action((options) => {
|
|
361
|
+
const statuses = Object.values(APP_STATUS);
|
|
362
|
+
if (options.json) {
|
|
363
|
+
console.log(JSON.stringify(statuses, null, 2));
|
|
364
|
+
} else {
|
|
365
|
+
logger.log(chalk.bold("App Statuses:"));
|
|
366
|
+
for (const s of statuses) logger.log(` ${chalk.cyan(s)}`);
|
|
367
|
+
}
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
// lowcode components-v2
|
|
371
|
+
lowcode
|
|
372
|
+
.command("components-v2")
|
|
373
|
+
.description("List built-in components with category filter (V2)")
|
|
374
|
+
.option("-c, --category <cat>", "Filter by category")
|
|
375
|
+
.option("--json", "Output as JSON")
|
|
376
|
+
.action((options) => {
|
|
377
|
+
try {
|
|
378
|
+
const list = listComponentsV2(
|
|
379
|
+
options.category ? { category: options.category } : {},
|
|
380
|
+
);
|
|
381
|
+
if (options.json) {
|
|
382
|
+
console.log(JSON.stringify(list, null, 2));
|
|
383
|
+
} else {
|
|
384
|
+
logger.log(chalk.bold(`Components (${list.length}):`));
|
|
385
|
+
for (const c of list) {
|
|
386
|
+
logger.log(
|
|
387
|
+
` ${chalk.cyan(c.name)} [${c.category}] props: ${c.props.join(", ")}`,
|
|
388
|
+
);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
} catch (err) {
|
|
392
|
+
logger.error(err.message);
|
|
393
|
+
process.exit(1);
|
|
394
|
+
}
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
// lowcode datasource-v2 <app-id> <name> <type>
|
|
398
|
+
lowcode
|
|
399
|
+
.command("datasource-v2")
|
|
400
|
+
.description("Register a validated data source (V2)")
|
|
401
|
+
.argument("<app-id>", "Application ID")
|
|
402
|
+
.argument("<name>", "Data source name")
|
|
403
|
+
.argument("<type>", "Type: rest|graphql|database|csv")
|
|
404
|
+
.option("--config <json>", "Config as JSON string", "{}")
|
|
405
|
+
.action(async (appId, name, type, options) => {
|
|
406
|
+
const spinner = ora("Registering data source...").start();
|
|
407
|
+
try {
|
|
408
|
+
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
409
|
+
if (!ctx.db) {
|
|
410
|
+
spinner.fail("Database not available");
|
|
411
|
+
process.exit(1);
|
|
412
|
+
}
|
|
413
|
+
const db = ctx.db.getDatabase();
|
|
414
|
+
ensureLowcodeTables(db);
|
|
415
|
+
|
|
416
|
+
let config;
|
|
417
|
+
try {
|
|
418
|
+
config = JSON.parse(options.config);
|
|
419
|
+
} catch (_err) {
|
|
420
|
+
config = {};
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
const result = registerDataSourceV2(db, {
|
|
424
|
+
appId,
|
|
425
|
+
name,
|
|
426
|
+
type,
|
|
427
|
+
config,
|
|
428
|
+
});
|
|
429
|
+
spinner.succeed(
|
|
430
|
+
`Data source "${chalk.cyan(name)}" registered (${type})`,
|
|
431
|
+
);
|
|
432
|
+
logger.log(` ID: ${chalk.gray(result.id)}`);
|
|
433
|
+
|
|
434
|
+
await shutdown();
|
|
435
|
+
} catch (err) {
|
|
436
|
+
spinner.fail(err.message);
|
|
437
|
+
process.exit(1);
|
|
438
|
+
}
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
// lowcode test-connection <datasource-id>
|
|
442
|
+
lowcode
|
|
443
|
+
.command("test-connection")
|
|
444
|
+
.description("Heuristic connection check for a data source (V2)")
|
|
445
|
+
.argument("<datasource-id>", "Data source ID")
|
|
446
|
+
.option("--json", "Output as JSON")
|
|
447
|
+
.action((dsId, options) => {
|
|
448
|
+
const result = testDataSourceConnection(dsId);
|
|
449
|
+
if (options.json) {
|
|
450
|
+
console.log(JSON.stringify(result, null, 2));
|
|
451
|
+
} else {
|
|
452
|
+
const icon = result.ok ? chalk.green("✓") : chalk.red("✗");
|
|
453
|
+
logger.log(
|
|
454
|
+
`${icon} ${chalk.cyan(dsId)} (${result.type || "?"}): ${result.reason}`,
|
|
455
|
+
);
|
|
456
|
+
}
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
// lowcode set-status <app-id> <status>
|
|
460
|
+
lowcode
|
|
461
|
+
.command("set-status")
|
|
462
|
+
.description("Update app status with validated transition (V2)")
|
|
463
|
+
.argument("<app-id>", "Application ID")
|
|
464
|
+
.argument("<status>", "New status: draft|published|archived")
|
|
465
|
+
.action(async (appId, status) => {
|
|
466
|
+
const spinner = ora(`Transitioning to ${status}...`).start();
|
|
467
|
+
try {
|
|
468
|
+
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
469
|
+
if (!ctx.db) {
|
|
470
|
+
spinner.fail("Database not available");
|
|
471
|
+
process.exit(1);
|
|
472
|
+
}
|
|
473
|
+
const db = ctx.db.getDatabase();
|
|
474
|
+
ensureLowcodeTables(db);
|
|
475
|
+
|
|
476
|
+
const result = updateAppStatus(db, { appId, status });
|
|
477
|
+
spinner.succeed(
|
|
478
|
+
`${chalk.cyan(appId)}: ${result.previous} → ${chalk.bold(result.status)}`,
|
|
479
|
+
);
|
|
480
|
+
|
|
481
|
+
await shutdown();
|
|
482
|
+
} catch (err) {
|
|
483
|
+
spinner.fail(err.message);
|
|
484
|
+
process.exit(1);
|
|
485
|
+
}
|
|
486
|
+
});
|
|
487
|
+
|
|
488
|
+
// lowcode archive <app-id>
|
|
489
|
+
lowcode
|
|
490
|
+
.command("archive")
|
|
491
|
+
.description("Archive an application (V2)")
|
|
492
|
+
.argument("<app-id>", "Application ID")
|
|
493
|
+
.action(async (appId) => {
|
|
494
|
+
const spinner = ora("Archiving...").start();
|
|
495
|
+
try {
|
|
496
|
+
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
497
|
+
if (!ctx.db) {
|
|
498
|
+
spinner.fail("Database not available");
|
|
499
|
+
process.exit(1);
|
|
500
|
+
}
|
|
501
|
+
const db = ctx.db.getDatabase();
|
|
502
|
+
ensureLowcodeTables(db);
|
|
503
|
+
|
|
504
|
+
archiveApp(db, appId);
|
|
505
|
+
spinner.succeed(`${chalk.cyan(appId)} archived`);
|
|
506
|
+
|
|
507
|
+
await shutdown();
|
|
508
|
+
} catch (err) {
|
|
509
|
+
spinner.fail(err.message);
|
|
510
|
+
process.exit(1);
|
|
511
|
+
}
|
|
512
|
+
});
|
|
513
|
+
|
|
514
|
+
// lowcode status-history <app-id>
|
|
515
|
+
lowcode
|
|
516
|
+
.command("status-history")
|
|
517
|
+
.description("Show status transition history for an app (V2)")
|
|
518
|
+
.argument("<app-id>", "Application ID")
|
|
519
|
+
.option("--json", "Output as JSON")
|
|
520
|
+
.action((appId, options) => {
|
|
521
|
+
const hist = getStatusHistory(appId);
|
|
522
|
+
if (options.json) {
|
|
523
|
+
console.log(JSON.stringify(hist, null, 2));
|
|
524
|
+
} else if (hist.length === 0) {
|
|
525
|
+
logger.info("No status transitions recorded");
|
|
526
|
+
} else {
|
|
527
|
+
logger.log(chalk.bold(`Status History (${hist.length}):`));
|
|
528
|
+
for (const h of hist) {
|
|
529
|
+
logger.log(` ${chalk.gray(h.at)} ${h.from} → ${chalk.cyan(h.to)}`);
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
});
|
|
533
|
+
|
|
534
|
+
// lowcode clone <source-id>
|
|
535
|
+
lowcode
|
|
536
|
+
.command("clone")
|
|
537
|
+
.description("Clone an application (V2)")
|
|
538
|
+
.argument("<source-id>", "Source app ID")
|
|
539
|
+
.option("--name <name>", "New name for the clone")
|
|
540
|
+
.action(async (sourceId, options) => {
|
|
541
|
+
const spinner = ora("Cloning...").start();
|
|
542
|
+
try {
|
|
543
|
+
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
544
|
+
if (!ctx.db) {
|
|
545
|
+
spinner.fail("Database not available");
|
|
546
|
+
process.exit(1);
|
|
547
|
+
}
|
|
548
|
+
const db = ctx.db.getDatabase();
|
|
549
|
+
ensureLowcodeTables(db);
|
|
550
|
+
|
|
551
|
+
const result = cloneApp(db, {
|
|
552
|
+
sourceId,
|
|
553
|
+
newName: options.name,
|
|
554
|
+
});
|
|
555
|
+
spinner.succeed(`Cloned ${chalk.cyan(sourceId)} → ${result.clonedId}`);
|
|
556
|
+
logger.log(` Name: ${result.name}`);
|
|
557
|
+
|
|
558
|
+
await shutdown();
|
|
559
|
+
} catch (err) {
|
|
560
|
+
spinner.fail(err.message);
|
|
561
|
+
process.exit(1);
|
|
562
|
+
}
|
|
563
|
+
});
|
|
564
|
+
|
|
565
|
+
// lowcode export-json <app-id>
|
|
566
|
+
lowcode
|
|
567
|
+
.command("export-json")
|
|
568
|
+
.description("Export an app as canonical JSON (V2)")
|
|
569
|
+
.argument("<app-id>", "Application ID")
|
|
570
|
+
.option("-o, --output <file>", "Write to file instead of stdout")
|
|
571
|
+
.action(async (appId, options) => {
|
|
572
|
+
try {
|
|
573
|
+
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
574
|
+
if (!ctx.db) {
|
|
575
|
+
logger.error("Database not available");
|
|
576
|
+
process.exit(1);
|
|
577
|
+
}
|
|
578
|
+
const db = ctx.db.getDatabase();
|
|
579
|
+
ensureLowcodeTables(db);
|
|
580
|
+
|
|
581
|
+
const result = exportAppJSON(db, appId);
|
|
582
|
+
const json = JSON.stringify(result, null, 2);
|
|
583
|
+
if (options.output) {
|
|
584
|
+
fs.writeFileSync(options.output, json, "utf-8");
|
|
585
|
+
logger.log(chalk.green(`Wrote ${options.output}`));
|
|
586
|
+
} else {
|
|
587
|
+
console.log(json);
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
await shutdown();
|
|
591
|
+
} catch (err) {
|
|
592
|
+
logger.error(err.message);
|
|
593
|
+
process.exit(1);
|
|
594
|
+
}
|
|
595
|
+
});
|
|
596
|
+
|
|
597
|
+
// lowcode import-json <file>
|
|
598
|
+
lowcode
|
|
599
|
+
.command("import-json")
|
|
600
|
+
.description("Import an app from a canonical JSON file (V2)")
|
|
601
|
+
.argument("<file>", "Path to JSON export")
|
|
602
|
+
.action(async (file) => {
|
|
603
|
+
const spinner = ora("Importing...").start();
|
|
604
|
+
try {
|
|
605
|
+
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
606
|
+
if (!ctx.db) {
|
|
607
|
+
spinner.fail("Database not available");
|
|
608
|
+
process.exit(1);
|
|
609
|
+
}
|
|
610
|
+
const db = ctx.db.getDatabase();
|
|
611
|
+
ensureLowcodeTables(db);
|
|
612
|
+
|
|
613
|
+
const raw = fs.readFileSync(file, "utf-8");
|
|
614
|
+
const json = JSON.parse(raw);
|
|
615
|
+
const result = importAppJSON(db, json);
|
|
616
|
+
spinner.succeed(
|
|
617
|
+
`Imported "${chalk.cyan(result.name)}" → ${result.importedId}`,
|
|
618
|
+
);
|
|
619
|
+
logger.log(` Data sources: ${result.dataSources}`);
|
|
620
|
+
|
|
621
|
+
await shutdown();
|
|
622
|
+
} catch (err) {
|
|
623
|
+
spinner.fail(err.message);
|
|
624
|
+
process.exit(1);
|
|
625
|
+
}
|
|
626
|
+
});
|
|
627
|
+
|
|
628
|
+
// lowcode stats-v2
|
|
629
|
+
lowcode
|
|
630
|
+
.command("stats-v2")
|
|
631
|
+
.description("Low-code platform statistics (V2)")
|
|
632
|
+
.option("--json", "Output as JSON")
|
|
633
|
+
.action(async (options) => {
|
|
634
|
+
try {
|
|
635
|
+
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
636
|
+
if (!ctx.db) {
|
|
637
|
+
logger.error("Database not available");
|
|
638
|
+
process.exit(1);
|
|
639
|
+
}
|
|
640
|
+
const db = ctx.db.getDatabase();
|
|
641
|
+
ensureLowcodeTables(db);
|
|
642
|
+
|
|
643
|
+
const stats = getLowcodeStatsV2(db);
|
|
644
|
+
if (options.json) {
|
|
645
|
+
console.log(JSON.stringify(stats, null, 2));
|
|
646
|
+
} else {
|
|
647
|
+
logger.log(chalk.bold("Low-Code Stats (V2):"));
|
|
648
|
+
logger.log(` Total apps: ${chalk.cyan(stats.totalApps)}`);
|
|
649
|
+
logger.log(` By status: ${JSON.stringify(stats.byStatus)}`);
|
|
650
|
+
logger.log(` By platform: ${JSON.stringify(stats.byPlatform)}`);
|
|
651
|
+
logger.log(
|
|
652
|
+
` Data sources: ${stats.dataSources.total} (${JSON.stringify(stats.dataSources.byType)})`,
|
|
653
|
+
);
|
|
654
|
+
logger.log(` Components: ${stats.componentsAvailable}`);
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
await shutdown();
|
|
658
|
+
} catch (err) {
|
|
659
|
+
logger.error(err.message);
|
|
660
|
+
process.exit(1);
|
|
661
|
+
}
|
|
662
|
+
});
|
|
663
|
+
|
|
308
664
|
// lowcode deploy <app-id>
|
|
309
665
|
lowcode
|
|
310
666
|
.command("deploy")
|