跳到内容
Lenso
简体中文
Esc
导航打开⌘J预览
本页内容

使用 TypeScript 构建 Host

准备真实运行文件,验证 Host 生命周期,并识别 Bun Plugin 当前阻塞。

Lenso 已有 TypeScript/Bun Host:@lenso/cli/host 描述组合,生成的 host.js 管理生命周期,Rust lenso-host-runtime 装配 Kernel 与 Bun/Process Adapter。 Host 控制 API 提供 startinspectstop,业务入口由 Plugin 持有。

验证状态与前置条件

2026-09-07 在 macOS ARM64 上从新目录验证的结果如下。当前不能把它当作带 Bun Plugin 的一键启动教程;先用空 Host 验证真实生命周期,再检查下面的 Plugin 阻塞。

路径 本次结果
Bun Plugin scaffold、check、pack 通过,生成 Bundle 4
将该 Bundle 加入 TypeScript Host 被运行 Profile 准入拒绝
空 Host build、check、show、prepare 通过
生成入口的 start、inspect、stop、再次 start 通过,恢复同一个 Generation
物理退出 termination: confirmed,但 forced: true
CLI plugin dev 执行业务调用 运行时嵌套错误,未成功调用

需要 Git、Rust 工具链、Bun 和 macOS ARM64;下列命令在新目录中执行。此次 Bun 版本为 1.4.1-canary.1,这不是对其他平台或所有 Bun 版本的验证。

mkdir host-walkthrough
cd host-walkthrough
bun add --dev @lenso/cli@0.16.1

获取可运行文件

npm CLI 自带当前平台的 resolver 和生成控制库,不自带完整 Host 运行环境。 下面固定源代码与 lockfile 来构建此次验证使用的两个二进制,不依赖同名的全局 CLI:

git clone https://github.com/LioRael/lenso-bun-adapter.git runtime-source
git -C runtime-source checkout 3c1f2f011f4f9d496db337f296ad686ab0a985e0
cargo build --locked --manifest-path runtime-source/Cargo.toml -p lenso-host-runtime

git clone https://github.com/LioRael/lenso-runtime-rust.git owner-source
git -C owner-source checkout 1e3915a
cargo build --locked --manifest-path owner-source/Cargo.toml \
  -p lenso-runner --bin lenso-process-owner --features process-owner
prepare 输入 来源
--runtime runtime-source/target/debug/lenso-host-runtime,版本 0.1.5
--owner owner-source/target/debug/lenso-process-owner,由 lenso-runner 0.2.13 提供
--resolver node_modules/@lenso/cli/vendor/darwin-arm64/lenso
控制库 通过 npm launcher 自动传入;不要单独调用系统中的旧 lenso
--bun 有 Bun 实现时必需,提供目标平台的真实可执行文件
--notices 对所分发文件适用的第三方声明文件,必须非空

如果配置了 CARGO_TARGET_DIR,二进制会位于该目录,而不是以上默认路径。 本地空 Host 演示可以用源仓库许可证作为 notices 输入:

cp runtime-source/LICENSE THIRD_PARTY_NOTICES.txt

这只是本地演示输入,不是对整个运行环境的完整再分发声明。交付给他人前,应收集 实际二进制、依赖和 Bun 的适用声明,并使用对应目标的发布构建。

构建一个空 Host

下面的 empty-host.ts 不需要虚构或另行下载的示例 Bundle。它用于验证控制路径, 不执行任何业务 Plugin。

import { defineHost } from "@lenso/cli/host";
export default defineHost({ id: "example.empty-host", plugins: [] });
bun --bun run lenso app build --source empty-host.ts --target aarch64-apple-darwin --out build/empty
bun --bun run lenso app check --root build/empty
bun --bun run lenso app show --root build/empty --json

预期输出包含零个 Instance 和 binding。每次构建/prepare 都需要新的输出目录。 构建输出只有 authority 与 Bundle inventory;lenso run 不能启动它。

准备与启动

bun --bun run lenso app prepare \
  --build build/empty --target aarch64-apple-darwin \
  --runtime runtime-source/target/debug/lenso-host-runtime \
  --owner owner-source/target/debug/lenso-process-owner \
  --resolver node_modules/@lenso/cli/vendor/darwin-arm64/lenso \
  --notices THIRD_PARTY_NOTICES.txt --out dist/empty
mkdir -p state/app

空 Host 不需要 --bun。有 Bun 实现时还须把精确 Bun 可执行文件交给 prepare。 分发目录中的 lock 校验每个不可变文件;不要修改文件后重写摘要来绕过失败。 可变 App Root 使用 state/app,不要把 build/empty 当成运行 Root,也不要把另一份 Host authority 复制进去。

创建以下脚本,通过生成入口等待 Ready、检查结构并关闭:

import { start } from "./dist/empty/host.js";

const app = await start({ root: `${import.meta.dir}/state/app` });
try {
  console.log(JSON.stringify(await app.inspect()));
} finally {
  const outcome = await app.stop();
  console.log(JSON.stringify(outcome));
  if (outcome.shutdown !== "suspended" ||
      outcome.ownership.termination !== "confirmed") {
    process.exitCode = 1;
  }
}
bun lifecycle.ts
bun lifecycle.ts

start 返回表示 Ready Gate 已打开。检查结果包含 revisiongenerationinstancesdiagnostics;第二次启动应恢复同一个 Generation,revision 可以变化。 本次实际结果为 shutdown: suspendedtermination: confirmedforced: true。 前两项分别说明已持久化挂起与确认进程终止;forced 表示发生强制清理,不能称为完全 优雅退出。脚本不会隐藏这个字段。

常驻运行可用 bun dist/empty/host.js --root "$PWD/state/app",通过 Ctrl+C/SIGTERM 请求关闭。默认 ownership registry 在 Root 旁边的 .lenso-owners。重复启动必须使用 同一 registry;不要为绕过所有权冲突而换目录或删除锁。start 还接受 registrystartupMsstopMsconfirmationMs,它们控制等待预算,不保证强制终止等同于业务关闭。

添加真实 Bun Plugin:目前的阻塞

以下命令能生成并打包真实 Bundle,替代没有来源的 company.notes

bun --bun run lenso plugin new example.host-echo --runtime bun
bun --bun run lenso plugin check --repo-root example.host-echo --json
bun --bun run lenso plugin pack --repo-root example.host-echo --output echo.lenso-plugin --json
import { defineHost, pluginBundle } from "@lenso/cli/host";
export default defineHost({
  id: "example.echo-host",
  plugins: [pluginBundle("./echo.lenso-plugin")],
});
bun --bun run lenso app build --source app.ts --target aarch64-apple-darwin --out build/echo

在已验证的 CLI 版本上,最后一步报错 V4 Bundle has no implementation admitted by Host policy。 该 Bundle 声明 lenso.bun-authoring@2,而当前 Host builder 的 V2 准入使用 lenso.plugin-authoring@2。改成 --target javascript-bun 也不能解决这次 Profile 拒绝。 不要修改 Bundle manifest、伪造摘要或使用空 Host 的成功来替代真实 Plugin 验收。

业务调用仍应通过 Plugin 的公开入口,或开发期 plugin dev 验证;app.inspect() 只查看结构,没有 app.invoke()。本次 plugin dev --operation execute 出现 Cannot start a runtime from within a runtime,所以尚未获得成功业务返回。 document-sync的独立测试 Host 证据也不等于此分发路径已跑通。

bun --bun run lenso plugin dev --repo-root example.host-echo \
  --operation execute \
  --request-json '{"name":"example.host-echo","arguments_json":"{\"text\":\"hello\"}"}'

多 Instance、扩展与配置

下面是配置结构示例,依赖项目自己提供的、已被目标 Profile 接纳的 Store/Copy Bundle; 不是上面 echo 示例的可执行续篇。假设 Store 声明 store Slot、Copy 有两个命名依赖。

import { defineHost, pluginBundle } from "@lenso/cli/host";
const store = pluginBundle("./store.lenso-plugin");
export default defineHost({
  id: "company.copy-host",
  plugins: [
    { plugin: store, instance: "source", configuration: { namespace: "source" } },
    { plugin: store, instance: "destination", configuration: { namespace: "dest" } },
    pluginBundle("./copy.lenso-plugin"),
  ],
  slots: [{ id: "store", cardinality: "many" }],
  dependencies: [
    {
      consumer: { plugin: "company.copy" }, requirement: "source",
      allow: [{ plugin: "company.store", instance: "source" }],
      default: { plugin: "company.store", instance: "source" },
    },
    {
      consumer: { plugin: "company.copy" }, requirement: "destination",
      allow: [{ plugin: "company.store", instance: "destination" }],
      default: { plugin: "company.store", instance: "destination" },
    },
  ],
});

Host 默认封闭:现有配置必须通过 Plugin Schema,新增 Instance 和替换版本需要明确 授权。可扩展 Slot 使用 allow: [pluginBundle(...)]maxInstances(1–256); one Slot 的替换还需要 replaceable: trueconfigurationSchema 约束合并后的 配置,不能替代 Plugin 自己的 Schema,也不是 OS 沙箱。完整授权示例与支持的 Schema 关键字见Host 声明参考

路径相对声明文件解析。声明支持静态对象、数组、常量和相对默认导入,不执行环境读取、 动态导入、spread、任意函数或业务模块。Host 声明 Profile 目前只接纳 Request,最多 256 个 Instance/Slot;Bun SDK 的 Stream/Event 支持不会自动扩大它。

恢复、升级与排错

正常停止后保留外部 Root 与共享 registry,使用原始未修改分发目录重启。当前证据证明 同一精确 Generation 的恢复,不代表任意版本升级。升级使用新的 build/prepare 目录, 先确认旧进程已终止,再验证目标分发与持久状态兼容;备份 Root 和持久数据。没有公开的 通用热升级命令,不应直接覆盖运行目录或修改 lock。

现象 检查与处理
Host Catalog is unavailable 先确认 build 成功;不要继续检查未生成的输出
V4 Bundle has no implementation admitted by Host policy 比对 execution class、runtime profile 和目标;当前 echo 有上述已复现阻塞
Cannot start a runtime from within a runtime 当前 CLI dev 已复现;增加超时不能解决,应修复运行时集成后复验
prepared Host needs the generated npm control library 通过项目 npm launcher 调用 prepare,避免旧的全局二进制
distribution target ... does not support ... 平台/架构不匹配,重新提供正确目标的文件
failed integrity / not a regular file 恢复原始文件,检查符号链接与内容;不要绕过校验
ownership 冲突 检查原进程和共享 registry;不要删除锁或另建 registry 强行并发
startup timeout Ready 未确认;检查 Profile、Bundle 和 Root,不能把进程存在当作可用
shutdown: failed、终止未确认或 forced: true 分别保留业务关闭和物理退出结果;不能统一记录为优雅成功

此次验证只覆盖声明检查、真实空 Host 生命周期和上述失败路径,没有证明带 Bun Plugin 的完整分发,也没有验证崩溃注入或跨版本升级。后续修复后应重跑相同流程,更新这份状态表。

最后更新于 2026年9月6日

这个页面有帮助吗?