@aikdna/kdna-cli 0.17.0 → 0.18.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 +42 -23
- package/package.json +5 -4
- package/skills/kdna-loader/SKILL.md +5 -6
- package/src/agent.js +145 -109
- package/src/cli.js +104 -60
- package/src/cmds/_common.js +32 -16
- package/src/cmds/badge.js +7 -7
- package/src/cmds/changelog.js +1 -1
- package/src/cmds/cluster.js +16 -48
- package/src/cmds/doctor.js +10 -27
- package/src/cmds/domain.js +77 -400
- package/src/cmds/explain.js +122 -0
- package/src/cmds/legacy.js +8 -8
- package/src/cmds/license.js +483 -26
- package/src/cmds/quality.js +2 -2
- package/src/cmds/registry.js +15 -67
- package/src/cmds/studio.js +4 -5
- package/src/cmds/test.js +4 -4
- package/src/cmds/trace.js +11 -7
- package/src/compare.js +28 -22
- package/src/diff.js +11 -13
- package/src/init.js +2 -2
- package/src/install.js +138 -460
- package/src/loader.js +10 -10
- package/src/package-store.js +229 -0
- package/src/paths.js +44 -0
- package/src/publish.js +73 -22
- package/src/registry.js +76 -9
- package/src/setup.js +19 -20
- package/src/verify.js +233 -124
- package/templates/standard-domain/kdna.json +2 -1
- package/src/cmds/encrypt.js +0 -199
package/src/cmds/studio.js
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
const fs = require('fs');
|
|
12
12
|
const path = require('path');
|
|
13
|
-
const { error, readJson, writeJson, EXIT } = require('./_common');
|
|
13
|
+
const { error, readJson, writeJson, EXIT, isYesNoSelfCheck } = require('./_common');
|
|
14
14
|
|
|
15
15
|
// ─── Scaffold ─────────────────────────────────────────────────────────
|
|
16
16
|
|
|
@@ -240,8 +240,8 @@ function cmdCardsValidate(projectPath, args = []) {
|
|
|
240
240
|
const label = sc.id || '?';
|
|
241
241
|
if (!sc.question || sc.question.includes('[TODO]')) {
|
|
242
242
|
warn(`self_check ${label}: question is placeholder`);
|
|
243
|
-
} else if (!sc.question
|
|
244
|
-
fail(`self_check ${label}: question should
|
|
243
|
+
} else if (!isYesNoSelfCheck(sc.question)) {
|
|
244
|
+
fail(`self_check ${label}: question should be answerable with yes/no`);
|
|
245
245
|
} else {
|
|
246
246
|
ok(`self_check ${label}: question OK`);
|
|
247
247
|
}
|
|
@@ -398,7 +398,6 @@ function cmdStudioCompile(projectPath, args = []) {
|
|
|
398
398
|
// Compile axioms → KDNA_Core.json
|
|
399
399
|
const axioms = loadCards(project, path.dirname(abs), 'axioms');
|
|
400
400
|
const ontology = loadCards(project, path.dirname(abs), 'ontology');
|
|
401
|
-
const _boundaries = loadCards(project, path.dirname(abs), 'boundaries');
|
|
402
401
|
|
|
403
402
|
const core = {
|
|
404
403
|
meta: {
|
|
@@ -495,7 +494,7 @@ function cmdStudioCompile(projectPath, args = []) {
|
|
|
495
494
|
|
|
496
495
|
console.log('');
|
|
497
496
|
console.log('Next:');
|
|
498
|
-
console.log(` kdna validate ${outDir}`);
|
|
497
|
+
console.log(` kdna dev validate ${outDir}`);
|
|
499
498
|
}
|
|
500
499
|
|
|
501
500
|
function loadCards(project, projectDir, cardType) {
|
package/src/cmds/test.js
CHANGED
|
@@ -12,9 +12,9 @@ const fs = require('fs');
|
|
|
12
12
|
const path = require('path');
|
|
13
13
|
const { error, readJson, writeJson, EXIT } = require('./_common');
|
|
14
14
|
const { parseName } = require('../registry');
|
|
15
|
+
const { getInstalled } = require('../package-store');
|
|
15
16
|
|
|
16
17
|
const USER_KDNA_DIR = path.join(process.env.HOME || process.env.USERPROFILE || '.', '.kdna');
|
|
17
|
-
const INSTALL_DIR = path.join(USER_KDNA_DIR, 'domains');
|
|
18
18
|
const RUNS_DIR = path.join(USER_KDNA_DIR, 'runs');
|
|
19
19
|
|
|
20
20
|
function cmdTestRun(args = []) {
|
|
@@ -38,8 +38,8 @@ function cmdTestRun(args = []) {
|
|
|
38
38
|
|
|
39
39
|
const parsed = parseName(domain);
|
|
40
40
|
if (!parsed) error(`Invalid name "${domain}".`, EXIT.INPUT_ERROR);
|
|
41
|
-
const
|
|
42
|
-
if (!
|
|
41
|
+
const installed = getInstalled(parsed.full);
|
|
42
|
+
if (!installed) {
|
|
43
43
|
error(`${parsed.full} not installed. Run: kdna install ${domain}`, EXIT.INPUT_ERROR);
|
|
44
44
|
}
|
|
45
45
|
|
|
@@ -64,7 +64,7 @@ function cmdTestRun(args = []) {
|
|
|
64
64
|
const result = {
|
|
65
65
|
test_id: testCase.id || `test_${Date.now()}`,
|
|
66
66
|
domain: parsed.full,
|
|
67
|
-
|
|
67
|
+
domain_asset: installed.asset_path,
|
|
68
68
|
input: typeof testCase.input === 'string' ? testCase.input : JSON.stringify(testCase.input),
|
|
69
69
|
run_at: new Date().toISOString(),
|
|
70
70
|
expected: {
|
package/src/cmds/trace.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
|
-
const
|
|
4
|
-
const
|
|
3
|
+
const { EXIT } = require('./_common');
|
|
4
|
+
const PATHS = require('../paths');
|
|
5
5
|
|
|
6
|
-
const
|
|
7
|
-
const TRACES_DIR = path.join(USER_KDNA_DIR, 'traces');
|
|
6
|
+
const TRACES_DIR = PATHS.traces;
|
|
8
7
|
|
|
9
8
|
function ensureTracesDir() {
|
|
10
9
|
fs.mkdirSync(TRACES_DIR, { recursive: true });
|
|
@@ -60,9 +59,14 @@ function readAllTraces(opts = {}) {
|
|
|
60
59
|
}
|
|
61
60
|
|
|
62
61
|
function recordTrace(entry) {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
62
|
+
try {
|
|
63
|
+
ensureTracesDir();
|
|
64
|
+
const line = JSON.stringify(entry) + '\n';
|
|
65
|
+
fs.appendFileSync(todayFile(), line);
|
|
66
|
+
} catch {
|
|
67
|
+
// Traces are observability data. Loading and comparing KDNA assets must not
|
|
68
|
+
// fail just because the local trace directory is unavailable or read-only.
|
|
69
|
+
}
|
|
66
70
|
}
|
|
67
71
|
|
|
68
72
|
function parseSinceFlag(args) {
|
package/src/compare.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* kdna compare <name> --input "<text>" — Reasoning trajectory diff.
|
|
2
|
+
* kdna compare <name|file.kdna> --input "<text>" — Reasoning trajectory diff.
|
|
3
3
|
*
|
|
4
4
|
* Runs the same prompt twice on a real LLM:
|
|
5
5
|
* 1. Without KDNA loaded (baseline)
|
|
@@ -24,7 +24,7 @@ const path = require('path');
|
|
|
24
24
|
const https = require('https');
|
|
25
25
|
|
|
26
26
|
const USER_KDNA_DIR = path.join(process.env.HOME || process.env.USERPROFILE || '.', '.kdna');
|
|
27
|
-
const
|
|
27
|
+
const { readContainer, resolveAsset } = require('./package-store');
|
|
28
28
|
const CONFIG_FILE = path.join(USER_KDNA_DIR, 'config.json');
|
|
29
29
|
|
|
30
30
|
const { parseName } = require('./registry');
|
|
@@ -179,10 +179,10 @@ async function callLlm(cfg, systemPrompt, userMessage) {
|
|
|
179
179
|
|
|
180
180
|
// ─── KDNA → system prompt ─────────────────────────────────────────────
|
|
181
181
|
|
|
182
|
-
function buildKdnaPrompt(
|
|
183
|
-
const core =
|
|
184
|
-
const pat =
|
|
185
|
-
const manifest =
|
|
182
|
+
function buildKdnaPrompt(container) {
|
|
183
|
+
const core = container.core;
|
|
184
|
+
const pat = container.patterns;
|
|
185
|
+
const manifest = container.manifest;
|
|
186
186
|
|
|
187
187
|
if (!core || !pat) return '';
|
|
188
188
|
|
|
@@ -302,7 +302,6 @@ function emitMarkdownReport(parsed, manifest, core, pat, responseA, responseB, d
|
|
|
302
302
|
const bannedTerms = (pat.terminology?.banned_terms || []).map((t) =>
|
|
303
303
|
typeof t === 'string' ? t : t.term,
|
|
304
304
|
);
|
|
305
|
-
const misunderstandings = pat.misunderstandings || [];
|
|
306
305
|
|
|
307
306
|
const lines = [];
|
|
308
307
|
lines.push('# KDNA Judgment Comparison Report');
|
|
@@ -487,27 +486,26 @@ async function cmdCompare(input, args = []) {
|
|
|
487
486
|
const idxInput = args.indexOf('--input');
|
|
488
487
|
if (idxInput < 0 || !args[idxInput + 1]) {
|
|
489
488
|
error(
|
|
490
|
-
'Usage: kdna compare <name> --input "<text>" [--report-md|--report-json] [--output <file>]',
|
|
489
|
+
'Usage: kdna compare <name|file.kdna> --input "<text>" [--report-md|--report-json] [--output <file>]',
|
|
491
490
|
EXIT.INPUT_ERROR,
|
|
492
491
|
);
|
|
493
492
|
}
|
|
494
493
|
const userInput = args[idxInput + 1];
|
|
495
494
|
|
|
496
|
-
const
|
|
497
|
-
if (!
|
|
498
|
-
const
|
|
499
|
-
|
|
500
|
-
error(`${parsed.full} not installed. Run: kdna install ${input}`, EXIT.INPUT_ERROR);
|
|
501
|
-
}
|
|
495
|
+
const asset = resolveAsset(input);
|
|
496
|
+
if (!asset) error(`KDNA asset not found: ${input}. Use an installed name or a .kdna file.`, EXIT.INPUT_ERROR);
|
|
497
|
+
const parsed = asset.parsed || parseName(asset.name || '');
|
|
498
|
+
const label = parsed?.full || asset.name || input;
|
|
502
499
|
|
|
503
500
|
const llm = loadLlmConfig();
|
|
504
|
-
const
|
|
505
|
-
const
|
|
506
|
-
const
|
|
501
|
+
const container = readContainer(asset.asset_path);
|
|
502
|
+
const manifest = container.manifest || {};
|
|
503
|
+
const core = container.core || {};
|
|
504
|
+
const pat = container.patterns || {};
|
|
507
505
|
|
|
508
506
|
if (!jsonMode && !reportMd && !reportJson) {
|
|
509
507
|
console.log('═'.repeat(64));
|
|
510
|
-
console.log(` kdna compare ${
|
|
508
|
+
console.log(` kdna compare ${label}`);
|
|
511
509
|
console.log(` provider: ${llm.provider} / ${llm.model}`);
|
|
512
510
|
console.log(` input length: ${userInput.length} chars`);
|
|
513
511
|
console.log('═'.repeat(64));
|
|
@@ -516,7 +514,7 @@ async function cmdCompare(input, args = []) {
|
|
|
516
514
|
|
|
517
515
|
const BASELINE_SYSTEM =
|
|
518
516
|
'You are a helpful assistant. Respond to the user request concisely and specifically.';
|
|
519
|
-
const kdnaPrompt = buildKdnaPrompt(
|
|
517
|
+
const kdnaPrompt = buildKdnaPrompt(container);
|
|
520
518
|
if (!kdnaPrompt) error('Could not build KDNA prompt — missing KDNA_Core or KDNA_Patterns.');
|
|
521
519
|
const TREATMENT_SYSTEM =
|
|
522
520
|
'You are a helpful assistant. The following domain judgment is loaded and you MUST apply it when relevant.\n\n' +
|
|
@@ -540,13 +538,21 @@ async function cmdCompare(input, args = []) {
|
|
|
540
538
|
recordTrace({
|
|
541
539
|
timestamp: new Date().toISOString(),
|
|
542
540
|
agent: 'cli',
|
|
543
|
-
domain:
|
|
541
|
+
domain: label,
|
|
544
542
|
type: 'compare',
|
|
543
|
+
asset: {
|
|
544
|
+
asset_path: asset.asset_path,
|
|
545
|
+
asset_digest: asset.asset_digest || null,
|
|
546
|
+
content_digest: asset.content_digest || null,
|
|
547
|
+
version: manifest.version || asset.version || null,
|
|
548
|
+
judgment_version: manifest.judgment_version || asset.judgment_version || null,
|
|
549
|
+
access: manifest.access || asset.access || null,
|
|
550
|
+
},
|
|
545
551
|
compare: { model: llm.model, input_length: userInput.length },
|
|
546
552
|
});
|
|
547
553
|
|
|
548
554
|
if (reportMd) {
|
|
549
|
-
const report = emitMarkdownReport(parsed, manifest, core, pat, responseA, responseB, diff, llm);
|
|
555
|
+
const report = emitMarkdownReport(parsed || { full: label }, manifest, core, pat, responseA, responseB, diff, llm);
|
|
550
556
|
if (outputFile) {
|
|
551
557
|
fs.writeFileSync(outputFile, report);
|
|
552
558
|
console.log(`Report saved to ${outputFile}`);
|
|
@@ -558,7 +564,7 @@ async function cmdCompare(input, args = []) {
|
|
|
558
564
|
|
|
559
565
|
if (reportJson) {
|
|
560
566
|
const report = emitJsonReport(
|
|
561
|
-
parsed,
|
|
567
|
+
parsed || { full: label },
|
|
562
568
|
manifest,
|
|
563
569
|
core,
|
|
564
570
|
pat,
|
package/src/diff.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* kdna diff <name>@<ver1> <name>@<ver2> — Judgment-level diff between versions.
|
|
3
3
|
*
|
|
4
|
-
* Downloads two .kdna packages from the registry, extracts to temp dirs,
|
|
4
|
+
* Downloads two .kdna dev packages from the registry, extracts to temp dirs,
|
|
5
5
|
* compares axioms / misunderstandings / banned_terms / stances / boundary,
|
|
6
6
|
* and surfaces what would change for an agent loading the new version.
|
|
7
7
|
*
|
|
@@ -19,11 +19,10 @@
|
|
|
19
19
|
const fs = require('fs');
|
|
20
20
|
const path = require('path');
|
|
21
21
|
const { execSync, execFileSync } = require('child_process');
|
|
22
|
-
const { RegistryResolver
|
|
22
|
+
const { RegistryResolver } = require('./registry');
|
|
23
23
|
const { EXIT } = require('./cmds/_common');
|
|
24
|
+
const { getInstalled, readContainer } = require('./package-store');
|
|
24
25
|
|
|
25
|
-
const USER_KDNA_DIR = path.join(process.env.HOME || process.env.USERPROFILE || '.', '.kdna');
|
|
26
|
-
const INSTALL_DIR = path.join(USER_KDNA_DIR, 'domains');
|
|
27
26
|
const TMP_DIR = '/tmp';
|
|
28
27
|
|
|
29
28
|
function error(msg, code = EXIT.VALIDATION_FAILED) {
|
|
@@ -58,14 +57,15 @@ function parseNameVersion(input) {
|
|
|
58
57
|
// ─── Download specific version ────────────────────────────────────────
|
|
59
58
|
|
|
60
59
|
function downloadVersion(entry, version, destDir) {
|
|
61
|
-
|
|
60
|
+
const assetUrl = entry.asset_url;
|
|
61
|
+
// assetUrl is for the registry-current version. For older versions
|
|
62
62
|
// we infer the URL pattern from the registry-current URL.
|
|
63
63
|
if (entry.version === version) {
|
|
64
|
-
return downloadAndExtract(
|
|
64
|
+
return downloadAndExtract(assetUrl, destDir);
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
// Infer pattern: replace v<current> in the URL with v<requested>
|
|
68
|
-
const inferredUrl =
|
|
68
|
+
const inferredUrl = assetUrl
|
|
69
69
|
.replace(`/v${entry.version}/`, `/v${version}/`)
|
|
70
70
|
.replace(`-${entry.version}.kdna`, `-${version}.kdna`);
|
|
71
71
|
|
|
@@ -232,12 +232,11 @@ async function cmdDiff(a, b, args = []) {
|
|
|
232
232
|
newEntry = entryB;
|
|
233
233
|
} else {
|
|
234
234
|
// single-arg form: installed vs registry-current
|
|
235
|
-
const
|
|
236
|
-
|
|
237
|
-
if (!fs.existsSync(localDir)) {
|
|
235
|
+
const installed = getInstalled(aParsed.full);
|
|
236
|
+
if (!installed) {
|
|
238
237
|
error(`${aParsed.full} not installed. Run: kdna install ${aParsed.full}`, EXIT.INPUT_ERROR);
|
|
239
238
|
}
|
|
240
|
-
const localManifest =
|
|
239
|
+
const localManifest = readContainer(installed.asset_path).manifest || {};
|
|
241
240
|
oldVersion = localManifest?.version || '?';
|
|
242
241
|
newVersion = entryA.version;
|
|
243
242
|
oldEntry = entryA;
|
|
@@ -285,7 +284,7 @@ async function cmdDiff(a, b, args = []) {
|
|
|
285
284
|
}
|
|
286
285
|
|
|
287
286
|
const axiomsDiff = diffMaps('axioms', oldJ.axioms, newJ.axioms, (a) => a.one_sentence || a.id, jsonMode);
|
|
288
|
-
|
|
287
|
+
diffMaps('ontology', oldJ.ontology, newJ.ontology, (o) => o.one_sentence || o.id, jsonMode);
|
|
289
288
|
const misunderstandingsDiff = diffMaps(
|
|
290
289
|
'misunderstandings',
|
|
291
290
|
oldJ.misunderstandings,
|
|
@@ -345,7 +344,6 @@ async function cmdDiff(a, b, args = []) {
|
|
|
345
344
|
}));
|
|
346
345
|
|
|
347
346
|
// Determine recommended version bump
|
|
348
|
-
const axiomDrift = Object.keys(newJ.axioms).length - Object.keys(oldJ.axioms).length;
|
|
349
347
|
const hasRemoved = axiomsDiff.removed.length > 0 || misunderstandingsDiff.removed.length > 0;
|
|
350
348
|
const hasAdded = axiomsDiff.added.length > 0 || misunderstandingsDiff.added.length > 0;
|
|
351
349
|
const hasChanged = axiomsDiff.changed.length > 0 || bannedDiff.changed.length > 0;
|
package/src/init.js
CHANGED
|
@@ -91,7 +91,7 @@ function cmdInit(name) {
|
|
|
91
91
|
` 2. Edit ${targetDir}/KDNA_Patterns.json — replace terminology and misunderstandings`,
|
|
92
92
|
);
|
|
93
93
|
console.log(` 3. Edit ${targetDir}/kdna.json — set author, description, repo`);
|
|
94
|
-
console.log(` 4. Run: kdna validate ${name}
|
|
94
|
+
console.log(` 4. Run: kdna dev validate ${name} (structural check)`);
|
|
95
95
|
console.log(` 5. Run: kdna publish --check ${name} (content quality gate)`);
|
|
96
96
|
console.log(` 6. Run: kdna verify ${name} (full judgment scoring)`);
|
|
97
97
|
}
|
|
@@ -162,7 +162,7 @@ function cmdClusterInit(name) {
|
|
|
162
162
|
console.log(
|
|
163
163
|
` 3. Add more sub-domains: cp -r ${targetDir}/domain_one ${targetDir}/your_new_domain`,
|
|
164
164
|
);
|
|
165
|
-
console.log(` 4. Run: kdna validate ${name}
|
|
165
|
+
console.log(` 4. Run: kdna dev validate ${name} (check all sub-domains)`);
|
|
166
166
|
}
|
|
167
167
|
|
|
168
168
|
module.exports = { cmdInit, cmdClusterInit };
|