@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.
@@ -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) error('Usage: kdna cluster compose <cluster.json> --input "<task>" [--profile=compact] [--json]');
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(JSON.stringify({
256
- cluster: manifest.cluster_id,
257
- input: input.slice(0, 200),
258
- selected: classification.selected.map((d) => ({
259
- id: d.id,
260
- role: d.role,
261
- reason: d.reason,
262
- })),
263
- excluded: classification.excluded.map((d) => ({
264
- id: d.id,
265
- reason: d.reason,
266
- })),
267
- context,
268
- }, null, 2));
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(`Selected: ${classification.selected.length} | Excluded: ${classification.excluded.length}`);
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(JSON.stringify({
304
- cluster: manifest.cluster_id,
305
- input: input.slice(0, 200),
306
- selected: classification.selected.map((d) => ({ id: d.id, role: d.role })),
307
- conflicts: conflicts.map((c) => ({
308
- type: c.type,
309
- domains: c.domains,
310
- description: c.description,
311
- severity: c.severity || 'warn',
312
- })),
313
- conflict_count: conflicts.length,
314
- safe: conflicts.length === 0,
315
- }, null, 2));
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(`Selected: ${classification.selected.length} domains | Conflicts: ${conflicts.length}`);
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(` "${d.id || d.role}" [label="${d.id || d.role}\\n[${d.role}]",shape=${shape}${required}];`);
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 = r.type === 'conflicts' ? ',style=dashed,color=red' :
393
- r.type === 'extends' ? ',style=bold' : '';
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 || []).map((d) => {
406
- const domainId = d.id;
407
- if (!domainId) return null;
408
- const loaded = loadInstalledDomain(domainId);
409
- if (!loaded) return null;
410
- return { id: domainId, role: d.role, required: d.required !== false, ...loaded };
411
- }).filter(Boolean);
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 };
@@ -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
- kdna_spec: '1.0-rc',
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
- language: 'en',
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: system zip command
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 = fs.readFileSync(path.join(srcDir, f));
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 || m.kdna_spec || null,
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 || m.kdna_spec || '0.4'}`);
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 || '';
@@ -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);
@@ -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) error(`Not a valid test run file: ${absTest}`, EXIT.INPUT_ERROR);
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 (runData.expected?.classification && runData.expected.classification !== runData.results?.classification) {
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(JSON.stringify({ proposal_id: proposal.proposal_id, saved: outFile, suggested_changes: proposal.suggested_changes.length }, null, 2));
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 = args.filter((a) => !a.startsWith('--'))[2] || args.filter((a) => !a.startsWith('--'))[1];
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) issues.push('reasoning too short (min 10 chars)');
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(JSON.stringify({
128
- proposal_id: proposal.proposal_id,
129
- valid: issues.length === 0,
130
- issues,
131
- }, null, 2));
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(JSON.stringify({
188
- proposal_id: proposal.proposal_id,
189
- decision: sub,
190
- by,
191
- reason,
192
- }, null, 2));
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('No studio.project.json found in current directory. Run: kdna studio scaffold', EXIT.INPUT_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(JSON.stringify({
244
- card: `${type}.${id}`,
245
- locked: true,
246
- lock: card.human_lock,
247
- }, null, 2));
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(`Card not found: ${cardId}. Check the card ID and that a studio project exists.`, EXIT.INPUT_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(JSON.stringify({
324
- domain: path.basename(abs),
325
- total_stages: stages.length,
326
- pending_changes: pending.length,
327
- stages: stages.map((s) => ({
328
- stage: s.stage,
329
- version: s.version,
330
- date: s.date,
331
- changes: s.changes?.length || 0,
332
- })),
333
- }, null, 2));
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('Usage: kdna regression <old-domain> <new-domain> --evals <dir> [--json]', EXIT.INPUT_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: { axioms: oldAxiomCount, misunderstandings: oldMisCount, self_checks: oldSelfCheckCount, governance_coverage: oldGov },
425
- new: { axioms: newAxiomCount, misunderstandings: newMisCount, self_checks: newSelfCheckCount, governance_coverage: newGov },
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(` Axioms: ${oldAxiomCount} → ${newAxiomCount} (${result.delta.axioms >= 0 ? '+' : ''}${result.delta.axioms})`);
446
- console.log(` Misunderstandings: ${oldMisCount} → ${newMisCount} (${result.delta.misunderstandings >= 0 ? '+' : ''}${result.delta.misunderstandings})`);
447
- console.log(` Self-checks: ${oldSelfCheckCount} → ${newSelfCheckCount} (${result.delta.self_checks >= 0 ? '+' : ''}${result.delta.self_checks})`);
448
- console.log(` Governance coverage: ${oldGov}% → ${newGov}% (${result.delta.governance_coverage >= 0 ? '+' : ''}${result.delta.governance_coverage}%)`);
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(` Evals: ${passedEvals} passed, ${failedEvals} failed out of ${totalEvals}`);
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 ? '✓' : '✗';
@@ -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
 
@@ -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(extra.server || license?.activation_server || license?.license_server_url),
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 || ['claude_code', 'codex', 'opencode', 'cursor', 'gemini'],
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('Usage: kdna license activate <domain> --key <license-key> --server <url>', EXIT.INPUT_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,
@@ -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.slice(1).filter((a) => a !== '--json').join(' ').trim();
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) error('Usage: kdna load <name|file.kdna> [--as=prompt|json|raw] [--profile=index|compact|scenario|full]');
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