@aikdna/kdna-cli 0.17.0 → 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');
@@ -39,6 +37,9 @@ const {
39
37
  cmdLicenseBind,
40
38
  cmdLicenseShow,
41
39
  cmdLicenseInstall,
40
+ cmdLicenseStatus,
41
+ cmdLicenseActivate,
42
+ cmdLicenseSync,
42
43
  } = require('./cmds/license');
43
44
  const { cmdPreview, cmdProject, cmdEval, cmdExport, cmdDemo } = require('./cmds/legacy');
44
45
  const {
@@ -58,7 +59,8 @@ const {
58
59
  cmdEvolution,
59
60
  cmdRegression,
60
61
  } = require('./cmds/governance');
61
- const { cmdBadgeCompute, cmdRegistryAudit, cmdPackage } = require('./cmds/badge');
62
+ const { cmdBadgeCompute, cmdRegistryAudit } = require('./cmds/badge');
63
+ const { cmdExplain } = require('./cmds/explain');
62
64
 
63
65
  // ─── Main ─────────────────────────────────────────────────────────────
64
66
 
@@ -80,15 +82,14 @@ Usage: kdna <command> [options]
80
82
 
81
83
  Domain Authoring:
82
84
  init <name> Scaffold a new domain from template
83
- validate <path> Validate domain structure
84
- validate --schema <path> Schema-only validation
85
- pack <path> Pack into .kdna container
86
- pack <path> --encrypt --license <file> Pack encrypted .kdnae container
87
- unpack <file> Unpack .kdna container
88
- unpack <file> --license <file> Unpack encrypted .kdnae container
89
- inspect <path> Inspect domain or .kdna file
90
- inspect <path> --locale zh-CN Inspect with localized governance data
91
- 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
92
93
  publish <path> Pack + sign + publish
93
94
  publish --check <path> Quality gate check only
94
95
  version bump <level> [path] Bump domain version
@@ -106,18 +107,18 @@ Agent Runtime:
106
107
  available [--json] List installed domains with v2.1 fields
107
108
  match "<task>" [--json] Signal matching — find relevant domains
108
109
  select --input "..." [--json] Selection policy — decide which domains to load
109
- load <name> [--as=prompt|json|raw] Emit domain in agent-ready format
110
- 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)
111
112
  postvalidate <name> --output <file> Post-generation judgment check
112
113
 
113
114
  Testing & Verification:
114
- verify <name> 3-layer: structure + trust + judgment
115
- verify <name> --i18n I18N verification: locales, overlays, card completeness
116
- verify <name> --governance Governance verification: risk_level, KDNA_CARD, provenance
117
- verify <name> --judgment --run-tests Judgment validation with eval cases
118
- compare <name> --input "..." With/without KDNA reasoning diff
119
- compare <name> --input "..." --report-md Markdown report format
120
- 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
121
122
  diff <name>@<v1> <name>@<v2> Judgment-level diff between versions
122
123
  test run <name> --input <file> Record test result against domain
123
124
  test import <run> --as-eval Convert test result to eval card
@@ -148,6 +149,7 @@ Quality & Distribution (Phase 7):
148
149
 
149
150
  Registry & Distribution:
150
151
  install <name> Install domain from registry
152
+ install <file.kdna> Install a local .kdna asset
151
153
  remove <name> Uninstall a domain
152
154
  update <name> Update installed domain
153
155
  info <name> Show domain metadata and trust status
@@ -172,9 +174,12 @@ Trace & Diagnostics:
172
174
  License & Authorization:
173
175
  license generate <domain> --to <email> Generate signed license
174
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
175
179
  license verify <license.json> Verify license signature
176
180
  license bind <license.json> Bind license to this machine
177
181
  license show <license.json> Display license details
182
+ license status [domain] [--json] Show installed license activation status
178
183
 
179
184
  Flags:
180
185
  --json Structured JSON output (machine-readable)
@@ -190,41 +195,69 @@ Exit Codes:
190
195
  const cmd = args[0];
191
196
 
192
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
+ }
193
251
  case 'validate': {
194
- const schemaFlag = args.includes('--schema');
195
- const jsonFlag = args.includes('--json');
196
- const target = args.filter((a, i) => i > 0 && a !== '--schema' && a !== '--json')[0];
197
- if (!target) error('Usage: kdna validate <path>');
198
- cmdValidate(target, schemaFlag, jsonFlag);
252
+ error('Directory validation is a dev-only operation. Use: kdna dev validate <source-dir>', EXIT.INPUT_ERROR);
199
253
  break;
200
254
  }
201
255
  case 'pack': {
202
- let output = null;
203
- let target = null;
204
- for (let i = 1; i < args.length; i++) {
205
- if (args[i] === '--output' || args[i] === '-o') {
206
- output = args[i + 1];
207
- i++;
208
- } else if (!target) {
209
- target = args[i];
210
- }
211
- }
212
- if (!target) error('Usage: kdna pack <path>');
213
- if (args.includes('--encrypt')) {
214
- cmdPackEncrypt(target, args);
215
- } else {
216
- cmdPack(target, output);
217
- }
256
+ error('Directory packaging is a dev-only operation. Use: kdna dev pack <source-dir>', EXIT.INPUT_ERROR);
218
257
  break;
219
258
  }
220
259
  case 'unpack': {
221
- const target = args[1];
222
- if (!target) error('Usage: kdna unpack <file.kdna|file.kdnae>');
223
- if (target.endsWith('.kdnae')) {
224
- cmdUnpackEncrypt(target, args);
225
- } else {
226
- cmdUnpack(target, args.includes('--force'));
227
- }
260
+ error('Unpacking exposes internal files and is dev-only. Use: kdna dev unpack <file.kdna>', EXIT.INPUT_ERROR);
228
261
  break;
229
262
  }
230
263
  case 'preview': {
@@ -242,7 +275,7 @@ switch (cmd) {
242
275
  domainId = args[i];
243
276
  }
244
277
  }
245
- if (!domainId) error('Usage: kdna install <domain-id|github:user/repo|./folder>');
278
+ if (!domainId) error('Usage: kdna install <domain-id|file.kdna>');
246
279
 
247
280
  const { cmdInstallExtended } = require('./install');
248
281
  if (fromGit) {
@@ -285,7 +318,7 @@ switch (cmd) {
285
318
  }
286
319
  case 'inspect': {
287
320
  const target = args.filter((a) => !a.startsWith('--'))[1];
288
- if (!target) error('Usage: kdna inspect <path> [--json] [--locale zh-CN]');
321
+ if (!target) error('Usage: kdna inspect <file.kdna> [--json] [--locale zh-CN]');
289
322
  const localeIdx = args.indexOf('--locale');
290
323
  const locale = localeIdx >= 0 ? args[localeIdx + 1] : null;
291
324
  cmdInspect(target, args.includes('--json'), locale);
@@ -293,7 +326,7 @@ switch (cmd) {
293
326
  }
294
327
  case 'card': {
295
328
  const target = args.filter((a) => !a.startsWith('--'))[1];
296
- if (!target) error('Usage: kdna card <path> [--json] [--locale zh-CN]');
329
+ if (!target) error('Usage: kdna card <file.kdna> [--json] [--locale zh-CN]');
297
330
  const localeIdx = args.indexOf('--locale');
298
331
  const locale = localeIdx >= 0 ? args[localeIdx + 1] : null;
299
332
  cmdCard(target, args.includes('--json'), locale);
@@ -305,10 +338,10 @@ switch (cmd) {
305
338
  if (!target) {
306
339
  error(
307
340
  'Usage:\n' +
308
- ' kdna verify <name> Run all three layers (structure / trust / judgment)\n' +
309
- ' kdna verify <name> --structure Files + schema only\n' +
310
- ' kdna verify <name> --trust Signature + scope + Ed25519 only\n' +
311
- ' 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',
312
345
  );
313
346
  }
314
347
  cmdVerify(target, args);
@@ -430,9 +463,7 @@ switch (cmd) {
430
463
  break;
431
464
  }
432
465
  case 'package': {
433
- const target = args.filter((a) => !a.startsWith('--'))[1];
434
- if (!target) error('Usage: kdna package <domain> --format=kdna');
435
- cmdPackage(target, args);
466
+ error('Directory packaging is a dev-only operation. Use: kdna dev pack <source-dir>', EXIT.INPUT_ERROR);
436
467
  break;
437
468
  }
438
469
  // Legacy (removed) commands
@@ -452,6 +483,10 @@ switch (cmd) {
452
483
  cmdDemo();
453
484
  break;
454
485
  }
486
+ case 'explain': {
487
+ cmdExplain(args);
488
+ break;
489
+ }
455
490
  case 'list': {
456
491
  const localeIdx = args.indexOf('--locale');
457
492
  const locale = localeIdx >= 0 ? args[localeIdx + 1] : null;
@@ -491,14 +526,23 @@ switch (cmd) {
491
526
  cmdLicenseShow(rest);
492
527
  } else if (sub === 'install') {
493
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));
494
535
  } else {
495
536
  error(
496
537
  'Usage:\n' +
497
538
  ' kdna license generate <domain> --to <email> [--expires <date>]\n' +
498
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' +
499
542
  ' kdna license verify <license.json>\n' +
500
543
  ' kdna license bind <license.json>\n' +
501
- ' kdna license show <license.json>',
544
+ ' kdna license show <license.json>\n' +
545
+ ' kdna license status [domain] [--json]',
502
546
  EXIT.INPUT_ERROR,
503
547
  );
504
548
  }
@@ -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