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.
Files changed (60) hide show
  1. package/README.md +53 -0
  2. package/dist/application-assembly.d.ts +2 -2
  3. package/dist/application-assembly.js +1 -1
  4. package/dist/index-96qHPZj2.d.ts +126 -0
  5. package/dist/{index-FdimP_SL.d.ts → index-Cqh9pEBa.d.ts} +10 -1
  6. package/dist/{index-DKwcVwK6.d.ts → index-D2mpux6L.d.ts} +1 -1
  7. package/dist/index-DdRHFKSQ.d.ts +192 -0
  8. package/dist/index.d.ts +9 -3
  9. package/dist/index.js +22 -3
  10. package/dist/kind-definition.d.ts +1 -1
  11. package/dist/resource-core-Byhqyadq.d.ts +20 -0
  12. package/dist/resource-core.d.ts +3 -2
  13. package/dist/resource-core.js +432 -2
  14. package/dist/resource-mapping.d.ts +14 -1
  15. package/dist/resource-mapping.js +2 -2
  16. package/dist/resource-projection.d.ts +1 -1
  17. package/dist/skill-capsule.d.ts +3 -2
  18. package/dist/skill-capsule.js +2 -2
  19. package/dist/src-25wZPUyX.js +305 -0
  20. package/dist/src-D1Bmq7Lo.js +1205 -0
  21. package/dist/src-DCRih45n.js +947 -0
  22. package/dist/{src-4m42imop.js → src-DRIws6tY.js} +43 -3
  23. package/dist/system-skills/resource-dsl/KindDefinitions/SkillCapsule/manifest.xnl +21 -0
  24. package/dist/system-skills/resource-dsl/KindDefinitions/WikiPage/manifest.xnl +10 -0
  25. package/dist/system-skills/resource-dsl/SkillCapsules/System/SKILL.metadata.yaml +2 -0
  26. package/dist/system-skills/resource-dsl/SkillCapsules/System/SKILL.template.ejs +20 -0
  27. package/dist/system-skills/resource-dsl/SkillCapsules/System/manifest.xnl +18 -0
  28. package/dist/system-skills/resource-dsl/SkillCapsules/System/resource-mappings.xnl +10 -0
  29. package/dist/system-skills/resource-dsl/WikiPages/documents/manifest.xnl +6 -0
  30. package/dist/system-skills/resource-dsl/WikiPages/files/manifest.xnl +6 -0
  31. package/dist/system-skills/resource-dsl/WikiPages/index/manifest.xnl +6 -0
  32. package/dist/system-skills/resource-dsl/WikiPages/language/manifest.xnl +6 -0
  33. package/dist/system-skills/resource-dsl/WikiPages/migration/manifest.xnl +6 -0
  34. package/dist/system-skills/resource-dsl/WikiPages/projections/manifest.xnl +6 -0
  35. package/dist/system-skills/resource-dsl/WikiPages/skill-capsules/manifest.xnl +6 -0
  36. package/dist/system-skills/resource-dsl/documents.md +119 -0
  37. package/dist/system-skills/resource-dsl/examples/function.xnl +12 -0
  38. package/dist/system-skills/resource-dsl/examples/index.md +17 -0
  39. package/dist/system-skills/resource-dsl/examples/kind-definition.xnl +12 -0
  40. package/dist/system-skills/resource-dsl/examples/resource-mappings.xnl +21 -0
  41. package/dist/system-skills/resource-dsl/examples/resource-package.xnl +19 -0
  42. package/dist/system-skills/resource-dsl/examples/skill-capsule-authoring.xnl +11 -0
  43. package/dist/system-skills/resource-dsl/examples/skill-capsule-devops.xnl +12 -0
  44. package/dist/system-skills/resource-dsl/examples/skill-capsule-kind-definition.xnl +27 -0
  45. package/dist/system-skills/resource-dsl/examples/skill-capsule-resource-dsl.xnl +8 -0
  46. package/dist/system-skills/resource-dsl/examples/skill-capsule-run.xnl +8 -0
  47. package/dist/system-skills/resource-dsl/files.md +47 -0
  48. package/dist/system-skills/resource-dsl/index.md +59 -0
  49. package/dist/system-skills/resource-dsl/language.md +64 -0
  50. package/dist/system-skills/resource-dsl/manifest.xnl +10 -0
  51. package/dist/system-skills/resource-dsl/migration.md +40 -0
  52. package/dist/system-skills/resource-dsl/projections.md +142 -0
  53. package/dist/system-skills/resource-dsl/skill-capsules.md +94 -0
  54. package/dist/system-skills/sys-halfcode-resource-dsl.plan.js +267 -0
  55. package/package.json +2 -2
  56. package/dist/index-DqYap2u_.d.ts +0 -81
  57. package/dist/index-wU-iKJnW.d.ts +0 -38
  58. package/dist/src-BlKlpg0J.js +0 -180
  59. package/dist/src-D8xlMdXx.js +0 -561
  60. package/dist/src-DKkIFGWH.js +0 -507
@@ -0,0 +1,64 @@
1
+ # Language Axioms
2
+
3
+ ## 身份与分类
4
+
5
+ - 根 tag 是资源 kind;PascalCase 保留给 DSL 结构节点。
6
+ - 可跨容器复用的资源在 `#id` 使用点分 FQN,例如 `#demo.resource_workflow.prepare_data`。
7
+ - 文件路径只负责物理布局,不决定 kind 或 identity。移动文件不改变 `#id`。
8
+ - `apiVersion` 与 `version` 写在 metadata 位;title、lifecycle、description 等业务数据若属于该 Kind,则写入 `{}`。
9
+ - 通用资源边界只要求根 `#id` 与 `apiVersion`。`lifecycle`、`description` 的存在性和语义由具体 Kind 或 consumer contract 决定,resource-core 不提供虚假默认值。
10
+ - 每个 KindDefinition 显式声明 `currentApiVersion` 与 `supportedApiVersions`;loader 不猜测未知版本,也不自动执行迁移。具体系统通过公开 `ResourceMigrationRegistry` 注册纯转换函数,得到唯一版本链后再加载目标文档。
11
+ - XNL authority 默认单根。只有 source shape 严格为 `single-file` 的 Kind 可以通过 `documentCardinality = "many"` 授权同 Kind forest;每个顶层根仍是独立资源,`[]` 继续只表达节点内部的重复子项。
12
+ - 静态描述数据由所属节点自持,不寄存在另一域再引用回来。
13
+
14
+ ## 子域与重复事实
15
+
16
+ `()` 表示父节点拥有的唯一子域概念。同一父节点的 `()` 中,同名 tag 只能出现一次。重复条目由复数子域的 `[]` 承载:
17
+
18
+ ```xnl
19
+ <ResourcePackage #demo.package (
20
+ <Catalogs [
21
+ <Catalog #functions { kind = "Function" root = "vfs://./Functions/" entry = "manifest.xnl" }>
22
+ <Catalog #skills { kind = "SkillCapsule" root = "vfs://./Skills/" entry = "manifest.xnl" }>
23
+ ]>
24
+ )>
25
+ ```
26
+
27
+ 直接、有序或可重复的事实进入 `[]`。禁止为了凑层级增加没有领域语义的 `Nodes`、`Items` 或 `Block` 包装;复数容器必须确实代表一个唯一子域概念。
28
+
29
+ ## URI 与代码引用
30
+
31
+ 所有跨节点/文件引用都是引号字符串 URI:
32
+
33
+ | 目标 | canonical 形态 | 示例 |
34
+ |---|---|---|
35
+ | 当前 bundle 相对文件 | `vfs://./<path>` | `vfs://./instruction.md` |
36
+ | workspace 文件 | `vfs://@/<path>` | `vfs://@/apps/demo/src/procedures.ts` |
37
+ | TypeScript 导出 | `vfs://...#<ExportName>` | `vfs://@/apps/demo/src/procedures.ts#prepareProcedure` |
38
+ | 规范资源 identity | `resource://<FQN>` | `resource://demo.resource_workflow.prepare_data` |
39
+ | 当前容器 id | `<domain>://#<id>` | `catalog://#functions` |
40
+
41
+ 代码引用必须包含 export fragment。XNL 只保存声明式 binding;函数、闭包、表达式字符串和 handler object 不得内嵌到 XNL。执行代码的协议和副作用由 runtime/component contract 定义,不属于 parser。
42
+
43
+ ## Authoring 与 projection
44
+
45
+ ```text
46
+ XNL authority document
47
+ -> xnl-core node tree
48
+ -> validated normalized resource descriptor + provenance
49
+ -> registry / mapping / application assembly projections
50
+ ```
51
+
52
+ - authority:磁盘上的 `.xnl` 文档;唯一可编辑事实。
53
+ - parser tree:语法投影,只由 resource-core loader 消费。
54
+ - normalized descriptor:稳定领域边界,携带 `resourceId`、`kind`、metadata、members、subdomains、`documentUri`、`logicalPath`;Kind-owned 可选属性保持存在或缺失的原始事实。
55
+ - consumer projection:可重建;不得暴露 parser node 内部字段,也不得反写 authority。
56
+
57
+ package provenance 从 package manifest、document URI 与 logical path 派生。descriptor 不重复保存一份可由路径计算的 package identity。
58
+
59
+ ## 声明式限制
60
+
61
+ - 一个 bundle 内的配置只使用 XNL,不引入 JSON/XML/YAML 第二配置入口。
62
+ - 动态代码保存在 `.ts` 等外部文件,通过 `vfs://...#Export` 挂接。
63
+ - 不允许将 XML attributes 转换成 `@_name` 或其他前缀键后暴露给 consumer。
64
+ - 不允许根据文件名猜测 kind;文件内容的 tag 才是 authority。
@@ -0,0 +1,10 @@
1
+ <ResourcePackage #Halfcode.ResourceDsl.Package apiVersion="halfcode.resources/v1" version="1.0.0" {
2
+ lifecycle = "Stable"
3
+ description = "Canonical Halfcode Resource DSL documentation and consumer Skill resources."
4
+ } (
5
+ <Catalogs [
6
+ <Catalog #KindDefinitions { kind = "KindDefinition" shape = "directory" root = "vfs://./KindDefinitions/" entry = "manifest.xnl" }>
7
+ <Catalog #WikiPages { kind = "WikiPage" shape = "directory" root = "vfs://./WikiPages/" entry = "manifest.xnl" }>
8
+ <Catalog #SkillCapsules { kind = "SkillCapsule" shape = "directory" root = "vfs://./SkillCapsules/" entry = "manifest.xnl" }>
9
+ ]>
10
+ )>
@@ -0,0 +1,40 @@
1
+ # XML To XNL Migration
2
+
3
+ ## 迁移原则
4
+
5
+ 迁移单位是“资源语义”,不是 tag/attribute 的逐字符替换:
6
+
7
+ | XML-era 表达 | XNL authority |
8
+ |---|---|
9
+ | 根 element 名 | 根 tag(resource kind) |
10
+ | `Id`/`Name` 等身份 attribute | 根 `#id` FQN;display name 若存在则留在 `{}` |
11
+ | `Version`/schema version | metadata 位的 `version`/`apiVersion` |
12
+ | 普通 attributes | `{}` 中归节点所有的属性 |
13
+ | 唯一 child section | `()` 中的唯一子域 |
14
+ | 重复 child elements | 父 `[]` 或复数子域的 `[]` |
15
+ | 文件路径/code export | 引号字符串 `vfs://...#Export` |
16
+ | parser `@_foo`/XmlObject | 不迁移;在 normalized descriptor 边界消失 |
17
+
18
+ ## 顺序
19
+
20
+ 1. 用 `KindDefinition` 明确 kind contract。
21
+ - 声明 `currentApiVersion` 与 `supportedApiVersions`。
22
+ - 对不可直接兼容的历史版本,在代码侧 `ResourceMigrationRegistry` 注册唯一纯转换链;XNL 不内嵌 transformer。
23
+ 2. 将 package/catalog authority 改为 XNL。
24
+ 3. 逐个资源按领域语义分配 `{}`、`()`、`[]`,保留稳定 `#id`。
25
+ 4. 将路径与代码引用规范为 VFS URI。
26
+ 5. 通过 resource-core 得到 normalized descriptor,再迁移 consumer。
27
+ 6. 删除兼容 XML 与 `fast-xml-parser`,以产品 XML inventory 清零作为关闭条件。
28
+
29
+ ## 明确拒绝
30
+
31
+ - 在 TypeScript 中保留 `XmlObject`、`@_` 属性前缀或 XML child-array 作为公开类型。
32
+ - 同一资源同时维护 XML 与 XNL 两份长期 authority。
33
+ - 根据目录名/文件名猜 kind 或 identity。
34
+ - 在 XNL 内嵌函数、闭包或可执行表达式字符串。
35
+ - 用无语义的 wrapper 模拟 XML 层级。
36
+ - 在 BusinessObject/PageObject API 尚未稳定时提前设计二者的专用 XNL schema。
37
+
38
+ ## 暂时兼容
39
+
40
+ 后续实现 track 可以在内部短期 dual-read,用于小步迁移和 characterization test;兼容层不得进入 public API,并必须在 `close-xnl-only-product-surface` track 删除。
@@ -0,0 +1,142 @@
1
+ # Resource Projections and Dependency Authority
2
+
3
+ ## Authority map
4
+
5
+ 资源 authoring、组合与运行闭包是三个不同层次,不能互相替代:
6
+
7
+ | Fact | Authority owner | Halfcode projection |
8
+ |---|---|---|
9
+ | package、Catalog、KindDefinition、resource descriptor | XNL ResourcePackage | `LoadedResourceTree extends ResourceTree` |
10
+ | layer precedence | 调用方提供的有序 `ResourceLayerInput[]` | `EffectiveResourceRegistry.layers` |
11
+ | suppression | 调用方显式提供的 `ResourceTombstone` | effective/tombstone/shadow provenance |
12
+ | Kind-specific dependency semantics | 对应 Kind owner 或 consumer | `ResourceDependencyEdge[]` |
13
+ | XNL authority bytes | canonical loader 的同一次 raw-byte read | `LoadedResourceTree.contentIdentities` |
14
+ | Kind-specific material bytes | Kind owner 提供的显式 digest contribution | effective `ResourceContentIdentity` |
15
+ | roots 与 dependency closure | 调用方的显式 roots 加 typed edges | `ResourceDependencySnapshot` |
16
+
17
+ `ResourceTree` 是单个已验证 package 的规范化结果。`EffectiveResourceRegistry` 只是多个 tree 的确定性只读投影;它会 deep-clone/freeze record、metadata、node/value 与 KindDefinition facts,避免调用方之后修改输入而改变既有投影,但不会原地冻结或改写旧 `ResourceTree`。`ResourceDependencySnapshot` 又是某组 roots 在一个 content-sensitive registry revision 上的冻结闭包。两种投影都可由 authority facts 重建,不得反写任一 XNL package,也不得成为第二份 authoring 真源。
18
+
19
+ Snapshot builder 只接受同一 resource-core runtime 中由 `composeLayeredResourceRegistry()` 返回的 canonical immutable registry。手工构造、浅拷贝或改写 revision 字段的结构相似对象会 fail closed;需要跨进程恢复时,应从 XNL packages、ordered layers 与 tombstones 重新组合。Snapshot 会复制并冻结自己的 origin facts,不共享可变调用方引用。
20
+
21
+ ## Ordered named layers
22
+
23
+ layer 只包含一个不透明、稳定的 `id` 和一个已验证 `ResourceTree`。数组从低 precedence 到高 precedence 排列,后一个 layer 优先。Halfcode 不保留特殊 layer 名称,不根据名称重排,也不拥有任何产品安装目录或机器路径策略;实际 roots 由 consumer 在调用 resource-core 之前绑定。
24
+
25
+ 组合规则是:
26
+
27
+ 1. 同一 `resourceId`、同一 kind 的高层资源成为 effective;低层 origin 留在 `shadowed`。
28
+ 2. 同一 identity 跨 kind,或同一 resource kind 的规范化 KindDefinition contract 不兼容,组合失败并返回稳定 diagnostics。
29
+ 3. 高层没有某个资源只表示“未提供”,绝不表示删除。
30
+ 4. 删除语义必须通过 `ResourceTombstone { resourceId, expectedKind?, reason? }` 显式声明;tombstone origin 与历史保留在 projection 中。
31
+ 5. `byKind` 只包含 effective resources;完整 effective、shadow 与 tombstone 证据由 `byId` 保存。
32
+ 6. `documentUri` 必须是与安全相对 `logicalPath` 一致的 canonical `vfs://@/` URI;非 loader 来源的绝对机器路径或 traversal provenance 会 fail closed。
33
+
34
+ ```ts
35
+ import {
36
+ composeLayeredResourceRegistry,
37
+ type ResourceLayerInput,
38
+ } from "halfcode-compiler.xnl/resource-core"
39
+
40
+ declare const lowerPackage: ResourceLayerInput["tree"]
41
+ declare const higherPackage: ResourceLayerInput["tree"]
42
+
43
+ const registry = composeLayeredResourceRegistry({
44
+ layers: [
45
+ { id: "base", tree: lowerPackage },
46
+ {
47
+ id: "override",
48
+ tree: higherPackage,
49
+ tombstones: [{ resourceId: "demo.retired", expectedKind: "Function" }],
50
+ },
51
+ ],
52
+ })
53
+ ```
54
+
55
+ 示例中的名字仅用于展示调用顺序,不携带预定义语义。consumer 可以选择任何稳定 id;改变数组顺序才会改变 precedence。
56
+
57
+ ## Explicit content identity
58
+
59
+ canonical loader 对每个 XNL authority 文件只读取一次 raw bytes:同一次读取同时用于 fatal UTF-8 decode、XNL parse 和 SHA-256。成功加载后返回 additive `LoadedResourceTree`;其 `contentIdentities` 精确覆盖 `registry.byKind` 的业务 resources,不包含 package manifest 或 KindDefinition。multi-root document 的 roots 共享同一文件级 `authorityDigest`,但各自的 `resourceId` 和 `contentDigest` 独立。
60
+
61
+ `ResourceTree` 仍是兼容父接口,手工 structural tree 仍可参与 generic layer composition。只有 canonical loader 返回并由当前 runtime 登记的 `LoadedResourceTree` 才能进入 `resolveEffectiveResourceContentIdentities()`。projector exact 核对 registry 的 layer id、顺序、package 与 effective origin,从每个 effective layer 选择 loader identity;shadowed non-effective resource 与 tombstone 不进入结果。Kind owner 再把 prompt、schema、instruction 等 material 作为带稳定 `key`、`digest` 和可选 `sourceUri` 的 contribution 显式提供。
62
+
63
+ `createResourceContentIdentity()` 按 UTF-16 code-unit key 顺序 canonicalize contributions,并拒绝任何重复 key;即使 digest 相同,重复或不同 provenance 也不是可静默折叠的合法事实。snapshot builder 会对全部 effective resources 重新规范化 authority/contribution facts、重算 `contentDigest` 并核对 claim;它不会只验证 roots 可达的 identity,也不会信任调用方构造的对象。`sourceUri` 是 provenance,不允许机器绝对路径进入 content revision;调用方应使用 Resource DSL 定义的逻辑 URI。
64
+
65
+ ```ts
66
+ import {
67
+ composeLayeredResourceRegistry,
68
+ loadResourceTree,
69
+ resolveEffectiveResourceContentIdentities,
70
+ } from "halfcode-compiler.xnl/resource-core"
71
+
72
+ declare const lowerPackageRoot: string
73
+ declare const higherPackageRoot: string
74
+ declare const contributions: Parameters<typeof resolveEffectiveResourceContentIdentities>[0]["contributions"]
75
+
76
+ const lowerPackage = await loadResourceTree({ rootDir: lowerPackageRoot })
77
+ const higherPackage = await loadResourceTree({ rootDir: higherPackageRoot })
78
+ const registry = composeLayeredResourceRegistry({
79
+ layers: [
80
+ { id: "lower", tree: lowerPackage },
81
+ { id: "higher", tree: higherPackage },
82
+ ],
83
+ })
84
+
85
+ const identities = resolveEffectiveResourceContentIdentities({
86
+ registry,
87
+ layers: [
88
+ { id: "lower", tree: lowerPackage },
89
+ { id: "higher", tree: higherPackage },
90
+ ],
91
+ contributions,
92
+ })
93
+ ```
94
+
95
+ 示例中的 `lowerPackageRoot`、`higherPackageRoot` 与 `contributions` 由 consumer 在调用边界绑定。Halfcode 不定义机器安装目录或 layer precedence policy,也不会重复读取 XNL authority。projector 的结果可直接传给 snapshot builder;snapshot builder 仍不执行隐藏 IO。
96
+
97
+ ## Typed dependency closure
98
+
99
+ 依赖的字段语义属于 Kind owner。它负责把自己的 descriptor contract 转成 `ResourceDependencyEdge { fromResourceId, toResourceId, relation, declaredBy }`。resource-core 只校验 endpoint、从显式 roots 沿这些边遍历、拒绝可达 cycle,并生成稳定排序的 snapshot。
100
+
101
+ ```ts
102
+ import {
103
+ buildResourceDependencySnapshot,
104
+ type EffectiveResourceRegistry,
105
+ type ResourceDependencyEdge,
106
+ type ResourceContentIdentity,
107
+ } from "halfcode-compiler.xnl/resource-core"
108
+
109
+ declare const registry: EffectiveResourceRegistry
110
+ declare const workflowIdentity: ResourceContentIdentity
111
+ declare const schemaIdentity: ResourceContentIdentity
112
+
113
+ const edges: readonly ResourceDependencyEdge[] = [{
114
+ fromResourceId: workflowIdentity.resourceId,
115
+ toResourceId: schemaIdentity.resourceId,
116
+ relation: "uses-schema",
117
+ declaredBy: "WorkflowKindDefinition",
118
+ }]
119
+
120
+ const snapshot = buildResourceDependencySnapshot({
121
+ registry,
122
+ roots: [workflowIdentity.resourceId],
123
+ edges,
124
+ contentIdentities: new Map([
125
+ [workflowIdentity.resourceId, workflowIdentity],
126
+ [schemaIdentity.resourceId, schemaIdentity],
127
+ ]),
128
+ })
129
+ ```
130
+
131
+ 普通文本、instruction 或 `ResourceNode` property 即使看起来像资源 URI,只要 Kind owner 没有提供 typed edge,就不会进入 closure。resource-core 不遍历任意字符串、不匹配自然语言关键词,也不猜测引用字段。
132
+
133
+ ## Deterministic revisions
134
+
135
+ - content revision 覆盖 resource identity、authority digest 与按 key 排序的 material digests。
136
+ - `compositionRevision` 覆盖显式 layer 顺序、effective identity/presence、shadow/tombstone facts、选定 KindDefinition 的 authority `resourceId`/兼容 contract 与 canonical `documentUri/logicalPath` provenance;`EffectiveResourceRegistry.revision` 是它的精确兼容别名。ResourceRecord descriptor/node/metadata bytes 不进入该摘要,而由显式 content identity 负责。不同 definition identity 不会自行把相同 normalized Kind contract 变成冲突。
137
+ - snapshot 的 `registryRevision` 覆盖 `compositionRevision` 与全部 effective resource 的已验证 content revisions,包括当前 roots 不可达的资源。
138
+ - `snapshotRevision` 覆盖显式 root 顺序、可达资源 content revisions、参与闭包的 typed edges 与 `registryRevision`。
139
+ - revisions 使用带算法前缀的 SHA-256 形式;逻辑 provenance 在 projection 中保留,机器绝对路径不得进入摘要。
140
+ - canonical object key、resource、kind、edge 与 contribution 排序固定使用 ECMAScript UTF-16 code-unit 顺序,不依赖 locale、ICU、文件枚举或 Map 插入顺序。
141
+
142
+ 缺失 endpoint、缺失 content identity、identity-kind/KindDefinition conflict、矛盾 digest 或 dependency cycle 都会 fail closed;调用方不会收到看似完整的 partial snapshot。
@@ -0,0 +1,94 @@
1
+ # SkillCapsule Dependencies And Distribution
2
+
3
+ ## Identity authority
4
+
5
+ 新的 `SkillCapsule` descriptor 由 XNL 根节点独占 FQN、consumer-facing `name`、`apiVersion` 与 `version`。`SKILL.metadata.yaml` 只保存 title/description 等呈现字段,不重复 name/version;assembly 会把 canonical XNL name/version 投影给模板。若 descriptor 已声明 `name` 而 YAML 仍重复该字段,assembly 在 compiler 写入前以 `SKILL_CAPSULE_NAME_DUPLICATE` 失败。历史 descriptor 未声明 XNL name 时,既有 YAML name 与 FQN 尾段 fallback 继续兼容;新资源不得采用该兼容路径。
6
+
7
+ XNL `version` 也是 capsule identity 与 dependency binding 的唯一 version authority。历史 YAML 若仍带 `version`,必须与 XNL 严格相等,否则 assembly 以 `SKILL_CAPSULE_VERSION_CONFLICT` 失败。
8
+
9
+ ```xnl
10
+ <SkillCapsule #example.resource_lifecycle.skill.authoring
11
+ apiVersion="halfcode.resources/v1"
12
+ version="1.0.0" {
13
+ name = "example-resource-authoring"
14
+ description = "Generic resource authoring operations."
15
+ } (
16
+ <SkillMetadata { href = "vfs://./SKILL.metadata.yaml" format = "yaml" }>
17
+ <Template { href = "vfs://./SKILL.template.ejs" format = "ejs" }>
18
+ )>
19
+ ```
20
+
21
+ 对应 YAML 只保存呈现字段:
22
+
23
+ ```yaml
24
+ title: Example Resource Authoring
25
+ description: Generic resource authoring operations.
26
+ ```
27
+
28
+ ## `SkillDependencies` 与 `Includes`
29
+
30
+ 两种关系不可互换,也不做名称或文本推断:
31
+
32
+ - `SkillDependencies/SkillDependency` 声明同一个 `ApplicationAssembly.byFqn` resource universe 中的 sibling `SkillCapsule`。`ref` 必须是 `resource://<FQN>`,目标 kind 必须是 `SkillCapsule`,`version` 是必填的精确 binding;当前版本不解释 semver range。
33
+ - `Includes/Include` 选择要编入当前 capsule 的 Function、PromptFragment 等普通资源。即便一个 Include 写了 `kind = "SkillCapsule"`,planner 也不会把它提升为 sibling dependency。
34
+
35
+ ```xnl
36
+ <SkillDependencies [
37
+ <SkillDependency {
38
+ ref = "resource://example.resource_lifecycle.skill.resource_dsl"
39
+ version = "1.0.0"
40
+ }>
41
+ ]>
42
+ <Includes [
43
+ <Include {
44
+ kind = "PromptFragment"
45
+ ref = "resource://example.resource_lifecycle.prompt.authoring_prelude"
46
+ }>
47
+ ]>
48
+ ```
49
+
50
+ 缺失目标、错误 kind、重复 dependency、精确版本不匹配和 cycle 都会 fail closed。依赖解析只读取既有 application assembly,不创建第二份 catalog 或 scanner。
51
+
52
+ ## 四 Skill canonical topology
53
+
54
+ 规范示例使用与具体产品无关的四个 Skill:
55
+
56
+ ```text
57
+ resource DSL -> authoring -> devops/root
58
+ run -> devops/root
59
+ ```
60
+
61
+ - `devops/root` 显式依赖 `authoring` 与 `run`;
62
+ - `authoring` 显式依赖共享 `resource DSL`;
63
+ - `run` 与 `resource DSL` 没有 sibling dependency。
64
+
65
+ 完整 descriptor 分别位于 [skill-capsule-devops.xnl](examples/skill-capsule-devops.xnl)、[skill-capsule-authoring.xnl](examples/skill-capsule-authoring.xnl)、[skill-capsule-run.xnl](examples/skill-capsule-run.xnl) 和 [skill-capsule-resource-dsl.xnl](examples/skill-capsule-resource-dsl.xnl)。可加载、可规划的 bundle fixture 位于 `apps/demo-resource-workflow-authoring/resources-xnl/SkillCapsules/Topology*`。所有 consumer name 与 version 都由 XNL 声明,dependency 绑定 `1.0.0`,YAML 不重复 identity 字段。
66
+
67
+ ## Deterministic plan 与 atomic apply
68
+
69
+ `planSkillCapsuleDistribution` 与 `applySkillCapsuleDistributionPlan` 是两个独立阶段:
70
+
71
+ 1. planner 从显式 roots 解析传递闭包,按固定 code-unit 顺序生成 dependency-first topology;
72
+ 2. planner 读取所有 generated/mapped bytes,并将 canonical bytes 保存为不可变、可序列化的 `contentBase64` authority;兼容字段 `content` 每次读取只返回新的 defensive copy;
73
+ 3. planner 对所有会进入 SKILL/reference/callable bytes 的资源集合按 FQN 使用固定 UTF-16 code-unit comparator 排序,并对完整 closure 做重复 output name、相同 target 与文件/目录 prefix collision preflight;
74
+ 4. plan 保存 versioned content/capsule/closure digest,且不含绝对路径、时间戳或函数对象;plan 成功或失败都不写目标 root;
75
+ 5. applier 先 fail-closed 校验非空 roots、root 可达的完整闭包、canonical base64 与全部 digest,再在 caller 提供的 `outputRoot` 同父目录 stage、readback,以 backup/rename/rollback 成组切换。
76
+
77
+ 每个 planned capsule 还必须包含固定路径 `references/.halfcode/provenance.json`。该文件由 compiler 生成,不由模板维护;它记录 `halfcode.skill-provenance/v1` format、`halfcode.skill-distribution/v1` generator、SkillCapsule XNL 的 FQN/apiVersion/version,以及除自身以外全部 payload files 的 canonical path/content digest。manifest 自身作为普通 planned file 进入 capsule/closure digest,因此不需要自引用摘要。applier 会在任何目标写入前从 plan 重建并 exact 校验这些 facts。
78
+
79
+ ```ts
80
+ const plan = await planSkillCapsuleDistribution({
81
+ assembly,
82
+ rootSkillFqns: ["example.resource_lifecycle.skill.devops"],
83
+ })
84
+
85
+ await applySkillCapsuleDistributionPlan(plan, { outputRoot })
86
+ ```
87
+
88
+ Halfcode 只拥有通用 resource dependency、plan 与 atomic apply contract;目标 root、安装位置、生命周期阶段和升级策略都由 caller/host 决定。compiler 不推导这些 policy,也不把它们写进资源 authority。
89
+
90
+ ## Consumer Resource DSL Skill
91
+
92
+ `docs/resource-dsl/manifest.xnl` 将本目录的 canonical 文档登记为 ResourcePackage/WikiPage resources,并声明 `Halfcode.ResourceDsl.Skill.System`。compiler 从这些原始文档生成 `sys-halfcode-resource-dsl@1.0.0` 的 references;`SKILL.md` 只提供渐进加载顺序,不复制规范正文,也不包含仓库维护命令或 host 安装操作。仓库维护者继续使用 `skills/framework-resource-dsl`,两者职责不可互换。
93
+
94
+ 既有 `compileSkillCapsule`、`compileResourceSkillCapsule` 与 `SkillCapsulePlan` 保持兼容。新 planner/applier 和类型从 package root 及 `halfcode-compiler.xnl/skill-capsule` additive 导出。