@aikdna/kdna-cli 0.16.4 → 0.16.5

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.5",
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,7 @@ Agent Runtime:
81
107
 
82
108
  Testing & Verification:
83
109
  verify <name> 3-layer: structure + trust + judgment
110
+ verify <name> --i18n I18N verification: locale dirs, overlays, card completeness
84
111
  verify <name> --judgment --run-tests Judgment validation with eval cases
85
112
  compare <name> --input "..." With/without KDNA reasoning diff
86
113
  compare <name> --input "..." --report-md Markdown report format
@@ -332,7 +359,10 @@ switch (cmd) {
332
359
  } else if (sub === 'validate') {
333
360
  cmdProposalValidate(args);
334
361
  } else {
335
- error('Usage: kdna proposal create --from-test <run.json> --domain <path>\n kdna proposal validate <proposal.json>', EXIT.INPUT_ERROR);
362
+ error(
363
+ 'Usage: kdna proposal create --from-test <run.json> --domain <path>\n kdna proposal validate <proposal.json>',
364
+ EXIT.INPUT_ERROR,
365
+ );
336
366
  }
337
367
  break;
338
368
  }
@@ -405,7 +435,9 @@ switch (cmd) {
405
435
  break;
406
436
  }
407
437
  case 'list': {
408
- cmdList(args.includes('--available'), args.includes('--json'));
438
+ const localeIdx = args.indexOf('--locale');
439
+ const locale = localeIdx >= 0 ? args[localeIdx + 1] : null;
440
+ cmdList(args.includes('--available'), args.includes('--json'), locale);
409
441
  break;
410
442
  }
411
443
  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,94 @@ 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
+
370
470
  // ─── Main ──────────────────────────────────────────────────────────────
371
471
 
372
472
  function cmdVerify(input, args = []) {
@@ -376,15 +476,22 @@ function cmdVerify(input, args = []) {
376
476
  structure: args.includes('--structure'),
377
477
  trust: args.includes('--trust'),
378
478
  judgment: args.includes('--judgment'),
479
+ i18n: args.includes('--i18n'),
379
480
  };
380
- const all = !want.structure && !want.trust && !want.judgment;
481
+ const all = !want.structure && !want.trust && !want.judgment && !want.i18n;
381
482
  if (all) want.structure = want.trust = want.judgment = true;
382
483
 
383
484
  // Resolve name → installed path + scope/entry
384
485
  const parsed = parseName(input);
385
486
  if (!parsed) {
386
487
  if (jsonMode) {
387
- console.log(JSON.stringify({ name: input, ok: false, error: `Invalid name "${input}". Use @scope/name or bare name.` }));
488
+ console.log(
489
+ JSON.stringify({
490
+ name: input,
491
+ ok: false,
492
+ error: `Invalid name "${input}". Use @scope/name or bare name.`,
493
+ }),
494
+ );
388
495
  } else {
389
496
  console.error(`Invalid name "${input}". Use @scope/name or bare name.`);
390
497
  }
@@ -394,7 +501,13 @@ function cmdVerify(input, args = []) {
394
501
  const destDir = path.join(INSTALL_DIR, parsed.scope, parsed.ident);
395
502
  if (!fs.existsSync(destDir)) {
396
503
  if (jsonMode) {
397
- console.log(JSON.stringify({ name: parsed.full, ok: false, error: `${parsed.full} is not installed. Run: kdna install ${input}` }));
504
+ console.log(
505
+ JSON.stringify({
506
+ name: parsed.full,
507
+ ok: false,
508
+ error: `${parsed.full} is not installed. Run: kdna install ${input}`,
509
+ }),
510
+ );
398
511
  } else {
399
512
  console.error(`${parsed.full} is not installed. Run: kdna install ${input}`);
400
513
  }
@@ -418,6 +531,7 @@ function cmdVerify(input, args = []) {
418
531
  if (want.structure) results.push(checkStructure(destDir));
419
532
  if (want.trust) results.push(checkTrust(destDir, scope, entry));
420
533
  if (want.judgment) results.push(checkJudgment(destDir));
534
+ if (want.i18n) results.push(checkI18n(destDir));
421
535
 
422
536
  // ── JSON output ──────────────────────────────────────────────────────
423
537
  if (jsonMode) {
@@ -444,12 +558,18 @@ function cmdVerify(input, args = []) {
444
558
  exitCode = EXIT.JUDGMENT_QUALITY_FAILED;
445
559
  }
446
560
 
447
- console.log(JSON.stringify({
448
- name: parsed.full,
449
- path: destDir,
450
- layers,
451
- ok: exitCode === EXIT.OK,
452
- }, null, 2));
561
+ console.log(
562
+ JSON.stringify(
563
+ {
564
+ name: parsed.full,
565
+ path: destDir,
566
+ layers,
567
+ ok: exitCode === EXIT.OK,
568
+ },
569
+ null,
570
+ 2,
571
+ ),
572
+ );
453
573
  process.exit(exitCode);
454
574
  }
455
575