@aikdna/kdna-cli 0.18.0 → 0.19.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 +101 -101
- package/SECURITY.md +1 -1
- package/package.json +3 -2
- package/skills/kdna-loader/SKILL.md +18 -16
- package/src/agent.js +152 -57
- package/src/cli.js +17 -11
- package/src/cmds/_common.js +9 -3
- package/src/cmds/badge.js +8 -3
- package/src/cmds/changelog.js +31 -11
- package/src/cmds/cluster.js +67 -40
- package/src/cmds/domain.js +37 -27
- package/src/cmds/explain.js +1 -4
- package/src/cmds/governance.js +111 -42
- package/src/cmds/legacy.js +1 -2
- package/src/cmds/license.js +16 -8
- package/src/cmds/quality.js +9 -2
- package/src/cmds/studio.js +95 -42
- package/src/cmds/test.js +5 -2
- package/src/compare.js +15 -2
- package/src/diff.js +27 -11
- package/src/identity.js +9 -7
- package/src/install.js +17 -7
- package/src/package-store.js +4 -1
- package/src/paths.js +2 -2
- package/src/publish.js +90 -42
- package/src/registry.js +13 -8
- package/src/verify.js +61 -17
- package/src/version.js +15 -7
- package/templates/minimal-domain/kdna.json +7 -7
- package/templates/standard-domain/README.md +10 -10
- package/templates/standard-domain/kdna.json +6 -3
- package/validators/kdna-lint.js +45 -11
package/src/cmds/cluster.js
CHANGED
|
@@ -40,7 +40,10 @@ function cmdCluster(args) {
|
|
|
40
40
|
if (!target) error('Usage: kdna cluster match <cluster.json> --input "<task>"');
|
|
41
41
|
cmdClusterMatch(target, args);
|
|
42
42
|
} else if (sub === 'compose') {
|
|
43
|
-
if (!target)
|
|
43
|
+
if (!target)
|
|
44
|
+
error(
|
|
45
|
+
'Usage: kdna cluster compose <cluster.json> --input "<task>" [--profile=compact] [--json]',
|
|
46
|
+
);
|
|
44
47
|
cmdClusterCompose(target, args);
|
|
45
48
|
} else if (sub === 'conflicts') {
|
|
46
49
|
if (!target) error('Usage: kdna cluster conflicts <cluster.json> --input "<task>" [--json]');
|
|
@@ -252,20 +255,26 @@ function cmdClusterCompose(target, args = []) {
|
|
|
252
255
|
const { context } = composeContextWithAttribution(classification.selected);
|
|
253
256
|
|
|
254
257
|
if (jsonMode) {
|
|
255
|
-
console.log(
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
258
|
+
console.log(
|
|
259
|
+
JSON.stringify(
|
|
260
|
+
{
|
|
261
|
+
cluster: manifest.cluster_id,
|
|
262
|
+
input: input.slice(0, 200),
|
|
263
|
+
selected: classification.selected.map((d) => ({
|
|
264
|
+
id: d.id,
|
|
265
|
+
role: d.role,
|
|
266
|
+
reason: d.reason,
|
|
267
|
+
})),
|
|
268
|
+
excluded: classification.excluded.map((d) => ({
|
|
269
|
+
id: d.id,
|
|
270
|
+
reason: d.reason,
|
|
271
|
+
})),
|
|
272
|
+
context,
|
|
273
|
+
},
|
|
274
|
+
null,
|
|
275
|
+
2,
|
|
276
|
+
),
|
|
277
|
+
);
|
|
269
278
|
return;
|
|
270
279
|
}
|
|
271
280
|
|
|
@@ -273,7 +282,9 @@ function cmdClusterCompose(target, args = []) {
|
|
|
273
282
|
console.log(`Profile: ${profile}`);
|
|
274
283
|
console.log(`Input: ${input.slice(0, 100)}${input.length > 100 ? '...' : ''}`);
|
|
275
284
|
console.log('');
|
|
276
|
-
console.log(
|
|
285
|
+
console.log(
|
|
286
|
+
`Selected: ${classification.selected.length} | Excluded: ${classification.excluded.length}`,
|
|
287
|
+
);
|
|
277
288
|
console.log('');
|
|
278
289
|
console.log('─'.repeat(64));
|
|
279
290
|
console.log(context);
|
|
@@ -300,25 +311,33 @@ function cmdClusterConflicts(target, args = []) {
|
|
|
300
311
|
const conflicts = detectDomainConflicts(classification.selected);
|
|
301
312
|
|
|
302
313
|
if (jsonMode) {
|
|
303
|
-
console.log(
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
314
|
+
console.log(
|
|
315
|
+
JSON.stringify(
|
|
316
|
+
{
|
|
317
|
+
cluster: manifest.cluster_id,
|
|
318
|
+
input: input.slice(0, 200),
|
|
319
|
+
selected: classification.selected.map((d) => ({ id: d.id, role: d.role })),
|
|
320
|
+
conflicts: conflicts.map((c) => ({
|
|
321
|
+
type: c.type,
|
|
322
|
+
domains: c.domains,
|
|
323
|
+
description: c.description,
|
|
324
|
+
severity: c.severity || 'warn',
|
|
325
|
+
})),
|
|
326
|
+
conflict_count: conflicts.length,
|
|
327
|
+
safe: conflicts.length === 0,
|
|
328
|
+
},
|
|
329
|
+
null,
|
|
330
|
+
2,
|
|
331
|
+
),
|
|
332
|
+
);
|
|
316
333
|
process.exit(conflicts.length ? EXIT.HUMAN_LOCK_REQUIRED : EXIT.OK);
|
|
317
334
|
}
|
|
318
335
|
|
|
319
336
|
console.log(`Cluster: ${manifest.cluster_id}`);
|
|
320
337
|
console.log(`Input: ${input.slice(0, 100)}${input.length > 100 ? '...' : ''}`);
|
|
321
|
-
console.log(
|
|
338
|
+
console.log(
|
|
339
|
+
`Selected: ${classification.selected.length} domains | Conflicts: ${conflicts.length}`,
|
|
340
|
+
);
|
|
322
341
|
console.log('');
|
|
323
342
|
|
|
324
343
|
if (!conflicts.length) {
|
|
@@ -382,15 +401,21 @@ function cmdClusterGraph(target, args = []) {
|
|
|
382
401
|
for (const d of manifest.domains || []) {
|
|
383
402
|
const shape = d.role === 'primary' ? 'box' : d.role === 'critic' ? 'diamond' : 'ellipse';
|
|
384
403
|
const required = d.required !== false ? ',style=filled,fillcolor="#e8f0fe"' : ',style=dashed';
|
|
385
|
-
console.log(
|
|
404
|
+
console.log(
|
|
405
|
+
` "${d.id || d.role}" [label="${d.id || d.role}\\n[${d.role}]",shape=${shape}${required}];`,
|
|
406
|
+
);
|
|
386
407
|
}
|
|
387
408
|
|
|
388
409
|
// Edges
|
|
389
410
|
if (manifest.relationships) {
|
|
390
411
|
console.log('');
|
|
391
412
|
for (const r of manifest.relationships) {
|
|
392
|
-
const style =
|
|
393
|
-
|
|
413
|
+
const style =
|
|
414
|
+
r.type === 'conflicts'
|
|
415
|
+
? ',style=dashed,color=red'
|
|
416
|
+
: r.type === 'extends'
|
|
417
|
+
? ',style=bold'
|
|
418
|
+
: '';
|
|
394
419
|
console.log(` "${r.from}" -> "${r.to}" [label="${r.type}"${style}];`);
|
|
395
420
|
}
|
|
396
421
|
}
|
|
@@ -402,13 +427,15 @@ function cmdClusterGraph(target, args = []) {
|
|
|
402
427
|
* Shared domain loader for cluster commands.
|
|
403
428
|
*/
|
|
404
429
|
function loadClusterDomains(manifest) {
|
|
405
|
-
return (manifest.domains || [])
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
430
|
+
return (manifest.domains || [])
|
|
431
|
+
.map((d) => {
|
|
432
|
+
const domainId = d.id;
|
|
433
|
+
if (!domainId) return null;
|
|
434
|
+
const loaded = loadInstalledDomain(domainId);
|
|
435
|
+
if (!loaded) return null;
|
|
436
|
+
return { id: domainId, role: d.role, required: d.required !== false, ...loaded };
|
|
437
|
+
})
|
|
438
|
+
.filter(Boolean);
|
|
412
439
|
}
|
|
413
440
|
|
|
414
441
|
module.exports = { cmdCluster };
|
package/src/cmds/domain.js
CHANGED
|
@@ -235,12 +235,17 @@ function cmdPack(dir, outputDir) {
|
|
|
235
235
|
.readdirSync(abs)
|
|
236
236
|
.filter((f) => f.endsWith('.json') && f !== 'kdna.json').length;
|
|
237
237
|
manifest = {
|
|
238
|
-
|
|
238
|
+
format: 'kdna',
|
|
239
|
+
format_version: '1.0',
|
|
240
|
+
spec_version: '1.0-rc',
|
|
239
241
|
name: domainName,
|
|
240
242
|
version: core.meta?.version || '0.1.0',
|
|
243
|
+
judgment_version: core.meta?.version || '0.1.0',
|
|
241
244
|
status: 'experimental',
|
|
245
|
+
quality_badge: 'untested',
|
|
242
246
|
access: 'open',
|
|
243
|
-
|
|
247
|
+
languages: ['en'],
|
|
248
|
+
default_language: 'en',
|
|
244
249
|
author: { name: '', id: '' },
|
|
245
250
|
license: { type: 'CC-BY-4.0' },
|
|
246
251
|
description: core.meta?.purpose || `${domainName} domain cognition`,
|
|
@@ -268,6 +273,7 @@ function cmdPack(dir, outputDir) {
|
|
|
268
273
|
src = ${JSON.stringify(abs)}
|
|
269
274
|
out = ${JSON.stringify(outPath)}
|
|
270
275
|
with zipfile.ZipFile(out, 'w', zipfile.ZIP_DEFLATED) as zf:
|
|
276
|
+
zf.writestr(zipfile.ZipInfo('mimetype'), 'application/vnd.aikdna.kdna+zip', compress_type=zipfile.ZIP_STORED)
|
|
271
277
|
for f in sorted(os.listdir(src)):
|
|
272
278
|
fp = os.path.join(src, f)
|
|
273
279
|
if os.path.isfile(fp) and (f.endswith('.json') or f in ('README.md', 'LICENSE', 'kdna.json')):
|
|
@@ -286,7 +292,17 @@ with zipfile.ZipFile(out, 'w', zipfile.ZIP_DEFLATED) as zf:
|
|
|
286
292
|
}
|
|
287
293
|
}
|
|
288
294
|
|
|
289
|
-
// Strategy 2:
|
|
295
|
+
// Strategy 2: Node.js native ZIP, which preserves the required mimetype entry
|
|
296
|
+
if (!packed) {
|
|
297
|
+
try {
|
|
298
|
+
createNodeZip(abs, outPath);
|
|
299
|
+
packed = true;
|
|
300
|
+
} catch {
|
|
301
|
+
/* try external zip last */
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// Strategy 3: system zip command
|
|
290
306
|
if (!packed) {
|
|
291
307
|
const cwd = process.cwd();
|
|
292
308
|
try {
|
|
@@ -302,16 +318,6 @@ with zipfile.ZipFile(out, 'w', zipfile.ZIP_DEFLATED) as zf:
|
|
|
302
318
|
}
|
|
303
319
|
}
|
|
304
320
|
|
|
305
|
-
// #22: Strategy 3 — Node.js native ZIP (no external dependencies)
|
|
306
|
-
if (!packed) {
|
|
307
|
-
try {
|
|
308
|
-
createNodeZip(abs, outPath);
|
|
309
|
-
packed = true;
|
|
310
|
-
} catch {
|
|
311
|
-
/* last attempt failed */
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
|
|
315
321
|
if (!packed) {
|
|
316
322
|
const platform = process.platform;
|
|
317
323
|
const hints = {
|
|
@@ -341,11 +347,14 @@ function createNodeZip(srcDir, outPath) {
|
|
|
341
347
|
const fileData = [];
|
|
342
348
|
let offset = 0;
|
|
343
349
|
|
|
344
|
-
for (const f of files) {
|
|
345
|
-
const raw =
|
|
350
|
+
for (const f of ['mimetype', ...files]) {
|
|
351
|
+
const raw =
|
|
352
|
+
f === 'mimetype'
|
|
353
|
+
? Buffer.from('application/vnd.aikdna.kdna+zip')
|
|
354
|
+
: fs.readFileSync(path.join(srcDir, f));
|
|
346
355
|
const crc = crc32(raw);
|
|
347
356
|
const compressed = zlib.deflateRawSync(raw);
|
|
348
|
-
const useStore = compressed.length >= raw.length;
|
|
357
|
+
const useStore = f === 'mimetype' || compressed.length >= raw.length;
|
|
349
358
|
|
|
350
359
|
const nameBytes = Buffer.from(f, 'utf8');
|
|
351
360
|
const localHeader = Buffer.alloc(30);
|
|
@@ -513,7 +522,7 @@ function inspectKdnaFile(filePath, jsonMode = false) {
|
|
|
513
522
|
const result = {
|
|
514
523
|
name: m.name || c.meta?.domain || path.basename(abs, '.kdna'),
|
|
515
524
|
format: 'kdna-zip',
|
|
516
|
-
spec: m.spec_version ||
|
|
525
|
+
spec: m.spec_version || null,
|
|
517
526
|
version: m.version || null,
|
|
518
527
|
status: m.status || 'experimental',
|
|
519
528
|
access: m.access || 'open',
|
|
@@ -544,7 +553,7 @@ function inspectKdnaFile(filePath, jsonMode = false) {
|
|
|
544
553
|
console.log('═'.repeat(50));
|
|
545
554
|
console.log('');
|
|
546
555
|
console.log(` Format: .kdna (ZIP container)`);
|
|
547
|
-
console.log(` Spec: ${m.spec_version ||
|
|
556
|
+
console.log(` Spec: ${m.spec_version || '?'}`);
|
|
548
557
|
console.log(` Version: ${m.version || '?'}`);
|
|
549
558
|
console.log(` Status: ${m.status || 'experimental'}`);
|
|
550
559
|
console.log(` Access: ${m.access || 'open'}`);
|
|
@@ -620,6 +629,16 @@ function cmdInspect(dir, jsonMode = false, locale = null, options = {}) {
|
|
|
620
629
|
];
|
|
621
630
|
const filesPresent = expected.filter((f) => fs.existsSync(path.join(abs, f)));
|
|
622
631
|
|
|
632
|
+
// Governance metadata (with locale support)
|
|
633
|
+
let kdnaCard = readJson(path.join(abs, 'KDNA_CARD.json'));
|
|
634
|
+
if (locale && !kdnaCard) {
|
|
635
|
+
kdnaCard = readJson(path.join(abs, 'locales', locale, 'KDNA_CARD.json'));
|
|
636
|
+
}
|
|
637
|
+
if (locale && kdnaCard) {
|
|
638
|
+
const localeCard = readJson(path.join(abs, 'locales', locale, 'KDNA_CARD.json'));
|
|
639
|
+
if (localeCard) kdnaCard = localeCard;
|
|
640
|
+
}
|
|
641
|
+
|
|
623
642
|
if (jsonMode) {
|
|
624
643
|
const result = {
|
|
625
644
|
name: m.name || c.meta?.domain || path.basename(abs),
|
|
@@ -725,15 +744,6 @@ function cmdInspect(dir, jsonMode = false, locale = null, options = {}) {
|
|
|
725
744
|
|
|
726
745
|
if (evo) console.log(` Evolution stages: ${(evo.stages || []).length}`);
|
|
727
746
|
|
|
728
|
-
// Governance metadata (with locale support)
|
|
729
|
-
let kdnaCard = readJson(path.join(abs, 'KDNA_CARD.json'));
|
|
730
|
-
if (locale && !kdnaCard) {
|
|
731
|
-
kdnaCard = readJson(path.join(abs, 'locales', locale, 'KDNA_CARD.json'));
|
|
732
|
-
}
|
|
733
|
-
if (locale && kdnaCard) {
|
|
734
|
-
const localeCard = readJson(path.join(abs, 'locales', locale, 'KDNA_CARD.json'));
|
|
735
|
-
if (localeCard) kdnaCard = localeCard;
|
|
736
|
-
}
|
|
737
747
|
if (kdnaCard) {
|
|
738
748
|
const displayName = kdnaCard.display_name || '';
|
|
739
749
|
const summary = kdnaCard.summary || '';
|
package/src/cmds/explain.js
CHANGED
|
@@ -20,10 +20,7 @@ function cmdExplain(args) {
|
|
|
20
20
|
|
|
21
21
|
const installed = getInstalled(parsed.full);
|
|
22
22
|
if (!installed) {
|
|
23
|
-
error(
|
|
24
|
-
`${parsed.full} is not installed.\nRun: kdna install ${target}`,
|
|
25
|
-
EXIT.INPUT_ERROR,
|
|
26
|
-
);
|
|
23
|
+
error(`${parsed.full} is not installed.\nRun: kdna install ${target}`, EXIT.INPUT_ERROR);
|
|
27
24
|
}
|
|
28
25
|
|
|
29
26
|
const { core, patterns, scenarios } = readContainer(installed.asset_path);
|
package/src/cmds/governance.js
CHANGED
|
@@ -36,7 +36,8 @@ function cmdProposalCreate(args = []) {
|
|
|
36
36
|
if (!fs.existsSync(absTest)) error(`Test run file not found: ${absTest}`, EXIT.INPUT_ERROR);
|
|
37
37
|
|
|
38
38
|
const runData = readJson(absTest);
|
|
39
|
-
if (!runData || !runData.test_id)
|
|
39
|
+
if (!runData || !runData.test_id)
|
|
40
|
+
error(`Not a valid test run file: ${absTest}`, EXIT.INPUT_ERROR);
|
|
40
41
|
|
|
41
42
|
const absDomain = path.resolve(domainPath);
|
|
42
43
|
|
|
@@ -63,7 +64,10 @@ function cmdProposalCreate(args = []) {
|
|
|
63
64
|
};
|
|
64
65
|
|
|
65
66
|
// Auto-detect suggested changes from test result gaps
|
|
66
|
-
if (
|
|
67
|
+
if (
|
|
68
|
+
runData.expected?.classification &&
|
|
69
|
+
runData.expected.classification !== runData.results?.classification
|
|
70
|
+
) {
|
|
67
71
|
proposal.suggested_changes.push({
|
|
68
72
|
what: 'axiom',
|
|
69
73
|
field: 'applies_when',
|
|
@@ -80,7 +84,17 @@ function cmdProposalCreate(args = []) {
|
|
|
80
84
|
writeJson(outFile, proposal);
|
|
81
85
|
|
|
82
86
|
if (jsonMode) {
|
|
83
|
-
console.log(
|
|
87
|
+
console.log(
|
|
88
|
+
JSON.stringify(
|
|
89
|
+
{
|
|
90
|
+
proposal_id: proposal.proposal_id,
|
|
91
|
+
saved: outFile,
|
|
92
|
+
suggested_changes: proposal.suggested_changes.length,
|
|
93
|
+
},
|
|
94
|
+
null,
|
|
95
|
+
2,
|
|
96
|
+
),
|
|
97
|
+
);
|
|
84
98
|
return;
|
|
85
99
|
}
|
|
86
100
|
|
|
@@ -98,7 +112,8 @@ function cmdProposalCreate(args = []) {
|
|
|
98
112
|
|
|
99
113
|
function cmdProposalValidate(args = []) {
|
|
100
114
|
const jsonMode = args.includes('--json');
|
|
101
|
-
const target =
|
|
115
|
+
const target =
|
|
116
|
+
args.filter((a) => !a.startsWith('--'))[2] || args.filter((a) => !a.startsWith('--'))[1];
|
|
102
117
|
if (!target) error('Usage: kdna proposal validate <proposal.json>', EXIT.INPUT_ERROR);
|
|
103
118
|
|
|
104
119
|
const abs = path.resolve(target);
|
|
@@ -113,7 +128,8 @@ function cmdProposalValidate(args = []) {
|
|
|
113
128
|
if (!proposal.source) issues.push('missing source');
|
|
114
129
|
if (!proposal.domain) issues.push('missing domain');
|
|
115
130
|
if (!proposal.trigger?.test_id) issues.push('missing trigger.test_id');
|
|
116
|
-
if (!proposal.reasoning || proposal.reasoning.length < 10)
|
|
131
|
+
if (!proposal.reasoning || proposal.reasoning.length < 10)
|
|
132
|
+
issues.push('reasoning too short (min 10 chars)');
|
|
117
133
|
if (!proposal.suggested_changes || proposal.suggested_changes.length === 0) {
|
|
118
134
|
issues.push('no suggested changes');
|
|
119
135
|
} else {
|
|
@@ -124,11 +140,17 @@ function cmdProposalValidate(args = []) {
|
|
|
124
140
|
}
|
|
125
141
|
|
|
126
142
|
if (jsonMode) {
|
|
127
|
-
console.log(
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
143
|
+
console.log(
|
|
144
|
+
JSON.stringify(
|
|
145
|
+
{
|
|
146
|
+
proposal_id: proposal.proposal_id,
|
|
147
|
+
valid: issues.length === 0,
|
|
148
|
+
issues,
|
|
149
|
+
},
|
|
150
|
+
null,
|
|
151
|
+
2,
|
|
152
|
+
),
|
|
153
|
+
);
|
|
132
154
|
process.exit(issues.length ? EXIT.VALIDATION_FAILED : EXIT.OK);
|
|
133
155
|
}
|
|
134
156
|
|
|
@@ -184,12 +206,18 @@ function cmdReview(args = []) {
|
|
|
184
206
|
writeJson(abs, proposal);
|
|
185
207
|
|
|
186
208
|
if (jsonMode) {
|
|
187
|
-
console.log(
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
209
|
+
console.log(
|
|
210
|
+
JSON.stringify(
|
|
211
|
+
{
|
|
212
|
+
proposal_id: proposal.proposal_id,
|
|
213
|
+
decision: sub,
|
|
214
|
+
by,
|
|
215
|
+
reason,
|
|
216
|
+
},
|
|
217
|
+
null,
|
|
218
|
+
2,
|
|
219
|
+
),
|
|
220
|
+
);
|
|
193
221
|
process.exit(sub === 'reject' ? EXIT.POLICY_VIOLATION : EXIT.OK);
|
|
194
222
|
}
|
|
195
223
|
|
|
@@ -217,7 +245,10 @@ function cmdLockCard(args = []) {
|
|
|
217
245
|
// Lock card in the current studio project (finds studio.project.json)
|
|
218
246
|
const projectPath = path.resolve('studio.project.json');
|
|
219
247
|
if (!fs.existsSync(projectPath)) {
|
|
220
|
-
error(
|
|
248
|
+
error(
|
|
249
|
+
'No studio.project.json found in current directory. Run: kdna studio scaffold',
|
|
250
|
+
EXIT.INPUT_ERROR,
|
|
251
|
+
);
|
|
221
252
|
}
|
|
222
253
|
|
|
223
254
|
const project = readJson(projectPath);
|
|
@@ -240,11 +271,17 @@ function cmdLockCard(args = []) {
|
|
|
240
271
|
found = true;
|
|
241
272
|
|
|
242
273
|
if (jsonMode) {
|
|
243
|
-
console.log(
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
274
|
+
console.log(
|
|
275
|
+
JSON.stringify(
|
|
276
|
+
{
|
|
277
|
+
card: `${type}.${id}`,
|
|
278
|
+
locked: true,
|
|
279
|
+
lock: card.human_lock,
|
|
280
|
+
},
|
|
281
|
+
null,
|
|
282
|
+
2,
|
|
283
|
+
),
|
|
284
|
+
);
|
|
248
285
|
} else {
|
|
249
286
|
console.log(`✓ Locked: ${type}.${id}`);
|
|
250
287
|
console.log(` By: ${by}`);
|
|
@@ -254,7 +291,10 @@ function cmdLockCard(args = []) {
|
|
|
254
291
|
}
|
|
255
292
|
|
|
256
293
|
if (!found) {
|
|
257
|
-
error(
|
|
294
|
+
error(
|
|
295
|
+
`Card not found: ${cardId}. Check the card ID and that a studio project exists.`,
|
|
296
|
+
EXIT.INPUT_ERROR,
|
|
297
|
+
);
|
|
258
298
|
}
|
|
259
299
|
}
|
|
260
300
|
|
|
@@ -320,17 +360,23 @@ function cmdEvolutionReport(domainPath, jsonMode) {
|
|
|
320
360
|
const pending = evolution.pending || [];
|
|
321
361
|
|
|
322
362
|
if (jsonMode) {
|
|
323
|
-
console.log(
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
363
|
+
console.log(
|
|
364
|
+
JSON.stringify(
|
|
365
|
+
{
|
|
366
|
+
domain: path.basename(abs),
|
|
367
|
+
total_stages: stages.length,
|
|
368
|
+
pending_changes: pending.length,
|
|
369
|
+
stages: stages.map((s) => ({
|
|
370
|
+
stage: s.stage,
|
|
371
|
+
version: s.version,
|
|
372
|
+
date: s.date,
|
|
373
|
+
changes: s.changes?.length || 0,
|
|
374
|
+
})),
|
|
375
|
+
},
|
|
376
|
+
null,
|
|
377
|
+
2,
|
|
378
|
+
),
|
|
379
|
+
);
|
|
334
380
|
return;
|
|
335
381
|
}
|
|
336
382
|
|
|
@@ -362,7 +408,10 @@ function cmdRegression(args = []) {
|
|
|
362
408
|
const evalsDir = evalsIdx >= 0 ? args[evalsIdx + 1] : null;
|
|
363
409
|
|
|
364
410
|
if (!oldPath || !newPath) {
|
|
365
|
-
error(
|
|
411
|
+
error(
|
|
412
|
+
'Usage: kdna regression <old-domain> <new-domain> --evals <dir> [--json]',
|
|
413
|
+
EXIT.INPUT_ERROR,
|
|
414
|
+
);
|
|
366
415
|
}
|
|
367
416
|
|
|
368
417
|
const absOld = path.resolve(oldPath);
|
|
@@ -421,8 +470,18 @@ function cmdRegression(args = []) {
|
|
|
421
470
|
|
|
422
471
|
const result = {
|
|
423
472
|
domain: path.basename(absOld),
|
|
424
|
-
old: {
|
|
425
|
-
|
|
473
|
+
old: {
|
|
474
|
+
axioms: oldAxiomCount,
|
|
475
|
+
misunderstandings: oldMisCount,
|
|
476
|
+
self_checks: oldSelfCheckCount,
|
|
477
|
+
governance_coverage: oldGov,
|
|
478
|
+
},
|
|
479
|
+
new: {
|
|
480
|
+
axioms: newAxiomCount,
|
|
481
|
+
misunderstandings: newMisCount,
|
|
482
|
+
self_checks: newSelfCheckCount,
|
|
483
|
+
governance_coverage: newGov,
|
|
484
|
+
},
|
|
426
485
|
delta: {
|
|
427
486
|
axioms: newAxiomCount - oldAxiomCount,
|
|
428
487
|
misunderstandings: newMisCount - oldMisCount,
|
|
@@ -442,12 +501,22 @@ function cmdRegression(args = []) {
|
|
|
442
501
|
|
|
443
502
|
console.log(`Regression check: ${path.basename(absOld)} → ${path.basename(absNew)}`);
|
|
444
503
|
console.log('');
|
|
445
|
-
console.log(
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
console.log(
|
|
504
|
+
console.log(
|
|
505
|
+
` Axioms: ${oldAxiomCount} → ${newAxiomCount} (${result.delta.axioms >= 0 ? '+' : ''}${result.delta.axioms})`,
|
|
506
|
+
);
|
|
507
|
+
console.log(
|
|
508
|
+
` Misunderstandings: ${oldMisCount} → ${newMisCount} (${result.delta.misunderstandings >= 0 ? '+' : ''}${result.delta.misunderstandings})`,
|
|
509
|
+
);
|
|
510
|
+
console.log(
|
|
511
|
+
` Self-checks: ${oldSelfCheckCount} → ${newSelfCheckCount} (${result.delta.self_checks >= 0 ? '+' : ''}${result.delta.self_checks})`,
|
|
512
|
+
);
|
|
513
|
+
console.log(
|
|
514
|
+
` Governance coverage: ${oldGov}% → ${newGov}% (${result.delta.governance_coverage >= 0 ? '+' : ''}${result.delta.governance_coverage}%)`,
|
|
515
|
+
);
|
|
449
516
|
if (totalEvals) {
|
|
450
|
-
console.log(
|
|
517
|
+
console.log(
|
|
518
|
+
` Evals: ${passedEvals} passed, ${failedEvals} failed out of ${totalEvals}`,
|
|
519
|
+
);
|
|
451
520
|
}
|
|
452
521
|
console.log('');
|
|
453
522
|
const mark = result.safe ? '✓' : '✗';
|
package/src/cmds/legacy.js
CHANGED
|
@@ -4,8 +4,7 @@ function cmdPreview() {
|
|
|
4
4
|
// Removed in v0.9 — no real user scenario for browser preview.
|
|
5
5
|
// To inspect a .kdna file, use: kdna inspect <file.kdna>
|
|
6
6
|
error(
|
|
7
|
-
'kdna preview was removed in v0.9.\n' +
|
|
8
|
-
'Use: kdna inspect <file.kdna> to view a .kdna asset.',
|
|
7
|
+
'kdna preview was removed in v0.9.\n' + 'Use: kdna inspect <file.kdna> to view a .kdna asset.',
|
|
9
8
|
);
|
|
10
9
|
}
|
|
11
10
|
|
package/src/cmds/license.js
CHANGED
|
@@ -95,9 +95,7 @@ function verifyLicense(license, _scopePubkey, fingerprint) {
|
|
|
95
95
|
issues.push('License has been revoked');
|
|
96
96
|
}
|
|
97
97
|
if (license.require_online_check) {
|
|
98
|
-
const offlineUntil = license.offline_valid_until
|
|
99
|
-
? new Date(license.offline_valid_until)
|
|
100
|
-
: null;
|
|
98
|
+
const offlineUntil = license.offline_valid_until ? new Date(license.offline_valid_until) : null;
|
|
101
99
|
if (!offlineUntil || Number.isNaN(offlineUntil.getTime()) || offlineUntil < now) {
|
|
102
100
|
issues.push('License offline grace has expired');
|
|
103
101
|
}
|
|
@@ -144,7 +142,9 @@ function recordLicenseTrace(action, license, extra = {}) {
|
|
|
144
142
|
revoked: license?.revoked === true || license?.status === 'revoked',
|
|
145
143
|
require_online_check: !!license?.require_online_check,
|
|
146
144
|
offline_valid_until: license?.offline_valid_until || null,
|
|
147
|
-
server_type: licenseServerType(
|
|
145
|
+
server_type: licenseServerType(
|
|
146
|
+
extra.server || license?.activation_server || license?.license_server_url,
|
|
147
|
+
),
|
|
148
148
|
synced: extra.synced,
|
|
149
149
|
sync_error: extra.sync_error,
|
|
150
150
|
});
|
|
@@ -271,7 +271,13 @@ function normalizeActivation(domain, key, payload, server = null) {
|
|
|
271
271
|
machine_fingerprint: source.machine_fingerprint || fingerprint,
|
|
272
272
|
require_online_check: source.require_online_check !== false,
|
|
273
273
|
offline_grace_days: source.offline_grace_days || 7,
|
|
274
|
-
allowed_agents: source.allowed_agents || [
|
|
274
|
+
allowed_agents: source.allowed_agents || [
|
|
275
|
+
'claude_code',
|
|
276
|
+
'codex',
|
|
277
|
+
'opencode',
|
|
278
|
+
'cursor',
|
|
279
|
+
'gemini',
|
|
280
|
+
],
|
|
275
281
|
activation_server: server || source.activation_server || source.license_server_url || null,
|
|
276
282
|
});
|
|
277
283
|
}
|
|
@@ -542,7 +548,10 @@ async function cmdLicenseActivate(args = []) {
|
|
|
542
548
|
const server = argValue(args, '--server');
|
|
543
549
|
const jsonMode = args.includes('--json');
|
|
544
550
|
if (!domain || !key) {
|
|
545
|
-
error(
|
|
551
|
+
error(
|
|
552
|
+
'Usage: kdna license activate <domain> --key <license-key> --server <url>',
|
|
553
|
+
EXIT.INPUT_ERROR,
|
|
554
|
+
);
|
|
546
555
|
}
|
|
547
556
|
|
|
548
557
|
let activation;
|
|
@@ -637,8 +646,7 @@ function licenseStatusRecord(license, file) {
|
|
|
637
646
|
valid: result.valid,
|
|
638
647
|
issues: result.issues,
|
|
639
648
|
require_machine_binding: !!license.require_machine_binding,
|
|
640
|
-
machine_bound: !license.require_machine_binding
|
|
641
|
-
|| license.machine_fingerprint === fingerprint,
|
|
649
|
+
machine_bound: !license.require_machine_binding || license.machine_fingerprint === fingerprint,
|
|
642
650
|
expires_at: license.expires_at || null,
|
|
643
651
|
revoked: license.revoked === true || license.status === 'revoked',
|
|
644
652
|
file,
|
package/src/cmds/quality.js
CHANGED
|
@@ -63,7 +63,11 @@ function cmdDiff(args) {
|
|
|
63
63
|
function cmdSearch(args) {
|
|
64
64
|
const { cmdSearch } = require('../search');
|
|
65
65
|
const json = args.includes('--json');
|
|
66
|
-
const query = args
|
|
66
|
+
const query = args
|
|
67
|
+
.slice(1)
|
|
68
|
+
.filter((a) => a !== '--json')
|
|
69
|
+
.join(' ')
|
|
70
|
+
.trim();
|
|
67
71
|
cmdSearch(query, json);
|
|
68
72
|
}
|
|
69
73
|
|
|
@@ -91,7 +95,10 @@ function cmdSelect(args) {
|
|
|
91
95
|
function cmdLoad(args) {
|
|
92
96
|
const { cmdLoad } = require('../agent');
|
|
93
97
|
const target = args.filter((a) => !a.startsWith('--'))[1];
|
|
94
|
-
if (!target)
|
|
98
|
+
if (!target)
|
|
99
|
+
error(
|
|
100
|
+
'Usage: kdna load <name|file.kdna> [--as=prompt|json|raw] [--profile=index|compact|scenario|full]',
|
|
101
|
+
);
|
|
95
102
|
cmdLoad(target, args);
|
|
96
103
|
}
|
|
97
104
|
|