@aikdna/kdna-cli 0.9.0 → 0.11.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 +109 -31
- package/package.json +1 -1
- package/src/agent.js +410 -2
- package/src/cli.js +267 -38
- package/src/cmds/_common.js +65 -3
- package/src/cmds/badge.js +244 -0
- package/src/cmds/changelog.js +226 -0
- package/src/cmds/cluster.js +214 -3
- package/src/cmds/doctor.js +160 -0
- package/src/cmds/domain.js +110 -33
- package/src/cmds/governance.js +471 -0
- package/src/cmds/identity.js +5 -4
- package/src/cmds/quality.js +34 -9
- package/src/cmds/registry.js +62 -22
- package/src/cmds/studio.js +577 -0
- package/src/cmds/test.js +177 -0
- package/src/compare.js +46 -32
- package/src/diff.js +136 -38
- package/src/identity.js +20 -4
- package/src/install.js +181 -91
- package/src/publish.js +4 -3
- package/src/search.js +33 -2
- package/src/verify.js +76 -13
- package/src/version.js +110 -3
package/src/verify.js
CHANGED
|
@@ -7,15 +7,19 @@
|
|
|
7
7
|
*
|
|
8
8
|
* No flag = run all three.
|
|
9
9
|
*
|
|
10
|
-
* Exit codes:
|
|
10
|
+
* Exit codes (semantic, from cmds/_common.js):
|
|
11
11
|
* 0 all checks passed (warnings allowed)
|
|
12
|
-
* 1
|
|
12
|
+
* 1 VALIDATION_FAILED — structure layer failed
|
|
13
|
+
* 2 INPUT_ERROR — invalid name or not installed
|
|
14
|
+
* 3 TRUST_FAILED — trust layer failed
|
|
15
|
+
* 4 JUDGMENT_QUALITY_FAILED — judgment layer failed
|
|
13
16
|
*/
|
|
14
17
|
|
|
15
18
|
const fs = require('fs');
|
|
16
19
|
const path = require('path');
|
|
17
20
|
const crypto = require('crypto');
|
|
18
21
|
const { RegistryResolver, parseName } = require('./registry');
|
|
22
|
+
const { EXIT } = require('./cmds/_common');
|
|
19
23
|
|
|
20
24
|
const USER_KDNA_DIR = path.join(process.env.HOME || process.env.USERPROFILE || '.', '.kdna');
|
|
21
25
|
const INSTALL_DIR = path.join(USER_KDNA_DIR, 'domains');
|
|
@@ -355,6 +359,8 @@ function renderLayer(result) {
|
|
|
355
359
|
// ─── Main ──────────────────────────────────────────────────────────────
|
|
356
360
|
|
|
357
361
|
function cmdVerify(input, args = []) {
|
|
362
|
+
const jsonMode = args.includes('--json');
|
|
363
|
+
|
|
358
364
|
const want = {
|
|
359
365
|
structure: args.includes('--structure'),
|
|
360
366
|
trust: args.includes('--trust'),
|
|
@@ -366,14 +372,22 @@ function cmdVerify(input, args = []) {
|
|
|
366
372
|
// Resolve name → installed path + scope/entry
|
|
367
373
|
const parsed = parseName(input);
|
|
368
374
|
if (!parsed) {
|
|
369
|
-
|
|
370
|
-
|
|
375
|
+
if (jsonMode) {
|
|
376
|
+
console.log(JSON.stringify({ name: input, ok: false, error: `Invalid name "${input}". Use @scope/name or bare name.` }));
|
|
377
|
+
} else {
|
|
378
|
+
console.error(`Invalid name "${input}". Use @scope/name or bare name.`);
|
|
379
|
+
}
|
|
380
|
+
process.exit(EXIT.INPUT_ERROR);
|
|
371
381
|
}
|
|
372
382
|
|
|
373
383
|
const destDir = path.join(INSTALL_DIR, parsed.scope, parsed.ident);
|
|
374
384
|
if (!fs.existsSync(destDir)) {
|
|
375
|
-
|
|
376
|
-
|
|
385
|
+
if (jsonMode) {
|
|
386
|
+
console.log(JSON.stringify({ name: parsed.full, ok: false, error: `${parsed.full} is not installed. Run: kdna install ${input}` }));
|
|
387
|
+
} else {
|
|
388
|
+
console.error(`${parsed.full} is not installed. Run: kdna install ${input}`);
|
|
389
|
+
}
|
|
390
|
+
process.exit(EXIT.INPUT_ERROR);
|
|
377
391
|
}
|
|
378
392
|
|
|
379
393
|
let scope = null,
|
|
@@ -385,20 +399,55 @@ function cmdVerify(input, args = []) {
|
|
|
385
399
|
scope = r.scope;
|
|
386
400
|
entry = r.entry;
|
|
387
401
|
} catch (e) {
|
|
388
|
-
console.warn(` ⚠ registry lookup failed: ${e.message.split('\n')[0]}`);
|
|
402
|
+
if (!jsonMode) console.warn(` ⚠ registry lookup failed: ${e.message.split('\n')[0]}`);
|
|
389
403
|
}
|
|
390
404
|
}
|
|
391
405
|
|
|
392
|
-
console.log('═'.repeat(64));
|
|
393
|
-
console.log(` Verify ${parsed.full}`);
|
|
394
|
-
console.log(` Path: ${destDir}`);
|
|
395
|
-
console.log('═'.repeat(64));
|
|
396
|
-
|
|
397
406
|
const results = [];
|
|
398
407
|
if (want.structure) results.push(checkStructure(destDir));
|
|
399
408
|
if (want.trust) results.push(checkTrust(destDir, scope, entry));
|
|
400
409
|
if (want.judgment) results.push(checkJudgment(destDir));
|
|
401
410
|
|
|
411
|
+
// ── JSON output ──────────────────────────────────────────────────────
|
|
412
|
+
if (jsonMode) {
|
|
413
|
+
const layers = {};
|
|
414
|
+
for (const r of results) {
|
|
415
|
+
layers[r.layer] = {
|
|
416
|
+
passed: r.passed,
|
|
417
|
+
errors: r.issues.filter((i) => i.severity === 'error').map((i) => i.msg),
|
|
418
|
+
warnings: r.issues.filter((i) => i.severity === 'warn').map((i) => i.msg),
|
|
419
|
+
};
|
|
420
|
+
if (r.score) layers[r.layer].score = r.score;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
const structureResult = results.find((r) => r.layer === 'structure');
|
|
424
|
+
const trustResult = results.find((r) => r.layer === 'trust');
|
|
425
|
+
const judgmentResult = results.find((r) => r.layer === 'judgment');
|
|
426
|
+
|
|
427
|
+
let exitCode = EXIT.OK;
|
|
428
|
+
if (structureResult && structureResult.issues.some((i) => i.severity === 'error')) {
|
|
429
|
+
exitCode = EXIT.VALIDATION_FAILED;
|
|
430
|
+
} else if (trustResult && trustResult.issues.some((i) => i.severity === 'error')) {
|
|
431
|
+
exitCode = EXIT.TRUST_FAILED;
|
|
432
|
+
} else if (judgmentResult && judgmentResult.issues.some((i) => i.severity === 'error')) {
|
|
433
|
+
exitCode = EXIT.JUDGMENT_QUALITY_FAILED;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
console.log(JSON.stringify({
|
|
437
|
+
name: parsed.full,
|
|
438
|
+
path: destDir,
|
|
439
|
+
layers,
|
|
440
|
+
ok: exitCode === EXIT.OK,
|
|
441
|
+
}, null, 2));
|
|
442
|
+
process.exit(exitCode);
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
// ── Text output (default) ────────────────────────────────────────────
|
|
446
|
+
console.log('═'.repeat(64));
|
|
447
|
+
console.log(` Verify ${parsed.full}`);
|
|
448
|
+
console.log(` Path: ${destDir}`);
|
|
449
|
+
console.log('═'.repeat(64));
|
|
450
|
+
|
|
402
451
|
for (const r of results) renderLayer(r);
|
|
403
452
|
|
|
404
453
|
const totalErrors = results.reduce(
|
|
@@ -417,7 +466,21 @@ function cmdVerify(input, args = []) {
|
|
|
417
466
|
}
|
|
418
467
|
console.log('═'.repeat(64));
|
|
419
468
|
|
|
420
|
-
|
|
469
|
+
// Semantic exit codes for text mode
|
|
470
|
+
const structureResult = results.find((r) => r.layer === 'structure');
|
|
471
|
+
const trustResult = results.find((r) => r.layer === 'trust');
|
|
472
|
+
const judgmentResult = results.find((r) => r.layer === 'judgment');
|
|
473
|
+
|
|
474
|
+
let exitCode = EXIT.OK;
|
|
475
|
+
if (structureResult && structureResult.issues.some((i) => i.severity === 'error')) {
|
|
476
|
+
exitCode = EXIT.VALIDATION_FAILED;
|
|
477
|
+
} else if (trustResult && trustResult.issues.some((i) => i.severity === 'error')) {
|
|
478
|
+
exitCode = EXIT.TRUST_FAILED;
|
|
479
|
+
} else if (judgmentResult && judgmentResult.issues.some((i) => i.severity === 'error')) {
|
|
480
|
+
exitCode = EXIT.JUDGMENT_QUALITY_FAILED;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
process.exit(exitCode);
|
|
421
484
|
}
|
|
422
485
|
|
|
423
486
|
module.exports = { cmdVerify, checkStructure, checkTrust, checkJudgment };
|
package/src/version.js
CHANGED
|
@@ -6,10 +6,11 @@
|
|
|
6
6
|
|
|
7
7
|
const fs = require('fs');
|
|
8
8
|
const path = require('path');
|
|
9
|
+
const { EXIT } = require('./cmds/_common');
|
|
9
10
|
|
|
10
|
-
function error(msg) {
|
|
11
|
+
function error(msg, code = EXIT.VALIDATION_FAILED) {
|
|
11
12
|
console.error(`Error: ${msg}`);
|
|
12
|
-
process.exit(
|
|
13
|
+
process.exit(code);
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
function readJson(filePath) {
|
|
@@ -109,4 +110,110 @@ function cmdVersionBump(level, domainPath) {
|
|
|
109
110
|
console.log(`Done. Version: ${oldVersion} → ${newVersion}`);
|
|
110
111
|
}
|
|
111
112
|
|
|
112
|
-
|
|
113
|
+
/**
|
|
114
|
+
* kdna version bump --suggest [path]
|
|
115
|
+
* Suggest version bump based on judgment changes detected by kdna diff.
|
|
116
|
+
* Compares installed vs registry-current and suggests patch/minor/major.
|
|
117
|
+
*/
|
|
118
|
+
function cmdVersionSuggest(domainPath = '.', args = []) {
|
|
119
|
+
const jsonMode = args.includes('--json');
|
|
120
|
+
const abs = path.resolve(domainPath);
|
|
121
|
+
|
|
122
|
+
const manifest = readJson(path.join(abs, 'kdna.json'));
|
|
123
|
+
if (!manifest) {
|
|
124
|
+
if (jsonMode) {
|
|
125
|
+
console.log(JSON.stringify({ error: 'No kdna.json found', suggestion: 'none' }));
|
|
126
|
+
process.exit(EXIT.OK);
|
|
127
|
+
}
|
|
128
|
+
console.log('No kdna.json found in current directory. Cannot suggest version bump.');
|
|
129
|
+
process.exit(EXIT.OK);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const currentVersion = manifest.version;
|
|
133
|
+
if (!currentVersion) {
|
|
134
|
+
if (jsonMode) {
|
|
135
|
+
console.log(JSON.stringify({ error: 'No version field', suggestion: 'none' }));
|
|
136
|
+
process.exit(EXIT.OK);
|
|
137
|
+
}
|
|
138
|
+
console.log('No version field in kdna.json.');
|
|
139
|
+
process.exit(EXIT.OK);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Rules for suggesting:
|
|
143
|
+
// - If no previous version to diff against, suggest 'none'
|
|
144
|
+
// - Check for judgment_version changes
|
|
145
|
+
// - Check for axiom/ontology/misunderstanding changes
|
|
146
|
+
|
|
147
|
+
const changes = detectChanges(abs);
|
|
148
|
+
|
|
149
|
+
if (jsonMode) {
|
|
150
|
+
console.log(JSON.stringify({
|
|
151
|
+
current_version: currentVersion,
|
|
152
|
+
suggested_bump: changes.suggestion,
|
|
153
|
+
reasons: changes.reasons,
|
|
154
|
+
change_summary: changes.summary,
|
|
155
|
+
}, null, 2));
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
console.log(`Current version: ${currentVersion}`);
|
|
160
|
+
console.log(`Suggested bump: ${changes.suggestion}`);
|
|
161
|
+
console.log('');
|
|
162
|
+
if (changes.reasons.length) {
|
|
163
|
+
console.log('Reasons:');
|
|
164
|
+
changes.reasons.forEach((r) => console.log(` - ${r}`));
|
|
165
|
+
}
|
|
166
|
+
if (changes.suggestion !== 'none') {
|
|
167
|
+
console.log('');
|
|
168
|
+
console.log(`Run: kdna version bump ${changes.suggestion} ${domainPath}`);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function detectChanges(domainPath) {
|
|
173
|
+
const reasons = [];
|
|
174
|
+
let axiomChanges = 0;
|
|
175
|
+
const ontologyChanges = 0;
|
|
176
|
+
const misunderstandingChanges = 0;
|
|
177
|
+
|
|
178
|
+
// Simple heuristic: count content vs previous git state
|
|
179
|
+
// For now, use a heuristic based on file modification
|
|
180
|
+
const core = readJson(path.join(domainPath, 'KDNA_Core.json'));
|
|
181
|
+
|
|
182
|
+
// Check if evals/ dir has recent changes
|
|
183
|
+
const evalsDir = path.join(domainPath, 'evals');
|
|
184
|
+
if (fs.existsSync(evalsDir)) {
|
|
185
|
+
reasons.push('evals/ directory present');
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Check for judgment_version in manifest
|
|
189
|
+
const manifest = readJson(path.join(domainPath, 'kdna.json'));
|
|
190
|
+
if (manifest?.judgment_version) {
|
|
191
|
+
reasons.push(`judgment_version: ${manifest.judgment_version}`);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Count axioms with applies_when (v2.1 governance) vs without
|
|
195
|
+
if (core?.axioms) {
|
|
196
|
+
const total = core.axioms.length;
|
|
197
|
+
const governed = core.axioms.filter((a) => a.applies_when?.length && a.does_not_apply_when?.length).length;
|
|
198
|
+
if (governed < total) {
|
|
199
|
+
axiomChanges = total - governed;
|
|
200
|
+
reasons.push(`${axiomChanges} axioms missing v2.1 governance fields`);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
let suggestion = 'none';
|
|
205
|
+
if (axiomChanges > 0) suggestion = 'patch';
|
|
206
|
+
if (axiomChanges >= 3) suggestion = 'minor';
|
|
207
|
+
|
|
208
|
+
return {
|
|
209
|
+
suggestion,
|
|
210
|
+
reasons,
|
|
211
|
+
summary: {
|
|
212
|
+
axiom_changes: axiomChanges,
|
|
213
|
+
ontology_changes: ontologyChanges,
|
|
214
|
+
misunderstanding_changes: misunderstandingChanges,
|
|
215
|
+
},
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
module.exports = { cmdVersionBump, cmdVersionSuggest };
|