@aikdna/kdna-cli 0.16.3 → 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 +1 -1
- package/src/cli.js +42 -8
- package/src/cmds/domain.js +33 -13
- package/src/cmds/registry.js +1 -1
- package/src/verify.js +133 -13
package/package.json
CHANGED
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 {
|
|
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 {
|
|
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 {
|
|
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 {
|
|
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
|
|
@@ -252,8 +279,10 @@ switch (cmd) {
|
|
|
252
279
|
}
|
|
253
280
|
case 'inspect': {
|
|
254
281
|
const target = args.filter((a) => !a.startsWith('--'))[1];
|
|
255
|
-
if (!target) error('Usage: kdna inspect <path>');
|
|
256
|
-
|
|
282
|
+
if (!target) error('Usage: kdna inspect <path> [--json] [--locale zh-CN]');
|
|
283
|
+
const localeIdx = args.indexOf('--locale');
|
|
284
|
+
const locale = localeIdx >= 0 ? args[localeIdx + 1] : null;
|
|
285
|
+
cmdInspect(target, args.includes('--json'), locale);
|
|
257
286
|
break;
|
|
258
287
|
}
|
|
259
288
|
case 'verify': {
|
|
@@ -330,7 +359,10 @@ switch (cmd) {
|
|
|
330
359
|
} else if (sub === 'validate') {
|
|
331
360
|
cmdProposalValidate(args);
|
|
332
361
|
} else {
|
|
333
|
-
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
|
+
);
|
|
334
366
|
}
|
|
335
367
|
break;
|
|
336
368
|
}
|
|
@@ -403,7 +435,9 @@ switch (cmd) {
|
|
|
403
435
|
break;
|
|
404
436
|
}
|
|
405
437
|
case 'list': {
|
|
406
|
-
|
|
438
|
+
const localeIdx = args.indexOf('--locale');
|
|
439
|
+
const locale = localeIdx >= 0 ? args[localeIdx + 1] : null;
|
|
440
|
+
cmdList(args.includes('--available'), args.includes('--json'), locale);
|
|
407
441
|
break;
|
|
408
442
|
}
|
|
409
443
|
case 'setup': {
|
package/src/cmds/domain.js
CHANGED
|
@@ -587,14 +587,14 @@ function parseSimpleYaml(raw) {
|
|
|
587
587
|
|
|
588
588
|
// ─── Inspect ───────────────────────────────────────────────────────────
|
|
589
589
|
|
|
590
|
-
function cmdInspect(dir, jsonMode = false) {
|
|
590
|
+
function cmdInspect(dir, jsonMode = false, locale = null) {
|
|
591
591
|
const abs = path.resolve(dir);
|
|
592
592
|
const stat = fs.existsSync(abs) ? fs.statSync(abs) : null;
|
|
593
593
|
if (!stat) error(`Path not found: ${abs}`, EXIT.INPUT_ERROR);
|
|
594
594
|
|
|
595
595
|
// Single .kdna file
|
|
596
596
|
if (stat.isFile() && abs.endsWith('.kdna')) {
|
|
597
|
-
inspectKdnaFile(abs, jsonMode);
|
|
597
|
+
inspectKdnaFile(abs, jsonMode, locale);
|
|
598
598
|
return;
|
|
599
599
|
}
|
|
600
600
|
|
|
@@ -657,18 +657,27 @@ function cmdInspect(dir, jsonMode = false) {
|
|
|
657
657
|
axioms: (c.axioms || []).map((a) => a.one_sentence || null).filter(Boolean),
|
|
658
658
|
};
|
|
659
659
|
|
|
660
|
-
//
|
|
661
|
-
|
|
662
|
-
if (card) {
|
|
660
|
+
// Add governance + locale data
|
|
661
|
+
if (kdnaCard) {
|
|
663
662
|
result.governance = {
|
|
664
|
-
risk_level:
|
|
665
|
-
review_status:
|
|
666
|
-
intended_use:
|
|
667
|
-
out_of_scope:
|
|
668
|
-
known_limitations:
|
|
669
|
-
requires_expert_review:
|
|
663
|
+
risk_level: kdnaCard.risk_level || null,
|
|
664
|
+
review_status: kdnaCard.review_status || null,
|
|
665
|
+
intended_use: kdnaCard.intended_use || [],
|
|
666
|
+
out_of_scope: kdnaCard.out_of_scope || [],
|
|
667
|
+
known_limitations: kdnaCard.known_limitations || [],
|
|
668
|
+
requires_expert_review: kdnaCard.requires_expert_review || false,
|
|
670
669
|
};
|
|
670
|
+
if (locale) {
|
|
671
|
+
result.governance.display_name = kdnaCard.display_name || null;
|
|
672
|
+
result.governance.summary = kdnaCard.summary || null;
|
|
673
|
+
result.governance.locale = locale;
|
|
674
|
+
}
|
|
671
675
|
}
|
|
676
|
+
// Add i18n info from kdna.json
|
|
677
|
+
if (m.languages) result.languages = m.languages;
|
|
678
|
+
if (m.default_language) result.default_language = m.default_language;
|
|
679
|
+
if (m.i18n_level) result.i18n_level = m.i18n_level;
|
|
680
|
+
|
|
672
681
|
console.log(JSON.stringify(result, null, 2));
|
|
673
682
|
return;
|
|
674
683
|
}
|
|
@@ -718,11 +727,22 @@ function cmdInspect(dir, jsonMode = false) {
|
|
|
718
727
|
|
|
719
728
|
if (evo) console.log(` Evolution stages: ${(evo.stages || []).length}`);
|
|
720
729
|
|
|
721
|
-
// Governance metadata
|
|
722
|
-
|
|
730
|
+
// Governance metadata (with locale support)
|
|
731
|
+
let kdnaCard = readJson(path.join(abs, 'KDNA_CARD.json'));
|
|
732
|
+
if (locale && !kdnaCard) {
|
|
733
|
+
kdnaCard = readJson(path.join(abs, 'locales', locale, 'KDNA_CARD.json'));
|
|
734
|
+
}
|
|
735
|
+
if (locale && kdnaCard) {
|
|
736
|
+
const localeCard = readJson(path.join(abs, 'locales', locale, 'KDNA_CARD.json'));
|
|
737
|
+
if (localeCard) kdnaCard = localeCard;
|
|
738
|
+
}
|
|
723
739
|
if (kdnaCard) {
|
|
740
|
+
const displayName = kdnaCard.display_name || '';
|
|
741
|
+
const summary = kdnaCard.summary || '';
|
|
724
742
|
console.log('');
|
|
725
743
|
console.log(' ── Governance ──');
|
|
744
|
+
if (displayName && locale) console.log(` Display name: ${displayName}`);
|
|
745
|
+
if (summary && locale) console.log(` Summary: ${summary}`);
|
|
726
746
|
console.log(` Risk level: ${kdnaCard.risk_level || '?'}`);
|
|
727
747
|
console.log(` Review status: ${kdnaCard.review_status || '?'}`);
|
|
728
748
|
if (kdnaCard.intended_use?.length) console.log(` Intended use: ${kdnaCard.intended_use[0]}${kdnaCard.intended_use.length > 1 ? ` (+${kdnaCard.intended_use.length - 1} more)` : ''}`);
|
package/src/cmds/registry.js
CHANGED
|
@@ -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({
|
|
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({
|
|
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({
|
|
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({
|
|
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(
|
|
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(
|
|
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(
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
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
|
|