halfcode-compiler.xnl 0.2.1 → 0.2.3
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 +53 -0
- package/dist/application-assembly.d.ts +2 -2
- package/dist/application-assembly.js +1 -1
- package/dist/index-96qHPZj2.d.ts +126 -0
- package/dist/{index-FdimP_SL.d.ts → index-Cqh9pEBa.d.ts} +10 -1
- package/dist/{index-DKwcVwK6.d.ts → index-D2mpux6L.d.ts} +1 -1
- package/dist/index-DdRHFKSQ.d.ts +192 -0
- package/dist/index.d.ts +9 -3
- package/dist/index.js +22 -3
- package/dist/kind-definition.d.ts +1 -1
- package/dist/resource-core-Byhqyadq.d.ts +20 -0
- package/dist/resource-core.d.ts +3 -2
- package/dist/resource-core.js +432 -2
- package/dist/resource-mapping.d.ts +14 -1
- package/dist/resource-mapping.js +2 -2
- package/dist/resource-projection.d.ts +1 -1
- package/dist/skill-capsule.d.ts +3 -2
- package/dist/skill-capsule.js +2 -2
- package/dist/src-25wZPUyX.js +305 -0
- package/dist/src-D1Bmq7Lo.js +1205 -0
- package/dist/src-DCRih45n.js +947 -0
- package/dist/{src-4m42imop.js → src-DRIws6tY.js} +43 -3
- 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/dist/system-skills/sys-halfcode-resource-dsl.plan.js +267 -0
- package/package.json +2 -2
- package/dist/index-DqYap2u_.d.ts +0 -81
- package/dist/index-wU-iKJnW.d.ts +0 -38
- package/dist/src-BlKlpg0J.js +0 -180
- package/dist/src-D8xlMdXx.js +0 -561
- package/dist/src-DKkIFGWH.js +0 -507
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as loadResourceTree } from "./src-
|
|
1
|
+
import { n as loadResourceTree } from "./src-DCRih45n.js";
|
|
2
2
|
import { readFile } from "node:fs/promises";
|
|
3
3
|
import { dirname, join } from "node:path";
|
|
4
4
|
import { parse } from "yaml";
|
|
@@ -193,6 +193,7 @@ async function resolveApplicationAssembly(options) {
|
|
|
193
193
|
pageObjects: loaded.flatMap((module) => module.pageObjects),
|
|
194
194
|
byFqn
|
|
195
195
|
};
|
|
196
|
+
assertSkillDependencyBindings(assembly.skillCapsules, byFqn);
|
|
196
197
|
setObjectOperationCompilations(assembly, compilations);
|
|
197
198
|
return assembly;
|
|
198
199
|
}
|
|
@@ -385,22 +386,61 @@ async function readTextResource(module, record, kind) {
|
|
|
385
386
|
};
|
|
386
387
|
}
|
|
387
388
|
async function readSkillCapsule(module, record) {
|
|
388
|
-
const
|
|
389
|
+
const metadataMaterial = await readRequiredMaterial(module, record, "SkillMetadata");
|
|
389
390
|
const template = await readRequiredMaterial(module, record, "Template");
|
|
391
|
+
const version = record.metadata.version;
|
|
392
|
+
const apiVersion = record.metadata.apiVersion;
|
|
393
|
+
if (!apiVersion) throw new Error(`SKILL_CAPSULE_API_VERSION_MISSING: ${record.logicalPath} is missing XNL metadata apiVersion`);
|
|
394
|
+
if (!version) throw new Error(`SKILL_CAPSULE_VERSION_MISSING: ${record.logicalPath} is missing XNL metadata version`);
|
|
395
|
+
const parsedMetadata = parse(metadataMaterial.content);
|
|
396
|
+
if (!parsedMetadata || typeof parsedMetadata !== "object" || Array.isArray(parsedMetadata)) throw new Error(`SKILL_CAPSULE_METADATA_INVALID: ${record.logicalPath} Skill metadata must be a YAML object`);
|
|
397
|
+
const yamlVersion = parsedMetadata.version;
|
|
398
|
+
if (yamlVersion !== void 0 && yamlVersion !== version) throw new Error(`SKILL_CAPSULE_VERSION_CONFLICT: ${requiredFqn(record)} YAML version ${JSON.stringify(yamlVersion)} does not match XNL version ${version}`);
|
|
399
|
+
const hasXnlName = Object.prototype.hasOwnProperty.call(record.node.properties, "name");
|
|
400
|
+
const xnlName = stringResourceValue(record.node.properties.name);
|
|
401
|
+
if (hasXnlName && !xnlName) throw new Error(`SKILL_CAPSULE_NAME_INVALID: ${requiredFqn(record)} XNL name must be a non-empty string`);
|
|
402
|
+
if (hasXnlName && Object.prototype.hasOwnProperty.call(parsedMetadata, "name")) throw new Error(`SKILL_CAPSULE_NAME_DUPLICATE: ${requiredFqn(record)} name is owned by XNL and must not be repeated in YAML`);
|
|
390
403
|
return {
|
|
391
404
|
kind: "SkillCapsule",
|
|
392
405
|
fqn: requiredFqn(record),
|
|
406
|
+
...xnlName ? { name: xnlName } : {},
|
|
407
|
+
apiVersion,
|
|
408
|
+
version,
|
|
393
409
|
description: requiredDescription(record),
|
|
394
|
-
metadata:
|
|
410
|
+
metadata: {
|
|
411
|
+
...parsedMetadata,
|
|
412
|
+
version
|
|
413
|
+
},
|
|
395
414
|
template,
|
|
396
415
|
resourceMappings: await readOptionalMaterial(module, record, "ResourceMappings"),
|
|
397
416
|
includes: nodeMembers(record.node.subdomains.Includes).filter((node) => node.tag === "Include").map((include) => ({
|
|
398
417
|
kind: requiredNodeProperty(include, "kind", record),
|
|
399
418
|
ref: requiredNodeProperty(include, "ref", record)
|
|
400
419
|
})),
|
|
420
|
+
dependencies: nodeMembers(record.node.subdomains.SkillDependencies).filter((node) => node.tag === "SkillDependency").map((dependency) => {
|
|
421
|
+
const ref = requiredNodeProperty(dependency, "ref", record);
|
|
422
|
+
return {
|
|
423
|
+
ref,
|
|
424
|
+
fqn: resourceRefToFqn(ref),
|
|
425
|
+
version: requiredNodeProperty(dependency, "version", record)
|
|
426
|
+
};
|
|
427
|
+
}),
|
|
401
428
|
source: sourceFor(module, record)
|
|
402
429
|
};
|
|
403
430
|
}
|
|
431
|
+
function assertSkillDependencyBindings(skills, byFqn) {
|
|
432
|
+
for (const skill of skills) {
|
|
433
|
+
const seen = /* @__PURE__ */ new Set();
|
|
434
|
+
for (const dependency of skill.dependencies) {
|
|
435
|
+
if (seen.has(dependency.fqn)) throw new Error(`SKILL_DEPENDENCY_DUPLICATE: ${skill.fqn} declares ${dependency.fqn} more than once`);
|
|
436
|
+
seen.add(dependency.fqn);
|
|
437
|
+
const target = byFqn.get(dependency.fqn);
|
|
438
|
+
if (!target) throw new Error(`SKILL_DEPENDENCY_MISSING: ${skill.fqn} dependency ${dependency.ref} does not exist`);
|
|
439
|
+
if (target.kind !== "SkillCapsule") throw new Error(`SKILL_DEPENDENCY_KIND_MISMATCH: ${skill.fqn} dependency ${dependency.ref} targets ${target.kind}`);
|
|
440
|
+
if (target.version !== dependency.version) throw new Error(`SKILL_DEPENDENCY_VERSION_MISMATCH: ${skill.fqn} dependency ${dependency.ref} expected ${dependency.version} but found ${target.version}`);
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
}
|
|
404
444
|
async function readOptionalMaterial(module, record, childName) {
|
|
405
445
|
const child = record.node.subdomains[childName];
|
|
406
446
|
if (!child) return void 0;
|
|
@@ -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
|
+
)>
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# Resource Document Families
|
|
2
|
+
|
|
3
|
+
## ResourcePackage 与 Catalogs
|
|
4
|
+
|
|
5
|
+
一个 package 有且只有一个 `ResourcePackage` authority root。它拥有唯一 `Catalogs` 子域;每个 `Catalog` 声明一种资源的逻辑根与目录入口:
|
|
6
|
+
|
|
7
|
+
```xnl
|
|
8
|
+
<ResourcePackage #demo.resource_workflow.authoring apiVersion="halfcode.resources/v1" version="1.0.0" {
|
|
9
|
+
lifecycle = "Active"
|
|
10
|
+
description = "Demo authoring resource package"
|
|
11
|
+
} (
|
|
12
|
+
<Catalogs [
|
|
13
|
+
<Catalog #kind_definitions {
|
|
14
|
+
kind = "KindDefinition"
|
|
15
|
+
shape = "directory"
|
|
16
|
+
root = "vfs://./KindDefinitions/"
|
|
17
|
+
entry = "manifest.xnl"
|
|
18
|
+
}>
|
|
19
|
+
<Catalog #functions {
|
|
20
|
+
kind = "Function"
|
|
21
|
+
shape = "directory"
|
|
22
|
+
root = "vfs://./Functions/"
|
|
23
|
+
entry = "manifest.xnl"
|
|
24
|
+
}>
|
|
25
|
+
]>
|
|
26
|
+
)>
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
catalog 只描述组织,不复制每个 descriptor 的内容。`shape` 取 `single-file|directory|manifest`;后两者必须声明目录入口 `entry`。`single-file` 缺省扫描 `root` 下全部 `.xnl` 文件,也可以用可选 `entry = "<name>.xnl"` 精确选择同目录中的一个 authority 文件;该 entry 必须是无路径片段的 XNL 文件名。loader 用根 tag/`#id` 确认 kind/identity。
|
|
30
|
+
|
|
31
|
+
## KindDefinition
|
|
32
|
+
|
|
33
|
+
`KindDefinition` 声明 source shape 与 descriptor contract:
|
|
34
|
+
|
|
35
|
+
```xnl
|
|
36
|
+
<KindDefinition #halfcode.resource_kind.Function apiVersion="halfcode.resources/v1" version="1.0.0" {
|
|
37
|
+
lifecycle = "Stable"
|
|
38
|
+
sourceShapes = ["single-file" "directory"]
|
|
39
|
+
currentApiVersion = "halfcode.resources/v1"
|
|
40
|
+
supportedApiVersions = ["halfcode.resources/v1"]
|
|
41
|
+
} (
|
|
42
|
+
<DescriptorContract (
|
|
43
|
+
<Identity { required = true form = "fqn" }>
|
|
44
|
+
<CodeBinding { property = "src" scheme = "vfs" exportFragmentRequired = true }>
|
|
45
|
+
<Instruction { required = false source = "inline-or-vfs" }>
|
|
46
|
+
)>
|
|
47
|
+
)>
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
`currentApiVersion` 是新资源和迁移目标版本,`supportedApiVersions` 是 loader 可直接读取的兼容集合,且必须包含 current。未知版本必须先经过调用方在代码侧注册的确定性 migration,再交给 loader;可执行转换不写入 XNL。
|
|
51
|
+
|
|
52
|
+
`documentCardinality` 缺省为 `"one"`。只有 `sourceShapes = ["single-file"]` 的 Kind 可以声明 `documentCardinality = "many"`,表示一个 authority 文档允许包含多个并列的同 Kind 根;它不是对所有 XNL 文件放宽根约束。
|
|
53
|
+
|
|
54
|
+
Kind contract 可以按自身语义约束 lifecycle、description、instruction、code binding 与 includes;除 `#id` 和 `apiVersion` 外,这些字段都不是通用 loader 强加给所有 Kind 的共同要求。
|
|
55
|
+
|
|
56
|
+
加载成功后,consumer 从 `ResourceTree.registry.kindDefinitions` 按 `resourceKind` 取得规范化 contract。该 projection 包含 version、source shape、cardinality、required files 以及 KindDefinition 自身的 `resourceId`/`documentUri` provenance;KindDefinition 不混入业务资源的 `registry.byKind`。
|
|
57
|
+
|
|
58
|
+
## Resource descriptor
|
|
59
|
+
|
|
60
|
+
descriptor 根 tag 直接使用 kind,`#id` 是资源 FQN。唯一概念进入 `()`;重复成员进入 `[]`:
|
|
61
|
+
|
|
62
|
+
```xnl
|
|
63
|
+
<Function #demo.resource_workflow.prepare_data apiVersion="halfcode.resources/v1" version="1.0.0" {
|
|
64
|
+
lifecycle = "Active"
|
|
65
|
+
title = "Prepare workflow data"
|
|
66
|
+
} (
|
|
67
|
+
<Instruction ?instruction>
|
|
68
|
+
接收输入并产生下游 procedure 所需的规范数据。
|
|
69
|
+
</?instruction>
|
|
70
|
+
<CodeBinding {
|
|
71
|
+
src = "vfs://@/apps/demo-resource-workflow-authoring/src/procedures.ts#prepareProcedure"
|
|
72
|
+
}>
|
|
73
|
+
)>
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
通用资源外壳只规定 identity、metadata channel、members/subdomains 和 provenance。各 Kind 的稳定领域字段及其 requiredness 由对应 `KindDefinition` 或 consumer contract 收窄;缺失的可选字段不会被填成空字符串。
|
|
77
|
+
|
|
78
|
+
允许 forest 的 Kind 仍逐根执行同样的 kind、identity 与 `apiVersion` 校验。例如 Decision Kind 可以显式声明:
|
|
79
|
+
|
|
80
|
+
```xnl
|
|
81
|
+
<KindDefinition #codument.resource_kind.Decision apiVersion="halfcode.resources/v1" version="1.0.0" {
|
|
82
|
+
lifecycle = "Stable"
|
|
83
|
+
sourceShapes = ["single-file"]
|
|
84
|
+
currentApiVersion = "codument.tech/v1alpha1"
|
|
85
|
+
supportedApiVersions = ["codument.tech/v1alpha1"]
|
|
86
|
+
documentCardinality = "many"
|
|
87
|
+
}>
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
对应 authority 文件可以有多个并列 `<Decision ...>` 根。每个根归一化为独立 resource record,并共享该文件的 `documentUri` provenance;重复 `#id`、混合根 kind 或不受支持的版本仍是错误。
|
|
91
|
+
|
|
92
|
+
## ResourceMappings
|
|
93
|
+
|
|
94
|
+
mapping 根拥有多个唯一 collection subdomain;collection 的 `[]` 承载重复条目:
|
|
95
|
+
|
|
96
|
+
```xnl
|
|
97
|
+
<ResourceMappings #demo.resource_workflow.mappings apiVersion="halfcode.resources/v1" version="1.0.0" (
|
|
98
|
+
<ReferenceTargets [
|
|
99
|
+
<ReferenceTarget #function_dependency {
|
|
100
|
+
fromKind = "Function"
|
|
101
|
+
field = "dependsOn"
|
|
102
|
+
targetKind = "Function"
|
|
103
|
+
}>
|
|
104
|
+
]>
|
|
105
|
+
<CallableArtifacts [
|
|
106
|
+
<CallableArtifact #function_callable {
|
|
107
|
+
kind = "Function"
|
|
108
|
+
binding = "CodeBinding.src"
|
|
109
|
+
}>
|
|
110
|
+
]>
|
|
111
|
+
<SourceRoots [
|
|
112
|
+
<SourceRoot #authoring {
|
|
113
|
+
uri = "vfs://@/apps/demo-resource-workflow-authoring/resources/"
|
|
114
|
+
}>
|
|
115
|
+
]>
|
|
116
|
+
)>
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
mapping key 是显式属性或 `#id`,不得把用户数据动态拼进 tag 名。
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<Function #demo.resource_workflow.prepare_data apiVersion="halfcode.resources/v1" version="1.0.0" {
|
|
2
|
+
lifecycle = "Active"
|
|
3
|
+
title = "Prepare workflow data"
|
|
4
|
+
} (
|
|
5
|
+
<Instruction ?instruction>
|
|
6
|
+
接收输入并产生下游 procedure 所需的规范数据。
|
|
7
|
+
</?instruction>
|
|
8
|
+
<CodeBinding {
|
|
9
|
+
src = "vfs://@/apps/demo-resource-workflow-authoring/src/procedures.ts#prepareProcedure"
|
|
10
|
+
}>
|
|
11
|
+
)>
|
|
12
|
+
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Parseable Examples
|
|
2
|
+
|
|
3
|
+
> 目录职责 · holds: 由当前 xnl-core parser 机械验证的规范 resource DSL 样例 · excludes: demo 业务资源与运行态 fixtures · tier: stable · ⬆from: resource DSL 文档实例 · ⬇to: parser/loader contract tests
|
|
4
|
+
|
|
5
|
+
| 文件 | 文档族 |
|
|
6
|
+
|---|---|
|
|
7
|
+
| `resource-package.xnl` | package 与 catalogs |
|
|
8
|
+
| `kind-definition.xnl` | 通用 Function KindDefinition |
|
|
9
|
+
| `skill-capsule-kind-definition.xnl` | SkillCapsule exact dependency contract |
|
|
10
|
+
| `skill-capsule-devops.xnl` | 四 Skill 示例的 lifecycle root |
|
|
11
|
+
| `skill-capsule-authoring.xnl` | authoring -> shared resource DSL dependency |
|
|
12
|
+
| `skill-capsule-run.xnl` | 无 sibling dependency 的 run Skill |
|
|
13
|
+
| `skill-capsule-resource-dsl.xnl` | 被 authoring 复用的 shared resource DSL Skill |
|
|
14
|
+
| `function.xnl` | 带 instruction 与 code binding 的 descriptor |
|
|
15
|
+
| `resource-mappings.xnl` | reference/callable/source-root mappings |
|
|
16
|
+
|
|
17
|
+
这些文件由当前 `xnl-core` parser 做 parse/stringify/parse 验证。下游 resource-core track 会把相同检查变成持续测试。
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<KindDefinition #halfcode.resource_kind.Function apiVersion="halfcode.resources/v1" version="1.0.0" {
|
|
2
|
+
lifecycle = "Stable"
|
|
3
|
+
sourceShapes = ["single-file" "directory"]
|
|
4
|
+
currentApiVersion = "halfcode.resources/v1"
|
|
5
|
+
supportedApiVersions = ["halfcode.resources/v1"]
|
|
6
|
+
} (
|
|
7
|
+
<DescriptorContract (
|
|
8
|
+
<Identity { required = true form = "fqn" }>
|
|
9
|
+
<CodeBinding { property = "src" scheme = "vfs" exportFragmentRequired = true }>
|
|
10
|
+
<Instruction { required = false source = "inline-or-vfs" }>
|
|
11
|
+
)>
|
|
12
|
+
)>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<ResourceMappings #demo.resource_workflow.mappings apiVersion="halfcode.resources/v1" version="1.0.0" (
|
|
2
|
+
<ReferenceTargets [
|
|
3
|
+
<ReferenceTarget #function_dependency {
|
|
4
|
+
fromKind = "Function"
|
|
5
|
+
field = "dependsOn"
|
|
6
|
+
targetKind = "Function"
|
|
7
|
+
}>
|
|
8
|
+
]>
|
|
9
|
+
<CallableArtifacts [
|
|
10
|
+
<CallableArtifact #function_callable {
|
|
11
|
+
kind = "Function"
|
|
12
|
+
binding = "CodeBinding.src"
|
|
13
|
+
}>
|
|
14
|
+
]>
|
|
15
|
+
<SourceRoots [
|
|
16
|
+
<SourceRoot #authoring {
|
|
17
|
+
uri = "vfs://@/apps/demo-resource-workflow-authoring/resources/"
|
|
18
|
+
}>
|
|
19
|
+
]>
|
|
20
|
+
)>
|
|
21
|
+
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<ResourcePackage #demo.resource_workflow.authoring apiVersion="halfcode.resources/v1" version="1.0.0" {
|
|
2
|
+
lifecycle = "Active"
|
|
3
|
+
description = "Demo authoring resource package"
|
|
4
|
+
} (
|
|
5
|
+
<Catalogs [
|
|
6
|
+
<Catalog #kind_definitions {
|
|
7
|
+
kind = "KindDefinition"
|
|
8
|
+
shape = "directory"
|
|
9
|
+
root = "vfs://./KindDefinitions/"
|
|
10
|
+
entry = "manifest.xnl"
|
|
11
|
+
}>
|
|
12
|
+
<Catalog #functions {
|
|
13
|
+
kind = "Function"
|
|
14
|
+
shape = "directory"
|
|
15
|
+
root = "vfs://./Functions/"
|
|
16
|
+
entry = "manifest.xnl"
|
|
17
|
+
}>
|
|
18
|
+
]>
|
|
19
|
+
)>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<SkillCapsule #example.resource_lifecycle.skill.authoring apiVersion="halfcode.resources/v1" version="1.0.0" {
|
|
2
|
+
name = "example-resource-lifecycle-authoring"
|
|
3
|
+
lifecycle = "Active"
|
|
4
|
+
description = "Generic operations for resource creation and revision."
|
|
5
|
+
} (
|
|
6
|
+
<SkillMetadata { href = "vfs://./SKILL.metadata.yaml" format = "yaml" }>
|
|
7
|
+
<Template { href = "vfs://./SKILL.template.ejs" format = "ejs" }>
|
|
8
|
+
<SkillDependencies [
|
|
9
|
+
<SkillDependency { ref = "resource://example.resource_lifecycle.skill.resource_dsl" version = "1.0.0" }>
|
|
10
|
+
]>
|
|
11
|
+
)>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<SkillCapsule #example.resource_lifecycle.skill.devops apiVersion="halfcode.resources/v1" version="1.0.0" {
|
|
2
|
+
name = "example-resource-lifecycle-devops"
|
|
3
|
+
lifecycle = "Active"
|
|
4
|
+
description = "Generic lifecycle root that routes authoring and run operations."
|
|
5
|
+
} (
|
|
6
|
+
<SkillMetadata { href = "vfs://./SKILL.metadata.yaml" format = "yaml" }>
|
|
7
|
+
<Template { href = "vfs://./SKILL.template.ejs" format = "ejs" }>
|
|
8
|
+
<SkillDependencies [
|
|
9
|
+
<SkillDependency { ref = "resource://example.resource_lifecycle.skill.authoring" version = "1.0.0" }>
|
|
10
|
+
<SkillDependency { ref = "resource://example.resource_lifecycle.skill.run" version = "1.0.0" }>
|
|
11
|
+
]>
|
|
12
|
+
)>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<KindDefinition #halfcode.resource_kind.SkillCapsule apiVersion="halfcode.resources/v1" version="1.0.0" {
|
|
2
|
+
lifecycle = "Stable"
|
|
3
|
+
description = "Versioned Skill capsule with exact sibling dependencies."
|
|
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
|
+
]>
|
|
14
|
+
<SkillDependencyContract {
|
|
15
|
+
collection = "SkillDependencies"
|
|
16
|
+
member = "SkillDependency"
|
|
17
|
+
refScheme = "resource"
|
|
18
|
+
targetKind = "SkillCapsule"
|
|
19
|
+
versionBinding = "exact"
|
|
20
|
+
}>
|
|
21
|
+
<IncludeContract {
|
|
22
|
+
collection = "Includes"
|
|
23
|
+
relation = "compiled-resource-selection"
|
|
24
|
+
dependencySemantics = false
|
|
25
|
+
}>
|
|
26
|
+
)>
|
|
27
|
+
)>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<SkillCapsule #example.resource_lifecycle.skill.resource_dsl apiVersion="halfcode.resources/v1" version="1.0.0" {
|
|
2
|
+
name = "example-resource-lifecycle-dsl"
|
|
3
|
+
lifecycle = "Stable"
|
|
4
|
+
description = "Shared resource DSL reference used by authoring operations."
|
|
5
|
+
} (
|
|
6
|
+
<SkillMetadata { href = "vfs://./SKILL.metadata.yaml" format = "yaml" }>
|
|
7
|
+
<Template { href = "vfs://./SKILL.template.ejs" format = "ejs" }>
|
|
8
|
+
)>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<SkillCapsule #example.resource_lifecycle.skill.run apiVersion="halfcode.resources/v1" version="1.0.0" {
|
|
2
|
+
name = "example-resource-lifecycle-run"
|
|
3
|
+
lifecycle = "Active"
|
|
4
|
+
description = "Generic operations for running an authored resource."
|
|
5
|
+
} (
|
|
6
|
+
<SkillMetadata { href = "vfs://./SKILL.metadata.yaml" format = "yaml" }>
|
|
7
|
+
<Template { href = "vfs://./SKILL.template.ejs" format = "ejs" }>
|
|
8
|
+
)>
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Files And Bundles
|
|
2
|
+
|
|
3
|
+
## 内容为真源
|
|
4
|
+
|
|
5
|
+
kind 与 identity 来自文件根 tag 和 `#id`。目录名、文件名和 catalog 路径只是布局;扫描器不得通过后缀或目录名补写资源语义。
|
|
6
|
+
|
|
7
|
+
## 两种定义形态
|
|
8
|
+
|
|
9
|
+
- 单文件 definition:任意描述性 `.xnl` 文件名,文件内有一个语义根。
|
|
10
|
+
- 目录 bundle:入口固定为 `manifest.xnl`,域文件使用描述性 `.xnl` 文件名。
|
|
11
|
+
|
|
12
|
+
目录 bundle 示例:
|
|
13
|
+
|
|
14
|
+
```text
|
|
15
|
+
Functions/
|
|
16
|
+
PrepareData/
|
|
17
|
+
manifest.xnl # <Function #demo.resource_workflow.prepare_data ...>
|
|
18
|
+
instruction.md # CodeBinding/Instruction 引用的 material
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
`manifest.xnl` 的根决定 bundle kind 与 identity。独立子域可以从 manifest 的 `()` 原样外提为同型域文件;外提不改变 logical refs。
|
|
22
|
+
|
|
23
|
+
## 单文件 forest
|
|
24
|
+
|
|
25
|
+
单文件默认只有一个语义根。仅当对应 `KindDefinition` 同时声明 `sourceShapes = ["single-file"]` 与 `documentCardinality = "many"` 时,同一个 `.xnl` authority 文件才可以包含多个并列根。
|
|
26
|
+
|
|
27
|
+
forest 的每个根是独立资源,必须使用同一 Kind,具有独立 `#id`,并通过该 Kind 的版本契约。`ResourcePackage`、catalog、KindDefinition 与目录 bundle 入口始终保持单根。
|
|
28
|
+
|
|
29
|
+
## Provenance 与 logical path
|
|
30
|
+
|
|
31
|
+
loader 为每个 normalized descriptor 附加只读 provenance:
|
|
32
|
+
|
|
33
|
+
- `documentUri`:加载 authority 文档的 canonical VFS URI;
|
|
34
|
+
- `logicalPath`:相对 package catalog root 的逻辑路径;
|
|
35
|
+
- `packageId`:从 `ResourcePackage #id` 派生;
|
|
36
|
+
- `resourceId`:来自 descriptor 根 `#id`。
|
|
37
|
+
|
|
38
|
+
这些字段由 loader 拥有,author 不在 descriptor 中重复配置。consumer 可以记录 provenance 用于诊断,但不得修改后反写 XNL。
|
|
39
|
+
|
|
40
|
+
## 扫描边界
|
|
41
|
+
|
|
42
|
+
- 默认目录入口仅为 `manifest.xnl`。
|
|
43
|
+
- `single-file` catalog 缺省扫描 root 下全部 `.xnl`;声明 `entry = "name.xnl"` 时只加载该文件,便于多个不同 Kind 共用一个物理目录。
|
|
44
|
+
- 非入口 `.xnl` 文件只能作为显式域/物料被入口引用,不能被重复注册为第二资源。
|
|
45
|
+
- 多根文档必须由 KindDefinition 显式授权;loader 不根据文件名或根数量猜测 forest 语义。
|
|
46
|
+
- catalog root 必须是 `vfs://` URI。
|
|
47
|
+
- resource-core 负责 URI 解析、边界检查和重复 identity 诊断;consumer 不自行扫描磁盘。
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Halfcode XNL Resource DSL
|
|
2
|
+
|
|
3
|
+
## 目录职责
|
|
4
|
+
|
|
5
|
+
- **holds**:halfcode resource package、catalog、KindDefinition、descriptor、mapping、URI 与文件组织的 XNL authoring 真源。
|
|
6
|
+
- **excludes**:parser/registry 实现(→`packages/resource-core/`)、consumer 归一化逻辑(→各 consumer package)、运行态数据与 BusinessObject/PageObject 尚未稳定的专用 API。
|
|
7
|
+
- **tier**:`stable`
|
|
8
|
+
- **promotes_from**:Codument track `define-xnl-resource-dsl` 的 proposal、design、behavior 与 modeling delta。
|
|
9
|
+
- **promotes_to**:资源 authoring 文件、loader/validator、consumer contract tests 与公开文档。
|
|
10
|
+
|
|
11
|
+
本目录定义 halfcode 资源的 XNL-native 语言。XNL 文档是可持久化语义真源;normalized descriptors、application assembly、发布制品和运行快照都是可重建投影,不得反向成为第二份 authoring 定义。
|
|
12
|
+
|
|
13
|
+
## 核心公理
|
|
14
|
+
|
|
15
|
+
一个节点的完整形态是:
|
|
16
|
+
|
|
17
|
+
```xnl
|
|
18
|
+
<Tag #id apiVersion="halfcode.resources/v1" version="1.0.0" { properties } ( unique-subdomains ) [ repeated-or-ordered-members ]>
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
| 通道 | 唯一职责 | 资源 DSL 用法 |
|
|
22
|
+
|---|---|---|
|
|
23
|
+
| `Tag` | 节点类别 | `ResourcePackage`、`KindDefinition`、`Function`、`ResourceMappings` 等资源 kind |
|
|
24
|
+
| `#id` | 节点身份 | 可跨容器引用的 FQN;不从文件名推断 |
|
|
25
|
+
| metadata 位 | 系统级版本 | `apiVersion`、`version` |
|
|
26
|
+
| `{}` | 无序业务属性 | lifecycle、description、kind、src、root 等标量或内联结构 |
|
|
27
|
+
| `()` | 每父节点唯一的命名子域 | `Catalogs`、`DescriptorContract`、`Instruction`、`CodeBinding` 等 |
|
|
28
|
+
| `[]` | 直接、有序或可重复事实 | catalog 条目、mapping 条目、includes 等 |
|
|
29
|
+
|
|
30
|
+
规则的重点是语义分配,不是把 XML tag/attribute 机械换一种括号。consumer 不得读取 parser-private 字段,也不得重建 `@_attribute` 一类 XML 对象形状。
|
|
31
|
+
|
|
32
|
+
## 权威文档
|
|
33
|
+
|
|
34
|
+
| 文档 | 回答的问题 |
|
|
35
|
+
|---|---|
|
|
36
|
+
| [language.md](language.md) | XNL 通道、身份、引用、声明式边界与 normalized projection。 |
|
|
37
|
+
| [documents.md](documents.md) | package、catalog、KindDefinition、descriptor、mapping 各自长什么样。 |
|
|
38
|
+
| [files.md](files.md) | 单文件/目录 bundle、`manifest.xnl`、logical path 与 provenance。 |
|
|
39
|
+
| [projections.md](projections.md) | 单包 tree、ordered layers、tombstone、typed dependency 与 revision 的 authority 边界。 |
|
|
40
|
+
| [skill-capsules.md](skill-capsules.md) | SkillCapsule version authority、sibling dependency、closure plan/apply 与 host 边界。 |
|
|
41
|
+
| [migration.md](migration.md) | XML authority 如何迁移,哪些做法被明确拒绝。 |
|
|
42
|
+
| [examples/](examples/) | 由当前 `xnl-core` parser 验证的规范实例。 |
|
|
43
|
+
|
|
44
|
+
KindDefinition 同时拥有资源版本契约:`currentApiVersion` 指向当前 authoring 版本,`supportedApiVersions` 列出可直接加载的兼容版本。版本转换由 `halfcode-compiler.xnl/kind-definition` 的代码侧 migration registry 执行,XNL 不承载可执行转换。成功加载的规范化 contract 可从 `ResourceTree.registry.kindDefinitions` 读取,consumer 无需再次解析 Kind XNL。
|
|
45
|
+
|
|
46
|
+
多个 package 的组合不产生新的 authoring authority。canonical loader 在同一次 raw-byte read 中产生 `LoadedResourceTree.contentIdentities`;`resolveEffectiveResourceContentIdentities()` 再从 exact effective layer 选择 authority identity 并合并 Kind owner 的显式 digest contributions。`EffectiveResourceRegistry` 和 `ResourceDependencySnapshot` 都是由已验证 XNL、显式 tombstone、typed edge 与 digest contribution 重建的只读投影;它们不得被序列化回 XNL 作为第二份事实源。完整规则见 [projections.md](projections.md)。
|
|
47
|
+
|
|
48
|
+
本目录自身也是 `Halfcode.ResourceDsl.Package@1.0.0`:XNL descriptors 只登记 canonical Markdown/XNL materials,不复制正文。`Halfcode.ResourceDsl.Skill.System` 编译为 `sys-halfcode-resource-dsl@1.0.0`,供离线消费者按需加载这些文档;每个 capsule 的 `references/.halfcode/provenance.json` 绑定 source FQN/apiVersion/version、生成协议和 payload digests。
|
|
49
|
+
|
|
50
|
+
## 暂缓边界
|
|
51
|
+
|
|
52
|
+
BusinessObject 与 PageObject 的通用外壳仍服从本目录的 `Tag/#id/metadata/{}/()/[]` 公理,但以下内容在当前版本中**刻意不定义**:
|
|
53
|
+
|
|
54
|
+
- 专用字段与 operation/mutation/action 模型;
|
|
55
|
+
- application assembly 的二者专用 public types;
|
|
56
|
+
- 参考实现正在重构的 PageObject API 映射;
|
|
57
|
+
- 二者最终 KindDefinition descriptor contract。
|
|
58
|
+
|
|
59
|
+
这些内容由 mission `halfcode-compiler-xnl-migration` 的 `LATE-BO-PO` group 在重新观察参考实现后补充。
|