@aikdna/kdna-cli 0.9.0 → 0.12.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/README.md +109 -31
- package/SECURITY.md +41 -0
- package/package.json +3 -2
- package/src/agent.js +430 -2
- package/src/cli.js +280 -38
- package/src/cmds/_common.js +68 -3
- package/src/cmds/badge.js +244 -0
- package/src/cmds/changelog.js +226 -0
- package/src/cmds/cluster.js +214 -3
- package/src/cmds/doctor.js +233 -0
- package/src/cmds/domain.js +110 -33
- package/src/cmds/governance.js +471 -0
- package/src/cmds/identity.js +5 -4
- package/src/cmds/quality.js +34 -9
- package/src/cmds/registry.js +62 -22
- package/src/cmds/studio.js +577 -0
- package/src/cmds/test.js +177 -0
- package/src/cmds/trace.js +225 -0
- package/src/compare.js +46 -32
- package/src/diff.js +136 -38
- package/src/identity.js +20 -4
- package/src/install.js +181 -91
- package/src/publish.js +39 -3
- package/src/search.js +33 -2
- package/src/verify.js +98 -24
- package/src/version.js +110 -3
package/src/cmds/domain.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const { execSync } = require('child_process');
|
|
4
|
-
const { error, readJson, writeJson } = require('./_common');
|
|
4
|
+
const { error, readJson, writeJson, EXIT } = require('./_common');
|
|
5
5
|
|
|
6
6
|
// ─── Validate ────────────────────────────────────────────────────────
|
|
7
7
|
|
|
8
|
-
function cmdValidate(dir, schemaOnly) {
|
|
8
|
+
function cmdValidate(dir, schemaOnly, jsonMode = false) {
|
|
9
9
|
const abs = path.resolve(dir);
|
|
10
10
|
if (!fs.existsSync(abs) || !fs.statSync(abs).isDirectory()) {
|
|
11
|
-
error(`Not a directory: ${abs}
|
|
11
|
+
error(`Not a directory: ${abs}`, EXIT.INPUT_ERROR);
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
const { lintDomain, validateDomainSchema, validateCrossFile } = require('@aikdna/kdna-core');
|
|
@@ -87,6 +87,25 @@ function cmdValidate(dir, schemaOnly) {
|
|
|
87
87
|
errors.push(...crossResult.errors);
|
|
88
88
|
warnings.push(...crossResult.warnings);
|
|
89
89
|
|
|
90
|
+
const validCount = Object.keys(dataMap).filter((k) => dataMap[k]).length;
|
|
91
|
+
const schemaInfo = schemaOnly
|
|
92
|
+
? ` (schema-only mode, ${loadedSchemas.length} schemas loaded)`
|
|
93
|
+
: '';
|
|
94
|
+
|
|
95
|
+
if (jsonMode) {
|
|
96
|
+
const result = {
|
|
97
|
+
path: abs,
|
|
98
|
+
valid: errors.length === 0,
|
|
99
|
+
files: validCount,
|
|
100
|
+
schemas_loaded: loadedSchemas.length,
|
|
101
|
+
schema_only: schemaOnly,
|
|
102
|
+
errors,
|
|
103
|
+
warnings,
|
|
104
|
+
};
|
|
105
|
+
console.log(JSON.stringify(result, null, 2));
|
|
106
|
+
process.exit(errors.length ? EXIT.VALIDATION_FAILED : EXIT.OK);
|
|
107
|
+
}
|
|
108
|
+
|
|
90
109
|
if (warnings.length) {
|
|
91
110
|
console.log('Warnings:');
|
|
92
111
|
warnings.forEach((w) => console.log(` - ${w}`));
|
|
@@ -94,13 +113,9 @@ function cmdValidate(dir, schemaOnly) {
|
|
|
94
113
|
if (errors.length) {
|
|
95
114
|
console.error('Errors:');
|
|
96
115
|
errors.forEach((e) => console.error(` - ${e}`));
|
|
97
|
-
process.exit(
|
|
116
|
+
process.exit(EXIT.VALIDATION_FAILED);
|
|
98
117
|
}
|
|
99
118
|
|
|
100
|
-
const validCount = Object.keys(dataMap).filter((k) => dataMap[k]).length;
|
|
101
|
-
const schemaInfo = schemaOnly
|
|
102
|
-
? ` (schema-only mode, ${loadedSchemas.length} schemas loaded)`
|
|
103
|
-
: '';
|
|
104
119
|
console.log(`✓ KDNA domain valid: ${abs} (${validCount} files, schema OK${schemaInfo})`);
|
|
105
120
|
}
|
|
106
121
|
|
|
@@ -109,7 +124,7 @@ function cmdValidate(dir, schemaOnly) {
|
|
|
109
124
|
function cmdPack(dir, outputDir) {
|
|
110
125
|
const abs = path.resolve(dir);
|
|
111
126
|
if (!fs.existsSync(abs) || !fs.statSync(abs).isDirectory()) {
|
|
112
|
-
error(`Not a directory: ${abs}
|
|
127
|
+
error(`Not a directory: ${abs}`, EXIT.INPUT_ERROR);
|
|
113
128
|
}
|
|
114
129
|
|
|
115
130
|
const core = readJson(path.join(abs, 'KDNA_Core.json'));
|
|
@@ -126,7 +141,7 @@ function cmdPack(dir, outputDir) {
|
|
|
126
141
|
.readdirSync(abs)
|
|
127
142
|
.filter((f) => f.endsWith('.json') && f !== 'kdna.json').length;
|
|
128
143
|
manifest = {
|
|
129
|
-
kdna_spec: '0
|
|
144
|
+
kdna_spec: '1.0-rc',
|
|
130
145
|
name: domainName,
|
|
131
146
|
version: core.meta?.version || '0.1.0',
|
|
132
147
|
status: 'experimental',
|
|
@@ -300,17 +315,17 @@ function crc32(buf) {
|
|
|
300
315
|
function cmdUnpack(filePath, force) {
|
|
301
316
|
const abs = path.resolve(filePath);
|
|
302
317
|
if (!fs.existsSync(abs) || !fs.statSync(abs).isFile()) {
|
|
303
|
-
error(`Not a file: ${abs}
|
|
318
|
+
error(`Not a file: ${abs}`, EXIT.INPUT_ERROR);
|
|
304
319
|
}
|
|
305
320
|
if (!abs.endsWith('.kdna')) {
|
|
306
|
-
error(`Not a .kdna file: ${abs}
|
|
321
|
+
error(`Not a .kdna file: ${abs}`, EXIT.INPUT_ERROR);
|
|
307
322
|
}
|
|
308
323
|
|
|
309
324
|
const domainName = path.basename(abs, '.kdna');
|
|
310
325
|
const outDir = path.join(path.dirname(abs), domainName);
|
|
311
326
|
|
|
312
327
|
if (fs.existsSync(outDir)) {
|
|
313
|
-
if (!force) error(`Directory already exists: ${outDir}\nUse --force to overwrite
|
|
328
|
+
if (!force) error(`Directory already exists: ${outDir}\nUse --force to overwrite.`, EXIT.INPUT_ERROR);
|
|
314
329
|
fs.rmSync(outDir, { recursive: true, force: true });
|
|
315
330
|
}
|
|
316
331
|
|
|
@@ -352,7 +367,7 @@ zf.close()
|
|
|
352
367
|
|
|
353
368
|
// ─── Inspect .kdna file (ZIP container or legacy merged JSON) ────────────
|
|
354
369
|
|
|
355
|
-
function inspectKdnaFile(filePath) {
|
|
370
|
+
function inspectKdnaFile(filePath, jsonMode = false) {
|
|
356
371
|
const abs = path.resolve(filePath);
|
|
357
372
|
fs.statSync(abs); // verify file exists
|
|
358
373
|
|
|
@@ -458,6 +473,33 @@ zf.close()
|
|
|
458
473
|
const c = core;
|
|
459
474
|
const p = patterns || {};
|
|
460
475
|
|
|
476
|
+
if (jsonMode) {
|
|
477
|
+
const result = {
|
|
478
|
+
name: m.name || c.meta?.domain || path.basename(abs, '.kdna'),
|
|
479
|
+
format: isZip ? 'kdna-zip' : 'legacy-merged',
|
|
480
|
+
spec: m.spec_version || m.kdna_spec || null,
|
|
481
|
+
version: m.version || null,
|
|
482
|
+
status: m.status || 'experimental',
|
|
483
|
+
access: m.access || 'open',
|
|
484
|
+
author: m.author?.name || null,
|
|
485
|
+
license: m.license?.type || null,
|
|
486
|
+
created: m.created || c.meta?.created || null,
|
|
487
|
+
description: m.description || c.meta?.purpose || null,
|
|
488
|
+
content: {
|
|
489
|
+
axioms: (c.axioms || []).length,
|
|
490
|
+
ontology: (c.ontology || []).length,
|
|
491
|
+
frameworks: (c.frameworks || []).length,
|
|
492
|
+
stances: (c.stances || []).length,
|
|
493
|
+
banned_terms: (p.terminology?.banned_terms || []).length,
|
|
494
|
+
misunderstandings: (p.misunderstandings || []).length,
|
|
495
|
+
self_checks: (p.self_check || []).length,
|
|
496
|
+
},
|
|
497
|
+
files: presentFiles,
|
|
498
|
+
};
|
|
499
|
+
console.log(JSON.stringify(result, null, 2));
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
502
|
+
|
|
461
503
|
console.log('═'.repeat(50));
|
|
462
504
|
console.log(` ${m.name || c.meta?.domain || path.basename(abs, '.kdna')} — KDNA Domain`);
|
|
463
505
|
console.log('═'.repeat(50));
|
|
@@ -537,29 +579,78 @@ function parseSimpleYaml(raw) {
|
|
|
537
579
|
|
|
538
580
|
// ─── Inspect ───────────────────────────────────────────────────────────
|
|
539
581
|
|
|
540
|
-
function cmdInspect(dir) {
|
|
582
|
+
function cmdInspect(dir, jsonMode = false) {
|
|
541
583
|
const abs = path.resolve(dir);
|
|
542
584
|
const stat = fs.existsSync(abs) ? fs.statSync(abs) : null;
|
|
543
|
-
if (!stat) error(`Path not found: ${abs}
|
|
585
|
+
if (!stat) error(`Path not found: ${abs}`, EXIT.INPUT_ERROR);
|
|
544
586
|
|
|
545
587
|
// Single .kdna file
|
|
546
588
|
if (stat.isFile() && abs.endsWith('.kdna')) {
|
|
547
|
-
inspectKdnaFile(abs);
|
|
589
|
+
inspectKdnaFile(abs, jsonMode);
|
|
548
590
|
return;
|
|
549
591
|
}
|
|
550
592
|
|
|
551
593
|
// Directory — existing logic
|
|
552
|
-
if (!stat.isDirectory()) error(`Not a KDNA domain: ${abs}
|
|
594
|
+
if (!stat.isDirectory()) error(`Not a KDNA domain: ${abs}`, EXIT.INPUT_ERROR);
|
|
553
595
|
|
|
554
596
|
const core = readJson(path.join(abs, 'KDNA_Core.json'));
|
|
555
597
|
const manifest = readJson(path.join(abs, 'kdna.json'));
|
|
556
598
|
|
|
557
599
|
if (!core) {
|
|
558
|
-
error(`Not a KDNA domain (KDNA_Core.json not found in ${abs})
|
|
600
|
+
error(`Not a KDNA domain (KDNA_Core.json not found in ${abs})`, EXIT.INPUT_ERROR);
|
|
559
601
|
}
|
|
560
602
|
|
|
561
603
|
const m = manifest || {};
|
|
562
604
|
const c = core;
|
|
605
|
+
const pat = readJson(path.join(abs, 'KDNA_Patterns.json'));
|
|
606
|
+
const sce = readJson(path.join(abs, 'KDNA_Scenarios.json'));
|
|
607
|
+
const cas = readJson(path.join(abs, 'KDNA_Cases.json'));
|
|
608
|
+
const rea = readJson(path.join(abs, 'KDNA_Reasoning.json'));
|
|
609
|
+
const evo = readJson(path.join(abs, 'KDNA_Evolution.json'));
|
|
610
|
+
|
|
611
|
+
const expected = [
|
|
612
|
+
'KDNA_Core.json',
|
|
613
|
+
'KDNA_Patterns.json',
|
|
614
|
+
'KDNA_Scenarios.json',
|
|
615
|
+
'KDNA_Cases.json',
|
|
616
|
+
'KDNA_Reasoning.json',
|
|
617
|
+
'KDNA_Evolution.json',
|
|
618
|
+
];
|
|
619
|
+
const filesPresent = expected.filter((f) => fs.existsSync(path.join(abs, f)));
|
|
620
|
+
|
|
621
|
+
if (jsonMode) {
|
|
622
|
+
const result = {
|
|
623
|
+
name: m.name || c.meta?.domain || path.basename(abs),
|
|
624
|
+
version: m.version || c.meta?.version || null,
|
|
625
|
+
status: m.status || 'experimental',
|
|
626
|
+
access: m.access || 'open',
|
|
627
|
+
language: m.language || c.meta?.language || null,
|
|
628
|
+
author: m.author?.name || null,
|
|
629
|
+
author_id: m.author?.id || null,
|
|
630
|
+
license: m.license?.type || null,
|
|
631
|
+
created: c.meta?.created || null,
|
|
632
|
+
description: m.description || c.meta?.purpose || null,
|
|
633
|
+
files: filesPresent,
|
|
634
|
+
content: {
|
|
635
|
+
axioms: (c.axioms || []).length,
|
|
636
|
+
ontology: (c.ontology || []).length,
|
|
637
|
+
frameworks: (c.frameworks || []).length,
|
|
638
|
+
core_structures: (c.core_structure || []).length,
|
|
639
|
+
stances: (c.stances || []).length,
|
|
640
|
+
preferred_terms: (pat?.terminology?.preferred_terms || pat?.terminology?.standard_terms || []).length,
|
|
641
|
+
banned_terms: (pat?.terminology?.banned_terms || []).length,
|
|
642
|
+
misunderstandings: (pat?.misunderstandings || []).length,
|
|
643
|
+
self_checks: (pat?.self_check || []).length,
|
|
644
|
+
scenarios: sce ? (sce.scenes || []).length : 0,
|
|
645
|
+
cases: cas ? (cas.cases || []).length : 0,
|
|
646
|
+
reasoning_chains: rea ? (rea.reasoning_chains || []).length : 0,
|
|
647
|
+
evolution_stages: evo ? (evo.stages || []).length : 0,
|
|
648
|
+
},
|
|
649
|
+
axioms: (c.axioms || []).map((a) => a.one_sentence || null).filter(Boolean),
|
|
650
|
+
};
|
|
651
|
+
console.log(JSON.stringify(result, null, 2));
|
|
652
|
+
return;
|
|
653
|
+
}
|
|
563
654
|
|
|
564
655
|
console.log('═'.repeat(50));
|
|
565
656
|
console.log(` ${m.name || c.meta?.domain || path.basename(abs)} — KDNA Domain`);
|
|
@@ -576,15 +667,6 @@ function cmdInspect(dir) {
|
|
|
576
667
|
console.log(` Description: ${m.description || c.meta?.purpose || '?'}`);
|
|
577
668
|
console.log('');
|
|
578
669
|
|
|
579
|
-
const expected = [
|
|
580
|
-
'KDNA_Core.json',
|
|
581
|
-
'KDNA_Patterns.json',
|
|
582
|
-
'KDNA_Scenarios.json',
|
|
583
|
-
'KDNA_Cases.json',
|
|
584
|
-
'KDNA_Reasoning.json',
|
|
585
|
-
'KDNA_Evolution.json',
|
|
586
|
-
];
|
|
587
|
-
|
|
588
670
|
console.log(' ── File Set ──');
|
|
589
671
|
for (const f of expected) {
|
|
590
672
|
const exists = fs.existsSync(path.join(abs, f));
|
|
@@ -599,7 +681,6 @@ function cmdInspect(dir) {
|
|
|
599
681
|
console.log(` Core structures: ${(c.core_structure || []).length}`);
|
|
600
682
|
console.log(` Stances: ${(c.stances || []).length}`);
|
|
601
683
|
|
|
602
|
-
const pat = readJson(path.join(abs, 'KDNA_Patterns.json'));
|
|
603
684
|
if (pat) {
|
|
604
685
|
const preferred = pat.terminology?.preferred_terms || pat.terminology?.standard_terms || [];
|
|
605
686
|
console.log(` Preferred terms: ${preferred.length}`);
|
|
@@ -608,16 +689,12 @@ function cmdInspect(dir) {
|
|
|
608
689
|
console.log(` Self-checks: ${(pat.self_check || []).length}`);
|
|
609
690
|
}
|
|
610
691
|
|
|
611
|
-
const sce = readJson(path.join(abs, 'KDNA_Scenarios.json'));
|
|
612
692
|
if (sce) console.log(` Scenarios: ${(sce.scenes || []).length}`);
|
|
613
693
|
|
|
614
|
-
const cas = readJson(path.join(abs, 'KDNA_Cases.json'));
|
|
615
694
|
if (cas) console.log(` Cases: ${(cas.cases || []).length}`);
|
|
616
695
|
|
|
617
|
-
const rea = readJson(path.join(abs, 'KDNA_Reasoning.json'));
|
|
618
696
|
if (rea) console.log(` Reasoning chains: ${(rea.reasoning_chains || []).length}`);
|
|
619
697
|
|
|
620
|
-
const evo = readJson(path.join(abs, 'KDNA_Evolution.json'));
|
|
621
698
|
if (evo) console.log(` Evolution stages: ${(evo.stages || []).length}`);
|
|
622
699
|
|
|
623
700
|
console.log('');
|