Skip to content

sdk/rust: official Rust SDK for plugin backends (function protocol 2, credentials) - #2

Merged
1lck merged 3 commits into
mainfrom
sdk/rust
Oct 25, 2026
Merged

1lck merged 3 commits into
mainfrom
sdk/rust

Conversation

@1lck

@1lck 1lck commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

背景

数据库模块已改造成独立插件(主仓库 1lck/Lithe-IDEA#1470,已合并;插件现作为 Lithe Store 社区插件发布)。插件后端用 Rust 写,同一份代码给两个平台用,所以需要一个官方 Rust SDK。主仓库 #1470 已经在契约里新增了:

  • backend 1 能力:插件自己的后端进程;
  • 插件函数协议 v2;
  • 宿主凭据服务(lithe/host/credentials/*)。

本 PR 是这些契约在 SDK 侧的实现。

✅ 合并顺序:#1470 已合并进 preview(d046fd1),contract.lock.json 已重新锁定到这个合并提交(本 PR 的 2a83502)。

改动

1. 契约镜像(单独提交 contract: pin …)

  • contract.lock.json 和 contract/v1/ 同步到 Lithe preview d046fd1(#1470 的合并提交;新增网页桥接第 2 版的文件对话框和当前 Windows WebView2 状态)。
  • 新增:backend.plugin.json fixture、函数协议 v2 / hostRequests golden cases、backend 的拒绝用例和 schema 字段。
  • 顺带同步了上次锁定(18345cc)之后主仓库已合入的契约变更:native UI schema 和 fixtures、项目生成器 fixtures。

2. sdk/rust:lithe-plugin-sdk crate(新增)

  • 只依赖 serde_json,基于线程,MSRV Rust 1.87。

  • framing:LSP Content-Length 帧,限制与 Node SDK 一致(header 8 KiB、body 64 MiB)。非 JSON 的 body 回 -32700,不破坏帧位置。

  • 生命周期:initialize → shutdown → exit。初始化前的请求回 -32002,关闭中回 -32600。退出码为 shutdown+exit → 0,其余 → 1。

  • 协商:优先应答 host 提供的最新版本(2 → 1)。host 没提供就不声明函数,此时调用回 -32602。

  • 函数:

    • 每个调用一个线程。
    • 进度通过 lithe/function/progress 上报,message 截到 1024 字节、percentage 截到 100,调用结束后丢弃。
    • 取消:$/cancelRequest、shutdown、反注册都会触发 Cancellation。它提供 is_cancelled、check、wait_timeout、on_cancel 回调。
  • 错误映射:

    处理函数结果 回给 host
    PluginError -32000,data.code 带插件自己的错误码
    其他错误或 panic -32603 通用消息,细节只写 stderr
    已取消 -32800
    结果超过 1 MiB 按内部错误处理
  • 运行时注册:BackendHandle::register_function / unregister_function 发 lithe/function/register / unregister,并按调用顺序串行。注册被拒绝时回滚;反注册时取消该函数正在运行的调用。

  • 凭据:Credentials::get/set/delete,只在协商到 v2 时可用,否则返回 sdk.protocol.notNegotiated,不发送任何请求。key 和 secret 先在本地校验。从 Context 拿到的凭据请求会随调用取消立即返回 sdk.call.cancelled,? 会把它转成取消应答。

  • stdout 保护:Unix 上 listen() 把协议输出移到 stdout 的 dup,再把 fd 1 指向 stderr。这样插件或依赖里误用 println! 不会破坏协议。

  • 测试:

    • tests/session.rs 有 13 个用例,脚本化 host 通过进程内 pipe 驱动 session,所有等待都有上限,本地连跑 30 次稳定。
    • 另有 9 个单元测试(framing、校验、错误映射等)。

3. 示例 sdk/rust/examples/sample-backend

完整插件:plugin.json(backend + credentials.store + web 工具窗口)、CSP 合规的网页(ui/)和后端。演示的能力:

  • 在 ${stateDir} 存笔记,带进度;
  • 首次存笔记后在运行时注册 note.clear,重启时如果已有笔记,就在 on_initialize 里直接提供;
  • 通过宿主凭据服务存密码,页面只拿到“是否匹配”;
  • 可取消的等待;
  • 不泄露路径的意外失败。

4. 端到端:sdk/e2e/plugin_sdk/backend.rs + plugin_sdk_rust.rs

测试扮演宿主:

  • 用 backend: true 展开 launch plan,以 pluginBackend:<id> 启动打包好的示例,并传入 hostServices;
  • 用内存凭据库应答 Core 的 hostRequest 事件(lsp.hostResponse)。

覆盖:

  • 函数、进度、插件错误码;
  • 意外失败不泄露路径;
  • 凭据全流程;
  • 取消能传到处理函数;
  • 运行时注册;
  • 重启后状态保留;
  • 没有 credentials.store 时 Core 直接拒绝,请求不会到达宿主;
  • 插件包运行时不变。

scripts/sdk-e2e.mjs 会用 Cargo 编译示例(也可以用 LITHE_PLUGIN_SDK_RUST_SAMPLE 指定已编译的可执行文件),并多跑 plugin_sdk_rust。

5. CI / 发布 / 文档

  • verify.yml 新增 Rust SDK job:Rust 1.87 跑测试,stable 跑 fmt --check 和 clippy -D warnings。e2e 的缓存加上 sdk/rust/target。
  • 新增 release-rust-sdk.yml:推 sdk-rust-v* 标签时校验版本、跑测试,并发布 lithe-plugin-sdk-rust-<v>.crate 和 .sha256。
  • 新增 sdk/rust/README.md;根 README 的 SDK 表、测试命令和发版说明加入 Rust;.gitignore 忽略 sdk/rust/target/。
  • 暂不包含:构建后端、VCS 后端、进程辅助(README 中说明请用 Node.js / Java SDK)。

验证(本地,macOS arm64)

  • cargo test --locked:22 个测试全部通过。cargo clippy --all-targets -D warnings 和 cargo fmt --check 都干净。
  • node scripts/sdk-e2e.mjs --source <#1470 工作树> --ref feat/database-plugin:Node(构建、VCS)、Java、Rust 三个 e2e 全部通过。
  • 重新锁定后:node scripts/sdk-e2e.mjs(默认用锁定的 d046fd1)三个 e2e 全部通过;node scripts/contract.mjs verify --upstream 39 个文件校验通过;CI 全绿。
  • node scripts/contract.mjs verify:39 个文件与锁一致。node --test scripts/*.test.mjs:13 个通过。

🤖 Generated with Claude Code

1lck and others added 2 commits October 24, 2026 07:29
…n protocol 2)

Pins the commit of 1lck/Lithe-IDEA#1470 that adds the backend capability,
plugin-function protocol 2 with the credentials host service, and lists
the Rust SDK. Re-pin to preview once that pull request merges.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
lithe-plugin-sdk implements plugin-function protocols 1 and 2 for the
packaged backend a plugin declares under `backend`: framing, negotiation,
functions on their own threads with progress and cancellation, runtime
registration, error mapping (PluginError, internal failures, panics), and
the credentials host service. It depends only on serde_json.

The sample backend (notes in ${stateDir}, a secret in the host's
credential store, cancellation) runs a new end-to-end scenario against
Rust Core in which the test serves the host requests. CI tests on Rust
1.87 and lints on stable; sdk-rust-v* tags release a .crate and its SHA-256.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…plugin)

Lithe preview merged 1lck/Lithe-IDEA#1470. The mirror now matches that merge
commit: web bridge 2 file dialogs (dialog.openFile, dialog.saveFile) and the
current Windows WebView2 status.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@1lck
1lck marked this pull request as ready for review October 25, 2026 04:06
@1lck
1lck merged commit 2215a62 into main Oct 25, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant