@aikdna/kdna-cli 0.16.4 → 0.16.6

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aikdna/kdna-cli",
3
- "version": "0.16.4",
3
+ "version": "0.16.6",
4
4
  "description": "KDNA CLI — create, validate, install, and manage domain cognition packages for AI agents.",
5
5
  "type": "commonjs",
6
6
  "bin": {
package/src/cli.js CHANGED
@@ -7,7 +7,14 @@
7
7
  */
8
8
 
9
9
  const { error, EXIT, setQuiet, setExitCodeOnly } = require('./cmds/_common');
10
- const { cmdValidate, cmdPack, cmdPackEncrypt, cmdUnpack, cmdUnpackEncrypt, cmdInspect } = require('./cmds/domain');
10
+ const {
11
+ cmdValidate,
12
+ cmdPack,
13
+ cmdPackEncrypt,
14
+ cmdUnpack,
15
+ cmdUnpackEncrypt,
16
+ cmdInspect,
17
+ } = require('./cmds/domain');
11
18
  const { cmdList, cmdRegistry } = require('./cmds/registry');
12
19
  const {
13
20
  cmdCompare,
@@ -24,12 +31,31 @@ const { cmdIdentity } = require('./cmds/identity');
24
31
  const { cmdSetup } = require('./cmds/setup');
25
32
  const { cmdDoctor } = require('./cmds/doctor');
26
33
  const { cmdTrace, cmdHistory } = require('./cmds/trace');
27
- const { cmdLicenseGenerate, cmdLicenseVerify, cmdLicenseBind, cmdLicenseShow, cmdLicenseInstall } = require('./cmds/license');
34
+ const {
35
+ cmdLicenseGenerate,
36
+ cmdLicenseVerify,
37
+ cmdLicenseBind,
38
+ cmdLicenseShow,
39
+ cmdLicenseInstall,
40
+ } = require('./cmds/license');
28
41
  const { cmdPreview, cmdProject, cmdEval, cmdExport, cmdDemo } = require('./cmds/legacy');
29
- const { cmdStudioScaffold, cmdCardsValidate, cmdLockVerify, cmdStudioCompile, cmdStudioReadiness } = require('./cmds/studio');
42
+ const {
43
+ cmdStudioScaffold,
44
+ cmdCardsValidate,
45
+ cmdLockVerify,
46
+ cmdStudioCompile,
47
+ cmdStudioReadiness,
48
+ } = require('./cmds/studio');
30
49
  const { cmdTestRun, cmdTestImport } = require('./cmds/test');
31
50
  const { cmdChangelog } = require('./cmds/changelog');
32
- const { cmdProposalCreate, cmdProposalValidate, cmdReview, cmdLockCard, cmdEvolution, cmdRegression } = require('./cmds/governance');
51
+ const {
52
+ cmdProposalCreate,
53
+ cmdProposalValidate,
54
+ cmdReview,
55
+ cmdLockCard,
56
+ cmdEvolution,
57
+ cmdRegression,
58
+ } = require('./cmds/governance');
33
59
  const { cmdBadgeCompute, cmdRegistryAudit, cmdPackage } = require('./cmds/badge');
34
60
 
35
61
  // ─── Main ─────────────────────────────────────────────────────────────
@@ -81,6 +107,8 @@ Agent Runtime:
81
107
 
82
108
  Testing & Verification:
83
109
  verify <name> 3-layer: structure + trust + judgment
110
+ verify <name> --i18n I18N verification: locales, overlays, card completeness
111
+ verify <name> --governance Governance verification: risk_level, KDNA_CARD, provenance
84
112
  verify <name> --judgment --run-tests Judgment validation with eval cases
85
113
  compare <name> --input "..." With/without KDNA reasoning diff
86
114
  compare <name> --input "..." --report-md Markdown report format
@@ -332,7 +360,10 @@ switch (cmd) {
332
360
  } else if (sub === 'validate') {
333
361
  cmdProposalValidate(args);
334
362
  } else {
335
- error('Usage: kdna proposal create --from-test <run.json> --domain <path>\n kdna proposal validate <proposal.json>', EXIT.INPUT_ERROR);
363
+ error(
364
+ 'Usage: kdna proposal create --from-test <run.json> --domain <path>\n kdna proposal validate <proposal.json>',
365
+ EXIT.INPUT_ERROR,
366
+ );
336
367
  }
337
368
  break;
338
369
  }
@@ -405,7 +436,9 @@ switch (cmd) {
405
436
  break;
406
437
  }
407
438
  case 'list': {
408
- cmdList(args.includes('--available'), args.includes('--json'));
439
+ const localeIdx = args.indexOf('--locale');
440
+ const locale = localeIdx >= 0 ? args[localeIdx + 1] : null;
441
+ cmdList(args.includes('--available'), args.includes('--json'), locale);
409
442
  break;
410
443
  }
411
444
  case 'setup': {
@@ -3,7 +3,7 @@ const path = require('path');
3
3
  const { CANONICAL_REGISTRY_URL, REGISTRY_CACHE, fetchRegistry } = require('../registry');
4
4
  const { error, readJson, loadRegistry, INSTALL_DIR, EXIT } = require('./_common');
5
5
 
6
- function cmdList(showAvailable, jsonMode = false) {
6
+ function cmdList(showAvailable, jsonMode = false, locale = null) {
7
7
  if (showAvailable) {
8
8
  const domains = loadRegistry({ allowNetwork: true });
9
9
  if (!domains || !domains.length) {
package/src/verify.js CHANGED
@@ -240,10 +240,16 @@ function checkJudgment(destDir) {
240
240
  } else if (hasScope || hasOutOfScope) {
241
241
  score.max += 2;
242
242
  score.total += 1;
243
- issues.push({ severity: 'warn', msg: 'partial: README boundary declaration incomplete (missing Scope or Out-of-Scope section)' });
243
+ issues.push({
244
+ severity: 'warn',
245
+ msg: 'partial: README boundary declaration incomplete (missing Scope or Out-of-Scope section)',
246
+ });
244
247
  } else {
245
248
  score.max += 2;
246
- issues.push({ severity: 'error', msg: 'README missing boundary declaration: require ## Scope + ## Out of Scope (or v2.1 Four Questions)' });
249
+ issues.push({
250
+ severity: 'error',
251
+ msg: 'README missing boundary declaration: require ## Scope + ## Out of Scope (or v2.1 Four Questions)',
252
+ });
247
253
  }
248
254
 
249
255
  // 2. v2.1 axiom governance fields
@@ -321,14 +327,20 @@ function checkJudgment(destDir) {
321
327
  } else if (files.length > 0) {
322
328
  score.max += 2;
323
329
  score.total += 1;
324
- issues.push({ severity: 'warn', msg: `evals/ has only ${files.length} files (require ≥4: core/boundary/failure/excluded)` });
330
+ issues.push({
331
+ severity: 'warn',
332
+ msg: `evals/ has only ${files.length} files (require ≥4: core/boundary/failure/excluded)`,
333
+ });
325
334
  } else {
326
335
  score.max += 2;
327
336
  issues.push({ severity: 'error', msg: 'evals/ directory exists but contains no case files' });
328
337
  }
329
338
  } else {
330
339
  score.max += 2;
331
- issues.push({ severity: 'error', msg: 'evals/ directory missing: require ≥4 evaluation cases' });
340
+ issues.push({
341
+ severity: 'error',
342
+ msg: 'evals/ directory missing: require ≥4 evaluation cases',
343
+ });
332
344
  }
333
345
 
334
346
  // 6. judgment_version manifest field (REQUIRED)
@@ -367,6 +379,175 @@ function renderLayer(result) {
367
379
  }
368
380
  }
369
381
 
382
+ // ─── I18N layer ──────────────────────────────────────────────────────
383
+
384
+ function checkI18n(destDir) {
385
+ const issues = [];
386
+ const passed = [];
387
+ const manifest = readJson(path.join(destDir, 'kdna.json')) || {};
388
+ const languages = manifest.languages || [];
389
+ const i18nLevel = manifest.i18n_level || 'L0';
390
+
391
+ if (languages.length === 0) {
392
+ passed.push('i18n: no languages declared (L0 — monolingual)');
393
+ return { layer: 'i18n', passed: true, issues, results: passed };
394
+ }
395
+
396
+ passed.push(`languages declared: ${languages.join(', ')}`);
397
+ passed.push(`i18n level: ${i18nLevel}`);
398
+
399
+ const canonical = manifest.default_language || languages[0] || 'en';
400
+ for (const lang of languages) {
401
+ if (lang === canonical) continue;
402
+ const localeDir = path.join(destDir, 'locales', lang);
403
+
404
+ // L1: card + readme
405
+ if (['L1', 'L2', 'L3', 'L4'].includes(i18nLevel)) {
406
+ if (!fs.existsSync(path.join(localeDir, 'KDNA_CARD.json'))) {
407
+ issues.push({ severity: 'error', msg: `i18n: ${lang} KDNA_CARD.json missing` });
408
+ } else {
409
+ const card = readJson(path.join(localeDir, 'KDNA_CARD.json'));
410
+ if (card) {
411
+ passed.push(`locales/${lang}/KDNA_CARD.json OK`);
412
+ if (!card.display_name)
413
+ issues.push({ severity: 'warn', msg: `i18n: ${lang} card missing display_name` });
414
+ if (!card.intended_use?.length)
415
+ issues.push({ severity: 'warn', msg: `i18n: ${lang} card missing intended_use` });
416
+ }
417
+ }
418
+ if (!fs.existsSync(path.join(localeDir, 'README.md'))) {
419
+ issues.push({ severity: 'warn', msg: `i18n: ${lang} README.md missing` });
420
+ } else {
421
+ passed.push(`locales/${lang}/README.md OK`);
422
+ }
423
+ }
424
+
425
+ // L2: overlay files
426
+ if (['L2', 'L3', 'L4'].includes(i18nLevel)) {
427
+ const coreOverlay = path.join(localeDir, 'KDNA_Core.overlay.json');
428
+ if (!fs.existsSync(coreOverlay)) {
429
+ issues.push({ severity: 'error', msg: `i18n: ${lang} KDNA_Core.overlay.json missing` });
430
+ } else {
431
+ const overlay = readJson(coreOverlay);
432
+ if (overlay?.translations) {
433
+ const core = readJson(path.join(destDir, 'KDNA_Core.json'));
434
+ if (core?.axioms) {
435
+ const validIds = new Set(core.axioms.map((a) => a.id));
436
+ for (const key of Object.keys(overlay.translations)) {
437
+ const refId = key.split('.')[0];
438
+ if (!validIds.has(refId)) {
439
+ issues.push({
440
+ severity: 'error',
441
+ msg: `i18n: overlay refs unknown axiom: ${refId}`,
442
+ });
443
+ }
444
+ }
445
+ }
446
+ passed.push(
447
+ `locales/${lang}/KDNA_Core.overlay.json OK (${Object.keys(overlay.translations).length} translations)`,
448
+ );
449
+ }
450
+ }
451
+ if (!fs.existsSync(path.join(localeDir, 'KDNA_Patterns.overlay.json'))) {
452
+ issues.push({ severity: 'warn', msg: `i18n: ${lang} KDNA_Patterns.overlay.json missing` });
453
+ }
454
+ }
455
+ }
456
+
457
+ if (manifest.languages?.length && !manifest.i18n_level) {
458
+ issues.push({ severity: 'warn', msg: 'i18n: languages declared but i18n_level not set' });
459
+ }
460
+
461
+ return {
462
+ layer: 'i18n',
463
+ passed: issues.filter((i) => i.severity === 'error').length === 0,
464
+ issues,
465
+ results: passed.concat(issues.map((i) => i.msg)),
466
+ score: { total: passed.length, max: passed.length + issues.length },
467
+ };
468
+ }
469
+
470
+ // ─── Governance layer ───────────────────────────────────────────────
471
+
472
+ function checkGovernance(destDir) {
473
+ const issues = [];
474
+ const passed = [];
475
+ const card = readJson(path.join(destDir, 'KDNA_CARD.json')) || {};
476
+
477
+ if (!readJson(path.join(destDir, 'KDNA_CARD.json'))) {
478
+ issues.push({ severity: 'error', msg: 'governance: KDNA_CARD.json missing — required' });
479
+ return { layer: 'governance', passed: false, issues, results: issues.map((i) => i.msg) };
480
+ }
481
+ passed.push('KDNA_CARD.json present');
482
+
483
+ if (!card.risk_level) {
484
+ issues.push({ severity: 'error', msg: 'governance: risk_level not declared (R0/R1/R2/R3)' });
485
+ } else if (!['R0', 'R1', 'R2', 'R3'].includes(card.risk_level)) {
486
+ issues.push({ severity: 'error', msg: `governance: invalid risk_level "${card.risk_level}"` });
487
+ } else {
488
+ passed.push(`risk_level: ${card.risk_level}`);
489
+ }
490
+
491
+ if (!card.intended_use?.length) {
492
+ issues.push({ severity: 'error', msg: 'governance: intended_use empty' });
493
+ } else {
494
+ passed.push(`intended_use: ${card.intended_use.length} entries`);
495
+ }
496
+
497
+ if (!card.out_of_scope?.length) {
498
+ issues.push({ severity: 'error', msg: 'governance: out_of_scope empty' });
499
+ } else {
500
+ passed.push(`out_of_scope: ${card.out_of_scope.length} entries`);
501
+ }
502
+
503
+ if (!card.known_limitations?.length) {
504
+ issues.push({ severity: 'warn', msg: 'governance: known_limitations empty' });
505
+ } else {
506
+ passed.push(`known_limitations: ${card.known_limitations.length} entries`);
507
+ }
508
+
509
+ if (['R1', 'R2', 'R3'].includes(card.risk_level) && !card.author_responsibility) {
510
+ issues.push({
511
+ severity: 'warn',
512
+ msg: `governance: risk ${card.risk_level} should declare author_responsibility`,
513
+ });
514
+ }
515
+
516
+ if (['R2', 'R3'].includes(card.risk_level)) {
517
+ if (!card.reviewed_by && !card.requires_expert_review) {
518
+ issues.push({
519
+ severity: 'error',
520
+ msg: `governance: risk ${card.risk_level} requires expert_review`,
521
+ });
522
+ }
523
+ if (!card.risk_warnings?.length) {
524
+ issues.push({
525
+ severity: 'error',
526
+ msg: `governance: risk ${card.risk_level} requires risk_warnings`,
527
+ });
528
+ }
529
+ }
530
+
531
+ if (!card.human_lock_summary)
532
+ issues.push({ severity: 'warn', msg: 'governance: human_lock_summary missing' });
533
+ else passed.push('human_lock_summary present');
534
+
535
+ if (!card.provenance) issues.push({ severity: 'warn', msg: 'governance: provenance missing' });
536
+ else passed.push('provenance present');
537
+
538
+ if (!card.quality_badge)
539
+ issues.push({ severity: 'warn', msg: 'governance: quality_badge missing' });
540
+ else passed.push(`quality_badge: ${card.quality_badge}`);
541
+
542
+ return {
543
+ layer: 'governance',
544
+ passed: issues.filter((i) => i.severity === 'error').length === 0,
545
+ issues,
546
+ results: passed.concat(issues.map((i) => i.msg)),
547
+ score: { total: passed.length, max: passed.length + issues.length },
548
+ };
549
+ }
550
+
370
551
  // ─── Main ──────────────────────────────────────────────────────────────
371
552
 
372
553
  function cmdVerify(input, args = []) {
@@ -376,15 +557,23 @@ function cmdVerify(input, args = []) {
376
557
  structure: args.includes('--structure'),
377
558
  trust: args.includes('--trust'),
378
559
  judgment: args.includes('--judgment'),
560
+ i18n: args.includes('--i18n'),
561
+ governance: args.includes('--governance'),
379
562
  };
380
- const all = !want.structure && !want.trust && !want.judgment;
563
+ const all = !want.structure && !want.trust && !want.judgment && !want.i18n && !want.governance;
381
564
  if (all) want.structure = want.trust = want.judgment = true;
382
565
 
383
566
  // Resolve name → installed path + scope/entry
384
567
  const parsed = parseName(input);
385
568
  if (!parsed) {
386
569
  if (jsonMode) {
387
- console.log(JSON.stringify({ name: input, ok: false, error: `Invalid name "${input}". Use @scope/name or bare name.` }));
570
+ console.log(
571
+ JSON.stringify({
572
+ name: input,
573
+ ok: false,
574
+ error: `Invalid name "${input}". Use @scope/name or bare name.`,
575
+ }),
576
+ );
388
577
  } else {
389
578
  console.error(`Invalid name "${input}". Use @scope/name or bare name.`);
390
579
  }
@@ -394,7 +583,13 @@ function cmdVerify(input, args = []) {
394
583
  const destDir = path.join(INSTALL_DIR, parsed.scope, parsed.ident);
395
584
  if (!fs.existsSync(destDir)) {
396
585
  if (jsonMode) {
397
- console.log(JSON.stringify({ name: parsed.full, ok: false, error: `${parsed.full} is not installed. Run: kdna install ${input}` }));
586
+ console.log(
587
+ JSON.stringify({
588
+ name: parsed.full,
589
+ ok: false,
590
+ error: `${parsed.full} is not installed. Run: kdna install ${input}`,
591
+ }),
592
+ );
398
593
  } else {
399
594
  console.error(`${parsed.full} is not installed. Run: kdna install ${input}`);
400
595
  }
@@ -418,6 +613,8 @@ function cmdVerify(input, args = []) {
418
613
  if (want.structure) results.push(checkStructure(destDir));
419
614
  if (want.trust) results.push(checkTrust(destDir, scope, entry));
420
615
  if (want.judgment) results.push(checkJudgment(destDir));
616
+ if (want.i18n) results.push(checkI18n(destDir));
617
+ if (want.governance) results.push(checkGovernance(destDir));
421
618
 
422
619
  // ── JSON output ──────────────────────────────────────────────────────
423
620
  if (jsonMode) {
@@ -434,6 +631,8 @@ function cmdVerify(input, args = []) {
434
631
  const structureResult = results.find((r) => r.layer === 'structure');
435
632
  const trustResult = results.find((r) => r.layer === 'trust');
436
633
  const judgmentResult = results.find((r) => r.layer === 'judgment');
634
+ const i18nResult = results.find((r) => r.layer === 'i18n');
635
+ const governanceResult = results.find((r) => r.layer === 'governance');
437
636
 
438
637
  let exitCode = EXIT.OK;
439
638
  if (structureResult && structureResult.issues.some((i) => i.severity === 'error')) {
@@ -444,12 +643,18 @@ function cmdVerify(input, args = []) {
444
643
  exitCode = EXIT.JUDGMENT_QUALITY_FAILED;
445
644
  }
446
645
 
447
- console.log(JSON.stringify({
448
- name: parsed.full,
449
- path: destDir,
450
- layers,
451
- ok: exitCode === EXIT.OK,
452
- }, null, 2));
646
+ console.log(
647
+ JSON.stringify(
648
+ {
649
+ name: parsed.full,
650
+ path: destDir,
651
+ layers,
652
+ ok: exitCode === EXIT.OK,
653
+ },
654
+ null,
655
+ 2,
656
+ ),
657
+ );
453
658
  process.exit(exitCode);
454
659
  }
455
660