@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/src/cli.js CHANGED
@@ -1,24 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * kdna — Unified CLI for KDNA domain cognition assets.
3
+ * kdna — The runtime control plane for domain judgment.
4
4
  *
5
- * Commands:
6
- * kdna validate <path> Validate a domain directory or .kdna file
7
- * kdna verify <path> Verify a domain (alias for validate)
8
- * kdna pack <path> Pack a domain folder into .kdna container (ZIP)
9
- * kdna unpack <path> Unpack .kdna container to domain folder
10
- * kdna install <domain-id> Install a domain from registry
11
- * kdna inspect <path> Inspect a domain directory or .kdna file
12
- * kdna list List installed domains
13
- * kdna compare <before> <after> Compare judgment with/without KDNA
14
- * kdna match "<task>" Match task against available domains
15
- * kdna setup One-command setup: install CLI + skills + data root
16
- * kdna cluster lint <path> Validate a cluster manifest
17
- * kdna identity init Generate Ed25519 identity key pair
18
- * kdna identity show Display public key and buyer ID
5
+ * KDNA CLI is the runtime control plane for loading, validating,
6
+ * composing, testing, and governing domain judgment for AI agents.
19
7
  */
20
8
 
21
- const { usage, error } = require('./cmds/_common');
9
+ const { error, EXIT, setQuiet, setExitCodeOnly } = require('./cmds/_common');
22
10
  const { cmdValidate, cmdPack, cmdUnpack, cmdInspect } = require('./cmds/domain');
23
11
  const { cmdList, cmdRegistry } = require('./cmds/registry');
24
12
  const {
@@ -27,29 +15,137 @@ const {
27
15
  cmdSearch,
28
16
  cmdAvailable,
29
17
  cmdMatch,
18
+ cmdSelect,
30
19
  cmdLoad,
20
+ cmdPostvalidate,
31
21
  } = require('./cmds/quality');
32
22
  const { cmdCluster } = require('./cmds/cluster');
33
23
  const { cmdIdentity } = require('./cmds/identity');
34
24
  const { cmdSetup } = require('./cmds/setup');
35
- const { cmdPreview, cmdProject, cmdEval, cmdSelect, cmdExport, cmdDemo } = require('./cmds/legacy');
25
+ const { cmdDoctor } = require('./cmds/doctor');
26
+ const { cmdPreview, cmdProject, cmdEval, cmdExport, cmdDemo } = require('./cmds/legacy');
27
+ const { cmdStudioScaffold, cmdCardsValidate, cmdLockVerify, cmdStudioCompile, cmdStudioReadiness } = require('./cmds/studio');
28
+ const { cmdTestRun, cmdTestImport } = require('./cmds/test');
29
+ const { cmdChangelog } = require('./cmds/changelog');
30
+ const { cmdProposalCreate, cmdProposalValidate, cmdReview, cmdLockCard, cmdEvolution, cmdRegression } = require('./cmds/governance');
31
+ const { cmdBadgeCompute, cmdRegistryAudit, cmdPackage } = require('./cmds/badge');
36
32
 
37
33
  // ─── Main ─────────────────────────────────────────────────────────────
38
34
 
39
35
  const args = process.argv.slice(2);
40
36
  if (!args.length || args[0] === 'help' || args[0] === '--help' || args[0] === '-h') {
41
- usage();
37
+ showHelp();
42
38
  process.exit(0);
43
39
  }
44
40
 
41
+ // Global flags
42
+ if (args.includes('--quiet')) setQuiet(true);
43
+ if (args.includes('--exit-code')) setExitCodeOnly(true);
44
+
45
+ function showHelp() {
46
+ const v = require('../package.json').version;
47
+ console.log(`kdna v${v} — The runtime control plane for domain judgment
48
+
49
+ Usage: kdna <command> [options]
50
+
51
+ Domain Authoring:
52
+ init <name> Scaffold a new domain from template
53
+ validate <path> Validate domain structure
54
+ validate --schema <path> Schema-only validation
55
+ pack <path> Pack into .kdna container
56
+ unpack <file> Unpack .kdna container
57
+ inspect <path> Inspect domain or .kdna file
58
+ publish <path> Pack + sign + publish
59
+ publish --check <path> Quality gate check only
60
+ version bump <level> [path] Bump domain version
61
+ version bump --suggest [path] Suggest version bump level
62
+
63
+ Studio Integration (Phase 1):
64
+ studio scaffold <name> Create Studio project + card templates
65
+ cards validate <project.json> Validate Judgment Cards structure
66
+ lock verify <project.json> Verify Human Lock status
67
+ studio compile <project.json> Compile locked cards into KDNA domain
68
+ studio readiness <project.json> Generate domain readiness card
69
+
70
+ Agent Runtime:
71
+ available [--json] List installed domains with v2.1 fields
72
+ match "<task>" [--json] Signal matching — find relevant domains
73
+ select --input "..." [--json] Selection policy — decide which domains to load
74
+ load <name> [--as=prompt|json|raw] Emit domain in agent-ready format
75
+ load <name> --profile=index|compact|scenario|full Load profiles (Phase 2)
76
+ postvalidate <name> --output <file> Post-generation judgment check
77
+
78
+ Testing & Verification:
79
+ verify <name> 3-layer: structure + trust + judgment
80
+ verify <name> --judgment --run-tests Judgment validation with eval cases
81
+ compare <name> --input "..." With/without KDNA reasoning diff
82
+ diff <name>@<v1> <name>@<v2> Judgment-level diff between versions
83
+ test run <name> --input <file> Record test result against domain
84
+ test import <run> --as-eval Convert test result to eval card
85
+ changelog <name> --from --to Generate judgment changelog
86
+ doctor Check runtime environment health
87
+
88
+ Cluster Composition:
89
+ cluster lint <path> Validate cluster manifest
90
+ cluster match <path> --input ".." Match input to cluster domains
91
+ cluster compose <path> --input Compose context with source attribution
92
+ cluster conflicts <path> --input Detect inter-domain conflicts
93
+ cluster graph <path> Output domain relationship graph (DOT/JSON)
94
+
95
+ Governance & Release (Phase 6):
96
+ proposal create --from-test <run> --domain <path> Create improvement proposal
97
+ proposal validate <proposal.json> Validate proposal structure
98
+ review accept <proposal> --by --reason Accept improvement proposal
99
+ review reject <proposal> --by --reason Reject improvement proposal
100
+ lock card <id> --by --reason Record human lock on a card
101
+ evolution add-proposal <file> Add proposal to evolution record
102
+ evolution add-lock <file> Add lock to evolution record
103
+ evolution report <domain> Show domain evolution history
104
+ regression <old> <new> --evals <dir> Detect judgment regression
105
+
106
+ Quality & Distribution (Phase 7):
107
+ badge compute <domain> Compute quality badge (draft/tested/trusted)
108
+ registry audit --scope <@scope> Audit registry scope health
109
+ package <domain> --format=kdna Package domain as distributable asset
110
+
111
+ Registry & Distribution:
112
+ install <name> Install domain from registry
113
+ remove <name> Uninstall a domain
114
+ update <name> Update installed domain
115
+ info <name> Show domain metadata and trust status
116
+ list [--available] List installed or available domains
117
+ search <keyword> Search registry
118
+ registry refresh Refresh registry cache
119
+
120
+ Identity & Signing:
121
+ identity init Generate Ed25519 signing key
122
+ identity show Display public key and buyer ID
123
+ identity export [--out] Backup private key (encrypted)
124
+ identity import <file> Restore identity from backup
125
+
126
+ Setup:
127
+ setup One-command setup: CLI + skill + data root
128
+
129
+ Flags:
130
+ --json Structured JSON output (machine-readable)
131
+ --quiet Suppress non-error output
132
+
133
+ Exit Codes:
134
+ 0 OK 1 VALIDATION_FAILED 2 INPUT_ERROR 3 TRUST_FAILED
135
+ 4 JUDGMENT_QUALITY_FAILED 5 REGISTRY_ERROR 6 PROVIDER_ERROR
136
+ 7 POLICY_VIOLATION 8 HUMAN_LOCK_REQUIRED
137
+ `);
138
+ }
139
+
45
140
  const cmd = args[0];
46
141
 
47
142
  switch (cmd) {
48
143
  case 'validate': {
49
144
  const schemaFlag = args.includes('--schema');
50
- const target = args.filter((a, i) => i > 0 && a !== '--schema')[0];
145
+ const jsonFlag = args.includes('--json');
146
+ const target = args.filter((a, i) => i > 0 && a !== '--schema' && a !== '--json')[0];
51
147
  if (!target) error('Usage: kdna validate <path>');
52
- cmdValidate(target, schemaFlag);
148
+ cmdValidate(target, schemaFlag, jsonFlag);
53
149
  break;
54
150
  }
55
151
  case 'pack': {
@@ -113,9 +209,9 @@ switch (cmd) {
113
209
  }
114
210
  case 'info': {
115
211
  const { cmdInfo } = require('./install');
116
- const target = args[1];
212
+ const target = args.filter((a) => !a.startsWith('--'))[1];
117
213
  if (!target) error('Usage: kdna info <domain>');
118
- cmdInfo(target);
214
+ cmdInfo(target, args.includes('--json'));
119
215
  break;
120
216
  }
121
217
  case 'update': {
@@ -130,9 +226,9 @@ switch (cmd) {
130
226
  break;
131
227
  }
132
228
  case 'inspect': {
133
- const target = args[1];
229
+ const target = args.filter((a) => !a.startsWith('--'))[1];
134
230
  if (!target) error('Usage: kdna inspect <path>');
135
- cmdInspect(target);
231
+ cmdInspect(target, args.includes('--json'));
136
232
  break;
137
233
  }
138
234
  case 'verify': {
@@ -174,6 +270,97 @@ switch (cmd) {
174
270
  cmdLoad(args);
175
271
  break;
176
272
  }
273
+ case 'select': {
274
+ cmdSelect(args);
275
+ break;
276
+ }
277
+ case 'postvalidate': {
278
+ cmdPostvalidate(args);
279
+ break;
280
+ }
281
+ case 'test': {
282
+ const sub = args[1];
283
+ if (sub === 'run') {
284
+ cmdTestRun(['test', ...args.slice(2)]);
285
+ } else if (sub === 'import') {
286
+ cmdTestImport(['test', ...args.slice(2)]);
287
+ } else {
288
+ error(
289
+ 'Usage:\n' +
290
+ ' kdna test run <domain> --input <file> [--save <dir>]\n' +
291
+ ' kdna test import <run-file> --as-eval --out <file>',
292
+ EXIT.INPUT_ERROR,
293
+ );
294
+ }
295
+ break;
296
+ }
297
+ case 'changelog': {
298
+ cmdChangelog(args);
299
+ break;
300
+ }
301
+ case 'proposal': {
302
+ const sub = args[1];
303
+ if (sub === 'create') {
304
+ cmdProposalCreate(args);
305
+ } else if (sub === 'validate') {
306
+ cmdProposalValidate(args);
307
+ } else {
308
+ error('Usage: kdna proposal create --from-test <run.json> --domain <path>\n kdna proposal validate <proposal.json>', EXIT.INPUT_ERROR);
309
+ }
310
+ break;
311
+ }
312
+ case 'review': {
313
+ cmdReview(args);
314
+ break;
315
+ }
316
+ case 'lock': {
317
+ const sub = args[1];
318
+ if (sub === 'verify') {
319
+ const target = args.filter((a) => !a.startsWith('--'))[2];
320
+ if (!target) error('Usage: kdna lock verify <studio.project.json>');
321
+ cmdLockVerify(target, args);
322
+ } else if (sub === 'card') {
323
+ cmdLockCard(args);
324
+ } else {
325
+ error(
326
+ 'Usage:\n' +
327
+ ' kdna lock verify <studio.project.json> Verify human lock status\n' +
328
+ ' kdna lock card <card-id> --by <name> --reason "..." Lock a judgment card',
329
+ EXIT.INPUT_ERROR,
330
+ );
331
+ }
332
+ break;
333
+ }
334
+ case 'evolution': {
335
+ cmdEvolution(args);
336
+ break;
337
+ }
338
+ case 'regression': {
339
+ cmdRegression(args);
340
+ break;
341
+ }
342
+ case 'badge': {
343
+ const sub = args[1];
344
+ if (sub === 'compute') {
345
+ const target = args.filter((a) => !a.startsWith('--'))[2];
346
+ if (!target) error('Usage: kdna badge compute <domain>');
347
+ cmdBadgeCompute(target, args);
348
+ } else {
349
+ error('Usage: kdna badge compute <domain>', EXIT.INPUT_ERROR);
350
+ }
351
+ break;
352
+ }
353
+ case 'audit': {
354
+ cmdRegistryAudit(args);
355
+ break;
356
+ }
357
+ case 'package': {
358
+ const target = args.filter((a) => !a.startsWith('--'))[1];
359
+ if (!target) error('Usage: kdna package <domain> --format=kdna');
360
+ cmdPackage(target, args);
361
+ break;
362
+ }
363
+ // Legacy (removed) commands
177
364
  case 'project': {
178
365
  cmdProject();
179
366
  break;
@@ -182,22 +369,18 @@ switch (cmd) {
182
369
  cmdEval();
183
370
  break;
184
371
  }
185
- case 'select': {
186
- cmdSelect();
187
- break;
188
- }
189
372
  case 'export': {
190
373
  cmdExport();
191
374
  break;
192
375
  }
193
- case 'list': {
194
- cmdList(args.includes('--available'));
195
- break;
196
- }
197
376
  case 'demo': {
198
377
  cmdDemo();
199
378
  break;
200
379
  }
380
+ case 'list': {
381
+ cmdList(args.includes('--available'), args.includes('--json'));
382
+ break;
383
+ }
201
384
  case 'setup': {
202
385
  cmdSetup();
203
386
  break;
@@ -206,6 +389,10 @@ switch (cmd) {
206
389
  cmdCluster(args);
207
390
  break;
208
391
  }
392
+ case 'doctor': {
393
+ cmdDoctor(args);
394
+ break;
395
+ }
209
396
  case 'identity': {
210
397
  cmdIdentity(args);
211
398
  break;
@@ -239,19 +426,61 @@ switch (cmd) {
239
426
  break;
240
427
  }
241
428
  case 'version': {
242
- const { cmdVersionBump } = require('./version');
429
+ const { cmdVersionBump, cmdVersionSuggest } = require('./version');
243
430
  const sub = args[1];
244
431
  if (sub === 'bump') {
245
- const level = args[2];
246
- const target = args[3] || '.';
247
- if (!level || !['patch', 'minor', 'major'].includes(level)) {
248
- error('Usage: kdna version bump <patch|minor|major> [path]');
432
+ if (args.includes('--suggest')) {
433
+ const target = args.filter((a) => !a.startsWith('--'))[3] || '.';
434
+ cmdVersionSuggest(target, args);
435
+ } else {
436
+ const level = args[2];
437
+ const target = args[3] || '.';
438
+ if (!level || !['patch', 'minor', 'major'].includes(level)) {
439
+ error('Usage: kdna version bump <patch|minor|major> [path]');
440
+ }
441
+ cmdVersionBump(level, target);
249
442
  }
250
- cmdVersionBump(level, target);
251
443
  } else {
252
444
  console.log(`kdna v${require('../package.json').version}`);
253
445
  console.log('');
254
446
  console.log('Usage: kdna version bump <patch|minor|major> [path]');
447
+ console.log(' kdna version bump --suggest [path]');
448
+ }
449
+ break;
450
+ }
451
+ case 'cards': {
452
+ const sub = args[1];
453
+ if (sub === 'validate') {
454
+ const target = args.filter((a) => !a.startsWith('--'))[2];
455
+ if (!target) error('Usage: kdna cards validate <studio.project.json>');
456
+ cmdCardsValidate(target, args);
457
+ } else {
458
+ error('Usage: kdna cards validate <studio.project.json>', EXIT.INPUT_ERROR);
459
+ }
460
+ break;
461
+ }
462
+ case 'studio': {
463
+ const sub = args[1];
464
+ if (sub === 'scaffold') {
465
+ const target = args.filter((a) => !a.startsWith('--'))[2];
466
+ if (!target) error('Usage: kdna studio scaffold <name> [--type=cluster] [--minimal]');
467
+ cmdStudioScaffold(target, args);
468
+ } else if (sub === 'compile') {
469
+ const target = args.filter((a) => !a.startsWith('--'))[2];
470
+ if (!target) error('Usage: kdna studio compile <studio.project.json> [--out <dir>]');
471
+ cmdStudioCompile(target, args);
472
+ } else if (sub === 'readiness') {
473
+ const target = args.filter((a) => !a.startsWith('--'))[2];
474
+ if (!target) error('Usage: kdna studio readiness <studio.project.json>');
475
+ cmdStudioReadiness(target, args);
476
+ } else {
477
+ error(
478
+ 'Usage:\n' +
479
+ ' kdna studio scaffold <name> [--type=cluster] [--minimal]\n' +
480
+ ' kdna studio compile <studio.project.json> [--out <dir>]\n' +
481
+ ' kdna studio readiness <studio.project.json>',
482
+ EXIT.INPUT_ERROR,
483
+ );
255
484
  }
256
485
  break;
257
486
  }
@@ -5,6 +5,48 @@ const { loadRegistry: loadCanonicalRegistry } = require('../registry');
5
5
  const USER_KDNA_DIR = path.join(process.env.HOME || process.env.USERPROFILE || '.', '.kdna');
6
6
  const INSTALL_DIR = path.join(USER_KDNA_DIR, 'domains');
7
7
 
8
+ // ─── Global flags ──────────────────────────────────────────────────────
9
+
10
+ let _quiet = false;
11
+ let _exitCodeOnly = false;
12
+ const _originalLog = console.log;
13
+ const _originalError = console.error;
14
+ const _originalWarn = console.warn;
15
+
16
+ function setQuiet(val) {
17
+ _quiet = val;
18
+ if (val) {
19
+ console.log = () => {};
20
+ } else {
21
+ console.log = _originalLog;
22
+ }
23
+ }
24
+
25
+ function isQuiet() { return _quiet; }
26
+
27
+ function setExitCodeOnly(val) {
28
+ _exitCodeOnly = val;
29
+ if (val) {
30
+ console.log = () => {};
31
+ console.warn = () => {};
32
+ console.error = () => {};
33
+ } else {
34
+ console.log = _originalLog;
35
+ console.warn = _originalWarn;
36
+ console.error = _originalError;
37
+ }
38
+ }
39
+
40
+ function isExitCodeOnly() { return _exitCodeOnly; }
41
+
42
+ function log(...args) {
43
+ if (!_quiet && !_exitCodeOnly) _originalLog(...args);
44
+ }
45
+
46
+ function warn(...args) {
47
+ if (!_exitCodeOnly) _originalWarn(...args);
48
+ }
49
+
8
50
  function usage() {
9
51
  console.log(`kdna — KDNA domain cognition asset tool
10
52
 
@@ -68,9 +110,22 @@ Examples:
68
110
  kdna publish ./my_domain --release-tag v0.1.0 --repo yourname/kdna-my_domain`);
69
111
  }
70
112
 
71
- function error(msg) {
72
- console.error(`Error: ${msg}`);
73
- process.exit(1);
113
+ // Exit codes — semantic exit codes for all KDNA CLI commands
114
+ const EXIT = {
115
+ OK: 0,
116
+ VALIDATION_FAILED: 1,
117
+ INPUT_ERROR: 2,
118
+ TRUST_FAILED: 3,
119
+ JUDGMENT_QUALITY_FAILED: 4,
120
+ REGISTRY_ERROR: 5,
121
+ PROVIDER_ERROR: 6,
122
+ POLICY_VIOLATION: 7,
123
+ HUMAN_LOCK_REQUIRED: 8,
124
+ };
125
+
126
+ function error(msg, code = EXIT.VALIDATION_FAILED) {
127
+ if (!_exitCodeOnly) _originalError(`Error: ${msg}`);
128
+ process.exit(code);
74
129
  }
75
130
 
76
131
  function readJson(file) {
@@ -90,10 +145,17 @@ function loadRegistry() {
90
145
  }
91
146
 
92
147
  module.exports = {
148
+ EXIT,
93
149
  USER_KDNA_DIR,
94
150
  INSTALL_DIR,
95
151
  usage,
96
152
  error,
153
+ log,
154
+ warn,
155
+ setQuiet,
156
+ isQuiet,
157
+ setExitCodeOnly,
158
+ isExitCodeOnly,
97
159
  readJson,
98
160
  writeJson,
99
161
  loadRegistry,