@aikdna/kdna-cli 0.16.10 → 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/src/cli.js CHANGED
@@ -10,9 +10,7 @@ const { error, EXIT, setQuiet, setExitCodeOnly } = require('./cmds/_common');
10
10
  const {
11
11
  cmdValidate,
12
12
  cmdPack,
13
- cmdPackEncrypt,
14
13
  cmdUnpack,
15
- cmdUnpackEncrypt,
16
14
  cmdInspect,
17
15
  cmdCard,
18
16
  } = require('./cmds/domain');
@@ -26,6 +24,7 @@ const {
26
24
  cmdSelect,
27
25
  cmdLoad,
28
26
  cmdPostvalidate,
27
+ cmdRoute,
29
28
  } = require('./cmds/quality');
30
29
  const { cmdCluster } = require('./cmds/cluster');
31
30
  const { cmdIdentity } = require('./cmds/identity');
@@ -38,6 +37,9 @@ const {
38
37
  cmdLicenseBind,
39
38
  cmdLicenseShow,
40
39
  cmdLicenseInstall,
40
+ cmdLicenseStatus,
41
+ cmdLicenseActivate,
42
+ cmdLicenseSync,
41
43
  } = require('./cmds/license');
42
44
  const { cmdPreview, cmdProject, cmdEval, cmdExport, cmdDemo } = require('./cmds/legacy');
43
45
  const {
@@ -57,7 +59,8 @@ const {
57
59
  cmdEvolution,
58
60
  cmdRegression,
59
61
  } = require('./cmds/governance');
60
- const { cmdBadgeCompute, cmdRegistryAudit, cmdPackage } = require('./cmds/badge');
62
+ const { cmdBadgeCompute, cmdRegistryAudit } = require('./cmds/badge');
63
+ const { cmdExplain } = require('./cmds/explain');
61
64
 
62
65
  // ─── Main ─────────────────────────────────────────────────────────────
63
66
 
@@ -79,15 +82,14 @@ Usage: kdna <command> [options]
79
82
 
80
83
  Domain Authoring:
81
84
  init <name> Scaffold a new domain from template
82
- validate <path> Validate domain structure
83
- validate --schema <path> Schema-only validation
84
- pack <path> Pack into .kdna container
85
- pack <path> --encrypt --license <file> Pack encrypted .kdnae container
86
- unpack <file> Unpack .kdna container
87
- unpack <file> --license <file> Unpack encrypted .kdnae container
88
- inspect <path> Inspect domain or .kdna file
89
- inspect <path> --locale zh-CN Inspect with localized governance data
90
- card <path> [--locale zh-CN] Display KDNA Card (governance metadata)
85
+ dev validate <path> Validate a dev source directory
86
+ dev pack <path> Build a dev source directory into .kdna
87
+ dev unpack <file> Unpack .kdna into a dev source directory
88
+ dev inspect <path> Inspect a dev source directory
89
+ dev card <path> Display KDNA Card from a dev source directory
90
+ inspect <file.kdna> Inspect a .kdna asset
91
+ card <file.kdna> [--locale zh-CN] Display KDNA Card from a .kdna asset
92
+ explain <name> Natural language summary: axioms, terms, scenarios
91
93
  publish <path> Pack + sign + publish
92
94
  publish --check <path> Quality gate check only
93
95
  version bump <level> [path] Bump domain version
@@ -101,21 +103,22 @@ Studio Integration (Phase 1):
101
103
  studio readiness <project.json> Generate domain readiness card
102
104
 
103
105
  Agent Runtime:
106
+ route "<task>" [--json] [--discover] 5-Gate 7-State routing decision
104
107
  available [--json] List installed domains with v2.1 fields
105
108
  match "<task>" [--json] Signal matching — find relevant domains
106
109
  select --input "..." [--json] Selection policy — decide which domains to load
107
- load <name> [--as=prompt|json|raw] Emit domain in agent-ready format
108
- load <name> --profile=index|compact|scenario|full Load profiles (Phase 2)
110
+ load <name|file.kdna> [--as=prompt|json|raw] Emit asset in agent-ready format
111
+ load <name|file.kdna> --profile=index|compact|scenario|full Load profiles (Phase 2)
109
112
  postvalidate <name> --output <file> Post-generation judgment check
110
113
 
111
114
  Testing & Verification:
112
- verify <name> 3-layer: structure + trust + judgment
113
- verify <name> --i18n I18N verification: locales, overlays, card completeness
114
- verify <name> --governance Governance verification: risk_level, KDNA_CARD, provenance
115
- verify <name> --judgment --run-tests Judgment validation with eval cases
116
- compare <name> --input "..." With/without KDNA reasoning diff
117
- compare <name> --input "..." --report-md Markdown report format
118
- compare <name> --input "..." --report-json JSON report with scoring
115
+ verify <name|file.kdna> 3-layer: structure + trust + judgment
116
+ verify <name|file.kdna> --i18n I18N verification: locales, overlays, card completeness
117
+ verify <name|file.kdna> --governance Governance verification: risk_level, KDNA_CARD, provenance
118
+ verify <name|file.kdna> --judgment --run-tests Judgment validation with eval cases
119
+ compare <name|file.kdna> --input "..." With/without KDNA reasoning diff
120
+ compare <name|file.kdna> --input "..." --report-md Markdown report format
121
+ compare <name|file.kdna> --input "..." --report-json JSON report with scoring
119
122
  diff <name>@<v1> <name>@<v2> Judgment-level diff between versions
120
123
  test run <name> --input <file> Record test result against domain
121
124
  test import <run> --as-eval Convert test result to eval card
@@ -146,6 +149,7 @@ Quality & Distribution (Phase 7):
146
149
 
147
150
  Registry & Distribution:
148
151
  install <name> Install domain from registry
152
+ install <file.kdna> Install a local .kdna asset
149
153
  remove <name> Uninstall a domain
150
154
  update <name> Update installed domain
151
155
  info <name> Show domain metadata and trust status
@@ -170,9 +174,12 @@ Trace & Diagnostics:
170
174
  License & Authorization:
171
175
  license generate <domain> --to <email> Generate signed license
172
176
  license install <license.json> Register license for auto-decrypt
177
+ license activate <domain> --key --server Activate license from entitlement source
178
+ license sync [domain] [--server] Refresh entitlement / revocation status
173
179
  license verify <license.json> Verify license signature
174
180
  license bind <license.json> Bind license to this machine
175
181
  license show <license.json> Display license details
182
+ license status [domain] [--json] Show installed license activation status
176
183
 
177
184
  Flags:
178
185
  --json Structured JSON output (machine-readable)
@@ -188,41 +195,69 @@ Exit Codes:
188
195
  const cmd = args[0];
189
196
 
190
197
  switch (cmd) {
198
+ case 'dev': {
199
+ const sub = args[1];
200
+ if (sub === 'validate') {
201
+ const schemaFlag = args.includes('--schema');
202
+ const jsonFlag = args.includes('--json');
203
+ const target = args.filter((a, i) => i > 1 && a !== '--schema' && a !== '--json')[0];
204
+ if (!target) error('Usage: kdna dev validate <source-dir>');
205
+ cmdValidate(target, schemaFlag, jsonFlag);
206
+ break;
207
+ }
208
+ if (sub === 'pack') {
209
+ let output = null;
210
+ let target = null;
211
+ for (let i = 2; i < args.length; i++) {
212
+ if (args[i] === '--output' || args[i] === '-o') {
213
+ output = args[i + 1];
214
+ i++;
215
+ } else if (args[i].startsWith('-')) {
216
+ error(`Unknown option for kdna dev pack: ${args[i]}`, EXIT.INPUT_ERROR);
217
+ } else if (!target) {
218
+ target = args[i];
219
+ }
220
+ }
221
+ if (!target) error('Usage: kdna dev pack <source-dir>');
222
+ cmdPack(target, output);
223
+ break;
224
+ }
225
+ if (sub === 'unpack') {
226
+ const target = args[2];
227
+ if (!target) error('Usage: kdna dev unpack <file.kdna>');
228
+ if (!target.endsWith('.kdna')) error('Not a .kdna asset.', EXIT.INPUT_ERROR);
229
+ cmdUnpack(target, args.includes('--force'));
230
+ break;
231
+ }
232
+ if (sub === 'inspect') {
233
+ const target = args.filter((a, i) => i > 1 && !a.startsWith('--'))[0];
234
+ if (!target) error('Usage: kdna dev inspect <source-dir> [--json] [--locale zh-CN]');
235
+ const localeIdx = args.indexOf('--locale');
236
+ const locale = localeIdx >= 0 ? args[localeIdx + 1] : null;
237
+ cmdInspect(target, args.includes('--json'), locale, { allowDirectory: true });
238
+ break;
239
+ }
240
+ if (sub === 'card') {
241
+ const target = args.filter((a, i) => i > 1 && !a.startsWith('--'))[0];
242
+ if (!target) error('Usage: kdna dev card <source-dir> [--json] [--locale zh-CN]');
243
+ const localeIdx = args.indexOf('--locale');
244
+ const locale = localeIdx >= 0 ? args[localeIdx + 1] : null;
245
+ cmdCard(target, args.includes('--json'), locale, { allowDirectory: true });
246
+ break;
247
+ }
248
+ error('Usage: kdna dev <validate|pack|unpack|inspect|card> ...', EXIT.INPUT_ERROR);
249
+ break;
250
+ }
191
251
  case 'validate': {
192
- const schemaFlag = args.includes('--schema');
193
- const jsonFlag = args.includes('--json');
194
- const target = args.filter((a, i) => i > 0 && a !== '--schema' && a !== '--json')[0];
195
- if (!target) error('Usage: kdna validate <path>');
196
- cmdValidate(target, schemaFlag, jsonFlag);
252
+ error('Directory validation is a dev-only operation. Use: kdna dev validate <source-dir>', EXIT.INPUT_ERROR);
197
253
  break;
198
254
  }
199
255
  case 'pack': {
200
- let output = null;
201
- let target = null;
202
- for (let i = 1; i < args.length; i++) {
203
- if (args[i] === '--output' || args[i] === '-o') {
204
- output = args[i + 1];
205
- i++;
206
- } else if (!target) {
207
- target = args[i];
208
- }
209
- }
210
- if (!target) error('Usage: kdna pack <path>');
211
- if (args.includes('--encrypt')) {
212
- cmdPackEncrypt(target, args);
213
- } else {
214
- cmdPack(target, output);
215
- }
256
+ error('Directory packaging is a dev-only operation. Use: kdna dev pack <source-dir>', EXIT.INPUT_ERROR);
216
257
  break;
217
258
  }
218
259
  case 'unpack': {
219
- const target = args[1];
220
- if (!target) error('Usage: kdna unpack <file.kdna|file.kdnae>');
221
- if (target.endsWith('.kdnae')) {
222
- cmdUnpackEncrypt(target, args);
223
- } else {
224
- cmdUnpack(target, args.includes('--force'));
225
- }
260
+ error('Unpacking exposes internal files and is dev-only. Use: kdna dev unpack <file.kdna>', EXIT.INPUT_ERROR);
226
261
  break;
227
262
  }
228
263
  case 'preview': {
@@ -240,7 +275,7 @@ switch (cmd) {
240
275
  domainId = args[i];
241
276
  }
242
277
  }
243
- if (!domainId) error('Usage: kdna install <domain-id|github:user/repo|./folder>');
278
+ if (!domainId) error('Usage: kdna install <domain-id|file.kdna>');
244
279
 
245
280
  const { cmdInstallExtended } = require('./install');
246
281
  if (fromGit) {
@@ -283,7 +318,7 @@ switch (cmd) {
283
318
  }
284
319
  case 'inspect': {
285
320
  const target = args.filter((a) => !a.startsWith('--'))[1];
286
- if (!target) error('Usage: kdna inspect <path> [--json] [--locale zh-CN]');
321
+ if (!target) error('Usage: kdna inspect <file.kdna> [--json] [--locale zh-CN]');
287
322
  const localeIdx = args.indexOf('--locale');
288
323
  const locale = localeIdx >= 0 ? args[localeIdx + 1] : null;
289
324
  cmdInspect(target, args.includes('--json'), locale);
@@ -291,10 +326,10 @@ switch (cmd) {
291
326
  }
292
327
  case 'card': {
293
328
  const target = args.filter((a) => !a.startsWith('--'))[1];
294
- if (!target) error('Usage: kdna card <path> [--json] [--locale zh-CN]');
329
+ if (!target) error('Usage: kdna card <file.kdna> [--json] [--locale zh-CN]');
295
330
  const localeIdx = args.indexOf('--locale');
296
331
  const locale = localeIdx >= 0 ? args[localeIdx + 1] : null;
297
- cmdCard(target, locale);
332
+ cmdCard(target, args.includes('--json'), locale);
298
333
  break;
299
334
  }
300
335
  case 'verify': {
@@ -303,10 +338,10 @@ switch (cmd) {
303
338
  if (!target) {
304
339
  error(
305
340
  'Usage:\n' +
306
- ' kdna verify <name> Run all three layers (structure / trust / judgment)\n' +
307
- ' kdna verify <name> --structure Files + schema only\n' +
308
- ' kdna verify <name> --trust Signature + scope + Ed25519 only\n' +
309
- ' kdna verify <name> --judgment v2.1 governance fields + eval cases only',
341
+ ' kdna verify <name|file.kdna> Run all three layers (structure / trust / judgment)\n' +
342
+ ' kdna verify <name|file.kdna> --structure Files + schema only\n' +
343
+ ' kdna verify <name|file.kdna> --trust Signature + scope + Ed25519 only\n' +
344
+ ' kdna verify <name|file.kdna> --judgment v2.1 governance fields + eval cases only',
310
345
  );
311
346
  }
312
347
  cmdVerify(target, args);
@@ -340,6 +375,10 @@ switch (cmd) {
340
375
  cmdSelect(args);
341
376
  break;
342
377
  }
378
+ case 'route': {
379
+ cmdRoute(args);
380
+ break;
381
+ }
343
382
  case 'postvalidate': {
344
383
  cmdPostvalidate(args);
345
384
  break;
@@ -424,9 +463,7 @@ switch (cmd) {
424
463
  break;
425
464
  }
426
465
  case 'package': {
427
- const target = args.filter((a) => !a.startsWith('--'))[1];
428
- if (!target) error('Usage: kdna package <domain> --format=kdna');
429
- cmdPackage(target, args);
466
+ error('Directory packaging is a dev-only operation. Use: kdna dev pack <source-dir>', EXIT.INPUT_ERROR);
430
467
  break;
431
468
  }
432
469
  // Legacy (removed) commands
@@ -446,6 +483,10 @@ switch (cmd) {
446
483
  cmdDemo();
447
484
  break;
448
485
  }
486
+ case 'explain': {
487
+ cmdExplain(args);
488
+ break;
489
+ }
449
490
  case 'list': {
450
491
  const localeIdx = args.indexOf('--locale');
451
492
  const locale = localeIdx >= 0 ? args[localeIdx + 1] : null;
@@ -485,14 +526,23 @@ switch (cmd) {
485
526
  cmdLicenseShow(rest);
486
527
  } else if (sub === 'install') {
487
528
  cmdLicenseInstall(rest);
529
+ } else if (sub === 'status') {
530
+ cmdLicenseStatus(rest);
531
+ } else if (sub === 'activate') {
532
+ cmdLicenseActivate(rest).catch((e) => error(e.message, EXIT.TRUST_FAILED));
533
+ } else if (sub === 'sync') {
534
+ cmdLicenseSync(rest).catch((e) => error(e.message, EXIT.TRUST_FAILED));
488
535
  } else {
489
536
  error(
490
537
  'Usage:\n' +
491
538
  ' kdna license generate <domain> --to <email> [--expires <date>]\n' +
492
539
  ' kdna license install <license.json>\n' +
540
+ ' kdna license activate <domain> --key <license-key> --server <url>\n' +
541
+ ' kdna license sync [domain] [--server <url>]\n' +
493
542
  ' kdna license verify <license.json>\n' +
494
543
  ' kdna license bind <license.json>\n' +
495
- ' kdna license show <license.json>',
544
+ ' kdna license show <license.json>\n' +
545
+ ' kdna license status [domain] [--json]',
496
546
  EXIT.INPUT_ERROR,
497
547
  );
498
548
  }
@@ -513,7 +563,7 @@ switch (cmd) {
513
563
  const idx = args.indexOf('--check');
514
564
  const target = args[idx + 1] || args.filter((a) => !a.startsWith('--'))[1] || '.';
515
565
  if (!target || target.startsWith('--')) error('Usage: kdna publish --check <path>');
516
- cmdPublishCheck(target);
566
+ cmdPublishCheck(target, args);
517
567
  } else {
518
568
  const { cmdPublish } = require('./publish');
519
569
  const target = args.filter((a) => !a.startsWith('--'))[1];
@@ -1,9 +1,6 @@
1
1
  const fs = require('fs');
2
- const path = require('path');
3
2
  const { loadRegistry: loadCanonicalRegistry } = require('../registry');
4
-
5
- const USER_KDNA_DIR = path.join(process.env.HOME || process.env.USERPROFILE || '.', '.kdna');
6
- const INSTALL_DIR = path.join(USER_KDNA_DIR, 'domains');
3
+ const { USER_KDNA_DIR, INSTALL_DIR } = require('../paths');
7
4
 
8
5
  // ─── Global flags ──────────────────────────────────────────────────────
9
6
 
@@ -54,14 +51,13 @@ Usage:
54
51
 
55
52
  --- Domain authors ---
56
53
  kdna init <name> Scaffold a new KDNA domain from template
57
- kdna validate <path> Validate a domain directory
58
- kdna validate --schema <path> ...with JSON Schema
59
- kdna pack <path> Pack a domain folder into a .kdna container
60
- kdna pack <path> --encrypt --license <file> Pack encrypted .kdnae container
61
- kdna pack --output <dir> <path> Output .kdna to specific directory
62
- kdna unpack <path> Unpack a .kdna or .kdnae container to a folder
63
- kdna inspect <path> Inspect a domain directory or .kdna file
64
- kdna publish <path> Pack + sign + output registry patch
54
+ kdna dev validate <path> Validate a dev source directory
55
+ kdna dev pack <path> Build a dev source directory into .kdna
56
+ kdna dev unpack <path> Unpack .kdna into a dev source directory
57
+ kdna dev inspect <path> Inspect a dev source directory
58
+ kdna dev card <path> Display KDNA Card from a dev source directory
59
+ kdna inspect <file.kdna> Inspect a .kdna asset
60
+ kdna publish <path> Pack + sign a dev source directory
65
61
  kdna publish <path> --release-tag <tag> --repo <o/r> ...also upload to GitHub
66
62
  kdna publish --check <path> Run quality gate only (no pack/upload)
67
63
  kdna version bump <patch|minor|major> [path] Bump domain version
@@ -72,7 +68,6 @@ Usage:
72
68
  kdna install @scope/name Install any scoped domain
73
69
  kdna install @aikdna/animation Install a cluster (installs all sub-domains)
74
70
  kdna install ./file.kdna Install from a local .kdna file
75
- kdna install ./folder Install from a local directory (dev)
76
71
  kdna remove <name> Uninstall a domain
77
72
  kdna update <name> Update an installed domain
78
73
  kdna update --all Update all installed domains
@@ -83,14 +78,14 @@ Usage:
83
78
  kdna registry refresh Refresh the canonical registry cache
84
79
 
85
80
  --- Quality + judgment ---
86
- kdna verify <name> Quality check: structure + trust + judgment
87
- kdna compare <name> --input "<text>" With/without KDNA reasoning diff
81
+ kdna verify <name|file.kdna> Quality check: structure + trust + judgment
82
+ kdna compare <name|file.kdna> --input "<text>" With/without KDNA reasoning diff
88
83
  kdna diff <name>@<v1> <name>@<v2> Judgment-level diff between versions
89
84
 
90
85
  --- Agent-facing (called by the kdna-loader skill) ---
91
86
  kdna available [--json] List installed domains + v2.1 fields
92
87
  kdna match "<task>" [--json] Hint signals (dropped + weak overlap)
93
- kdna load <name> [--as=prompt|json|raw] Emit domain in agent-ready format
88
+ kdna load <name|file.kdna> [--as=prompt|json|raw] Emit asset in agent-ready format
94
89
 
95
90
  --- Identity ---
96
91
  kdna identity init Generate Ed25519 identity key pair
@@ -144,6 +139,25 @@ function writeJson(file, data) {
144
139
  fs.writeFileSync(file, JSON.stringify(data, null, 2) + '\n');
145
140
  }
146
141
 
142
+ function selfCheckText(item) {
143
+ if (typeof item === 'string') return item;
144
+ if (item && typeof item === 'object' && typeof item.question === 'string') return item.question;
145
+ return '';
146
+ }
147
+
148
+ function isYesNoSelfCheck(item) {
149
+ const raw = selfCheckText(item).trim();
150
+ if (!raw) return false;
151
+ const lower = raw.toLowerCase();
152
+ return (
153
+ lower.endsWith('?') ||
154
+ raw.endsWith('?') ||
155
+ raw.endsWith('吗') ||
156
+ raw.includes('是否') ||
157
+ /^(have|has|can|does|do|is|are|did|was|were|should|will|would|could|might|can not|cannot|能不能|会不会|有没有|要不要|是不是)/.test(lower)
158
+ );
159
+ }
160
+
147
161
  function loadRegistry() {
148
162
  return loadCanonicalRegistry({ allowNetwork: true });
149
163
  }
@@ -162,5 +176,7 @@ module.exports = {
162
176
  isExitCodeOnly,
163
177
  readJson,
164
178
  writeJson,
179
+ selfCheckText,
180
+ isYesNoSelfCheck,
165
181
  loadRegistry,
166
182
  };
package/src/cmds/badge.js CHANGED
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * kdna badge compute <domain> [--json]
5
5
  * kdna registry audit --scope <scope> [--json]
6
- * kdna package <domain> --format=kdna
6
+ * kdna dev pack <domain>
7
7
  */
8
8
 
9
9
  const fs = require('fs');
@@ -142,9 +142,9 @@ function cmdRegistryAudit(args = []) {
142
142
  status: d.status || 'experimental',
143
143
  yanked: d.yanked || false,
144
144
  deprecated: d.deprecated || false,
145
- has_kdna_url: !!d.kdna_url,
145
+ has_asset_url: !!d.asset_url,
146
146
  has_signature: !!d.signature,
147
- has_sha256: !!d.sha256,
147
+ has_asset_digest: !!d.asset_digest,
148
148
  })),
149
149
  issues: [],
150
150
  };
@@ -152,12 +152,12 @@ function cmdRegistryAudit(args = []) {
152
152
  // Detect issues
153
153
  const yanked = scopeDomains.filter((d) => d.yanked);
154
154
  const deprecated = scopeDomains.filter((d) => d.deprecated);
155
- const noPackage = scopeDomains.filter((d) => !d.kdna_url);
155
+ const noPackage = scopeDomains.filter((d) => !d.asset_url);
156
156
  const noSignature = scopeDomains.filter((d) => !d.signature);
157
157
 
158
158
  if (yanked.length) audit.issues.push(`${yanked.length} yanked domain(s)`);
159
159
  if (deprecated.length) audit.issues.push(`${deprecated.length} deprecated domain(s)`);
160
- if (noPackage.length) audit.issues.push(`${noPackage.length} domain(s) without .kdna package`);
160
+ if (noPackage.length) audit.issues.push(`${noPackage.length} domain(s) without .kdna dev package`);
161
161
  if (noSignature.length) audit.issues.push(`${noSignature.length} domain(s) without signature`);
162
162
 
163
163
  audit.healthy = audit.issues.length === 0;
@@ -183,7 +183,7 @@ function cmdRegistryAudit(args = []) {
183
183
  const flags = [];
184
184
  if (d.yanked) flags.push('yanked');
185
185
  if (d.deprecated) flags.push('deprecated');
186
- if (!d.has_kdna_url) flags.push('no-package');
186
+ if (!d.has_asset_url) flags.push('no-package');
187
187
  console.log(` ${d.name.padEnd(36)} v${d.version || '?'} ${flags.length ? `[${flags.join(', ')}]` : '✓'}`);
188
188
  }
189
189
  }
@@ -205,7 +205,7 @@ function cmdPackage(domainPath, args = []) {
205
205
  }
206
206
 
207
207
  const manifest = readJson(path.join(abs, 'kdna.json'));
208
- if (!manifest) error(`No kdna.json found in ${abs}. Run: kdna pack`, EXIT.INPUT_ERROR);
208
+ if (!manifest) error(`No kdna.json found in ${abs}. Run: kdna dev pack`, EXIT.INPUT_ERROR);
209
209
 
210
210
  const domainName = manifest.name?.split('/')?.[1] || path.basename(abs);
211
211
  const outFile = path.join(abs, 'dist', `${domainName}-${manifest.version || '0.1.0'}.kdna`);
@@ -18,7 +18,7 @@ function downloadVersion(entry, version, destDir) {
18
18
  const { execSync, execFileSync } = require('child_process');
19
19
  const tmpFile = `${destDir}.kdna.tmp`;
20
20
  try {
21
- execFileSync('curl', ['-fsSL', '--retry', '2', '-o', tmpFile, entry.kdna_url], {
21
+ execFileSync('curl', ['-fsSL', '--retry', '2', '-o', tmpFile, entry.asset_url], {
22
22
  timeout: 60000,
23
23
  stdio: 'pipe',
24
24
  });
@@ -8,6 +8,16 @@ const {
8
8
  detectDomainConflicts,
9
9
  generateClusterTrace,
10
10
  } = require('@aikdna/kdna-core');
11
+ const { getInstalled, readContainer } = require('../package-store');
12
+
13
+ function loadInstalledDomain(domainId) {
14
+ const full = domainId.startsWith('@') ? domainId : `@aikdna/${domainId}`;
15
+ const installed = getInstalled(full);
16
+ if (!installed) return null;
17
+ const { core, patterns } = readContainer(installed.asset_path);
18
+ if (!core || !patterns) return null;
19
+ return { core, patterns };
20
+ }
11
21
 
12
22
  function cmdCluster(args) {
13
23
  const { cmdClusterLint } = require('../cluster');
@@ -101,7 +111,7 @@ function cmdClusterInfo(target, _format = 'human') {
101
111
  }
102
112
 
103
113
  /**
104
- * Load a cluster: resolve domains from installed ~/.kdna/domains/,
114
+ * Load a cluster: resolve domains from installed .kdna assets,
105
115
  * classify input signals, compose context with attribution, detect
106
116
  * conflicts, and emit the composed context.
107
117
  */
@@ -116,23 +126,7 @@ function cmdClusterLoad(target, args = []) {
116
126
  const manifest = readJson(abs);
117
127
  if (!manifest || !manifest.cluster_id) error('Not a valid cluster manifest');
118
128
 
119
- const INSTALL_DIR = path.join(
120
- process.env.HOME || process.env.USERPROFILE || '.',
121
- '.kdna',
122
- 'domains',
123
- );
124
-
125
- // Domain loader: resolve from installed ~/.kdna/domains/
126
- const domainLoader = (domainId) => {
127
- const [scope, ident] = domainId.startsWith('@')
128
- ? [domainId.slice(0, domainId.indexOf('/')), domainId.slice(domainId.indexOf('/') + 1)]
129
- : ['@aikdna', domainId];
130
- const dir = path.join(INSTALL_DIR, scope, ident);
131
- const core = readJson(path.join(dir, 'KDNA_Core.json'));
132
- const pat = readJson(path.join(dir, 'KDNA_Patterns.json'));
133
- if (!core || !pat) return null;
134
- return { core, patterns: pat };
135
- };
129
+ const domainLoader = loadInstalledDomain;
136
130
 
137
131
  const result = loadCluster(abs, domainLoader);
138
132
  if (result.errors.length) {
@@ -208,22 +202,7 @@ function cmdClusterMatch(target, args = []) {
208
202
  const manifest = readJson(abs);
209
203
  if (!manifest || !manifest.cluster_id) error('Not a valid cluster manifest');
210
204
 
211
- const INSTALL_DIR = path.join(
212
- process.env.HOME || process.env.USERPROFILE || '.',
213
- '.kdna',
214
- 'domains',
215
- );
216
-
217
- const domainLoader = (domainId) => {
218
- const [scope, ident] = domainId.startsWith('@')
219
- ? [domainId.slice(0, domainId.indexOf('/')), domainId.slice(domainId.indexOf('/') + 1)]
220
- : ['@aikdna', domainId];
221
- const dir = path.join(INSTALL_DIR, scope, ident);
222
- const core = readJson(path.join(dir, 'KDNA_Core.json'));
223
- const pat = readJson(path.join(dir, 'KDNA_Patterns.json'));
224
- if (!core || !pat) return null;
225
- return { core, patterns: pat };
226
- };
205
+ const domainLoader = loadInstalledDomain;
227
206
 
228
207
  const result = loadCluster(abs, domainLoader);
229
208
  const classification = classifySignalsAcrossDomains(input, result.domains);
@@ -423,23 +402,12 @@ function cmdClusterGraph(target, args = []) {
423
402
  * Shared domain loader for cluster commands.
424
403
  */
425
404
  function loadClusterDomains(manifest) {
426
- const INSTALL_DIR = path.join(
427
- process.env.HOME || process.env.USERPROFILE || '.',
428
- '.kdna',
429
- 'domains',
430
- );
431
-
432
405
  return (manifest.domains || []).map((d) => {
433
406
  const domainId = d.id;
434
407
  if (!domainId) return null;
435
- const [scope, ident] = domainId.startsWith('@')
436
- ? [domainId.slice(0, domainId.indexOf('/')), domainId.slice(domainId.indexOf('/') + 1)]
437
- : ['@aikdna', domainId];
438
- const dir = path.join(INSTALL_DIR, scope, ident);
439
- const core = readJson(path.join(dir, 'KDNA_Core.json'));
440
- const pat = readJson(path.join(dir, 'KDNA_Patterns.json'));
441
- if (!core || !pat) return null;
442
- return { id: domainId, role: d.role, required: d.required !== false, core, patterns: pat };
408
+ const loaded = loadInstalledDomain(domainId);
409
+ if (!loaded) return null;
410
+ return { id: domainId, role: d.role, required: d.required !== false, ...loaded };
443
411
  }).filter(Boolean);
444
412
  }
445
413
 
@@ -1,8 +1,9 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
- const { EXIT, error } = require('./_common');
3
+ const { EXIT } = require('./_common');
4
4
  const USER_KDNA_DIR = path.join(process.env.HOME || process.env.USERPROFILE || '.', '.kdna');
5
- const INSTALL_DIR = path.join(USER_KDNA_DIR, 'domains');
5
+ const PATHS = require('../paths');
6
+ const { listInstalled } = require('../package-store');
6
7
 
7
8
  const AGENTS = [
8
9
  { name: 'OpenCode', dir: path.join(process.env.HOME || '', '.agents'), skillsDir: 'skills' },
@@ -17,11 +18,6 @@ const AGENTS = [
17
18
  ];
18
19
 
19
20
  const V2_1_MARKER = 'kdna available';
20
-
21
- function detectAgents() {
22
- return AGENTS.filter((a) => fs.existsSync(a.dir));
23
- }
24
-
25
21
  function checkAgentSkill(agent) {
26
22
  const skillPath = path.join(agent.dir, agent.skillsDir, 'kdna-loader', 'SKILL.md');
27
23
  if (!fs.existsSync(skillPath)) return { installed: false, version: null, path: skillPath };
@@ -74,38 +70,25 @@ function cmdDoctor(args) {
74
70
  checks.push({ name: 'KDNA data directory', status: 'warn', detail: '~/.kdna/ not found' });
75
71
  }
76
72
 
77
- // 4. ~/.kdna/domains/ exists and has domains
78
- if (fs.existsSync(INSTALL_DIR)) {
79
- const domains = fs
80
- .readdirSync(INSTALL_DIR, { withFileTypes: true })
81
- .filter((d) => d.isDirectory())
82
- .reduce((acc, scopeDir) => {
83
- if (scopeDir.name.startsWith('@')) {
84
- try {
85
- return acc + fs.readdirSync(path.join(INSTALL_DIR, scopeDir.name)).length;
86
- } catch {
87
- return acc;
88
- }
89
- }
90
- return acc + 1;
91
- }, 0);
73
+ // 4. ~/.kdna/packages/ exists and has .kdna assets
74
+ if (fs.existsSync(PATHS.packages)) {
75
+ const domains = listInstalled().length;
92
76
  checks.push({
93
- name: 'Installed domains',
77
+ name: 'Installed assets',
94
78
  status: domains > 0 ? 'ok' : 'warn',
95
- detail: `${domains} domain${domains !== 1 ? 's' : ''} installed`,
79
+ detail: `${domains} .kdna asset${domains !== 1 ? 's' : ''} installed`,
96
80
  });
97
81
  } else {
98
82
  checks.push({
99
- name: 'Domains directory',
83
+ name: 'Package asset store',
100
84
  status: 'warn',
101
- detail: '~/.kdna/domains/ not found',
85
+ detail: '~/.kdna/packages/ not found',
102
86
  });
103
87
  }
104
88
  }
105
89
 
106
90
  if (!domainsOnly) {
107
91
  // 5. Agent integration check
108
- const detected = detectAgents();
109
92
  for (const agent of AGENTS) {
110
93
  const agentDirExists = fs.existsSync(agent.dir);
111
94
  const skill = agentDirExists