@aikdna/kdna-core 0.17.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.
- package/CHANGELOG.md +227 -64
- package/README.md +114 -77
- package/package.json +8 -2
- package/schema/agent-host-capabilities.schema.json +62 -0
- package/schema/agent-host-receipt.schema.json +371 -0
- package/schema/agent-host-request.schema.json +223 -0
- package/schema/{bundle-profile-v1.schema.json → bundle-profile.schema.json} +9 -5
- package/schema/checksums.schema.json +42 -3
- package/schema/consumption-plan.schema.json +428 -0
- package/schema/digest-evidence.schema.json +212 -0
- package/schema/{kdna-envelope-external-grant-v1.schema.json → external-grant-envelope.schema.json} +17 -4
- package/schema/{kdna-key-grant-v1.schema.json → external-key-grant.schema.json} +39 -7
- package/schema/judgment-trace.schema.json +1251 -0
- package/schema/load-plan.schema.json +7 -5
- package/schema/manifest.schema.json +70 -10
- package/schema/{payload-profile-v1.schema.json → payload-profile.schema.json} +30 -6
- package/schema/runtime-capsule.schema.json +116 -0
- package/src/asset-reader.js +106 -120
- package/src/{v1 → container}/index.js +566 -209
- package/src/container/index.mjs +20 -0
- package/src/container-dispatcher.js +10 -7
- package/src/crypto-profile.js +37 -107
- package/src/external-key-grant.js +41 -15
- package/src/index.js +11 -4
- package/src/index.mjs +143 -24
- package/src/loader-compatibility.js +59 -0
- package/src/loader.js +1 -1
- package/src/public-api.js +59 -163
- package/src/remote-runtime.d.ts +13 -0
- package/src/remote-runtime.js +27 -0
- package/src/remote-runtime.mjs +3 -0
- package/src/runtime-api.js +9 -10
- package/src/runtime-capsule.js +529 -0
- package/src/runtime-contract.js +1882 -0
- package/src/types.d.ts +1127 -136
- package/src/workpack-pure.js +1 -1
- package/src/lint-pure.js +0 -430
- package/src/v1/index.mjs +0 -20
package/src/index.mjs
CHANGED
|
@@ -10,10 +10,9 @@ export {
|
|
|
10
10
|
formatContext,
|
|
11
11
|
} from './loader.js';
|
|
12
12
|
|
|
13
|
-
export { lintDomain } from './lint-pure.js';
|
|
14
|
-
|
|
15
13
|
export {
|
|
16
14
|
MIMETYPE,
|
|
15
|
+
KDNA_LOADER_VERSION,
|
|
17
16
|
REQUIRED_DIR_ENTRIES,
|
|
18
17
|
isKdnaSourceDir,
|
|
19
18
|
detectContainerFormat,
|
|
@@ -23,12 +22,17 @@ export {
|
|
|
23
22
|
buildChecksums,
|
|
24
23
|
pack,
|
|
25
24
|
unpack,
|
|
26
|
-
buildCapsule,
|
|
27
25
|
FORBIDDEN_OUTPUT_TERMS,
|
|
28
26
|
parseSemver,
|
|
29
27
|
compareSemver,
|
|
30
28
|
satisfies,
|
|
31
|
-
} from './
|
|
29
|
+
} from './container/index.js';
|
|
30
|
+
|
|
31
|
+
import loaderCompatibility from './loader-compatibility.js';
|
|
32
|
+
export const STRICT_LOADER_VERSION = loaderCompatibility.STRICT_LOADER_VERSION;
|
|
33
|
+
export const parseLoaderVersion = loaderCompatibility.parseLoaderVersion;
|
|
34
|
+
export const compareLoaderVersions = loaderCompatibility.compareLoaderVersions;
|
|
35
|
+
export const assessLoaderCompatibility = loaderCompatibility.assessLoaderCompatibility;
|
|
32
36
|
|
|
33
37
|
import runtimeApi from './runtime-api.js';
|
|
34
38
|
export const planLoad = runtimeApi.planLoad;
|
|
@@ -40,30 +44,145 @@ export { validateDomainSchema, validateCrossFile } from './validate-pure.js';
|
|
|
40
44
|
|
|
41
45
|
export { renderPreviewHTML, escHtml, renderCard } from './render.js';
|
|
42
46
|
|
|
43
|
-
export {
|
|
47
|
+
export {
|
|
48
|
+
composeContext,
|
|
49
|
+
composeContextWithAttribution,
|
|
50
|
+
classifySignals,
|
|
51
|
+
classifySignalsAcrossDomains,
|
|
52
|
+
composeChecks,
|
|
53
|
+
loadAndCompose,
|
|
54
|
+
loadCluster,
|
|
55
|
+
detectDomainConflicts,
|
|
56
|
+
generateClusterTrace,
|
|
57
|
+
} from './compose.js';
|
|
44
58
|
|
|
45
59
|
import assetReader from './asset-reader.js';
|
|
46
60
|
import cryptoProfile from './crypto-profile.js';
|
|
47
61
|
import externalKeyGrant from './external-key-grant.js';
|
|
62
|
+
import publicApi from './public-api.js';
|
|
63
|
+
import workpackPure from './workpack-pure.js';
|
|
64
|
+
import runtimeCapsule from './runtime-capsule.js';
|
|
65
|
+
import runtimeContract from './runtime-contract.js';
|
|
66
|
+
|
|
67
|
+
export const openKDNA = publicApi.openKDNA;
|
|
68
|
+
export const openKDNASync = publicApi.openKDNASync;
|
|
69
|
+
export const inspectKDNA = publicApi.inspectKDNA;
|
|
70
|
+
export const inspectKDNASync = publicApi.inspectKDNASync;
|
|
71
|
+
export const loadKDNA = publicApi.loadKDNA;
|
|
72
|
+
export const loadKDNASync = publicApi.loadKDNASync;
|
|
73
|
+
export const validateKDNA = publicApi.validateKDNA;
|
|
74
|
+
export const validateKDNASync = publicApi.validateKDNASync;
|
|
75
|
+
export const renderForAgent = publicApi.renderForAgent;
|
|
76
|
+
export const renderForAgentSync = publicApi.renderForAgentSync;
|
|
77
|
+
export const verifyAsset = publicApi.verifyAsset;
|
|
78
|
+
export const verifyAssetSync = publicApi.verifyAssetSync;
|
|
79
|
+
export const verifyDigest = publicApi.verifyDigest;
|
|
80
|
+
export const verifyDigestSync = publicApi.verifyDigestSync;
|
|
81
|
+
export const verifySignature = publicApi.verifySignature;
|
|
82
|
+
export const verifySignatureSync = publicApi.verifySignatureSync;
|
|
83
|
+
export const matchDomain = publicApi.matchDomain;
|
|
84
|
+
export const matchDomainSync = publicApi.matchDomainSync;
|
|
85
|
+
export const composeKDNA = publicApi.composeKDNA;
|
|
86
|
+
|
|
87
|
+
export const DIGEST_PROFILE = runtimeCapsule.DIGEST_PROFILE;
|
|
88
|
+
export const DIGEST_PROFILE_VERSION = runtimeCapsule.DIGEST_PROFILE_VERSION;
|
|
89
|
+
export const CAPSULE_DIGEST_PROFILE = runtimeCapsule.CAPSULE_DIGEST_PROFILE;
|
|
90
|
+
export const CANONICALIZATION_PROFILE_VERSION = runtimeCapsule.CANONICALIZATION_PROFILE_VERSION;
|
|
91
|
+
export const RUNTIME_CAPSULE_CONTRACT_VERSION = runtimeCapsule.RUNTIME_CAPSULE_CONTRACT_VERSION;
|
|
92
|
+
export const BASIS = runtimeCapsule.BASIS;
|
|
93
|
+
export const computeAssetDigest = runtimeCapsule.computeAssetDigest;
|
|
94
|
+
export const computeRuntimeEntrySetDigest = runtimeCapsule.computeRuntimeEntrySetDigest;
|
|
95
|
+
export const computeDigestEvidence = runtimeCapsule.computeDigestEvidence;
|
|
96
|
+
export const canonicalizeJcs = runtimeCapsule.canonicalizeJcs;
|
|
97
|
+
export const computeCapsuleDeliveryDigest = runtimeCapsule.computeCapsuleDeliveryDigest;
|
|
98
|
+
export const buildRuntimeCapsule = runtimeCapsule.buildRuntimeCapsule;
|
|
99
|
+
export const loadRuntimeCapsule = runtimeCapsule.loadRuntimeCapsule;
|
|
100
|
+
|
|
101
|
+
export const KDNARuntimeContractError = runtimeContract.KDNARuntimeContractError;
|
|
102
|
+
export const PLAN_DIGEST_PROFILE = runtimeContract.PLAN_DIGEST_PROFILE;
|
|
103
|
+
export const PLAN_DIGEST_PROFILE_VERSION = runtimeContract.PLAN_DIGEST_PROFILE_VERSION;
|
|
104
|
+
export const HOST_PROTOCOL = runtimeContract.HOST_PROTOCOL;
|
|
105
|
+
export const HOST_PROTOCOL_VERSION = runtimeContract.HOST_PROTOCOL_VERSION;
|
|
106
|
+
export const DEFAULT_CORE_CAPSULE_CONTRACT_VERSIONS =
|
|
107
|
+
runtimeContract.DEFAULT_CORE_CAPSULE_CONTRACT_VERSIONS;
|
|
108
|
+
export const parseRuntimeContractJson = runtimeContract.parseRuntimeContractJson;
|
|
109
|
+
export const computeConsumptionPlanDigest = runtimeContract.computeConsumptionPlanDigest;
|
|
110
|
+
export const buildConsumptionPlan = runtimeContract.buildConsumptionPlan;
|
|
111
|
+
export const validateConsumptionPlan = runtimeContract.validateConsumptionPlan;
|
|
112
|
+
export const negotiateRuntimePair = runtimeContract.negotiateRuntimePair;
|
|
113
|
+
export const buildAgentHostRequest = runtimeContract.buildAgentHostRequest;
|
|
114
|
+
export const validateAgentHostRequest = runtimeContract.validateAgentHostRequest;
|
|
115
|
+
export const validateAgentHostReceipt = runtimeContract.validateAgentHostReceipt;
|
|
116
|
+
export const deriveBudgetEvidence = runtimeContract.deriveBudgetEvidence;
|
|
117
|
+
export const buildPreHostBudgetBlockedTrace =
|
|
118
|
+
runtimeContract.buildPreHostBudgetBlockedTrace;
|
|
119
|
+
export const validatePreHostBudgetBlockedTrace =
|
|
120
|
+
runtimeContract.validatePreHostBudgetBlockedTrace;
|
|
121
|
+
export const buildJudgmentTrace = runtimeContract.buildJudgmentTrace;
|
|
122
|
+
export const validateJudgmentTrace = runtimeContract.validateJudgmentTrace;
|
|
48
123
|
|
|
49
124
|
export const STANDARD_ENTRIES = assetReader.STANDARD_ENTRIES;
|
|
50
125
|
export const createKdnaAssetReader = assetReader.createKdnaAssetReader;
|
|
51
|
-
|
|
52
|
-
export const
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
126
|
+
|
|
127
|
+
export const {
|
|
128
|
+
LICENSED_ENTRY_PROFILE,
|
|
129
|
+
PASSWORD_PROTECTED_PROFILE,
|
|
130
|
+
PASSWORD_PROTECTED_SCRYPT_PROFILE,
|
|
131
|
+
ENCRYPTION_PROFILE_VERSION,
|
|
132
|
+
ALG,
|
|
133
|
+
RFC_KDF,
|
|
134
|
+
RFC_KEY_WRAPPING,
|
|
135
|
+
PASSWORD_KDF,
|
|
136
|
+
SCRYPT_KDF,
|
|
137
|
+
deriveWrappingKey,
|
|
138
|
+
generateCEK,
|
|
139
|
+
wrapCEK,
|
|
140
|
+
unwrapCEK,
|
|
141
|
+
encryptLicensedEntry,
|
|
142
|
+
decryptLicensedEntry,
|
|
143
|
+
derivePasswordKey,
|
|
144
|
+
generateRecoveryCode,
|
|
145
|
+
decodeRecoveryCode,
|
|
146
|
+
encryptProtectedEntry,
|
|
147
|
+
decryptProtectedEntry,
|
|
148
|
+
createPasswordDecryptEntry,
|
|
149
|
+
createRecoveryDecryptEntry,
|
|
150
|
+
derivePasswordKeyScrypt,
|
|
151
|
+
encryptProtectedEntryScrypt,
|
|
152
|
+
decryptProtectedEntryScrypt,
|
|
153
|
+
createPasswordDecryptEntryScrypt,
|
|
154
|
+
createLicensedDecryptEntry,
|
|
155
|
+
hkdfSha256,
|
|
156
|
+
aesWrap,
|
|
157
|
+
aesUnwrap,
|
|
158
|
+
} = cryptoProfile;
|
|
159
|
+
|
|
160
|
+
export const {
|
|
161
|
+
EXTERNAL_ENVELOPE_PROFILE,
|
|
162
|
+
EXTERNAL_GRANT_PROFILE,
|
|
163
|
+
EXTERNAL_AAD_PROFILE,
|
|
164
|
+
DEVICE_KEK_PROFILE,
|
|
165
|
+
EXTERNAL_GRANT_CONTRACT_VERSION,
|
|
166
|
+
KDNAExternalGrantError,
|
|
167
|
+
canonicalJson,
|
|
168
|
+
grantSigningPayload,
|
|
169
|
+
validateExternalEnvelope,
|
|
170
|
+
validateExternalKeyGrant,
|
|
171
|
+
externalEnvelopeAad,
|
|
172
|
+
deriveExternalAssetCek,
|
|
173
|
+
encodeExternalEnvelope,
|
|
174
|
+
decodeExternalEnvelope,
|
|
175
|
+
encryptExternalGrantEntry,
|
|
176
|
+
generateDeviceKeyPairs,
|
|
177
|
+
createExternalKeyGrant,
|
|
178
|
+
authorizeExternalKeyGrant,
|
|
179
|
+
isVerifiedExternalEntitlement,
|
|
180
|
+
} = externalKeyGrant;
|
|
181
|
+
|
|
182
|
+
export const {
|
|
183
|
+
WORK_PACK_SCHEMA,
|
|
184
|
+
validateWorkPackManifest,
|
|
185
|
+
checkWorkPackStructure,
|
|
186
|
+
inspectWorkPack,
|
|
187
|
+
loadWorkPack,
|
|
188
|
+
} = workpackPure;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { version: KDNA_LOADER_VERSION } = require('../package.json');
|
|
4
|
+
|
|
5
|
+
const STRICT_LOADER_VERSION = /^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$/u;
|
|
6
|
+
|
|
7
|
+
function parseLoaderVersion(value) {
|
|
8
|
+
if (typeof value !== 'string') return null;
|
|
9
|
+
const match = STRICT_LOADER_VERSION.exec(value);
|
|
10
|
+
return match ? Object.freeze(match.slice(1)) : null;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function compareNumericIdentifier(left, right) {
|
|
14
|
+
if (left.length !== right.length) return left.length < right.length ? -1 : 1;
|
|
15
|
+
if (left === right) return 0;
|
|
16
|
+
return left < right ? -1 : 1;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function compareLoaderVersions(leftVersion, rightVersion) {
|
|
20
|
+
const left = parseLoaderVersion(leftVersion);
|
|
21
|
+
const right = parseLoaderVersion(rightVersion);
|
|
22
|
+
if (!left || !right) {
|
|
23
|
+
throw new TypeError('loader versions must use strict x.y.z SemVer without leading zeros');
|
|
24
|
+
}
|
|
25
|
+
for (let index = 0; index < 3; index += 1) {
|
|
26
|
+
const comparison = compareNumericIdentifier(left[index], right[index]);
|
|
27
|
+
if (comparison !== 0) return comparison;
|
|
28
|
+
}
|
|
29
|
+
return 0;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (!parseLoaderVersion(KDNA_LOADER_VERSION)) {
|
|
33
|
+
throw new Error(`@aikdna/kdna-core package version is not a strict loader coordinate: ${KDNA_LOADER_VERSION}`);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function assessLoaderCompatibility(manifest) {
|
|
37
|
+
const requiredValue = manifest?.compatibility?.min_loader_version;
|
|
38
|
+
const required = parseLoaderVersion(requiredValue);
|
|
39
|
+
return Object.freeze({
|
|
40
|
+
loader_version: KDNA_LOADER_VERSION,
|
|
41
|
+
min_loader_version: typeof requiredValue === 'string' ? requiredValue : null,
|
|
42
|
+
loader_compatible: required
|
|
43
|
+
? compareLoaderVersions(requiredValue, KDNA_LOADER_VERSION) <= 0
|
|
44
|
+
: null,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function loaderVersionUnsupportedMessage(requiredVersion) {
|
|
49
|
+
return `KDNA_LOADER_VERSION_UNSUPPORTED: asset requires loader ${requiredVersion}, current loader is ${KDNA_LOADER_VERSION}`;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
module.exports = {
|
|
53
|
+
KDNA_LOADER_VERSION,
|
|
54
|
+
STRICT_LOADER_VERSION,
|
|
55
|
+
parseLoaderVersion,
|
|
56
|
+
compareLoaderVersions,
|
|
57
|
+
assessLoaderCompatibility,
|
|
58
|
+
loaderVersionUnsupportedMessage,
|
|
59
|
+
};
|
package/src/loader.js
CHANGED
|
@@ -157,7 +157,7 @@ function detectOldFieldNames(obj, path = '', warnings = []) {
|
|
|
157
157
|
for (const key of Object.keys(obj)) {
|
|
158
158
|
if (FIELD_ALIASES[key]) {
|
|
159
159
|
warnings.push(
|
|
160
|
-
`[KDNA LOADER] ${path}.${key}: field "${key}" is not in spec
|
|
160
|
+
`[KDNA LOADER] ${path}.${key}: field "${key}" is not in spec 0.4. Use "${FIELD_ALIASES[key]}" instead. See docs/authoring-guide.md §0.`,
|
|
161
161
|
);
|
|
162
162
|
}
|
|
163
163
|
if (typeof obj[key] === 'object' && obj[key] !== null) {
|
package/src/public-api.js
CHANGED
|
@@ -1,22 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Compatibility names for the stable current KDNA Runtime API.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* These names previously implemented a second legacy source-tree validator and
|
|
5
|
+
* loader. They now route to the same current inspect/validate/LoadPlan/Capsule
|
|
6
|
+
* implementation as the unversioned package API. No current payload is
|
|
7
|
+
* reverse-projected into KDNA_Core.json or KDNA_Patterns.json.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
+
const fs = require('fs');
|
|
10
11
|
const { createKdnaAssetReader } = require('./asset-reader');
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
const { formatContext } = require('./loader');
|
|
14
|
-
const {
|
|
15
|
-
composeContextWithAttribution,
|
|
16
|
-
detectDomainConflicts,
|
|
17
|
-
classifySignalsAcrossDomains,
|
|
18
|
-
generateClusterTrace,
|
|
19
|
-
} = require('./compose');
|
|
12
|
+
const container = require('./container');
|
|
13
|
+
const runtimeApi = require('./runtime-api');
|
|
20
14
|
|
|
21
15
|
function readerFrom(options = {}) {
|
|
22
16
|
return options.reader || createKdnaAssetReader();
|
|
@@ -26,6 +20,18 @@ function isAsset(value) {
|
|
|
26
20
|
return value && typeof value === 'object' && value.entries instanceof Map && typeof value.readEntry === 'function';
|
|
27
21
|
}
|
|
28
22
|
|
|
23
|
+
const ASSET_SOURCE_BYTES = Symbol.for('@aikdna/kdna-core.asset-source-bytes');
|
|
24
|
+
|
|
25
|
+
function canonicalBytes(input) {
|
|
26
|
+
if (Buffer.isBuffer(input)) return input;
|
|
27
|
+
if (input instanceof Uint8Array) return Buffer.from(input);
|
|
28
|
+
if (typeof input === 'string') return fs.readFileSync(input);
|
|
29
|
+
if (isAsset(input) && Buffer.isBuffer(input[ASSET_SOURCE_BYTES])) {
|
|
30
|
+
return input[ASSET_SOURCE_BYTES];
|
|
31
|
+
}
|
|
32
|
+
throw new Error('KDNA operation expects a .kdna path, Buffer, Uint8Array, or asset opened by openKDNA');
|
|
33
|
+
}
|
|
34
|
+
|
|
29
35
|
async function asAsset(input, options = {}) {
|
|
30
36
|
if (isAsset(input)) return input;
|
|
31
37
|
return readerFrom(options).open(input);
|
|
@@ -47,156 +53,69 @@ function openKDNASync(input, options = {}) {
|
|
|
47
53
|
async function inspectKDNA(input, options = {}) {
|
|
48
54
|
const reader = readerFrom(options);
|
|
49
55
|
const asset = await asAsset(input, { ...options, reader });
|
|
50
|
-
const
|
|
56
|
+
const current = container.inspect(canonicalBytes(asset), options);
|
|
57
|
+
const manifest = await reader.readManifest(asset);
|
|
58
|
+
const entries = await reader.listEntries(asset);
|
|
59
|
+
const contentDigest = await reader.contentDigest(asset);
|
|
51
60
|
const verification = options.verify === false ? null : await reader.verify(asset, options);
|
|
52
61
|
return {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
status: profile.manifest.status || null,
|
|
58
|
-
quality_badge: profile.manifest.quality_badge || null,
|
|
59
|
-
risk_level: profile.manifest.risk_level || null,
|
|
60
|
-
keywords: profile.keywords,
|
|
61
|
-
entries: profile.entries,
|
|
62
|
-
asset_digest: profile.asset_digest,
|
|
63
|
-
content_digest: profile.content_digest,
|
|
62
|
+
...current,
|
|
63
|
+
entries,
|
|
64
|
+
asset_digest: asset.asset_digest,
|
|
65
|
+
content_digest: contentDigest,
|
|
64
66
|
signature_valid: verification ? verification.signature_valid : null,
|
|
65
67
|
ok: verification ? verification.ok : null,
|
|
66
68
|
errors: verification ? verification.errors : [],
|
|
67
69
|
warnings: verification ? verification.warnings : [],
|
|
68
|
-
manifest
|
|
70
|
+
manifest,
|
|
69
71
|
};
|
|
70
72
|
}
|
|
71
73
|
|
|
72
74
|
function inspectKDNASync(input, options = {}) {
|
|
73
75
|
const reader = readerFrom(options);
|
|
74
76
|
const asset = asAssetSync(input, { ...options, reader });
|
|
75
|
-
const
|
|
77
|
+
const current = container.inspect(canonicalBytes(asset), options);
|
|
78
|
+
const manifest = reader.readManifestSync(asset);
|
|
79
|
+
const entries = reader.listEntriesSync(asset);
|
|
80
|
+
const contentDigest = reader.contentDigestSync(asset);
|
|
76
81
|
const verification = options.verify === false ? null : reader.verifySync(asset, options);
|
|
77
82
|
return {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
status: profile.manifest.status || null,
|
|
83
|
-
quality_badge: profile.manifest.quality_badge || null,
|
|
84
|
-
risk_level: profile.manifest.risk_level || null,
|
|
85
|
-
keywords: profile.keywords,
|
|
86
|
-
entries: profile.entries,
|
|
87
|
-
asset_digest: profile.asset_digest,
|
|
88
|
-
content_digest: profile.content_digest,
|
|
83
|
+
...current,
|
|
84
|
+
entries,
|
|
85
|
+
asset_digest: asset.asset_digest,
|
|
86
|
+
content_digest: contentDigest,
|
|
89
87
|
signature_valid: verification ? verification.signature_valid : null,
|
|
90
88
|
ok: verification ? verification.ok : null,
|
|
91
89
|
errors: verification ? verification.errors : [],
|
|
92
90
|
warnings: verification ? verification.warnings : [],
|
|
93
|
-
manifest
|
|
91
|
+
manifest,
|
|
94
92
|
};
|
|
95
93
|
}
|
|
96
94
|
|
|
97
95
|
async function loadKDNA(input, options = {}) {
|
|
98
|
-
|
|
99
|
-
const asset = await asAsset(input, { ...options, reader });
|
|
100
|
-
return reader.loadProfile(asset, options.profile || 'compact', options);
|
|
96
|
+
return runtimeApi.loadAuthorized(isAsset(input) ? canonicalBytes(input) : input, options);
|
|
101
97
|
}
|
|
102
98
|
|
|
103
99
|
function loadKDNASync(input, options = {}) {
|
|
104
|
-
|
|
105
|
-
const asset = asAssetSync(input, { ...options, reader });
|
|
106
|
-
return reader.loadProfileSync(asset, options.profile || 'compact', options);
|
|
100
|
+
return runtimeApi.loadAuthorized(isAsset(input) ? canonicalBytes(input) : input, options);
|
|
107
101
|
}
|
|
108
102
|
|
|
109
103
|
async function validateKDNA(input, options = {}) {
|
|
110
|
-
|
|
111
|
-
const asset = await asAsset(input, { ...options, reader });
|
|
112
|
-
const assetResult = await reader.verify(asset, options);
|
|
113
|
-
let dataMap;
|
|
114
|
-
let lintResult = { errors: [], warnings: [] };
|
|
115
|
-
let schemaResult = { errors: [], warnings: [] };
|
|
116
|
-
let crossFileResult = { errors: [], warnings: [] };
|
|
117
|
-
|
|
118
|
-
try {
|
|
119
|
-
dataMap = await reader.readDataMap(asset, undefined, options);
|
|
120
|
-
lintResult = lintDomain(dataMap);
|
|
121
|
-
schemaResult = validateDomainSchema(dataMap, options.schemas || {});
|
|
122
|
-
crossFileResult = validateCrossFile(dataMap);
|
|
123
|
-
} catch (e) {
|
|
124
|
-
lintResult.errors.push(e.message);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
const errors = [
|
|
128
|
-
...assetResult.errors,
|
|
129
|
-
...lintResult.errors,
|
|
130
|
-
...schemaResult.errors,
|
|
131
|
-
...crossFileResult.errors,
|
|
132
|
-
];
|
|
133
|
-
const warnings = [
|
|
134
|
-
...assetResult.warnings,
|
|
135
|
-
...lintResult.warnings,
|
|
136
|
-
...schemaResult.warnings,
|
|
137
|
-
...crossFileResult.warnings,
|
|
138
|
-
];
|
|
139
|
-
return {
|
|
140
|
-
ok: errors.length === 0,
|
|
141
|
-
errors,
|
|
142
|
-
warnings,
|
|
143
|
-
asset: assetResult,
|
|
144
|
-
lint: lintResult,
|
|
145
|
-
schema: schemaResult,
|
|
146
|
-
cross_file: crossFileResult,
|
|
147
|
-
};
|
|
104
|
+
return container.validate(isAsset(input) ? canonicalBytes(input) : input, options);
|
|
148
105
|
}
|
|
149
106
|
|
|
150
107
|
function validateKDNASync(input, options = {}) {
|
|
151
|
-
|
|
152
|
-
const asset = asAssetSync(input, { ...options, reader });
|
|
153
|
-
const assetResult = reader.verifySync(asset, options);
|
|
154
|
-
let lintResult = { errors: [], warnings: [] };
|
|
155
|
-
let schemaResult = { errors: [], warnings: [] };
|
|
156
|
-
let crossFileResult = { errors: [], warnings: [] };
|
|
157
|
-
|
|
158
|
-
try {
|
|
159
|
-
const dataMap = reader.readDataMapSync(asset, undefined, options);
|
|
160
|
-
lintResult = lintDomain(dataMap);
|
|
161
|
-
schemaResult = validateDomainSchema(dataMap, options.schemas || {});
|
|
162
|
-
crossFileResult = validateCrossFile(dataMap);
|
|
163
|
-
} catch (e) {
|
|
164
|
-
lintResult.errors.push(e.message);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
const errors = [
|
|
168
|
-
...assetResult.errors,
|
|
169
|
-
...lintResult.errors,
|
|
170
|
-
...schemaResult.errors,
|
|
171
|
-
...crossFileResult.errors,
|
|
172
|
-
];
|
|
173
|
-
const warnings = [
|
|
174
|
-
...assetResult.warnings,
|
|
175
|
-
...lintResult.warnings,
|
|
176
|
-
...schemaResult.warnings,
|
|
177
|
-
...crossFileResult.warnings,
|
|
178
|
-
];
|
|
179
|
-
return {
|
|
180
|
-
ok: errors.length === 0,
|
|
181
|
-
errors,
|
|
182
|
-
warnings,
|
|
183
|
-
asset: assetResult,
|
|
184
|
-
lint: lintResult,
|
|
185
|
-
schema: schemaResult,
|
|
186
|
-
cross_file: crossFileResult,
|
|
187
|
-
};
|
|
108
|
+
return container.validate(isAsset(input) ? canonicalBytes(input) : input, options);
|
|
188
109
|
}
|
|
189
110
|
|
|
190
111
|
async function renderForAgent(input, options = {}) {
|
|
191
|
-
const loaded = await loadKDNA(input, options);
|
|
192
|
-
|
|
193
|
-
return loaded.domain ? formatContext(loaded.domain) : '';
|
|
112
|
+
const loaded = await loadKDNA(input, { ...options, as: 'prompt' });
|
|
113
|
+
return loaded && typeof loaded.text === 'string' ? loaded.text : '';
|
|
194
114
|
}
|
|
195
115
|
|
|
196
116
|
function renderForAgentSync(input, options = {}) {
|
|
197
|
-
const loaded = loadKDNASync(input, options);
|
|
198
|
-
|
|
199
|
-
return loaded.domain ? formatContext(loaded.domain) : '';
|
|
117
|
+
const loaded = loadKDNASync(input, { ...options, as: 'prompt' });
|
|
118
|
+
return loaded && typeof loaded.text === 'string' ? loaded.text : '';
|
|
200
119
|
}
|
|
201
120
|
|
|
202
121
|
async function verifyAsset(input, options = {}) {
|
|
@@ -230,8 +149,10 @@ function verifySignatureSync(input, options = {}) {
|
|
|
230
149
|
function scoreMatch(input, info) {
|
|
231
150
|
const haystack = String(input || '').toLowerCase();
|
|
232
151
|
const terms = [
|
|
233
|
-
info.
|
|
234
|
-
|
|
152
|
+
info.asset_id,
|
|
153
|
+
info.title,
|
|
154
|
+
...(info.keywords || info.manifest?.keywords || []),
|
|
155
|
+
info.summary || info.manifest?.summary,
|
|
235
156
|
info.manifest?.description,
|
|
236
157
|
info.manifest?.core_insight,
|
|
237
158
|
]
|
|
@@ -250,7 +171,7 @@ async function matchDomain(input, candidates, options = {}) {
|
|
|
250
171
|
const match = scoreMatch(input, info);
|
|
251
172
|
if (match.score > 0) results.push({ ...info, score: match.score, matched: match.matched });
|
|
252
173
|
}
|
|
253
|
-
return results.sort((a, b) => b.score - a.score || String(a.
|
|
174
|
+
return results.sort((a, b) => b.score - a.score || String(a.asset_id).localeCompare(String(b.asset_id)));
|
|
254
175
|
}
|
|
255
176
|
|
|
256
177
|
function matchDomainSync(input, candidates, options = {}) {
|
|
@@ -262,42 +183,17 @@ function matchDomainSync(input, candidates, options = {}) {
|
|
|
262
183
|
const match = scoreMatch(input, info);
|
|
263
184
|
if (match.score > 0) results.push({ ...info, score: match.score, matched: match.matched });
|
|
264
185
|
}
|
|
265
|
-
return results.sort((a, b) => b.score - a.score || String(a.
|
|
186
|
+
return results.sort((a, b) => b.score - a.score || String(a.asset_id).localeCompare(String(b.asset_id)));
|
|
266
187
|
}
|
|
267
188
|
|
|
268
189
|
async function composeKDNA(inputs, options = {}) {
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
manifest: profile.manifest,
|
|
277
|
-
...profile.domain,
|
|
278
|
-
});
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
const { selected, excluded } = classifySignalsAcrossDomains(options.input || '', loaded);
|
|
282
|
-
const selectedIds = new Set(selected.map((d) => d.id));
|
|
283
|
-
const activeDomains = options.input ? loaded.filter((d) => selectedIds.has(d.id)) : loaded;
|
|
284
|
-
const conflicts = detectDomainConflicts(activeDomains);
|
|
285
|
-
const { context, attributionMap } = composeContextWithAttribution(activeDomains, options);
|
|
286
|
-
return {
|
|
287
|
-
domains: loaded,
|
|
288
|
-
activeDomains,
|
|
289
|
-
selected,
|
|
290
|
-
excluded,
|
|
291
|
-
conflicts,
|
|
292
|
-
context,
|
|
293
|
-
attributionMap,
|
|
294
|
-
trace: generateClusterTrace({
|
|
295
|
-
input: options.input || '',
|
|
296
|
-
loadedDomains: loaded,
|
|
297
|
-
activeDomains,
|
|
298
|
-
conflicts,
|
|
299
|
-
}),
|
|
300
|
-
};
|
|
190
|
+
void inputs;
|
|
191
|
+
void options;
|
|
192
|
+
const error = new Error(
|
|
193
|
+
'composeKDNA is unavailable until the current Cluster/Capsule composition protocol is defined.',
|
|
194
|
+
);
|
|
195
|
+
error.code = 'KDNA_COMPOSE_PROTOCOL_UNAVAILABLE';
|
|
196
|
+
throw error;
|
|
301
197
|
}
|
|
302
198
|
|
|
303
199
|
module.exports = {
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { KDNARuntimeCapsule } from './types';
|
|
2
|
+
|
|
3
|
+
/** A final packaged `.kdna` file path or its immutable packaged bytes. */
|
|
4
|
+
export type KDNARemoteRuntimeInput = string | Uint8Array;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Load one deployer-controlled `access: "remote"` asset for server-side
|
|
8
|
+
* projection. The function always returns a full JSON Runtime Capsule and
|
|
9
|
+
* accepts no caller policy options.
|
|
10
|
+
*/
|
|
11
|
+
export function loadRemoteRuntimeAsset(
|
|
12
|
+
input: KDNARemoteRuntimeInput,
|
|
13
|
+
): KDNARuntimeCapsule;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const container = require('./container');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Load one deployer-controlled `access: "remote"` packaged asset for a
|
|
7
|
+
* server-side projection Runtime.
|
|
8
|
+
*
|
|
9
|
+
* This API intentionally accepts no caller policy options. Physical control
|
|
10
|
+
* of the packaged remote asset is the deployment authorization boundary; the
|
|
11
|
+
* embedding server remains responsible for request authentication,
|
|
12
|
+
* entitlement checks, projection minimization, and audit policy.
|
|
13
|
+
*/
|
|
14
|
+
function loadRemoteRuntimeAsset(input) {
|
|
15
|
+
if (arguments.length !== 1) {
|
|
16
|
+
const error = new Error(
|
|
17
|
+
'loadRemoteRuntimeAsset accepts exactly one packaged asset input and no caller policy options.',
|
|
18
|
+
);
|
|
19
|
+
error.code = 'KDNA_REMOTE_RUNTIME_OPTIONS_FORBIDDEN';
|
|
20
|
+
throw error;
|
|
21
|
+
}
|
|
22
|
+
return container.loadRemoteRuntimeAssetForServer(input);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
module.exports = {
|
|
26
|
+
loadRemoteRuntimeAsset,
|
|
27
|
+
};
|
package/src/runtime-api.js
CHANGED
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
const fs = require('node:fs');
|
|
4
4
|
const path = require('node:path');
|
|
5
|
-
const
|
|
5
|
+
const container = require('./container');
|
|
6
6
|
|
|
7
7
|
function invalidDirectoryPlan(inputPath) {
|
|
8
8
|
const resolved = path.resolve(inputPath);
|
|
9
9
|
return {
|
|
10
|
-
|
|
10
|
+
format_version: null,
|
|
11
11
|
asset: { asset_id: null, asset_uid: null, title: null, version: null, judgment_version: null },
|
|
12
12
|
access: null,
|
|
13
13
|
access_alias: null,
|
|
@@ -64,23 +64,22 @@ function guardResolver(options = {}) {
|
|
|
64
64
|
|
|
65
65
|
function planLoad(inputPath, options = {}) {
|
|
66
66
|
if (isDirectory(inputPath)) return invalidDirectoryPlan(inputPath);
|
|
67
|
-
return
|
|
67
|
+
return container.planLoad(inputPath, guardResolver(options));
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
function loadAuthorized(inputPath, options = {}) {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
const issueCodes = Array.isArray(plan.issues)
|
|
74
|
-
? plan.issues.map((issue) => issue.code).filter(Boolean)
|
|
75
|
-
: [];
|
|
71
|
+
if (isDirectory(inputPath)) {
|
|
72
|
+
const plan = invalidDirectoryPlan(inputPath);
|
|
76
73
|
const error = new Error(
|
|
77
74
|
`LoadPlan denied loading: state=${plan.state || 'invalid'} required_action=${plan.required_action || 'block'}`,
|
|
78
75
|
);
|
|
79
|
-
error.code =
|
|
76
|
+
error.code = 'KDNA_ASSET_FILE_REQUIRED';
|
|
80
77
|
error.plan = plan;
|
|
81
78
|
throw error;
|
|
82
79
|
}
|
|
83
|
-
|
|
80
|
+
// container.loadAuthorized snapshots packaged paths once and uses that same Buffer
|
|
81
|
+
// for its LoadPlan, authorization decision, and Runtime Capsule projection.
|
|
82
|
+
return container.loadAuthorized(inputPath, guardResolver(options));
|
|
84
83
|
}
|
|
85
84
|
|
|
86
85
|
module.exports = {
|