@avantf/dsh-plugin-base 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (135) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +303 -0
  3. package/dist/artifact.d.ts +29 -0
  4. package/dist/artifact.d.ts.map +1 -0
  5. package/dist/artifact.js +60 -0
  6. package/dist/artifact.js.map +1 -0
  7. package/dist/bootstrap.d.ts +54 -0
  8. package/dist/bootstrap.d.ts.map +1 -0
  9. package/dist/bootstrap.js +334 -0
  10. package/dist/bootstrap.js.map +1 -0
  11. package/dist/cli.d.ts +4 -0
  12. package/dist/cli.d.ts.map +1 -0
  13. package/dist/cli.js +37 -0
  14. package/dist/cli.js.map +1 -0
  15. package/dist/compat.d.ts +413 -0
  16. package/dist/compat.d.ts.map +1 -0
  17. package/dist/compat.js +742 -0
  18. package/dist/compat.js.map +1 -0
  19. package/dist/conformance.d.ts +55 -0
  20. package/dist/conformance.d.ts.map +1 -0
  21. package/dist/conformance.js +702 -0
  22. package/dist/conformance.js.map +1 -0
  23. package/dist/errors.d.ts +26 -0
  24. package/dist/errors.d.ts.map +1 -0
  25. package/dist/errors.js +28 -0
  26. package/dist/errors.js.map +1 -0
  27. package/dist/fs.d.ts +18 -0
  28. package/dist/fs.d.ts.map +1 -0
  29. package/dist/fs.js +152 -0
  30. package/dist/fs.js.map +1 -0
  31. package/dist/index.d.ts +22 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +35 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/integrity.d.ts +5 -0
  36. package/dist/integrity.d.ts.map +1 -0
  37. package/dist/integrity.js +33 -0
  38. package/dist/integrity.js.map +1 -0
  39. package/dist/interface.d.ts +262 -0
  40. package/dist/interface.d.ts.map +1 -0
  41. package/dist/interface.js +136 -0
  42. package/dist/interface.js.map +1 -0
  43. package/dist/interface_gate.d.ts +61 -0
  44. package/dist/interface_gate.d.ts.map +1 -0
  45. package/dist/interface_gate.js +103 -0
  46. package/dist/interface_gate.js.map +1 -0
  47. package/dist/internal.d.ts +23 -0
  48. package/dist/internal.d.ts.map +1 -0
  49. package/dist/internal.js +18 -0
  50. package/dist/internal.js.map +1 -0
  51. package/dist/kit/family.d.ts +52 -0
  52. package/dist/kit/family.d.ts.map +1 -0
  53. package/dist/kit/family.js +65 -0
  54. package/dist/kit/family.js.map +1 -0
  55. package/dist/kit/index.d.ts +26 -0
  56. package/dist/kit/index.d.ts.map +1 -0
  57. package/dist/kit/index.js +26 -0
  58. package/dist/kit/index.js.map +1 -0
  59. package/dist/kit/logger.d.ts +41 -0
  60. package/dist/kit/logger.d.ts.map +1 -0
  61. package/dist/kit/logger.js +42 -0
  62. package/dist/kit/logger.js.map +1 -0
  63. package/dist/kit/prompt_files.d.ts +90 -0
  64. package/dist/kit/prompt_files.d.ts.map +1 -0
  65. package/dist/kit/prompt_files.js +121 -0
  66. package/dist/kit/prompt_files.js.map +1 -0
  67. package/dist/kit/typert.d.ts +40 -0
  68. package/dist/kit/typert.d.ts.map +1 -0
  69. package/dist/kit/typert.js +17 -0
  70. package/dist/kit/typert.js.map +1 -0
  71. package/dist/layout.d.ts +28 -0
  72. package/dist/layout.d.ts.map +1 -0
  73. package/dist/layout.js +84 -0
  74. package/dist/layout.js.map +1 -0
  75. package/dist/lint.d.ts +33 -0
  76. package/dist/lint.d.ts.map +1 -0
  77. package/dist/lint.js +271 -0
  78. package/dist/lint.js.map +1 -0
  79. package/dist/lock.d.ts +12 -0
  80. package/dist/lock.d.ts.map +1 -0
  81. package/dist/lock.js +93 -0
  82. package/dist/lock.js.map +1 -0
  83. package/dist/manifest.d.ts +12 -0
  84. package/dist/manifest.d.ts.map +1 -0
  85. package/dist/manifest.js +75 -0
  86. package/dist/manifest.js.map +1 -0
  87. package/dist/net.d.ts +23 -0
  88. package/dist/net.d.ts.map +1 -0
  89. package/dist/net.js +112 -0
  90. package/dist/net.js.map +1 -0
  91. package/dist/package-name.d.ts +3 -0
  92. package/dist/package-name.d.ts.map +1 -0
  93. package/dist/package-name.js +13 -0
  94. package/dist/package-name.js.map +1 -0
  95. package/dist/preset.d.ts +46 -0
  96. package/dist/preset.d.ts.map +1 -0
  97. package/dist/preset.js +230 -0
  98. package/dist/preset.js.map +1 -0
  99. package/dist/providers/archive.d.ts +32 -0
  100. package/dist/providers/archive.d.ts.map +1 -0
  101. package/dist/providers/archive.js +248 -0
  102. package/dist/providers/archive.js.map +1 -0
  103. package/dist/providers/model.d.ts +25 -0
  104. package/dist/providers/model.d.ts.map +1 -0
  105. package/dist/providers/model.js +550 -0
  106. package/dist/providers/model.js.map +1 -0
  107. package/dist/providers/npm.d.ts +21 -0
  108. package/dist/providers/npm.d.ts.map +1 -0
  109. package/dist/providers/npm.js +458 -0
  110. package/dist/providers/npm.js.map +1 -0
  111. package/dist/provisioner.d.ts +21 -0
  112. package/dist/provisioner.d.ts.map +1 -0
  113. package/dist/provisioner.js +962 -0
  114. package/dist/provisioner.js.map +1 -0
  115. package/dist/semver.d.ts +31 -0
  116. package/dist/semver.d.ts.map +1 -0
  117. package/dist/semver.js +244 -0
  118. package/dist/semver.js.map +1 -0
  119. package/dist/state.d.ts +71 -0
  120. package/dist/state.d.ts.map +1 -0
  121. package/dist/state.js +225 -0
  122. package/dist/state.js.map +1 -0
  123. package/dist/tar.d.ts +10 -0
  124. package/dist/tar.d.ts.map +1 -0
  125. package/dist/tar.js +178 -0
  126. package/dist/tar.js.map +1 -0
  127. package/dist/types.d.ts +431 -0
  128. package/dist/types.d.ts.map +1 -0
  129. package/dist/types.js +2 -0
  130. package/dist/types.js.map +1 -0
  131. package/dist/zip.d.ts +8 -0
  132. package/dist/zip.d.ts.map +1 -0
  133. package/dist/zip.js +109 -0
  134. package/dist/zip.js.map +1 -0
  135. package/package.json +84 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 qunqi.ff
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,303 @@
1
+ # @avantf/dsh-plugin-base
2
+
3
+ 给 DSH 插件用的基础包,把三件容易各写一遍的事收在一起:**启动期资源预装**、**宿主兼容门禁**、
4
+ **一组与 DSH 无关的共享工具**。
5
+
6
+ - **运行期零依赖**:`dependencies` 为空,源码里连 `zod` 都不 import。
7
+ - 唯一一条 peer 是 `zod`(`>=4.4.3 <5`),由宿主 / 上层提供,好让调用方、本包与宿主解析到**同一份**
8
+ `zod` —— 两份物理副本的 schema 身份不同,strict codec 会因此判不兼容。
9
+ - 要求 **Node.js ≥ 22**。
10
+
11
+ ## 主要功能
12
+
13
+ ### 1. 资源预装(声明式 provisioner)
14
+
15
+ 调用方只写一份清单,其余交给框架:
16
+
17
+ ```
18
+ 声明 → 探测 → 获取 → 校验 → 报告
19
+ ```
20
+
21
+ - 已经在盘上 / PATH 上的直接用,不重复下载;
22
+ - 需要安装的由框架下载、校验完整性、**原子落盘**(同目录临时文件 + rename;跨进程一把族根锁);
23
+ - 每一项给出 `present / installed / skipped / failed`,失败带稳定 `code`;
24
+ - 三种内置资源种类:`npm-package`、`binary-archive`、`model-cache`。新的种类 = 一个新的 provider,
25
+ 核心不动;
26
+ - 策略可配:离线、镜像、每项的并发与超时、启动预算、下载总闸。
27
+
28
+ ### 2. 宿主兼容门禁
29
+
30
+ 在挂载之前判断"当前宿主能不能跑这段代码",语义是**只有被证实的不兼容才拒绝**:
31
+
32
+ - 调用方交出自己真实的 contribution 与契约(服务、工具、方法、wire schema),由探针在**真实宿主**上验;
33
+ - 说不清只是一条备注,版本差异只是警告,**绝不抛错**;
34
+ - `compatReport(verdict, words)` 把裁决渲染成一份报告:**结构归本包,措辞归调用方**;
35
+ - `registerMegaphone` 在拒绝加载的路径上留一条用户可见的命令(那时它是唯一的信息渠道);
36
+ - `verifyRegisteredFaces` 在挂载后复查"声明的每个 schema / 工具真的注册上了"(只告警)。
37
+
38
+ ### 3. 共享工具(kit)
39
+
40
+ 与 DSH 无关的纯逻辑,调用方在运行时复用:
41
+
42
+ | 工具 | 作用 |
43
+ | --- | --- |
44
+ | `PromptFiles` | "缺失或空白就写入默认、有内容则逐字读回"的用户可编辑文本文件层(含崩溃残留的死临时文件清理) |
45
+ | `createPluginLogger` | 带统一前缀、可镜像到宿主 logger 的 logger |
46
+ | `familyHome` / `familyToolsDir` / `familyModelsDir` / `resolveDataHome` / `expandHome` | 家族根与数据根解析:**⑤ 显式 → ④ 环境变量 → ② 配置值 → 默认**,一律传**具名 slot** |
47
+ | `strictCodec` / `endpointId` / `fieldSymbol` / `resultSymbol` | 组装 Typert wire 描述符的几行约定 |
48
+
49
+ ### 4. 接口世代
50
+
51
+ `.` 上的导出构成本包的**接口**,由世代号冻结:
52
+
53
+ - `INTERFACE_VERSION`(正整数)+ `api/interface-vN.json` 快照(该代的值名与类型名,随源码在仓库里,
54
+ 不进产物);
55
+ - `checkInterface(required, module)`:把"调用方构建时所对的世代"与"运行时加载到的本包报告的世代"
56
+ 比一比,返回 `ok` / `incompatible` / `cannot-tell`。纯函数、**双向**、读属性有守卫(取属性就抛的
57
+ 对象读成"没报")、**永不抛**;
58
+ - `readInterfaceRequirement(url)`:读调用方产物里烘着的那条记录 `{ baseVersion, interfaceVersion }`;
59
+ 缺失或畸形返回 `undefined`("没烘"),不抛;
60
+ - 拿到 `incompatible` 时的建议动作是**降级**(不使用本包的共享能力)而不是拒绝挂载 —— 本包只把裁决与
61
+ 一句话的 `reason` 交出去,怎么处理由调用方决定。
62
+
63
+ ## 怎么用
64
+
65
+ ### 安装
66
+
67
+ ```bash
68
+ npm install @avantf/dsh-plugin-base
69
+ ```
70
+
71
+ ### 预装资源
72
+
73
+ ```ts
74
+ import { homedir } from 'node:os'
75
+ import { join } from 'node:path'
76
+ import type { Provisioner } from '@avantf/dsh-plugin-base'
77
+
78
+ const home = join(homedir(), '.avantf', 'env')
79
+
80
+ const provisioner: Provisioner = framework.createProvisioner({ home, logger })
81
+ provisioner.register(framework.npmPackageProvider())
82
+ provisioner.register(framework.binaryArchiveProvider())
83
+ provisioner.register(framework.modelCacheProvider())
84
+ provisioner.declare(manifest)
85
+
86
+ // 挂载前必须就绪的项:阻塞等待
87
+ await provisioner.ensure({ only: ['my-plugin:compat'], deadlineMs: 30_000 })
88
+
89
+ // 其余项(含 background)后台预装,到达终态时回调
90
+ void provisioner.ensure({
91
+ onSettled: entry => {
92
+ if (entry.id === 'my-plugin:model' && entry.action === 'installed') useModel()
93
+ if (entry.action === 'failed') logger.warn(`${entry.id}: ${entry.code}`)
94
+ },
95
+ })
96
+ ```
97
+
98
+ ### 写清单
99
+
100
+ ```jsonc
101
+ {
102
+ "plugin": "my-plugin",
103
+ "items": [
104
+ {
105
+ "id": "my-plugin:compat",
106
+ "kind": "npm-package",
107
+ "spec": { "name": "@scope/compat", "range": "^1.0.0" },
108
+ "target": { "root": "runtime" },
109
+ "startup": "blocking",
110
+ "schemaVersion": 1
111
+ },
112
+ {
113
+ "id": "my-plugin:tool",
114
+ "kind": "binary-archive",
115
+ "spec": {
116
+ "id": "tool", "version": "1.2.3",
117
+ "packs": { "linux-x64": { "url": "https://…/tool.tar.gz", "sha256": "<hex>" } }
118
+ },
119
+ "target": { "root": "tools" },
120
+ "onMissing": { "atStartup": "degrade", "atUse": "error" },
121
+ "schemaVersion": 1
122
+ },
123
+ {
124
+ "id": "my-plugin:model",
125
+ "kind": "model-cache",
126
+ "spec": { "repo": "org/name", "revision": "main", "layout": "flat", "files": ["config.json"] },
127
+ "target": { "root": "models" },
128
+ "startup": "background",
129
+ "schemaVersion": 1
130
+ }
131
+ ]
132
+ }
133
+ ```
134
+
135
+ - `startup`:`blocking`(缺省,`ensure` 等它)或 `background`(派发后不占启动预算)。
136
+ - `onMissing.atStartup`:`degrade`(缺了也继续)/ `refuse`;`onMissing.atUse`:`degrade` / `error`。
137
+ - `needs`:同一清单内其它 item 的 id。
138
+
139
+ `model-cache` 的 `spec.layout` 决定文件怎么落盘:
140
+
141
+ | layout | 落盘形态 | 谁读 |
142
+ | --- | --- | --- |
143
+ | `hub`(缺省) | `<root>/models--<org>--<name>/{blobs,refs,snapshots/<sha>/<file>}` 的内容寻址快照树 | 认这套缓存形状的客户端 |
144
+ | `flat` | `<root>/<org>/<name>/<file>`,文件直接可读;revision 记录与 blob 在 `<root>/.envinit/` 侧车目录 | 直接按 `<repo>/<file>` 路径读取的运行时 |
145
+
146
+ 两种布局共用同一套 revision 解析、文件列表、模型 hub 端点、内容寻址 blob 与原子落盘;`config.json`
147
+ 在两种布局里都必需,`spec.requiredFiles` 在其上追加。已经落位但内容不对的条目(旧残留、指向错误 blob
148
+ 的链接、同名目录)会在下次落位时被换成指向正确 blob 的链接。
149
+
150
+ `probe` 只做廉价的存在性判断(存在、不是目录、大小 > 0),不联网、不改盘;`verify` 才证明内容:
151
+ `hub` 逐项核对链接目标、blob 名与内容哈希;`flat` 按侧车记录里的 sha256 逐项核对(只有文件名的旧记录
152
+ 仍然接受,不会把装好的树判成未安装)。落位与完成标记在同一把族根锁内完成。
153
+
154
+ > **只增不减**:受管的模型数据不会回收。`blobs` 与 `snapshots` 永不删除,换一个 revision 就会再存一份;
155
+ > `experimental().prune()` 只是打一条告警的 no-op。
156
+
157
+ `endpoint` 默认是内置的模型 hub;`policy.mirrors.model` 可给一组镜像端点(按序尝试、内置端点兜底),
158
+ `spec.endpoint` 优先于镜像。显式给出空白的 `endpoint`、非法的 `revision`(空、`.`、`..`、绝对路径、
159
+ 反斜杠、控制字符)都会报 `invalid-option`。
160
+
161
+ ```ts
162
+ framework.createProvisioner({
163
+ home,
164
+ logger,
165
+ policy: { mirrors: { archive: [], model: ['https://mirror.example'] } },
166
+ })
167
+ ```
168
+
169
+ 清单可以离线检查:
170
+
171
+ ```bash
172
+ provision lint manifest.json
173
+ ```
174
+
175
+ ### 取用就绪资源
176
+
177
+ ```ts
178
+ const state = provisioner.resolve('my-plugin:tool')
179
+ if (state.state === 'ready') {
180
+ const entry = state.handle.dir // 可用入口目录(归档:可执行文件所在目录)
181
+ const env = state.handle.env // PATH 等环境增量
182
+ }
183
+ ```
184
+
185
+ `resolve()` 的五个状态:`ready` / `pending` / `failed` / `skipped` / `missing`。`ensure()` 返回的报告里
186
+ `ok` **不**把"还在后台装"算成失败。
187
+
188
+ ### 跑兼容门禁
189
+
190
+ ```ts
191
+ import { compatReport, gatherEvidence, verdictOf } from '@avantf/dsh-plugin-base'
192
+
193
+ const verdict = verdictOf(gatherEvidence(ctx, spec))
194
+ if (!verdict.load) {
195
+ log.error(compatReport(verdict, {
196
+ heading: '插件未加载:与当前宿主的兼容性检查未通过。',
197
+ warningsLabel: '风险提示:',
198
+ warnings: verdict.warnings,
199
+ fix: '升级宿主,或按本插件声明的版本重建。',
200
+ logPointer: prefix => `完整诊断见日志里 ${prefix} 开头的行。`,
201
+ }))
202
+ }
203
+ ```
204
+
205
+ ### 取用共享工具
206
+
207
+ ```ts
208
+ import { PromptFiles, createPluginLogger } from '@avantf/dsh-plugin-base'
209
+
210
+ const log = createPluginLogger({ prefix: '@scope/my-plugin' })
211
+ const files = new PromptFiles({ dir: join(dataHome, 'prompts'), logger: log })
212
+ .load([{ file: 'my-plugin-prompt.md', fallback: '内置默认正文\n' }])
213
+ // files[0].text —— 用户写的正文(逐字),或刚写下的默认正文
214
+ ```
215
+
216
+ ### 运行时装载(`./bootstrap`)
217
+
218
+ 如果调用方要在**运行时**装载本包(而不是让它出现在自己的 import 图里),本包提供零依赖的
219
+ `./bootstrap`:解析本包在哪 → 校验版本落在给定区间 → 动态 `import()`。它**不安装任何东西**,
220
+ 失败只返回 `undefined` 并给出原因。
221
+
222
+ ```ts
223
+ import { loadFramework, readDependencyRange } from '@avantf/dsh-plugin-base/bootstrap'
224
+
225
+ const range = await readDependencyRange(import.meta.url) // 调用方自己声明的区间
226
+ const framework = await loadFramework<typeof import('@avantf/dsh-plugin-base')>({ logger })
227
+ if (framework === undefined) {
228
+ logger.warn('本包不可用,按自己的默认路径继续')
229
+ } else {
230
+ // 用 framework.xxx
231
+ }
232
+ ```
233
+
234
+ 有打包步骤时,本包提供构建预设把 `./bootstrap` 内联进产物、并断言产物里没有本包的静态引用:
235
+
236
+ ```ts
237
+ import { envinitPreset, assertEnvinitArtifacts, assertEnvinitPresetChecks } from '@avantf/dsh-plugin-base/preset'
238
+
239
+ const preset = envinitPreset({ external: [/* 自己的外部名白名单 */] })
240
+ assertEnvinitPresetChecks(preset.checks)
241
+ // bundler:external 用 preset.external,内联 preset.noExternal;产物写出后再断言:
242
+ assertEnvinitPresetChecks(assertEnvinitArtifacts({
243
+ artifacts: ['dist/plugin.js'],
244
+ clientArtifacts: ['dist/client.js'],
245
+ }))
246
+ ```
247
+
248
+ ### 写 provider(可选)
249
+
250
+ 新增资源种类 = 新增一个 provider(不动核心)。provider 是实现五个动作的 npm 包:
251
+
252
+ ```ts
253
+ import type { Provider } from '@avantf/dsh-plugin-base'
254
+
255
+ export const myProvider: Provider = {
256
+ id: '@scope/my-provider',
257
+ kinds: ['@scope/my-kind'],
258
+ identify: item => ({ name: '…', range: '…' }),
259
+ probe: async (item, ctx) => ({ found: false }), // 只读、不联网
260
+ plan: () => ({ action: 'install' }), // 纯函数
261
+ targetDir: (_item, ref) => `${ref.name}/${ref.segment}`, // 安全相对路径
262
+ install: async (item, ctx) => ctx.publish(await ctx.stage(), { name: '…', version: '…' }),
263
+ verify: async (item, resolved, ctx) => { /* 证明能用 */ },
264
+ }
265
+ ```
266
+
267
+ 用一致性套件跑一遍再发布:
268
+
269
+ ```ts
270
+ import { assertProviderConformance, runProviderConformance } from '@avantf/dsh-plugin-base/conformance'
271
+
272
+ const report = await runProviderConformance({ provider: myProvider, items: [...], packageName: '@scope/my-provider' })
273
+ assertProviderConformance(report)
274
+ ```
275
+
276
+ ## 边界(不做的事)
277
+
278
+ - **不做包管理器**:不推导传递依赖、不生成 lockfile、不做版本求解;每个 item 自包含。
279
+ - **不接管原生模块**:`binding.gyp` / `*.node` / 依赖 `postinstall` 的包会被识别并拒绝。
280
+ - **不跳过校验**:npm 包核对 `dist.integrity`,归档核对 `sha256`。
281
+ - **不做进程内预热**:让文件在盘上是框架的事,读进内存是调用方自己的事。
282
+
283
+ ## 版本承诺
284
+
285
+ - 承诺稳定的接口是 `.` 上的导出(值 + 类型)与 `./preset` / `./conformance` / `./bootstrap` 三个子路径;
286
+ `./internal` 是内部件,不承诺稳定。
287
+ - **接口与包版本是两条轴**:接口换代只升 `INTERFACE_VERSION` 并新增 `api/interface-vN.json`;包版本是
288
+ 普通 semver,只表达包自身(行为变更 minor、修复 patch)。
289
+ - 顺序敏感的参数一律传**具名对象**(如 `resolveDataHome({ explicit, env, configured })`);可观察的文案
290
+ 由调用方给(如 `compatReport` 的 `words`)。
291
+
292
+ ## 开发
293
+
294
+ ```bash
295
+ pnpm check # 类型检查 + 测试
296
+ pnpm build # tsc → dist/
297
+ pnpm pack # 打包到 release/ 并断言产物
298
+ pnpm release:check # 发布门禁:typecheck → build → test → pack
299
+ ```
300
+
301
+ ## 许可
302
+
303
+ MIT
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Build-time artifact scanning.
3
+ * @module artifact
4
+ */
5
+ /** The framework package name. */
6
+ export declare const FRAMEWORK_PACKAGE = "@avantf/dsh-plugin-base";
7
+ /** The one subpath a plugin build must inline rather than externalise. */
8
+ export declare const BOOTSTRAP_SUBPATH = "@avantf/dsh-plugin-base/bootstrap";
9
+ /** How a specifier was referenced, when it really is a module reference. */
10
+ export type FrameworkImportKind = 'static' | 'side-effect' | 'dynamic' | 'require';
11
+ export interface FrameworkImportRef {
12
+ readonly specifier: string;
13
+ readonly kind: FrameworkImportKind;
14
+ /** True for `@avantf/dsh-plugin-base/bootstrap` and anything under it. */
15
+ readonly bootstrap: boolean;
16
+ /** Byte offset of the specifier in the scanned text. */
17
+ readonly index: number;
18
+ }
19
+ /** True for the bootstrap subpath. */
20
+ export declare function isBootstrapSpecifier(specifier: string): boolean;
21
+ /** Control-plane literals of the framework's own implementation; counted once {@link MIN_INLINING_BEACONS} distinct names appear. */
22
+ export declare const FRAMEWORK_INLINING_BEACONS: readonly string[];
23
+ /** How many distinct beacons count as "the framework was inlined". */
24
+ export declare const MIN_INLINING_BEACONS = 3;
25
+ /** The inlining beacons present in one artifact. */
26
+ export declare function findInliningBeacons(text: string): readonly string[];
27
+ /** Every framework module reference in one emitted artifact, in source order. */
28
+ export declare function findFrameworkImports(text: string): readonly FrameworkImportRef[];
29
+ //# sourceMappingURL=artifact.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"artifact.d.ts","sourceRoot":"","sources":["../src/artifact.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,kCAAkC;AAClC,eAAO,MAAM,iBAAiB,4BAA4B,CAAA;AAE1D,0EAA0E;AAC1E,eAAO,MAAM,iBAAiB,sCAAmC,CAAA;AAEjE,4EAA4E;AAC5E,MAAM,MAAM,mBAAmB,GAAG,QAAQ,GAAG,aAAa,GAAG,SAAS,GAAG,SAAS,CAAA;AAElF,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAA;IAClC,0EAA0E;IAC1E,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;IAC3B,wDAAwD;IACxD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CACvB;AAED,sCAAsC;AACtC,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAE/D;AAED,qIAAqI;AACrI,eAAO,MAAM,0BAA0B,EAAE,SAAS,MAAM,EAOvD,CAAA;AAED,sEAAsE;AACtE,eAAO,MAAM,oBAAoB,IAAI,CAAA;AAErC,oDAAoD;AACpD,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAEnE;AAgBD,iFAAiF;AACjF,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,kBAAkB,EAAE,CAYhF"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Build-time artifact scanning.
3
+ * @module artifact
4
+ */
5
+ /** The framework package name. */
6
+ export const FRAMEWORK_PACKAGE = '@avantf/dsh-plugin-base';
7
+ /** The one subpath a plugin build must inline rather than externalise. */
8
+ export const BOOTSTRAP_SUBPATH = `${FRAMEWORK_PACKAGE}/bootstrap`;
9
+ /** True for the bootstrap subpath. */
10
+ export function isBootstrapSpecifier(specifier) {
11
+ return specifier === BOOTSTRAP_SUBPATH || specifier.startsWith(`${BOOTSTRAP_SUBPATH}/`);
12
+ }
13
+ /** Control-plane literals of the framework's own implementation; counted once {@link MIN_INLINING_BEACONS} distinct names appear. */
14
+ export const FRAMEWORK_INLINING_BEACONS = [
15
+ '.status.lock',
16
+ '.layout.json',
17
+ '.quarantine',
18
+ '.envinit',
19
+ 'status.json',
20
+ 'declared.json',
21
+ ];
22
+ /** How many distinct beacons count as "the framework was inlined". */
23
+ export const MIN_INLINING_BEACONS = 3;
24
+ /** The inlining beacons present in one artifact. */
25
+ export function findInliningBeacons(text) {
26
+ return FRAMEWORK_INLINING_BEACONS.filter(beacon => text.includes(beacon));
27
+ }
28
+ const ESCAPED_PACKAGE = FRAMEWORK_PACKAGE.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
29
+ const SPECIFIER = new RegExp(`(['"])(${ESCAPED_PACKAGE}(?:/[^'"]*)?)\\1`, 'g');
30
+ const WINDOW = 40;
31
+ /** Classify a specifier by the token in front of the literal. */
32
+ function classify(prefix) {
33
+ const trimmed = prefix.trimEnd();
34
+ if (/(?:^|[^\w$])import\s*\($/.test(trimmed))
35
+ return 'dynamic';
36
+ if (/require\s*\($/.test(trimmed))
37
+ return 'require';
38
+ if (/(?:^|[^\w$])from$/.test(trimmed))
39
+ return 'static';
40
+ if (/(?:^|[^\w$])import$/.test(trimmed))
41
+ return 'side-effect';
42
+ return undefined;
43
+ }
44
+ /** Every framework module reference in one emitted artifact, in source order. */
45
+ export function findFrameworkImports(text) {
46
+ const found = [];
47
+ SPECIFIER.lastIndex = 0;
48
+ for (let match = SPECIFIER.exec(text); match !== null; match = SPECIFIER.exec(text)) {
49
+ const specifier = match[2];
50
+ if (specifier === undefined)
51
+ continue;
52
+ const index = match.index;
53
+ const kind = classify(text.slice(Math.max(0, index - WINDOW), index));
54
+ if (kind === undefined)
55
+ continue;
56
+ found.push({ specifier, kind, bootstrap: isBootstrapSpecifier(specifier), index });
57
+ }
58
+ return found;
59
+ }
60
+ //# sourceMappingURL=artifact.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"artifact.js","sourceRoot":"","sources":["../src/artifact.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,kCAAkC;AAClC,MAAM,CAAC,MAAM,iBAAiB,GAAG,yBAAyB,CAAA;AAE1D,0EAA0E;AAC1E,MAAM,CAAC,MAAM,iBAAiB,GAAG,GAAG,iBAAiB,YAAY,CAAA;AAcjE,sCAAsC;AACtC,MAAM,UAAU,oBAAoB,CAAC,SAAiB;IACpD,OAAO,SAAS,KAAK,iBAAiB,IAAI,SAAS,CAAC,UAAU,CAAC,GAAG,iBAAiB,GAAG,CAAC,CAAA;AACzF,CAAC;AAED,qIAAqI;AACrI,MAAM,CAAC,MAAM,0BAA0B,GAAsB;IAC3D,cAAc;IACd,cAAc;IACd,aAAa;IACb,UAAU;IACV,aAAa;IACb,eAAe;CAChB,CAAA;AAED,sEAAsE;AACtE,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAA;AAErC,oDAAoD;AACpD,MAAM,UAAU,mBAAmB,CAAC,IAAY;IAC9C,OAAO,0BAA0B,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAA;AAC3E,CAAC;AAED,MAAM,eAAe,GAAG,iBAAiB,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAA;AAChF,MAAM,SAAS,GAAG,IAAI,MAAM,CAAC,UAAU,eAAe,kBAAkB,EAAE,GAAG,CAAC,CAAA;AAC9E,MAAM,MAAM,GAAG,EAAE,CAAA;AAEjB,iEAAiE;AACjE,SAAS,QAAQ,CAAC,MAAc;IAC9B,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,EAAE,CAAA;IAChC,IAAI,0BAA0B,CAAC,IAAI,CAAC,OAAO,CAAC;QAAE,OAAO,SAAS,CAAA;IAC9D,IAAI,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC;QAAE,OAAO,SAAS,CAAA;IACnD,IAAI,mBAAmB,CAAC,IAAI,CAAC,OAAO,CAAC;QAAE,OAAO,QAAQ,CAAA;IACtD,IAAI,qBAAqB,CAAC,IAAI,CAAC,OAAO,CAAC;QAAE,OAAO,aAAa,CAAA;IAC7D,OAAO,SAAS,CAAA;AAClB,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,oBAAoB,CAAC,IAAY;IAC/C,MAAM,KAAK,GAAyB,EAAE,CAAA;IACtC,SAAS,CAAC,SAAS,GAAG,CAAC,CAAA;IACvB,KAAK,IAAI,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,KAAK,KAAK,IAAI,EAAE,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACpF,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC,CAAA;QAC1B,IAAI,SAAS,KAAK,SAAS;YAAE,SAAQ;QACrC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAA;QACzB,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC,EAAE,KAAK,CAAC,CAAC,CAAA;QACrE,IAAI,IAAI,KAAK,SAAS;YAAE,SAAQ;QAChC,KAAK,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,oBAAoB,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,CAAC,CAAA;IACpF,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Resolve the framework copy the caller's tree already has.
3
+ * @module bootstrap
4
+ */
5
+ /** The bootstrap version; the resolved framework must satisfy {@link supportedRange}. */
6
+ export declare const VERSION = "0.3.1";
7
+ /**
8
+ * The framework interval this bootstrap can launch.
9
+ *
10
+ * Kept equal to the plugins' peer range for the base: the plugin passes no override, so THIS is the
11
+ * runtime gate. It is a plain comparator interval, NOT a caret: the package version is ordinary
12
+ * semver again and no longer tracks the interface, so the interval stays as wide as the family's
13
+ * compatibility promise — `>=0.3.0 <1.0.0` admits every 0.x base this generation of plugins can
14
+ * consume, and stops at the major that invented a new interface generation. The interface itself is
15
+ * the separate, runtime axis: a base inside this interval whose `INTERFACE_VERSION` differs is judged
16
+ * by the base's own gate (INTERFACE.md §1, §3), which degrades rather than refusing.
17
+ */
18
+ export declare const supportedRange = ">=0.3.0 <1.0.0";
19
+ /** Sink for the warnings that replace a throw. */
20
+ export interface BootstrapLogger {
21
+ warn(message: string): void;
22
+ info?(message: string): void;
23
+ }
24
+ /** What {@link ensureFramework} needs to accept the resolved copy. */
25
+ export interface EnsureFrameworkOptions {
26
+ readonly logger?: BootstrapLogger;
27
+ /** Override the baked {@link supportedRange}. */
28
+ readonly supportedRange?: string;
29
+ }
30
+ /** The framework copy the caller's tree resolves to. */
31
+ export interface FrameworkLocation {
32
+ /** A `file://` URL ready for `import()`. */
33
+ readonly url: string;
34
+ readonly version: string;
35
+ readonly dir: string;
36
+ /** Always `resolved`: the package manager's copy. */
37
+ readonly source: 'resolved';
38
+ }
39
+ /**
40
+ * Report the framework copy this caller's tree resolves to, or `undefined` with a warning.
41
+ * Never throws and never installs anything.
42
+ *
43
+ * @param options - the logger and an optional interval override.
44
+ * @returns the located copy, or `undefined` when it is absent or outside the interval.
45
+ */
46
+ export declare function ensureFramework(options: EnsureFrameworkOptions): Promise<FrameworkLocation | undefined>;
47
+ /** `ensureFramework` + a dynamic `import()` of the located module; never throws. */
48
+ export declare function loadFramework<T = unknown>(options: EnsureFrameworkOptions): Promise<T | undefined>;
49
+ /**
50
+ * Read the range a plugin declares in the nearest `package.json`: walk up from `from`,
51
+ * preferring `peerDependencies` over `devDependencies`; `undefined` when none is found.
52
+ */
53
+ export declare function readDependencyRange(from?: string): Promise<string | undefined>;
54
+ //# sourceMappingURL=bootstrap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bootstrap.d.ts","sourceRoot":"","sources":["../src/bootstrap.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,yFAAyF;AACzF,eAAO,MAAM,OAAO,UAAU,CAAA;AAC9B;;;;;;;;;;GAUG;AACH,eAAO,MAAM,cAAc,mBAAmB,CAAA;AAI9C,kDAAkD;AAClD,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,IAAI,CAAC,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;CAC7B;AAED,sEAAsE;AACtE,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,MAAM,CAAC,EAAE,eAAe,CAAA;IACjC,iDAAiD;IACjD,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAA;CACjC;AAED,wDAAwD;AACxD,MAAM,WAAW,iBAAiB;IAChC,4CAA4C;IAC5C,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,qDAAqD;IACrD,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAA;CAC5B;AA8LD;;;;;;GAMG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,iBAAiB,GAAG,SAAS,CAAC,CAoC7G;AAED,oFAAoF;AACpF,wBAAsB,aAAa,CAAC,CAAC,GAAG,OAAO,EAAE,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,CAaxG;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,IAAI,GAAE,MAAsB,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAuCnG"}