@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.
@@ -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(1);
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.4',
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('');