halfcode-compiler.xnl 0.2.2 → 0.2.4
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/README.md +14 -0
- package/dist/application-assembly.js +1 -1
- package/dist/{index-96qHPZj2.d.ts → index-D7UtYNm7.d.ts} +1 -1
- package/dist/{index-DdRHFKSQ.d.ts → index-DihSfO7X.d.ts} +33 -2
- package/dist/{index-D2mpux6L.d.ts → index-DjvNDidT.d.ts} +1 -1
- package/dist/index.d.ts +5 -4
- package/dist/index.js +14 -4
- package/dist/kind-definition.d.ts +1 -1
- package/dist/{resource-core-Byhqyadq.d.ts → resource-core-UAvFx3m-.d.ts} +1 -1
- package/dist/resource-core.d.ts +3 -3
- package/dist/resource-core.js +4 -4
- package/dist/resource-projection.d.ts +1 -1
- package/dist/skill-capsule.d.ts +1 -1
- package/dist/skill-capsule.js +1 -1
- package/dist/{src-DRIws6tY.js → src-6nezdi57.js} +1 -1
- package/dist/{src-DCRih45n.js → src-Bj7BZokJ.js} +237 -36
- package/dist/{src-D1Bmq7Lo.js → src-ClihwpeP.js} +1 -1
- package/dist/system-skills/resource-dsl/KindDefinitions/SkillCapsule/manifest.xnl +21 -0
- package/dist/system-skills/resource-dsl/KindDefinitions/WikiPage/manifest.xnl +10 -0
- package/dist/system-skills/resource-dsl/SkillCapsules/System/SKILL.metadata.yaml +2 -0
- package/dist/system-skills/resource-dsl/SkillCapsules/System/SKILL.template.ejs +20 -0
- package/dist/system-skills/resource-dsl/SkillCapsules/System/manifest.xnl +18 -0
- package/dist/system-skills/resource-dsl/SkillCapsules/System/resource-mappings.xnl +10 -0
- package/dist/system-skills/resource-dsl/WikiPages/documents/manifest.xnl +6 -0
- package/dist/system-skills/resource-dsl/WikiPages/files/manifest.xnl +6 -0
- package/dist/system-skills/resource-dsl/WikiPages/index/manifest.xnl +6 -0
- package/dist/system-skills/resource-dsl/WikiPages/language/manifest.xnl +6 -0
- package/dist/system-skills/resource-dsl/WikiPages/migration/manifest.xnl +6 -0
- package/dist/system-skills/resource-dsl/WikiPages/projections/manifest.xnl +6 -0
- package/dist/system-skills/resource-dsl/WikiPages/skill-capsules/manifest.xnl +6 -0
- package/dist/system-skills/resource-dsl/documents.md +119 -0
- package/dist/system-skills/resource-dsl/examples/function.xnl +12 -0
- package/dist/system-skills/resource-dsl/examples/index.md +17 -0
- package/dist/system-skills/resource-dsl/examples/kind-definition.xnl +12 -0
- package/dist/system-skills/resource-dsl/examples/resource-mappings.xnl +21 -0
- package/dist/system-skills/resource-dsl/examples/resource-package.xnl +19 -0
- package/dist/system-skills/resource-dsl/examples/skill-capsule-authoring.xnl +11 -0
- package/dist/system-skills/resource-dsl/examples/skill-capsule-devops.xnl +12 -0
- package/dist/system-skills/resource-dsl/examples/skill-capsule-kind-definition.xnl +27 -0
- package/dist/system-skills/resource-dsl/examples/skill-capsule-resource-dsl.xnl +8 -0
- package/dist/system-skills/resource-dsl/examples/skill-capsule-run.xnl +8 -0
- package/dist/system-skills/resource-dsl/files.md +47 -0
- package/dist/system-skills/resource-dsl/index.md +59 -0
- package/dist/system-skills/resource-dsl/language.md +64 -0
- package/dist/system-skills/resource-dsl/manifest.xnl +10 -0
- package/dist/system-skills/resource-dsl/migration.md +40 -0
- package/dist/system-skills/resource-dsl/projections.md +142 -0
- package/dist/system-skills/resource-dsl/skill-capsules.md +94 -0
- package/package.json +1 -1
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { n as wordToString, t as parseXnl } from "./dist-Bkv7YeVi.js";
|
|
2
2
|
import { readFile, readdir, realpath, stat } from "node:fs/promises";
|
|
3
|
-
import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
3
|
+
import { dirname, extname, isAbsolute, join, posix, relative, resolve, sep } from "node:path";
|
|
4
4
|
import { createHash } from "node:crypto";
|
|
5
|
+
import { Buffer } from "node:buffer";
|
|
5
6
|
//#region ../resource-core/src/canonical.ts
|
|
6
7
|
function compareCodeUnits(left, right) {
|
|
7
8
|
if (left < right) return -1;
|
|
@@ -72,17 +73,17 @@ function createResourceContentIdentity(input) {
|
|
|
72
73
|
strictCanonicalInput: false,
|
|
73
74
|
validateClaimedDigest: false
|
|
74
75
|
});
|
|
75
|
-
if (diagnostics.length > 0 || !identity) throw new ResourceCompositionError(stableDiagnostics(diagnostics));
|
|
76
|
+
if (diagnostics.length > 0 || !identity) throw new ResourceCompositionError(stableDiagnostics$1(diagnostics));
|
|
76
77
|
return identity;
|
|
77
78
|
}
|
|
78
79
|
function buildResourceDependencySnapshot(input) {
|
|
79
80
|
const diagnostics = [];
|
|
80
|
-
if (!isEffectiveRegistryAuthentic(input.registry) || input.registry.revision !== input.registry.compositionRevision) throw new ResourceCompositionError(Object.freeze([diagnostic("RESOURCE_EFFECTIVE_REGISTRY_UNTRUSTED", "effective-registry:revision", "Dependency snapshots require an authentic immutable registry returned by composeLayeredResourceRegistry().")]));
|
|
81
|
+
if (!isEffectiveRegistryAuthentic(input.registry) || input.registry.revision !== input.registry.compositionRevision) throw new ResourceCompositionError(Object.freeze([diagnostic$1("RESOURCE_EFFECTIVE_REGISTRY_UNTRUSTED", "effective-registry:revision", "Dependency snapshots require an authentic immutable registry returned by composeLayeredResourceRegistry().")]));
|
|
81
82
|
const roots = validateRoots(input.roots, input.registry, diagnostics);
|
|
82
83
|
const edges = validateEdges(input.edges, input.registry, diagnostics);
|
|
83
84
|
validateContentIdentityIndex(input.contentIdentities, diagnostics);
|
|
84
85
|
const validatedIdentities = validateEffectiveContentIdentities(input.registry, input.contentIdentities, diagnostics);
|
|
85
|
-
if (diagnostics.length > 0) throw new ResourceCompositionError(stableDiagnostics(diagnostics));
|
|
86
|
+
if (diagnostics.length > 0) throw new ResourceCompositionError(stableDiagnostics$1(diagnostics));
|
|
86
87
|
const registryRevision = digestCanonical({
|
|
87
88
|
compositionRevision: input.registry.compositionRevision,
|
|
88
89
|
resources: [...validatedIdentities.values()].sort((left, right) => compareCodeUnits(left.resourceId, right.resourceId)).map((identity) => ({
|
|
@@ -106,7 +107,7 @@ function buildResourceDependencySnapshot(input) {
|
|
|
106
107
|
if (visiting.has(resourceId)) {
|
|
107
108
|
const cycleStart = path.indexOf(resourceId);
|
|
108
109
|
const cycle = [...path.slice(cycleStart), resourceId];
|
|
109
|
-
diagnostics.push(diagnostic("RESOURCE_DEPENDENCY_CYCLE", dependencyLocation(resourceId), `Resource dependency cycle detected: ${cycle.join(" -> ")}.`));
|
|
110
|
+
diagnostics.push(diagnostic$1("RESOURCE_DEPENDENCY_CYCLE", dependencyLocation(resourceId), `Resource dependency cycle detected: ${cycle.join(" -> ")}.`));
|
|
110
111
|
return;
|
|
111
112
|
}
|
|
112
113
|
if (visited.has(resourceId)) return;
|
|
@@ -122,7 +123,7 @@ function buildResourceDependencySnapshot(input) {
|
|
|
122
123
|
visited.add(resourceId);
|
|
123
124
|
};
|
|
124
125
|
for (const root of roots) visit(root);
|
|
125
|
-
if (diagnostics.length > 0) throw new ResourceCompositionError(stableDiagnostics(diagnostics));
|
|
126
|
+
if (diagnostics.length > 0) throw new ResourceCompositionError(stableDiagnostics$1(diagnostics));
|
|
126
127
|
const closure = Object.freeze([...reachable].sort(compareCodeUnits).map((resourceId) => {
|
|
127
128
|
const entry = input.registry.byId.get(resourceId);
|
|
128
129
|
const identity = validatedIdentities.get(resourceId);
|
|
@@ -160,19 +161,19 @@ function validateRoots(inputRoots, registry, diagnostics) {
|
|
|
160
161
|
for (const value of inputRoots) {
|
|
161
162
|
const resourceId = value.trim();
|
|
162
163
|
if (resourceId.length === 0) {
|
|
163
|
-
diagnostics.push(diagnostic("RESOURCE_DEPENDENCY_ROOT_EMPTY", "dependency-root:unnamed", "Dependency snapshot roots must be non-empty resource ids."));
|
|
164
|
+
diagnostics.push(diagnostic$1("RESOURCE_DEPENDENCY_ROOT_EMPTY", "dependency-root:unnamed", "Dependency snapshot roots must be non-empty resource ids."));
|
|
164
165
|
continue;
|
|
165
166
|
}
|
|
166
167
|
if (seen.has(resourceId)) {
|
|
167
|
-
diagnostics.push(diagnostic("RESOURCE_DEPENDENCY_ROOT_DUPLICATE", dependencyLocation(resourceId), `Dependency snapshot root '${resourceId}' is declared more than once.`));
|
|
168
|
+
diagnostics.push(diagnostic$1("RESOURCE_DEPENDENCY_ROOT_DUPLICATE", dependencyLocation(resourceId), `Dependency snapshot root '${resourceId}' is declared more than once.`));
|
|
168
169
|
continue;
|
|
169
170
|
}
|
|
170
171
|
seen.add(resourceId);
|
|
171
172
|
roots.push(resourceId);
|
|
172
173
|
const entry = registry.byId.get(resourceId);
|
|
173
|
-
if (!entry || !entry.resource) diagnostics.push(diagnostic("RESOURCE_DEPENDENCY_ROOT_MISSING", dependencyLocation(resourceId), `Dependency snapshot root '${resourceId}' is not an effective resource.`));
|
|
174
|
+
if (!entry || !entry.resource) diagnostics.push(diagnostic$1("RESOURCE_DEPENDENCY_ROOT_MISSING", dependencyLocation(resourceId), `Dependency snapshot root '${resourceId}' is not an effective resource.`));
|
|
174
175
|
}
|
|
175
|
-
if (roots.length === 0 && diagnostics.length === 0) diagnostics.push(diagnostic("RESOURCE_DEPENDENCY_ROOTS_EMPTY", "dependency-root:none", "Dependency snapshot requires at least one explicit root."));
|
|
176
|
+
if (roots.length === 0 && diagnostics.length === 0) diagnostics.push(diagnostic$1("RESOURCE_DEPENDENCY_ROOTS_EMPTY", "dependency-root:none", "Dependency snapshot requires at least one explicit root."));
|
|
176
177
|
return roots;
|
|
177
178
|
}
|
|
178
179
|
function validateEdges(inputEdges, registry, diagnostics) {
|
|
@@ -185,13 +186,13 @@ function validateEdges(inputEdges, registry, diagnostics) {
|
|
|
185
186
|
declaredBy: inputEdge.declaredBy.trim()
|
|
186
187
|
});
|
|
187
188
|
if (!edge.fromResourceId || !edge.toResourceId || !edge.relation || !edge.declaredBy) {
|
|
188
|
-
diagnostics.push(diagnostic("RESOURCE_DEPENDENCY_EDGE_INVALID", `dependency-edge:${index}`, "Dependency edges require non-empty fromResourceId, toResourceId, relation, and declaredBy fields."));
|
|
189
|
+
diagnostics.push(diagnostic$1("RESOURCE_DEPENDENCY_EDGE_INVALID", `dependency-edge:${index}`, "Dependency edges require non-empty fromResourceId, toResourceId, relation, and declaredBy fields."));
|
|
189
190
|
return;
|
|
190
191
|
}
|
|
191
192
|
const source = registry.byId.get(edge.fromResourceId);
|
|
192
193
|
const target = registry.byId.get(edge.toResourceId);
|
|
193
|
-
if (!source?.resource) diagnostics.push(diagnostic("RESOURCE_DEPENDENCY_SOURCE_MISSING", dependencyLocation(edge.fromResourceId), `Dependency edge source '${edge.fromResourceId}' is not an effective resource.`));
|
|
194
|
-
if (!target?.resource) diagnostics.push(diagnostic("RESOURCE_DEPENDENCY_TARGET_MISSING", dependencyLocation(edge.toResourceId), `Dependency edge target '${edge.toResourceId}' is not an effective resource.`));
|
|
194
|
+
if (!source?.resource) diagnostics.push(diagnostic$1("RESOURCE_DEPENDENCY_SOURCE_MISSING", dependencyLocation(edge.fromResourceId), `Dependency edge source '${edge.fromResourceId}' is not an effective resource.`));
|
|
195
|
+
if (!target?.resource) diagnostics.push(diagnostic$1("RESOURCE_DEPENDENCY_TARGET_MISSING", dependencyLocation(edge.toResourceId), `Dependency edge target '${edge.toResourceId}' is not an effective resource.`));
|
|
195
196
|
values.set(edgeKey(edge), edge);
|
|
196
197
|
});
|
|
197
198
|
return [...values.values()].sort(compareEdges);
|
|
@@ -199,41 +200,41 @@ function validateEdges(inputEdges, registry, diagnostics) {
|
|
|
199
200
|
function normalizeContentIdentity(input, diagnostics, options) {
|
|
200
201
|
const initialDiagnosticCount = diagnostics.length;
|
|
201
202
|
if (!isRecord(input)) {
|
|
202
|
-
diagnostics.push(diagnostic("RESOURCE_CONTENT_IDENTITY_INVALID", contentLocation(""), "Resource content identity must be an object fact."));
|
|
203
|
+
diagnostics.push(diagnostic$1("RESOURCE_CONTENT_IDENTITY_INVALID", contentLocation(""), "Resource content identity must be an object fact."));
|
|
203
204
|
return;
|
|
204
205
|
}
|
|
205
206
|
const rawResourceId = input.resourceId;
|
|
206
207
|
const resourceId = typeof rawResourceId === "string" ? rawResourceId.trim() : "";
|
|
207
|
-
if (resourceId.length === 0) diagnostics.push(diagnostic("RESOURCE_CONTENT_IDENTITY_ID_EMPTY", contentLocation(""), "Resource content identity requires a non-empty resource id."));
|
|
208
|
-
else if (options.strictCanonicalInput && rawResourceId !== resourceId) diagnostics.push(diagnostic("RESOURCE_CONTENT_IDENTITY_NON_CANONICAL", contentLocation(resourceId), `Resource content identity '${resourceId}' must use its canonical id without surrounding whitespace.`));
|
|
208
|
+
if (resourceId.length === 0) diagnostics.push(diagnostic$1("RESOURCE_CONTENT_IDENTITY_ID_EMPTY", contentLocation(""), "Resource content identity requires a non-empty resource id."));
|
|
209
|
+
else if (options.strictCanonicalInput && rawResourceId !== resourceId) diagnostics.push(diagnostic$1("RESOURCE_CONTENT_IDENTITY_NON_CANONICAL", contentLocation(resourceId), `Resource content identity '${resourceId}' must use its canonical id without surrounding whitespace.`));
|
|
209
210
|
const authorityDigest = typeof input.authorityDigest === "string" ? input.authorityDigest : "";
|
|
210
|
-
if (!isSha256Digest(authorityDigest)) diagnostics.push(diagnostic("RESOURCE_CONTENT_AUTHORITY_DIGEST_INVALID", contentLocation(resourceId), `Resource '${resourceId || "unnamed"}' has an invalid authority digest.`));
|
|
211
|
+
if (!isSha256Digest(authorityDigest)) diagnostics.push(diagnostic$1("RESOURCE_CONTENT_AUTHORITY_DIGEST_INVALID", contentLocation(resourceId), `Resource '${resourceId || "unnamed"}' has an invalid authority digest.`));
|
|
211
212
|
const rawContributions = input.contributions;
|
|
212
213
|
let contributionFacts = [];
|
|
213
214
|
if (rawContributions === void 0 && !options.requireContributions) contributionFacts = [];
|
|
214
|
-
else if (!Array.isArray(rawContributions)) diagnostics.push(diagnostic("RESOURCE_DIGEST_CONTRIBUTIONS_INVALID", contentLocation(resourceId), `Resource '${resourceId || "unnamed"}' must provide an explicit digest contribution array.`));
|
|
215
|
+
else if (!Array.isArray(rawContributions)) diagnostics.push(diagnostic$1("RESOURCE_DIGEST_CONTRIBUTIONS_INVALID", contentLocation(resourceId), `Resource '${resourceId || "unnamed"}' must provide an explicit digest contribution array.`));
|
|
215
216
|
else contributionFacts = rawContributions;
|
|
216
217
|
const contributions = /* @__PURE__ */ new Map();
|
|
217
218
|
for (const fact of contributionFacts) {
|
|
218
219
|
if (!isRecord(fact)) {
|
|
219
|
-
diagnostics.push(diagnostic("RESOURCE_DIGEST_CONTRIBUTION_INVALID", contentLocation(resourceId), `Resource '${resourceId || "unnamed"}' has a non-object digest contribution.`));
|
|
220
|
+
diagnostics.push(diagnostic$1("RESOURCE_DIGEST_CONTRIBUTION_INVALID", contentLocation(resourceId), `Resource '${resourceId || "unnamed"}' has a non-object digest contribution.`));
|
|
220
221
|
continue;
|
|
221
222
|
}
|
|
222
223
|
const rawKey = fact.key;
|
|
223
224
|
const key = typeof rawKey === "string" ? rawKey.trim() : "";
|
|
224
225
|
if (key.length === 0) {
|
|
225
|
-
diagnostics.push(diagnostic("RESOURCE_DIGEST_CONTRIBUTION_KEY_EMPTY", contentLocation(resourceId), `Resource '${resourceId || "unnamed"}' has a digest contribution with an empty key.`));
|
|
226
|
+
diagnostics.push(diagnostic$1("RESOURCE_DIGEST_CONTRIBUTION_KEY_EMPTY", contentLocation(resourceId), `Resource '${resourceId || "unnamed"}' has a digest contribution with an empty key.`));
|
|
226
227
|
continue;
|
|
227
228
|
}
|
|
228
|
-
if (options.strictCanonicalInput && rawKey !== key) diagnostics.push(diagnostic("RESOURCE_DIGEST_CONTRIBUTION_NON_CANONICAL", contentLocation(resourceId, key), `Digest contribution '${key}' for resource '${resourceId}' must use its canonical key.`));
|
|
229
|
+
if (options.strictCanonicalInput && rawKey !== key) diagnostics.push(diagnostic$1("RESOURCE_DIGEST_CONTRIBUTION_NON_CANONICAL", contentLocation(resourceId, key), `Digest contribution '${key}' for resource '${resourceId}' must use its canonical key.`));
|
|
229
230
|
const digest = typeof fact.digest === "string" ? fact.digest : "";
|
|
230
231
|
if (!isSha256Digest(digest)) {
|
|
231
|
-
diagnostics.push(diagnostic("RESOURCE_DIGEST_CONTRIBUTION_INVALID", contentLocation(resourceId, key), `Digest contribution '${key}' for resource '${resourceId || "unnamed"}' is invalid.`));
|
|
232
|
+
diagnostics.push(diagnostic$1("RESOURCE_DIGEST_CONTRIBUTION_INVALID", contentLocation(resourceId, key), `Digest contribution '${key}' for resource '${resourceId || "unnamed"}' is invalid.`));
|
|
232
233
|
continue;
|
|
233
234
|
}
|
|
234
235
|
const sourceUri = fact.sourceUri;
|
|
235
236
|
if (sourceUri !== void 0 && typeof sourceUri !== "string") {
|
|
236
|
-
diagnostics.push(diagnostic("RESOURCE_DIGEST_CONTRIBUTION_SOURCE_INVALID", contentLocation(resourceId, key), `Digest contribution '${key}' for resource '${resourceId}' has an invalid source URI.`));
|
|
237
|
+
diagnostics.push(diagnostic$1("RESOURCE_DIGEST_CONTRIBUTION_SOURCE_INVALID", contentLocation(resourceId, key), `Digest contribution '${key}' for resource '${resourceId}' has an invalid source URI.`));
|
|
237
238
|
continue;
|
|
238
239
|
}
|
|
239
240
|
const contribution = Object.freeze({
|
|
@@ -244,7 +245,7 @@ function normalizeContentIdentity(input, diagnostics, options) {
|
|
|
244
245
|
const current = contributions.get(key);
|
|
245
246
|
if (current) {
|
|
246
247
|
const conflicting = current.digest !== digest;
|
|
247
|
-
diagnostics.push(diagnostic(conflicting ? "RESOURCE_DIGEST_CONTRIBUTION_CONFLICT" : "RESOURCE_DIGEST_CONTRIBUTION_DUPLICATE", contentLocation(resourceId, key), conflicting ? `Digest contribution '${key}' for resource '${resourceId || "unnamed"}' has conflicting digests.` : `Digest contribution '${key}' for resource '${resourceId || "unnamed"}' is declared more than once.`));
|
|
248
|
+
diagnostics.push(diagnostic$1(conflicting ? "RESOURCE_DIGEST_CONTRIBUTION_CONFLICT" : "RESOURCE_DIGEST_CONTRIBUTION_DUPLICATE", contentLocation(resourceId, key), conflicting ? `Digest contribution '${key}' for resource '${resourceId || "unnamed"}' has conflicting digests.` : `Digest contribution '${key}' for resource '${resourceId || "unnamed"}' is declared more than once.`));
|
|
248
249
|
continue;
|
|
249
250
|
}
|
|
250
251
|
contributions.set(key, contribution);
|
|
@@ -262,11 +263,11 @@ function normalizeContentIdentity(input, diagnostics, options) {
|
|
|
262
263
|
if (options.validateClaimedDigest) {
|
|
263
264
|
const claimedDigest = input.contentDigest;
|
|
264
265
|
if (typeof claimedDigest !== "string" || !isSha256Digest(claimedDigest)) {
|
|
265
|
-
diagnostics.push(diagnostic("RESOURCE_CONTENT_DIGEST_INVALID", contentLocation(resourceId), `Resource '${resourceId}' has an invalid claimed content digest.`));
|
|
266
|
+
diagnostics.push(diagnostic$1("RESOURCE_CONTENT_DIGEST_INVALID", contentLocation(resourceId), `Resource '${resourceId}' has an invalid claimed content digest.`));
|
|
266
267
|
return;
|
|
267
268
|
}
|
|
268
269
|
if (claimedDigest !== contentDigest) {
|
|
269
|
-
diagnostics.push(diagnostic("RESOURCE_CONTENT_DIGEST_MISMATCH", contentLocation(resourceId), `Resource '${resourceId}' claimed a content digest that does not match its explicit authority and contributions.`));
|
|
270
|
+
diagnostics.push(diagnostic$1("RESOURCE_CONTENT_DIGEST_MISMATCH", contentLocation(resourceId), `Resource '${resourceId}' claimed a content digest that does not match its explicit authority and contributions.`));
|
|
270
271
|
return;
|
|
271
272
|
}
|
|
272
273
|
}
|
|
@@ -283,7 +284,7 @@ function validateEffectiveContentIdentities(registry, identities, diagnostics) {
|
|
|
283
284
|
for (const entry of effectiveEntries) {
|
|
284
285
|
const input = identities.get(entry.resourceId);
|
|
285
286
|
if (input === void 0) {
|
|
286
|
-
diagnostics.push(diagnostic("RESOURCE_CONTENT_IDENTITY_MISSING", dependencyLocation(entry.resourceId), `Effective resource '${entry.resourceId}' has no explicit content identity.`));
|
|
287
|
+
diagnostics.push(diagnostic$1("RESOURCE_CONTENT_IDENTITY_MISSING", dependencyLocation(entry.resourceId), `Effective resource '${entry.resourceId}' has no explicit content identity.`));
|
|
287
288
|
continue;
|
|
288
289
|
}
|
|
289
290
|
const identity = normalizeContentIdentity(input, diagnostics, {
|
|
@@ -298,7 +299,7 @@ function validateEffectiveContentIdentities(registry, identities, diagnostics) {
|
|
|
298
299
|
function validateContentIdentityIndex(identities, diagnostics) {
|
|
299
300
|
for (const [key, identity] of [...identities.entries()].sort(([left], [right]) => compareCodeUnits(left, right))) {
|
|
300
301
|
const identityResourceId = isRecord(identity) && typeof identity.resourceId === "string" ? identity.resourceId : void 0;
|
|
301
|
-
if (key !== identityResourceId) diagnostics.push(diagnostic("RESOURCE_CONTENT_IDENTITY_KEY_MISMATCH", dependencyLocation(key), `Content identity index key '${key}' does not match identity '${identityResourceId ?? "invalid"}'.`));
|
|
302
|
+
if (key !== identityResourceId) diagnostics.push(diagnostic$1("RESOURCE_CONTENT_IDENTITY_KEY_MISMATCH", dependencyLocation(key), `Content identity index key '${key}' does not match identity '${identityResourceId ?? "invalid"}'.`));
|
|
302
303
|
}
|
|
303
304
|
}
|
|
304
305
|
function isSha256Digest(value) {
|
|
@@ -344,10 +345,10 @@ function cloneOrigin(origin) {
|
|
|
344
345
|
...origin.logicalPath === void 0 ? {} : { logicalPath: origin.logicalPath }
|
|
345
346
|
});
|
|
346
347
|
}
|
|
347
|
-
function stableDiagnostics(diagnostics) {
|
|
348
|
+
function stableDiagnostics$1(diagnostics) {
|
|
348
349
|
return Object.freeze([...diagnostics].sort((left, right) => compareCodeUnits(left.location, right.location) || compareCodeUnits(left.code, right.code)));
|
|
349
350
|
}
|
|
350
|
-
function diagnostic(code, location, message) {
|
|
351
|
+
function diagnostic$1(code, location, message) {
|
|
351
352
|
return Object.freeze({
|
|
352
353
|
code,
|
|
353
354
|
location,
|
|
@@ -371,6 +372,184 @@ function isLoadedResourceTreeAuthentic(tree) {
|
|
|
371
372
|
return authenticLoadedResourceTrees.has(tree);
|
|
372
373
|
}
|
|
373
374
|
//#endregion
|
|
375
|
+
//#region ../resource-core/src/code-package.ts
|
|
376
|
+
const CODE_PACKAGE_ENTRY_CONTRIBUTION_KEY = "code-binding:module";
|
|
377
|
+
/** @internal Node effect implementation bound by the public facade. */
|
|
378
|
+
const nodeCodePackageRuntime = Object.freeze({
|
|
379
|
+
realpath,
|
|
380
|
+
readFile,
|
|
381
|
+
stat,
|
|
382
|
+
importModule: async (url) => import(url)
|
|
383
|
+
});
|
|
384
|
+
var CodePackageLoadError = class extends Error {
|
|
385
|
+
diagnostics;
|
|
386
|
+
constructor(diagnostics) {
|
|
387
|
+
super(`CodePackage loading failed with ${diagnostics.length} diagnostic(s)`);
|
|
388
|
+
this.name = "CodePackageLoadError";
|
|
389
|
+
this.diagnostics = Object.freeze([...diagnostics]);
|
|
390
|
+
}
|
|
391
|
+
};
|
|
392
|
+
/** @internal Used by the canonical XNL loader before it brands the completed tree. */
|
|
393
|
+
function normalizeCodePackageBinding(record) {
|
|
394
|
+
const diagnostics = [];
|
|
395
|
+
if (record.sourceShape !== "code-package") {
|
|
396
|
+
diagnostics.push(diagnostic("RESOURCE_CODE_PACKAGE_SHAPE_INVALID", record.documentUri, `Resource '${record.resourceId}' does not use the code-package source shape.`));
|
|
397
|
+
return { diagnostics };
|
|
398
|
+
}
|
|
399
|
+
const node = record.node.subdomains.CodeBinding;
|
|
400
|
+
if (!node || node.tag !== "CodeBinding") {
|
|
401
|
+
diagnostics.push(diagnostic("RESOURCE_CODE_PACKAGE_BINDING_MISSING", record.documentUri, `CodePackage resource '${record.resourceId}' requires one CodeBinding.`));
|
|
402
|
+
return { diagnostics };
|
|
403
|
+
}
|
|
404
|
+
if (node.properties.package !== void 0) diagnostics.push(diagnostic("RESOURCE_CODE_PACKAGE_BINDING_INVALID", record.documentUri, `CodePackage resource '${record.resourceId}' must bind a package-local module, not an external package.`));
|
|
405
|
+
const rawModule = stringValue(node.properties.module);
|
|
406
|
+
const moduleUri = rawModule === void 0 ? void 0 : normalizeModuleUri(rawModule);
|
|
407
|
+
if (!moduleUri) diagnostics.push(diagnostic("RESOURCE_CODE_PACKAGE_MODULE_INVALID", record.documentUri, `CodePackage resource '${record.resourceId}' requires a canonical package-local .js or .mjs module URI.`));
|
|
408
|
+
const rawExport = node.properties.export;
|
|
409
|
+
const exportName = stringValue(rawExport);
|
|
410
|
+
if (rawExport !== void 0 && (!exportName || !/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(exportName))) diagnostics.push(diagnostic("RESOURCE_CODE_PACKAGE_EXPORT_INVALID", record.documentUri, `CodePackage resource '${record.resourceId}' has an invalid named export binding.`));
|
|
411
|
+
if (diagnostics.length > 0 || !moduleUri) return { diagnostics: stableDiagnostics(diagnostics) };
|
|
412
|
+
return {
|
|
413
|
+
binding: Object.freeze({
|
|
414
|
+
resourceId: record.resourceId,
|
|
415
|
+
moduleUri,
|
|
416
|
+
...exportName ? { exportName } : {}
|
|
417
|
+
}),
|
|
418
|
+
diagnostics: Object.freeze([])
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
/** @internal Resolves and reads the exact entry bytes under the descriptor directory. */
|
|
422
|
+
async function readCodePackageEntry(runtime, rootDir, record, binding) {
|
|
423
|
+
const diagnostics = [];
|
|
424
|
+
const realRoot = await runtime.realpath(resolve(rootDir)).catch(() => void 0);
|
|
425
|
+
if (!realRoot) return { diagnostics: [diagnostic("RESOURCE_CODE_PACKAGE_ROOT_MISSING", record.documentUri, `The resource root for '${record.resourceId}' is missing or unreadable.`)] };
|
|
426
|
+
if (!isSafeLogicalPath(record.logicalPath)) return { diagnostics: [diagnostic("RESOURCE_CODE_PACKAGE_PROVENANCE_INVALID", record.documentUri, `CodePackage resource '${record.resourceId}' has unsafe logical provenance.`)] };
|
|
427
|
+
const descriptorPath = resolve(realRoot, record.logicalPath);
|
|
428
|
+
const descriptorDirectory = await runtime.realpath(dirname(descriptorPath)).catch(() => void 0);
|
|
429
|
+
if (!descriptorDirectory || !isWithin(realRoot, descriptorDirectory)) return { diagnostics: [diagnostic("RESOURCE_CODE_PACKAGE_ENTRY_CONTAINMENT", record.documentUri, `CodePackage resource '${record.resourceId}' resolves outside the resource root.`)] };
|
|
430
|
+
const localPath = moduleLocalPath(binding.moduleUri);
|
|
431
|
+
if (!localPath) return { diagnostics: [diagnostic("RESOURCE_CODE_PACKAGE_MODULE_INVALID", record.documentUri, `CodePackage resource '${record.resourceId}' has an invalid module URI.`)] };
|
|
432
|
+
const entryPath = await runtime.realpath(resolve(descriptorDirectory, ...localPath.split("/"))).catch(() => void 0);
|
|
433
|
+
if (!entryPath) return { diagnostics: [diagnostic("RESOURCE_CODE_PACKAGE_ENTRY_MISSING", `${record.documentUri}#CodeBinding`, `CodePackage entry is missing for '${record.resourceId}'.`)] };
|
|
434
|
+
if (!isWithin(descriptorDirectory, entryPath) || entryPath === descriptorDirectory) diagnostics.push(diagnostic("RESOURCE_CODE_PACKAGE_ENTRY_CONTAINMENT", `${record.documentUri}#CodeBinding`, `CodePackage entry for '${record.resourceId}' resolves outside its package directory.`));
|
|
435
|
+
if (!(await runtime.stat(entryPath).catch(() => void 0))?.isFile()) diagnostics.push(diagnostic("RESOURCE_CODE_PACKAGE_ENTRY_INVALID", `${record.documentUri}#CodeBinding`, `CodePackage entry for '${record.resourceId}' must be a regular file.`));
|
|
436
|
+
if (diagnostics.length > 0) return { diagnostics: stableDiagnostics(diagnostics) };
|
|
437
|
+
const bytes = await runtime.readFile(entryPath).catch(() => void 0);
|
|
438
|
+
if (!bytes) return { diagnostics: [diagnostic("RESOURCE_CODE_PACKAGE_ENTRY_MISSING", `${record.documentUri}#CodeBinding`, `CodePackage entry is unreadable for '${record.resourceId}'.`)] };
|
|
439
|
+
const resourceDirectory = posix.dirname(record.logicalPath);
|
|
440
|
+
return {
|
|
441
|
+
entryPath,
|
|
442
|
+
bytes,
|
|
443
|
+
sourceUri: `vfs://@/${resourceDirectory === "." ? localPath : `${resourceDirectory}/${localPath}`}`,
|
|
444
|
+
diagnostics: Object.freeze([])
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
async function loadCodePackageModule(input) {
|
|
448
|
+
return loadCodePackageModuleWithRuntime(nodeCodePackageRuntime, input);
|
|
449
|
+
}
|
|
450
|
+
/** @internal Pure orchestration over an injected effect runtime; hidden by the package facade. */
|
|
451
|
+
async function loadCodePackageModuleWithRuntime(runtime, input) {
|
|
452
|
+
if (!isLoadedResourceTreeAuthentic(input.tree)) throw loadError("RESOURCE_CODE_PACKAGE_TREE_UNTRUSTED", `code-package:${input.resourceId}`, "CodePackage modules require an authentic LoadedResourceTree.");
|
|
453
|
+
const record = findResource(input.tree, input.resourceId);
|
|
454
|
+
const binding = input.tree.codePackageBindings.get(input.resourceId);
|
|
455
|
+
const identity = input.tree.contentIdentities.get(input.resourceId);
|
|
456
|
+
if (!record || record.sourceShape !== "code-package" || !binding || !identity) throw loadError("RESOURCE_CODE_PACKAGE_RESOURCE_INVALID", `code-package:${input.resourceId}`, `Resource '${input.resourceId}' is not a loaded CodePackage.`);
|
|
457
|
+
const entry = await readCodePackageEntry(runtime, input.rootDir, record, binding);
|
|
458
|
+
if (entry.diagnostics.length > 0 || !entry.entryPath || !entry.bytes) throw new CodePackageLoadError(entry.diagnostics);
|
|
459
|
+
const contribution = identity.contributions.find((item) => item.key === CODE_PACKAGE_ENTRY_CONTRIBUTION_KEY);
|
|
460
|
+
if (!contribution || contribution.digest !== sha256Digest(entry.bytes) || contribution.sourceUri !== entry.sourceUri) throw loadError("RESOURCE_CODE_PACKAGE_REVISION_STALE", `${record.documentUri}#CodeBinding`, `CodePackage entry for '${record.resourceId}' changed after its ResourceTree was loaded.`);
|
|
461
|
+
const url = `data:text/javascript;base64,${Buffer.concat([Buffer.from(entry.bytes), Buffer.from(`\n/* halfcode_revision=${identity.contentDigest} */\n`)]).toString("base64")}`;
|
|
462
|
+
let moduleNamespace;
|
|
463
|
+
try {
|
|
464
|
+
moduleNamespace = await runtime.importModule(url);
|
|
465
|
+
} catch {
|
|
466
|
+
throw loadError("RESOURCE_CODE_PACKAGE_IMPORT_FAILED", `${record.documentUri}#CodeBinding`, `CodePackage entry for '${record.resourceId}' could not be imported.`);
|
|
467
|
+
}
|
|
468
|
+
if (binding.exportName && !(binding.exportName in moduleNamespace)) throw loadError("RESOURCE_CODE_PACKAGE_EXPORT_MISSING", `${record.documentUri}#CodeBinding`, `CodePackage entry for '${record.resourceId}' does not export '${binding.exportName}'.`);
|
|
469
|
+
const currentBytes = await runtime.readFile(entry.entryPath).catch(() => void 0);
|
|
470
|
+
if (!currentBytes || sha256Digest(currentBytes) !== contribution.digest) throw loadError("RESOURCE_CODE_PACKAGE_REVISION_STALE", `${record.documentUri}#CodeBinding`, `CodePackage entry for '${record.resourceId}' changed while it was being imported.`);
|
|
471
|
+
const frozenNamespace = Object.freeze(Object.fromEntries(Object.keys(moduleNamespace).sort(compareCodeUnits).map((name) => [name, moduleNamespace[name]])));
|
|
472
|
+
return Object.freeze({
|
|
473
|
+
resourceId: record.resourceId,
|
|
474
|
+
binding,
|
|
475
|
+
revision: identity.contentDigest,
|
|
476
|
+
moduleNamespace: frozenNamespace
|
|
477
|
+
});
|
|
478
|
+
}
|
|
479
|
+
function admitCodePackageExports(loaded, contract) {
|
|
480
|
+
return admitCandidates([{
|
|
481
|
+
loaded,
|
|
482
|
+
contract
|
|
483
|
+
}]);
|
|
484
|
+
}
|
|
485
|
+
function admitCodePackages(loaded, contract) {
|
|
486
|
+
return admitCandidates(loaded.map((item) => ({
|
|
487
|
+
loaded: item,
|
|
488
|
+
contract
|
|
489
|
+
})));
|
|
490
|
+
}
|
|
491
|
+
function admitCandidates(packages) {
|
|
492
|
+
const definitions = /* @__PURE__ */ new Map();
|
|
493
|
+
for (const { loaded, contract } of packages) {
|
|
494
|
+
const names = loaded.binding.exportName ? [loaded.binding.exportName] : Object.keys(loaded.moduleNamespace).sort(compareCodeUnits);
|
|
495
|
+
for (const name of names) {
|
|
496
|
+
const exported = loaded.moduleNamespace[name];
|
|
497
|
+
const candidates = Array.isArray(exported) ? exported : [exported];
|
|
498
|
+
for (const candidate of candidates) {
|
|
499
|
+
if (!contract.isDefinition(candidate)) continue;
|
|
500
|
+
const identity = contract.identityOf(candidate).trim();
|
|
501
|
+
if (!identity) throw new TypeError(`CodePackage definition from '${loaded.resourceId}' has an empty identity`);
|
|
502
|
+
if (definitions.has(identity)) throw new TypeError(`Duplicate CodePackage definition identity '${identity}'`);
|
|
503
|
+
definitions.set(identity, candidate);
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
return Object.freeze([...definitions.entries()].sort(([left], [right]) => compareCodeUnits(left, right)).map(([, definition]) => definition));
|
|
508
|
+
}
|
|
509
|
+
function normalizeModuleUri(value) {
|
|
510
|
+
const prefix = "vfs://./";
|
|
511
|
+
if (!value.startsWith(prefix) || value !== value.trim() || value.includes("%") || value.includes("\\") || value.includes("?") || value.includes("#")) return void 0;
|
|
512
|
+
const localPath = value.slice(8);
|
|
513
|
+
if (!localPath || isAbsolute(localPath) || posix.isAbsolute(localPath)) return void 0;
|
|
514
|
+
const parts = localPath.split("/");
|
|
515
|
+
if (parts.some((part) => !part || part === "." || part === "..")) return void 0;
|
|
516
|
+
const extension = extname(localPath).toLowerCase();
|
|
517
|
+
if (extension !== ".js" && extension !== ".mjs") return void 0;
|
|
518
|
+
return `${prefix}${parts.join("/")}`;
|
|
519
|
+
}
|
|
520
|
+
function moduleLocalPath(moduleUri) {
|
|
521
|
+
return normalizeModuleUri(moduleUri)?.slice(8);
|
|
522
|
+
}
|
|
523
|
+
function findResource(tree, resourceId) {
|
|
524
|
+
for (const records of tree.registry.byKind.values()) {
|
|
525
|
+
const record = records.find((item) => item.resourceId === resourceId);
|
|
526
|
+
if (record) return record;
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
function isSafeLogicalPath(value) {
|
|
530
|
+
return Boolean(value) && !isAbsolute(value) && !value.includes("\\") && !value.split("/").some((part) => !part || part === "." || part === "..");
|
|
531
|
+
}
|
|
532
|
+
function isWithin(boundary, candidate) {
|
|
533
|
+
const path = relative(boundary, candidate);
|
|
534
|
+
return path === "" || !path.startsWith(`..${sep}`) && path !== ".." && !isAbsolute(path);
|
|
535
|
+
}
|
|
536
|
+
function stringValue(value) {
|
|
537
|
+
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
538
|
+
}
|
|
539
|
+
function loadError(code, location, message) {
|
|
540
|
+
return new CodePackageLoadError([diagnostic(code, location, message)]);
|
|
541
|
+
}
|
|
542
|
+
function stableDiagnostics(diagnostics) {
|
|
543
|
+
return Object.freeze([...diagnostics].sort((left, right) => compareCodeUnits(left.location, right.location) || compareCodeUnits(left.code, right.code)));
|
|
544
|
+
}
|
|
545
|
+
function diagnostic(code, location, message) {
|
|
546
|
+
return Object.freeze({
|
|
547
|
+
code,
|
|
548
|
+
location,
|
|
549
|
+
message
|
|
550
|
+
});
|
|
551
|
+
}
|
|
552
|
+
//#endregion
|
|
374
553
|
//#region ../resource-core/src/readonly-map.ts
|
|
375
554
|
function readonlyMap(entries) {
|
|
376
555
|
const values = new Map(entries);
|
|
@@ -413,7 +592,9 @@ async function buildXnlResourceTree(options) {
|
|
|
413
592
|
resources: [],
|
|
414
593
|
seenIdentities: /* @__PURE__ */ new Map(),
|
|
415
594
|
authorityFiles: /* @__PURE__ */ new Map(),
|
|
416
|
-
recordAuthorityDigests: /* @__PURE__ */ new WeakMap()
|
|
595
|
+
recordAuthorityDigests: /* @__PURE__ */ new WeakMap(),
|
|
596
|
+
recordContributions: /* @__PURE__ */ new WeakMap(),
|
|
597
|
+
codePackageBindings: /* @__PURE__ */ new Map()
|
|
417
598
|
};
|
|
418
599
|
const manifest = await loadManifest(resolve(context.rootDir, options.manifestPath), "manifest", context, true);
|
|
419
600
|
if (!manifest || context.diagnostics.length > 0) return { diagnostics: context.diagnostics };
|
|
@@ -426,6 +607,7 @@ async function buildXnlResourceTree(options) {
|
|
|
426
607
|
const frozenByKind = readonlyMap([...byKind.entries()].sort(([left], [right]) => compareCodeUnits(left, right)).map(([kind, records]) => [kind, Object.freeze([...records].sort((left, right) => compareCodeUnits(left.resourceId, right.resourceId)))]));
|
|
427
608
|
const frozenKindDefinitions = readonlyMap([...context.kindDefinitions.entries()].sort(([left], [right]) => compareCodeUnits(left, right)));
|
|
428
609
|
const contentIdentities = readonlyMap(context.resources.map((resource) => [resource.resourceId, loadedContentIdentity(resource, context)]).sort(([left], [right]) => compareCodeUnits(left, right)));
|
|
610
|
+
const codePackageBindings = readonlyMap([...context.codePackageBindings.entries()].sort(([left], [right]) => compareCodeUnits(left, right)));
|
|
429
611
|
return {
|
|
430
612
|
diagnostics: [],
|
|
431
613
|
tree: markLoadedResourceTreeAuthentic(Object.freeze({
|
|
@@ -435,7 +617,8 @@ async function buildXnlResourceTree(options) {
|
|
|
435
617
|
kindDefinitions: frozenKindDefinitions
|
|
436
618
|
}),
|
|
437
619
|
diagnostics: Object.freeze([]),
|
|
438
|
-
contentIdentities
|
|
620
|
+
contentIdentities,
|
|
621
|
+
codePackageBindings
|
|
439
622
|
}))
|
|
440
623
|
};
|
|
441
624
|
}
|
|
@@ -524,6 +707,7 @@ async function loadCatalog(catalog, manifestDir, context) {
|
|
|
524
707
|
}
|
|
525
708
|
validateResourceApiVersion(record, definition, context.diagnostics);
|
|
526
709
|
await validateRequiredFiles(dirname(file), record, definition, context.diagnostics);
|
|
710
|
+
if (catalog.shape === "code-package" && !await prepareCodePackageRecord(record, context)) continue;
|
|
527
711
|
validateIdentity(record, context);
|
|
528
712
|
context.resources.push(record);
|
|
529
713
|
}
|
|
@@ -559,7 +743,7 @@ async function catalogFiles(catalog, manifestDir, context) {
|
|
|
559
743
|
context.diagnostics.push({
|
|
560
744
|
code: "RESOURCE_CATALOG_ENTRY_INVALID",
|
|
561
745
|
location: catalog.location,
|
|
562
|
-
message: "Directory and
|
|
746
|
+
message: "Directory, manifest and code-package catalogs require a plain XNL entry filename."
|
|
563
747
|
});
|
|
564
748
|
return [];
|
|
565
749
|
}
|
|
@@ -640,8 +824,25 @@ function loadedContentIdentity(resource, context) {
|
|
|
640
824
|
if (!authorityDigest) throw new Error(`Loader authority digest is missing for ${resource.resourceId}`);
|
|
641
825
|
return createResourceContentIdentity({
|
|
642
826
|
resourceId: resource.resourceId,
|
|
643
|
-
authorityDigest
|
|
827
|
+
authorityDigest,
|
|
828
|
+
contributions: context.recordContributions.get(resource) ?? []
|
|
829
|
+
});
|
|
830
|
+
}
|
|
831
|
+
async function prepareCodePackageRecord(record, context) {
|
|
832
|
+
const normalized = normalizeCodePackageBinding(record);
|
|
833
|
+
context.diagnostics.push(...normalized.diagnostics);
|
|
834
|
+
if (!normalized.binding) return false;
|
|
835
|
+
const entry = await readCodePackageEntry(nodeCodePackageRuntime, context.rootDir, record, normalized.binding);
|
|
836
|
+
context.diagnostics.push(...entry.diagnostics);
|
|
837
|
+
if (!entry.bytes || !entry.sourceUri) return false;
|
|
838
|
+
const contribution = Object.freeze({
|
|
839
|
+
key: CODE_PACKAGE_ENTRY_CONTRIBUTION_KEY,
|
|
840
|
+
digest: sha256Digest(entry.bytes),
|
|
841
|
+
sourceUri: entry.sourceUri
|
|
644
842
|
});
|
|
843
|
+
context.recordContributions.set(record, Object.freeze([contribution]));
|
|
844
|
+
context.codePackageBindings.set(record.resourceId, normalized.binding);
|
|
845
|
+
return true;
|
|
645
846
|
}
|
|
646
847
|
function resourceRecordFromRoot(root, filePath, sourceShape, context) {
|
|
647
848
|
const documentUri = documentUriFor(context.rootDir, filePath);
|
|
@@ -877,7 +1078,7 @@ function kindMismatch(actual, expected, location) {
|
|
|
877
1078
|
};
|
|
878
1079
|
}
|
|
879
1080
|
function isXnlShape(value) {
|
|
880
|
-
return value === "single-file" || value === "directory" || value === "manifest";
|
|
1081
|
+
return value === "single-file" || value === "directory" || value === "manifest" || value === "code-package";
|
|
881
1082
|
}
|
|
882
1083
|
function isDocumentCardinality(value) {
|
|
883
1084
|
return value === "one" || value === "many";
|
|
@@ -944,4 +1145,4 @@ function unsupportedAuthorityDiagnostic(options) {
|
|
|
944
1145
|
};
|
|
945
1146
|
}
|
|
946
1147
|
//#endregion
|
|
947
|
-
export {
|
|
1148
|
+
export { ResourceCompositionError as _, CODE_PACKAGE_ENTRY_CONTRIBUTION_KEY as a, admitCodePackages as c, buildResourceDependencySnapshot as d, createResourceContentIdentity as f, markEffectiveRegistryAuthentic as g, isEffectiveRegistryAuthentic as h, readonlyMap as i, loadCodePackageModule as l, effectiveRegistryLayerBindings as m, loadResourceTree as n, CodePackageLoadError as o, sha256Digest as p, validateResourceTree as r, admitCodePackageExports as s, ResourceValidationError as t, isLoadedResourceTreeAuthentic as u, compareCodeUnits as v, digestCanonical as y };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { l as resourceRefToFqn, u as resolveObjectOperationCompilation } from "./src-
|
|
1
|
+
import { l as resourceRefToFqn, u as resolveObjectOperationCompilation } from "./src-6nezdi57.js";
|
|
2
2
|
import { c as unsafeUnicodeCodeUnitIssue, i as planResourceMappings, o as safePathLexicalIssue, r as parseResourceMappings, t as ResourceMappingPathError } from "./src-25wZPUyX.js";
|
|
3
3
|
import { lstat, mkdir, mkdtemp, readFile, readdir, rename, rm, writeFile } from "node:fs/promises";
|
|
4
4
|
import { basename, dirname, join, posix, resolve } from "node:path";
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<KindDefinition #Halfcode.ResourceDsl.KindDefinition.SkillCapsule apiVersion="halfcode.resources/v1" version="1.0.0" {
|
|
2
|
+
lifecycle = "Stable"
|
|
3
|
+
description = "Kind definition for the versioned Resource DSL consumer SkillCapsule."
|
|
4
|
+
resourceKind = "SkillCapsule"
|
|
5
|
+
sourceShapes = ["directory"]
|
|
6
|
+
currentApiVersion = "halfcode.resources/v1"
|
|
7
|
+
supportedApiVersions = ["halfcode.resources/v1"]
|
|
8
|
+
} (
|
|
9
|
+
<DescriptorContract (
|
|
10
|
+
<RequiredFiles [
|
|
11
|
+
<File { name = "SKILL.metadata.yaml" }>
|
|
12
|
+
<File { name = "SKILL.template.ejs" }>
|
|
13
|
+
<File { name = "resource-mappings.xnl" }>
|
|
14
|
+
]>
|
|
15
|
+
<IncludeContract {
|
|
16
|
+
collection = "Includes"
|
|
17
|
+
relation = "compiled-resource-selection"
|
|
18
|
+
dependencySemantics = false
|
|
19
|
+
}>
|
|
20
|
+
)>
|
|
21
|
+
)>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<KindDefinition #Halfcode.ResourceDsl.KindDefinition.WikiPage apiVersion="halfcode.resources/v1" version="1.0.0" {
|
|
2
|
+
lifecycle = "Stable"
|
|
3
|
+
description = "Kind definition for canonical documentation pages referenced from the Resource DSL package root."
|
|
4
|
+
resourceKind = "WikiPage"
|
|
5
|
+
sourceShapes = ["directory"]
|
|
6
|
+
currentApiVersion = "halfcode.resources/v1"
|
|
7
|
+
supportedApiVersions = ["halfcode.resources/v1"]
|
|
8
|
+
} (
|
|
9
|
+
<DescriptorContract>
|
|
10
|
+
)>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: <%= metadata.name %>
|
|
3
|
+
description: <%= metadata.description %>
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# <%= metadata.title %>
|
|
7
|
+
|
|
8
|
+
Use this Skill for the generic XNL resource language and its deterministic compiler contracts. Product-specific authoring and runtime operations belong to their owner Skills.
|
|
9
|
+
|
|
10
|
+
## Progressive loading
|
|
11
|
+
|
|
12
|
+
1. Start with `references/resource-dsl/index.md`.
|
|
13
|
+
2. For XNL channels and source syntax, read `references/resource-dsl/language.md` and only the needed file under `references/resource-dsl/examples/`.
|
|
14
|
+
3. For ResourcePackage, Catalog or KindDefinition work, read `references/resource-dsl/documents.md` and `references/resource-dsl/files.md`.
|
|
15
|
+
4. For layered registries, content identities or snapshots, read `references/resource-dsl/projections.md`.
|
|
16
|
+
5. For SkillCapsule dependency/distribution work, read `references/resource-dsl/skill-capsules.md`.
|
|
17
|
+
6. Read `references/resource-dsl/migration.md` only for migration work.
|
|
18
|
+
7. Use `references/.halfcode/provenance.json` to verify source identity, version and payload digests.
|
|
19
|
+
|
|
20
|
+
Do not infer resource relationships from ordinary text. Use explicit catalogs, typed references and Kind-owned contracts, then rely on deterministic validation and compilation.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<SkillCapsule #Halfcode.ResourceDsl.Skill.System apiVersion="halfcode.resources/v1" version="1.0.0" {
|
|
2
|
+
name = "sys-halfcode-resource-dsl"
|
|
3
|
+
lifecycle = "Stable"
|
|
4
|
+
description = "Author and review XNL ResourcePackages, catalogs, KindDefinitions, VFS materials, projections and SkillCapsules using the canonical Halfcode Resource DSL."
|
|
5
|
+
} (
|
|
6
|
+
<SkillMetadata { href = "vfs://./SKILL.metadata.yaml" format = "yaml" }>
|
|
7
|
+
<Template { href = "vfs://./SKILL.template.ejs" format = "ejs" }>
|
|
8
|
+
<ResourceMappings { href = "vfs://./resource-mappings.xnl" format = "xnl" }>
|
|
9
|
+
<Includes [
|
|
10
|
+
<Include { kind = "WikiPage" ref = "resource://Halfcode.ResourceDsl.Wiki.index" }>
|
|
11
|
+
<Include { kind = "WikiPage" ref = "resource://Halfcode.ResourceDsl.Wiki.language" }>
|
|
12
|
+
<Include { kind = "WikiPage" ref = "resource://Halfcode.ResourceDsl.Wiki.documents" }>
|
|
13
|
+
<Include { kind = "WikiPage" ref = "resource://Halfcode.ResourceDsl.Wiki.files" }>
|
|
14
|
+
<Include { kind = "WikiPage" ref = "resource://Halfcode.ResourceDsl.Wiki.projections" }>
|
|
15
|
+
<Include { kind = "WikiPage" ref = "resource://Halfcode.ResourceDsl.Wiki.skill-capsules" }>
|
|
16
|
+
<Include { kind = "WikiPage" ref = "resource://Halfcode.ResourceDsl.Wiki.migration" }>
|
|
17
|
+
]>
|
|
18
|
+
)>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<ResourceMappings #Halfcode.ResourceDsl.ResourceMappings.System apiVersion="halfcode.resources/v1" version="1.0.0" (
|
|
2
|
+
<ReferenceTargets [
|
|
3
|
+
<ReferenceTarget { kind = "WikiPage" target = "references/resource-dsl/" }>
|
|
4
|
+
]>
|
|
5
|
+
<SourceRoots [
|
|
6
|
+
<SourceRoot #CanonicalExamples { sourceRoot = "vfs://module/ResourceDsl/" } [
|
|
7
|
+
<CopyDirectory { from = "examples" to = "references/resource-dsl/examples" }>
|
|
8
|
+
]>
|
|
9
|
+
]>
|
|
10
|
+
)>
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<WikiPage #Halfcode.ResourceDsl.Wiki.documents apiVersion="halfcode.resources/v1" version="1.0.0" {
|
|
2
|
+
lifecycle = "Stable"
|
|
3
|
+
description = "Resource documents, package catalogs and KindDefinition contracts."
|
|
4
|
+
} (
|
|
5
|
+
<Instruction { href = "vfs://@/documents.md" format = "markdown" }>
|
|
6
|
+
)>
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<WikiPage #Halfcode.ResourceDsl.Wiki.files apiVersion="halfcode.resources/v1" version="1.0.0" {
|
|
2
|
+
lifecycle = "Stable"
|
|
3
|
+
description = "Resource source shapes, VFS containment and file provenance."
|
|
4
|
+
} (
|
|
5
|
+
<Instruction { href = "vfs://@/files.md" format = "markdown" }>
|
|
6
|
+
)>
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<WikiPage #Halfcode.ResourceDsl.Wiki.index apiVersion="halfcode.resources/v1" version="1.0.0" {
|
|
2
|
+
lifecycle = "Stable"
|
|
3
|
+
description = "Resource DSL overview and progressive documentation index."
|
|
4
|
+
} (
|
|
5
|
+
<Instruction { href = "vfs://@/index.md" format = "markdown" }>
|
|
6
|
+
)>
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<WikiPage #Halfcode.ResourceDsl.Wiki.language apiVersion="halfcode.resources/v1" version="1.0.0" {
|
|
2
|
+
lifecycle = "Stable"
|
|
3
|
+
description = "XNL language channels and authority projection rules."
|
|
4
|
+
} (
|
|
5
|
+
<Instruction { href = "vfs://@/language.md" format = "markdown" }>
|
|
6
|
+
)>
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<WikiPage #Halfcode.ResourceDsl.Wiki.migration apiVersion="halfcode.resources/v1" version="1.0.0" {
|
|
2
|
+
lifecycle = "Stable"
|
|
3
|
+
description = "Migration guidance from non-canonical resource representations."
|
|
4
|
+
} (
|
|
5
|
+
<Instruction { href = "vfs://@/migration.md" format = "markdown" }>
|
|
6
|
+
)>
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<WikiPage #Halfcode.ResourceDsl.Wiki.projections apiVersion="halfcode.resources/v1" version="1.0.0" {
|
|
2
|
+
lifecycle = "Stable"
|
|
3
|
+
description = "Normalized, layered, content identity and dependency snapshot projections."
|
|
4
|
+
} (
|
|
5
|
+
<Instruction { href = "vfs://@/projections.md" format = "markdown" }>
|
|
6
|
+
)>
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<WikiPage #Halfcode.ResourceDsl.Wiki.skill-capsules apiVersion="halfcode.resources/v1" version="1.0.0" {
|
|
2
|
+
lifecycle = "Stable"
|
|
3
|
+
description = "SkillCapsule dependencies, deterministic plans and atomic distribution."
|
|
4
|
+
} (
|
|
5
|
+
<Instruction { href = "vfs://@/skill-capsules.md" format = "markdown" }>
|
|
6
|
+
)>
|