@aikdna/kdna-core 0.8.0 → 0.9.1

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@aikdna/kdna-core",
3
- "version": "0.8.0",
4
- "description": "KDNA core library — pure logic for loading, validating, linting, and rendering KDNA domain cognition packages. Zero Node.js dependencies.",
3
+ "version": "0.9.1",
4
+ "description": "KDNA core library — load, validate, lint, and render KDNA domain judgment assets. Supports KDNA Container format (payload.kdnab via CBOR).",
5
5
  "type": "commonjs",
6
6
  "main": "src/index.js",
7
7
  "module": "src/index.mjs",
@@ -1,8 +1,5 @@
1
1
  /**
2
2
  * KDNA Asset Reader — direct .kdna container access.
3
- *
4
- * Supports KDNA Container v2 (payload.kdnab via CBOR).
5
- * V1 plaintext containers (KDNA_Core.json etc. as ZIP entries) are rejected.
6
3
  */
7
4
 
8
5
  const fs = require('fs');
@@ -11,28 +8,25 @@ const zlib = require('zlib');
11
8
  const cbor = require('cbor-x');
12
9
  const { loadDomainFromFiles, formatContext } = require('./loader');
13
10
 
14
- const STANDARD_ENTRIES = [
15
- 'kdna.json',
16
- 'payload.kdnab',
17
- 'KDNA_Core.json',
18
- 'KDNA_Patterns.json',
19
- 'KDNA_Scenarios.json',
20
- 'KDNA_Cases.json',
21
- 'KDNA_Reasoning.json',
22
- 'KDNA_Evolution.json',
23
- ];
11
+ const KDNA_MEDIA_TYPE = 'application/vnd.aikdna.kdna+zip';
24
12
 
25
- const V1_ENTRIES = [
13
+ // Standard KDNA domain data entries — kept in lockstep with loader.FILE_MAP.
14
+ // Asset reader pre-loads these so callers don't have to enumerate entry names.
15
+ // NOTE: kdna.json / manifest.json are read separately via readManifest(); do not
16
+ // add them here. KDNA_Cluster is intentionally omitted — its schema exists but
17
+ // is not yet wired into the loader contract.
18
+ const STANDARD_ENTRIES = Object.freeze([
26
19
  'KDNA_Core.json',
27
20
  'KDNA_Patterns.json',
28
21
  'KDNA_Scenarios.json',
29
22
  'KDNA_Cases.json',
30
23
  'KDNA_Reasoning.json',
31
24
  'KDNA_Evolution.json',
32
- ];
25
+ ]);
33
26
 
27
+ // Matches any entry that holds JSON content (used to canonicalize the entry
28
+ // before hashing/signing so digests are stable across re-serialization).
34
29
  const JSON_ENTRY_RE = /\.json$/i;
35
- const KDNA_MEDIA_TYPE = 'application/vnd.aikdna.kdna+zip';
36
30
 
37
31
  function sha256Hex(buf) {
38
32
  return crypto.createHash('sha256').update(buf).digest('hex');
@@ -338,9 +332,9 @@ function validateManifestIdentity(manifest, errors, _warnings) {
338
332
  if (manifest.format && manifest.format !== 'kdna') {
339
333
  errors.push(`kdna.json.format: invalid value "${manifest.format}". Expected "kdna".`);
340
334
  }
341
- if (manifest.format_version && manifest.format_version !== '1.0') {
335
+ if (manifest.format_version && manifest.format_version !== '2.0') {
342
336
  errors.push(
343
- `kdna.json.format_version: invalid value "${manifest.format_version}". Expected "1.0".`,
337
+ `kdna.json.format_version: invalid value "${manifest.format_version}". Expected "2.0".`,
344
338
  );
345
339
  }
346
340
  if (!manifest.spec_version) errors.push('kdna.json: missing required field "spec_version"');
@@ -380,11 +374,10 @@ function readManifest(asset) {
380
374
  return parseJson(asset.readEntry('kdna.json'), 'kdna.json');
381
375
  }
382
376
 
383
- function readDataMapSync(asset, entries = STANDARD_ENTRIES, options = {}) {
377
+ function readDataMapSync(asset, options = {}) {
384
378
  const dataMap = {};
385
379
  const manifest = readManifest(asset);
386
380
 
387
- // ── KDNA Container v2: decode CBOR payload ──
388
381
  if (asset.entries.has('payload.kdnab')) {
389
382
  const payloadBuf = asset.readEntry('payload.kdnab');
390
383
  const payload = cbor.decode(payloadBuf);
@@ -396,19 +389,15 @@ function readDataMapSync(asset, entries = STANDARD_ENTRIES, options = {}) {
396
389
  if (payload.judgment.reasoning) dataMap['KDNA_Reasoning.json'] = payload.judgment.reasoning;
397
390
  if (payload.judgment.evolution) dataMap['KDNA_Evolution.json'] = payload.judgment.evolution;
398
391
  }
392
+
393
+ const encrypted = encryptedEntries(manifest);
394
+ if (encrypted.length && typeof options.decryptEntry !== 'function') {
395
+ throw new Error(`encrypted entries require decryptEntry hook: ${encrypted.join(', ')}`);
396
+ }
399
397
  return dataMap;
400
398
  }
401
399
 
402
- const encrypted = encryptedEntries(manifest).filter((entryName) => entries.includes(entryName));
403
- if (encrypted.length && typeof options.decryptEntry !== 'function') {
404
- throw new Error(`encrypted entries require decryptEntry hook: ${encrypted.join(', ')}`);
405
- }
406
- for (const entryName of entries) {
407
- if (!asset.entries.has(entryName)) continue;
408
- const buf = maybeDecryptEntrySync(asset, manifest, entryName, asset.readEntry(entryName), options);
409
- dataMap[entryName] = parseJson(buf, entryName);
410
- }
411
- return dataMap;
400
+ throw new Error('Not a KDNA asset: missing payload.kdnab');
412
401
  }
413
402
 
414
403
  function verifySync(asset, options = {}) {
@@ -418,10 +407,7 @@ function verifySync(asset, options = {}) {
418
407
 
419
408
  if (!asset.entries.has('kdna.json')) errors.push('required entry missing: kdna.json');
420
409
  verifyMediaType(asset, errors);
421
- if (!asset.entries.has('KDNA_Core.json')) errors.push('required entry missing: KDNA_Core.json');
422
- if (!asset.entries.has('KDNA_Patterns.json')) {
423
- errors.push('required entry missing: KDNA_Patterns.json');
424
- }
410
+ if (!asset.entries.has('payload.kdnab')) errors.push('required entry missing: payload.kdnab');
425
411
 
426
412
  const content_digest = buildContentDigest(asset);
427
413
  const asset_digest = asset.asset_digest;
package/src/lint-pure.js CHANGED
@@ -258,7 +258,7 @@ function lintDomain(dataMap) {
258
258
  */
259
259
  const VALID_STATUS = new Set(['draft', 'experimental', 'stable', 'deprecated', 'staging']);
260
260
  const VALID_BADGE = new Set(['untested', 'tested', 'validated', 'expert_reviewed', 'production_ready']);
261
- const VALID_ACCESS = new Set(['open', 'licensed', 'runtime']);
261
+ const VALID_ACCESS = new Set(['public', 'licensed', 'remote']);
262
262
  const VALID_RISK = new Set(['R0', 'R1', 'R2', 'R3']);
263
263
  const VALID_I18N = new Set(['L0', 'L1', 'L2', 'L3']);
264
264
  const VALID_PRIVACY = new Set(['public', 'private', 'sensitive', 'regulated']);
@@ -318,9 +318,9 @@ function validateManifest(manifest) {
318
318
  if (manifest.format && manifest.format !== 'kdna') {
319
319
  errors.push(`kdna.json.format: invalid value "${manifest.format}". Expected "kdna".`);
320
320
  }
321
- if (manifest.format_version && manifest.format_version !== '1.0') {
321
+ if (manifest.format_version && manifest.format_version !== '2.0') {
322
322
  errors.push(
323
- `kdna.json.format_version: invalid value "${manifest.format_version}". Expected "1.0".`,
323
+ `kdna.json.format_version: invalid value "${manifest.format_version}". Expected "2.0".`,
324
324
  );
325
325
  }
326
326
  if (manifest.status && !VALID_STATUS.has(manifest.status)) {
package/src/types.d.ts CHANGED
@@ -204,14 +204,14 @@ export interface KDNAFileDataMap {
204
204
 
205
205
  export interface KDNAManifest {
206
206
  format: 'kdna';
207
- format_version: '1.0';
207
+ format_version: '2.0';
208
208
  spec_version: string;
209
209
  name: string;
210
210
  version: string;
211
211
  judgment_version: string;
212
212
  status: 'draft' | 'experimental' | 'stable' | 'deprecated' | 'staging';
213
213
  quality_badge: 'untested' | 'tested' | 'validated' | 'expert_reviewed' | 'production_ready';
214
- access: 'open' | 'licensed' | 'runtime';
214
+ access: 'public' | 'licensed' | 'remote';
215
215
  language?: string;
216
216
  default_language: string;
217
217
  languages: string[];
@@ -25,7 +25,7 @@ const WORK_PACK_SCHEMA = {
25
25
  version: { type: 'string', pattern: '^\\d+\\.\\d+\\.\\d+(-[a-zA-Z0-9.]+)?(\\+[a-zA-Z0-9.]+)?$' },
26
26
  description: { type: 'string', maxLength: 280 },
27
27
  status: { type: 'string', enum: ['draft', 'experimental', 'stable', 'deprecated'] },
28
- access: { type: 'string', enum: ['open', 'licensed', 'runtime', 'enterprise', 'partner'], default: 'open' },
28
+ access: { type: 'string', enum: ['public', 'licensed', 'remote', 'enterprise', 'partner'], default: 'public' },
29
29
  license: { type: 'string', default: 'Apache-2.0' },
30
30
  kdna: {
31
31
  type: 'object',
@@ -179,7 +179,7 @@ function inspectWorkPack(manifest, rootDir) {
179
179
  version: manifest.version,
180
180
  description: manifest.description,
181
181
  status: manifest.status,
182
- access: manifest.access || 'open',
182
+ access: manifest.access || 'public',
183
183
  license: manifest.license || 'Apache-2.0',
184
184
  format_version: manifest.format_version,
185
185
  kdna: {