docs: correct plugindev toolchain usage, Lua execution model, and stale plugin examples

- 工具链:修正 bundle 默认开启(plugindev build 默认多平台合集)、补充 --no-bundle/debug/--target/--outdir/--sdk-path/--replace 用法、Lua 打包内容、安装端点语义
- 新增「执行模型」节:Lua 插件为被动回调模型,无常驻服务能力
- OVERVIEW/ARCHITECTURE:示例列表与 Lua 加载描述修正(internal/plugin gopher-lua,非 internal/lua VM;无热加载)
This commit is contained in:
root
2026-07-31 12:59:06 +08:00
parent 0f68608403
commit 96e6784a7c
6 changed files with 120 additions and 43 deletions

View File

@ -259,13 +259,13 @@ VM built-ins: `json.encode` / `json.decode` / `log` / `http_get` / `http_post`.
| Method | Registration Mechanism | Compilation | Usage | | Method | Registration Mechanism | Compilation | Usage |
|--------|----------------------|-------------|-------| |--------|----------------------|-------------|-------|
| Built-in | `init()``RegisterFactory` | `internal/plugins/` compiled into kernel | webui/cli/timer/mcp etc. | | Built-in | `init()``RegisterFactory` | `internal/plugins/` compiled into kernel | webui/cli/timer/mcp etc. |
| External `.so` | C ABI dynamic loading | `-buildmode=c-shared` + bridge | qq/files/web/memo etc. | | External `.so` | C ABI dynamic loading | `-buildmode=c-shared` + bridge | qq/browser/files etc. |
| Lua script plugin | Parse `main.lua` to register tools | No compilation, hot-reload | luaplugintest/testlua etc. | | Lua script plugin | Execute `main.lua` to register tools | No compilation, takes effect after restart/reload | luademo etc. |
| SKILL plugin | Parse `SKILL.md` | Markdown definition | Loaded via clawhubadapter | | SKILL plugin | Parse `SKILL.md` | Markdown definition | Loaded via clawhubadapter |
Built-in plugin registration: `internal/plugins/all.go` blank imports → each plugin `init()``Registry.Load()` scans directory to match factory. Built-in plugin registration: `internal/plugins/all.go` blank imports → each plugin `init()``Registry.Load()` scans directory to match factory.
External plugin loading: `internal/plugin/dynamic.go` → copy to SHA256 temp path (bypass `plugin.Open` path cache) → `Open` + `Lookup("NewPlugin")`. External plugin loading: `internal/plugin/dynamic.go` → copy to SHA256 temp path (bypass `plugin.Open` path cache) → `Open` + `Lookup("NewPlugin")`.
Lua script plugin loading: `internal/lua/`parse `main.lua` via Lua VM, call `start()` to register tools. Lua script plugin loading: `internal/plugin/`the gopher-lua interpreter executes `main.lua` (at load time `sdk.register_*` only buffers handlers), then `Start()` swaps in the real SDK implementation and registers them in batch. The script is read only once at load time; runtime execution happens via callbacks.
### Built-in vs External Plugins ### Built-in vs External Plugins

View File

@ -79,5 +79,5 @@ Code is in the project root, implemented in Go.
Core functionality is operational. Plugin system and SDK are ready for independent external plugin development. Core functionality is operational. Plugin system and SDK are ready for independent external plugin development.
- Built-in plugins: webui / cli / timer / cmd / mcp / agentcli / healthcheck / pluginmgr / clawhubadapter / files / cfgmgr - Built-in plugins: webui / cli / timer / cmd / mcp / agentcli / healthcheck / pluginmgr / clawhubadapter / files / cfgmgr
- External plugin examples ([homeagent-sdk](https://gitcode.com/JianFeeeee/homeagent-sdk) repo `example/`, both Go and Lua types): qq / files / web / memo / bili / editdoc / a2a / ocr / sanitizer / luaplugintest / testlua - External plugin examples ([homeagent-sdk](https://gitcode.com/JianFeeeee/homeagent-sdk) repo `example/`, both Go and Lua types): qq / files / a2a / ai_image / bili / browser / calendar / editdoc / memo / music / ocr / rss / sanitizer / weather / luademo
- Distribution: `.hmap` plugin package format, installable via WebUI - Distribution: `.hmap` plugin package format, installable via WebUI

View File

@ -64,6 +64,14 @@ plugindev sdk path # show current SDK path
SDK is stored at `~/.homeagent/plugindev/sdk/<version>/`; `plugindev init` reads the current SDK version for `go.mod`. SDK is stored at `~/.homeagent/plugindev/sdk/<version>/`; `plugindev init` reads the current SDK version for `go.mod`.
### Source Debugging
`plugindev debug` interprets plugin source and prints a call trace, no compilation environment needed:
```bash
plugindev debug [dir] # dir defaults to the current directory
```
### Creating a Go Plugin ### Creating a Go Plugin
```bash ```bash
@ -71,8 +79,11 @@ plugindev init myplugin
cd myplugin cd myplugin
# Edit plugin code # Edit plugin code
vim plugin.go vim plugin.go
# Build and package # Build and package (default is a multi-platform bundle, see below)
plugindev build plugindev build
# Output: dist/myplugin_bundle.hmap
# Single-platform build:
plugindev build --no-bundle
# Output: dist/myplugin_linux_amd64.hmap (or windows_amd64) # Output: dist/myplugin_linux_amd64.hmap (or windows_amd64)
``` ```
@ -121,14 +132,19 @@ myluaplugin/
```bash ```bash
cd myplugin cd myplugin
plugindev build plugindev build # default bundle mode (multi-platform)
plugindev build --no-bundle # single-target build (per plg.json targets)
plugindev build --target linux/amd64 # append a target on top of plg.json targets
plugindev build --outdir dist # output directory (default: dist)
plugindev build --sdk-path <path> # SDK path override (go.mod replace)
plugindev build --replace <mod@path> # append a go.mod replace directive (repeatable)
``` ```
Execution process: Execution process:
1. Reads `plg.json` `targets` field to determine target platforms 1. Reads `plg.json` `targets`/`bundle` fields to determine build targets (bundle takes priority, see below)
2. Auto-generates C ABI bridge code (`z_bridge_gen.go` + `z_entry.c`) 2. Auto-generates C ABI bridge code (`z_bridge_gen.go` + `z_entry.c`; Windows only `z_bridge_gen.go`)
3. **Go plugin**: Runs `go build -buildmode=c-shared` (produces `.so` / `.dylib` / `.dll`) 3. **Go plugin**: Runs `go build -buildmode=c-shared` (produces `.so` / `.dylib` / `.dll`)
4. **Lua plugin**: Packages source code directly, no compilation needed 4. **Lua plugin**: Packages source code directly, no compilation needed (contents: `plugin.json` + `main.lua`, plus optional `README.md`, `LICENSE`, `thirdpart/*.lua`)
5. Generates `plugin.json` output manifest 5. Generates `plugin.json` output manifest
6. Packages as `.hmap` distribution (zip format, containing `plugin.json` + binary) 6. Packages as `.hmap` distribution (zip format, containing `plugin.json` + binary)
@ -136,7 +152,7 @@ Execution process:
| File | Purpose | Key fields | | File | Purpose | Key fields |
|------|---------|------------| |------|---------|------------|
| `plg.json` | Project metadata, maintained by developer | `targets`build targets (e.g. `"linux/amd64,windows/amd64"`) | | `plg.json` | Project metadata, maintained by developer | `targets`single-target build list (e.g. `"linux/amd64,windows/amd64"`); `bundle` — multi-platform bundle switch (default `true`) |
| `plugin.json` | Build artifact manifest, auto-generated | `entry` — entry filename; `platforms` — declared platforms | | `plugin.json` | Build artifact manifest, auto-generated | `entry` — entry filename; `platforms` — declared platforms |
Each target produces a separate `.hmap`; binary name by platform: Each target produces a separate `.hmap`; binary name by platform:
@ -147,23 +163,28 @@ Each target produces a separate `.hmap`; binary name by platform:
| macOS | `plugin.dylib` | | macOS | `plugin.dylib` |
| Windows | `plugin.dll` | | Windows | `plugin.dll` |
### Multi-platform bundle: --bundle ### Build Targets & Multi-platform Bundle
**`plugindev build` defaults to bundle mode** (unless `plg.json` explicitly sets `"bundle": false`): it builds linux/amd64 + darwin/amd64 + windows/amd64 in one pass, producing a single `.hmap` with all platform binaries. The output manifest includes a `platforms` field. The kernel auto-selects the correct binary during installation.
```bash ```bash
plugindev build --bundle plugindev build # default bundle, outputs dist/myplugin_bundle.hmap
plugindev build --bundle # explicitly enable bundle (same as above)
plugindev build --no-bundle # disable bundle, build per plg.json targets
``` ```
Builds linux/amd64 + darwin/amd64 + windows/amd64 in one pass, producing a single `.hmap` Notes:
with all platform binaries. The output manifest includes a `platforms` field. - In bundle mode the `plg.json` `targets` field is ignored; the three platforms above are always built
The kernel auto-selects the correct binary during installation. - Cross-compilation needs the corresponding toolchains (e.g. building darwin on Linux requires clang/macOS SDK); if a toolchain is missing the build fails — use `--no-bundle` to build only the current platform
- Single-target output naming: `{name}_{os}_{arch}.hmap`, e.g. `myplugin_linux_amd64.hmap`
Output in `dist/` directory: Output in `dist/` directory:
``` ```
dist/ dist/
├── myplugin_linux_amd64.hmap # Single platform: Linux ├── myplugin_bundle.hmap # default bundle: multi-platform
├── myplugin_windows_amd64.hmap # Single platform: Windows ├── myplugin_linux_amd64.hmap # after --no-bundle: Linux
├── myplugin_darwin_amd64.hmap # Single platform: macOS ├── myplugin_windows_amd64.hmap # after --no-bundle: Windows
├── myplugin_bundle.hmap # Multi-platform bundle ├── myplugin_darwin_amd64.hmap # after --no-bundle: macOS
└── myplugin_lua.hmap # Lua plugin └── myplugin_lua.hmap # Lua plugin
``` ```
@ -172,12 +193,12 @@ dist/
Install via PluginMgr HTTP API (three methods): Install via PluginMgr HTTP API (three methods):
```bash ```bash
# 1. Install from URL (auto-cleanup) # 1. Install from URL (http/https only, streamed, no local temp file)
curl -X POST http://127.0.0.1:9876/plugins \ curl -X POST http://127.0.0.1:9876/plugins \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d '{"url": "https://example.com/myplugin.hmap"}' -d '{"url": "https://example.com/myplugin.hmap"}'
# 2. Install from local path (keeps source file) # 2. Install from local path (reads the given file, source file untouched)
curl -X POST http://127.0.0.1:9876/plugins \ curl -X POST http://127.0.0.1:9876/plugins \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d '{"path": "/path/to/myplugin.hmap"}' -d '{"path": "/path/to/myplugin.hmap"}'
@ -187,9 +208,18 @@ curl -X POST http://127.0.0.1:9876/plugins \
--data-binary @dist/myplugin.hmap --data-binary @dist/myplugin.hmap
``` ```
`9876` is the pluginmgr local port (defaults to listening on 127.0.0.1 only, no auth).
Reload plugins via `/api/v1/plugins/reload` or restart the kernel to activate. Reload plugins via `/api/v1/plugins/reload` or restart the kernel to activate.
Or upload via WebUI plugin management page. Or upload via the WebUI plugin management page, or through the WebUI HTTP API (default port 8080, requires the `api_key` bearer token; it proxies to pluginmgr):
```bash
curl -X POST http://127.0.0.1:8080/api/v1/plugins \
-H "Authorization: Bearer <api_key>" \
-H "Content-Type: application/json" \
-d '{"path": "/path/to/myplugin.hmap"}'
```
--- ---
@ -491,6 +521,14 @@ outputCh := s.OutputChan()
Lua plugins are suitable for lightweight rapid prototyping, requiring no Go compilation environment. Changes take effect after kernel restart. Lua plugins are suitable for lightweight rapid prototyping, requiring no Go compilation environment. Changes take effect after kernel restart.
### Execution Model
Lua plugins run inside the kernel process on a gopher-lua interpreter (single Lua state guarded by a mutex). This differs fundamentally from Go plugins:
- **Passive callback model**: `main.lua` executes only once at load time. Afterward, tools, stage hooks, output/input channels, and registered APIs are all invoked by the kernel via callbacks into Lua functions. Plugins cannot start background tasks on their own.
- **No concurrency / no long-running services**: Lua has no goroutines, coroutine scheduling, `os`/`io` libraries, or socket listening. The only outbound capability is `sdk.http.get/post` (synchronous). Any blocking loop will stall every call of that plugin while holding the lock.
- **For long-running services (listening on a port, background polling, timers) use a Go plugin** (`.so`/`.dll` built with the toolchain, which may spawn goroutines — see the webui/cli plugins). The Lua equivalent is event-driven: register tools/stage hooks/channels to be called back by the kernel, or interact with external processes via `sdk.http`.
### Plugin Structure ### Plugin Structure
```lua ```lua

View File

@ -257,13 +257,13 @@ VM 内置 `json.encode` / `json.decode` / `log` / `http_get` / `http_post`。
| 方式 | 注册机制 | 编译 | 用途 | | 方式 | 注册机制 | 编译 | 用途 |
|------|----------|------|------| |------|----------|------|------|
| 内置插件 | `init()``RegisterFactory` | `internal/plugins/` 编译进内核 | webui/cli/timer/mcp 等 | | 内置插件 | `init()``RegisterFactory` | `internal/plugins/` 编译进内核 | webui/cli/timer/mcp 等 |
| 外部 `.so` | C ABI 动态加载 | `-buildmode=c-shared` + bridge | qq/files/web/memo 等 | | 外部 `.so` | C ABI 动态加载 | `-buildmode=c-shared` + bridge | qq/browser/files 等 |
| Lua 脚本插件 | 解析 `main.lua` 注册工具 | 无需编译,热加载 | luaplugintest/testlua 等 | | Lua 脚本插件 | 执行 `main.lua` 注册工具 | 无需编译,重启/重载生效 | luademo 等 |
| SKILL 插件 | 解析 `SKILL.md` | Markdown 定义 | clawhubadapter 兼容加载 | | SKILL 插件 | 解析 `SKILL.md` | Markdown 定义 | clawhubadapter 兼容加载 |
内置插件注册:`internal/plugins/all.go` 空白导入 → 各插件 `init()``Registry.Load()` 扫描目录匹配工厂。 内置插件注册:`internal/plugins/all.go` 空白导入 → 各插件 `init()``Registry.Load()` 扫描目录匹配工厂。
外部插件加载:`internal/plugin/dynamic.go` → 复制到 SHA256 临时路径(绕过 `plugin.Open` 路径缓存)→ `Open` + `Lookup("NewPlugin")` 外部插件加载:`internal/plugin/dynamic.go` → 复制到 SHA256 临时路径(绕过 `plugin.Open` 路径缓存)→ `Open` + `Lookup("NewPlugin")`
Lua 脚本插件加载:`internal/lua/`通过 Lua VM 解析 `main.lua`,调用 `start()` 注册工具 Lua 脚本插件加载:`internal/plugin/`gopher-lua 解释器执行 `main.lua`(加载期 `sdk.register_*` 仅暂存 handler`Start()` 时替换为真实 SDK 实现并批量注册。脚本只在加载时读取一次,运行期通过回调执行
### 内置插件 vs 外部插件 ### 内置插件 vs 外部插件

View File

@ -79,5 +79,5 @@ HomeAgent 是一个持续运行的个人智能 Agent 框架。
核心功能已可运行。插件系统和 SDK 已就绪,可独立开发外部插件。 核心功能已可运行。插件系统和 SDK 已就绪,可独立开发外部插件。
- 内置插件webui / cli / timer / cmd / mcp / agentcli / healthcheck / pluginmgr / clawhubadapter / files / cfgmgr - 内置插件webui / cli / timer / cmd / mcp / agentcli / healthcheck / pluginmgr / clawhubadapter / files / cfgmgr
- 外部插件示例([homeagent-sdk](https://gitcode.com/JianFeeeee/homeagent-sdk) 仓库 `example/`,含 Go 和 Lua 两种类型qq / files / web / memo / bili / editdoc / a2a / ocr / sanitizer / luaplugintest / testlua - 外部插件示例([homeagent-sdk](https://gitcode.com/JianFeeeee/homeagent-sdk) 仓库 `example/`,含 Go 和 Lua 两种类型qq / files / a2a / ai_image / bili / browser / calendar / editdoc / memo / music / ocr / rss / sanitizer / weather / luademo
- 打包分发:`.hmap` 插件包格式,通过 WebUI 安装 - 打包分发:`.hmap` 插件包格式,通过 WebUI 安装

View File

@ -65,6 +65,14 @@ plugindev sdk path # 显示当前 SDK 路径
SDK 存储在 `~/.homeagent/plugindev/sdk/<version>/``plugindev init` 自动读取当前 SDK 版本填充 `go.mod` SDK 存储在 `~/.homeagent/plugindev/sdk/<version>/``plugindev init` 自动读取当前 SDK 版本填充 `go.mod`
### 源码调试
`plugindev debug` 直接用解释器执行插件源码并输出调用轨迹,无需编译环境:
```bash
plugindev debug [dir] # dir 默认当前目录
```
### 创建 Go 插件 ### 创建 Go 插件
```bash ```bash
@ -73,7 +81,10 @@ cd myplugin
# 编辑插件代码 # 编辑插件代码
vim plugin.go vim plugin.go
# 编译打包 # 编译打包
plugindev build plugindev build # 默认多平台 bundle见下节
# 输出: dist/myplugin_bundle.hmap
# 单平台构建:
plugindev build --no-bundle
# 输出: dist/myplugin_linux_amd64.hmap (或 windows_amd64) # 输出: dist/myplugin_linux_amd64.hmap (或 windows_amd64)
``` ```
@ -122,14 +133,19 @@ myluaplugin/
```bash ```bash
cd myplugin cd myplugin
plugindev build plugindev build # 默认 bundle 模式(多平台合集)
plugindev build --no-bundle # 单平台构建(仅当前 plg.json targets
plugindev build --target linux/amd64 # 在 targets 基础上追加一个目标
plugindev build --outdir dist # 指定输出目录(默认 dist
plugindev build --sdk-path <path> # 指定 SDK 路径(覆盖 go.mod replace
plugindev build --replace <mod@path> # 追加 go.mod replace 指令(可多次)
``` ```
执行过程: 执行过程:
1. 读取 `plg.json``targets` 字段确定目标平台 1. 读取 `plg.json``targets`/`bundle` 字段确定构建目标bundle 模式优先,见下节)
2. 自动生成 C ABI bridge 代码(`z_bridge_gen.go` + `z_entry.c` 2. 自动生成 C ABI bridge 代码(`z_bridge_gen.go` + `z_entry.c`Windows 仅 `z_bridge_gen.go`
3. **Go 插件**:执行 `go build -buildmode=c-shared`(生成 `.so` / `.dylib` / `.dll` 3. **Go 插件**:执行 `go build -buildmode=c-shared`(生成 `.so` / `.dylib` / `.dll`
4. **Lua 插件**:直接打包源码,无需编译 4. **Lua 插件**:直接打包源码,无需编译(打包内容:`plugin.json` + `main.lua`,以及可选的 `README.md``LICENSE``thirdpart/*.lua`
5. 生成 `plugin.json` 输出清单 5. 生成 `plugin.json` 输出清单
6. 打包为 `.hmap` 分发包zip 格式,内含 `plugin.json` + 二进制) 6. 打包为 `.hmap` 分发包zip 格式,内含 `plugin.json` + 二进制)
@ -137,7 +153,7 @@ plugindev build
| 文件 | 用途 | 关键字段 | | 文件 | 用途 | 关键字段 |
|------|------|---------| |------|------|---------|
| `plg.json` | 项目元信息,由开发者维护 | `targets` — 构建目标(如 `"linux/amd64,windows/amd64"`| | `plg.json` | 项目元信息,由开发者维护 | `targets`单平台构建目标(如 `"linux/amd64,windows/amd64"``bundle` — 多平台合集开关(默认 `true`|
| `plugin.json` | 构建产物清单,`plugindev build` 自动生成 | `entry` — 入口文件名;`platforms` — 声明的支持平台 | | `plugin.json` | 构建产物清单,`plugindev build` 自动生成 | `entry` — 入口文件名;`platforms` — 声明的支持平台 |
每个目标生成单独的 `.hmap`,二进制文件名由平台决定: 每个目标生成单独的 `.hmap`,二进制文件名由平台决定:
@ -148,22 +164,28 @@ plugindev build
| macOS | `plugin.dylib` | | macOS | `plugin.dylib` |
| Windows | `plugin.dll` | | Windows | `plugin.dll` |
### 多平台打包--bundle ### 构建目标与多平台打包bundle
**`plugindev build` 默认就是 bundle 模式**`plg.json` 未显式写 `"bundle": false` 时):一次编译 linux/amd64 + darwin/amd64 + windows/amd64生成包含所有平台二进制的单 `.hmap`,输出清单自动添加 `platforms` 字段。安装时核心自动选择当前平台的二进制,跳过其他平台。
```bash ```bash
plugindev build --bundle plugindev build # 默认 bundle输出 dist/myplugin_bundle.hmap
plugindev build --bundle # 显式开启 bundle同上
plugindev build --no-bundle # 关闭 bundle按 plg.json 的 targets 逐平台构建
``` ```
一次编译 linux/amd64 + darwin/amd64 + windows/amd64生成包含所有平台二进制的单 `.hmap` 注意:
输出清单自动添加 `platforms` 字段。安装时核心自动选择当前平台的二进制,跳过其他平台 - bundle 模式下 `plg.json``targets` 字段被忽略,固定构建上述三个平台
- 跨平台交叉编译需要对应工具链(如 Linux 上构建 darwin 需 clang/macOS SDK缺少工具链时编译会失败此时使用 `--no-bundle` 只构建当前平台
- 单平台输出文件名:`{name}_{os}_{arch}.hmap`,如 `myplugin_linux_amd64.hmap`
输出在 `dist/` 目录: 输出在 `dist/` 目录:
``` ```
dist/ dist/
├── myplugin_linux_amd64.hmap # 单平台Linux 版 ├── myplugin_bundle.hmap # 默认 bundle多平台合集
├── myplugin_windows_amd64.hmap # 单平台Windows ├── myplugin_linux_amd64.hmap # --no-bundle 后Linux
├── myplugin_darwin_amd64.hmap # 单平台macOS ├── myplugin_windows_amd64.hmap # --no-bundle 后Windows
├── myplugin_bundle.hmap # 多平台合集 ├── myplugin_darwin_amd64.hmap # --no-bundle 后macOS 版
└── myplugin_lua.hmap # Lua 插件 └── myplugin_lua.hmap # Lua 插件
``` ```
@ -172,12 +194,12 @@ dist/
通过 PluginMgr HTTP API 安装,支持三种方式: 通过 PluginMgr HTTP API 安装,支持三种方式:
```bash ```bash
# 1. 从 URL 安装(自动清理安装包 # 1. 从 URL 安装(仅支持 http/https流式下载不落盘
curl -X POST http://127.0.0.1:9876/plugins \ curl -X POST http://127.0.0.1:9876/plugins \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d '{"url": "https://example.com/myplugin.hmap"}' -d '{"url": "https://example.com/myplugin.hmap"}'
# 2. 从本地路径安装(保留安装包 # 2. 从本地路径安装(读取指定文件,不移动原文件
curl -X POST http://127.0.0.1:9876/plugins \ curl -X POST http://127.0.0.1:9876/plugins \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d '{"path": "/path/to/myplugin.hmap"}' -d '{"path": "/path/to/myplugin.hmap"}'
@ -187,9 +209,18 @@ curl -X POST http://127.0.0.1:9876/plugins \
--data-binary @dist/myplugin.hmap --data-binary @dist/myplugin.hmap
``` ```
`9876` 为 pluginmgr 本地监听端口(默认仅监听 127.0.0.1,无鉴权)。
安装后需调用 `/api/v1/plugins/reload` 或重启内核生效。 安装后需调用 `/api/v1/plugins/reload` 或重启内核生效。
也可通过 WebUI 插件管理页面上传安装 也可通过 WebUI 插件管理页面上传安装,或走 WebUI 的 HTTP API端口默认 8080`api_key` 鉴权,内部代理到 pluginmgr
```bash
curl -X POST http://127.0.0.1:8080/api/v1/plugins \
-H "Authorization: Bearer <api_key>" \
-H "Content-Type: application/json" \
-d '{"path": "/path/to/myplugin.hmap"}'
```
--- ---
@ -489,6 +520,14 @@ outputCh := s.OutputChan()
Lua 插件适合轻量级快速原型,无需 Go 编译环境,修改后直接重启内核即可生效。 Lua 插件适合轻量级快速原型,无需 Go 编译环境,修改后直接重启内核即可生效。
### 执行模型
Lua 插件运行在内核进程内的 gopher-lua 解释器中(单 Lua 状态 + 互斥锁),与 Go 插件的执行模型有本质区别:
- **被动回调模型**`main.lua` 仅在加载时执行一次,此后插件的工具、阶段钩子、输出/输入通道、注册 API 全部由内核事件驱动回调 Lua 函数;插件不能自己启动后台任务。
- **无并发/无常驻服务能力**Lua 侧没有 goroutine、协程调度、`os`/`io` 库和 socket 监听能力,唯一主动出站通道是 `sdk.http.get/post`(同步请求)。任何阻塞循环都会持锁卡死该插件的所有调用。
- **常驻服务(如监听端口、后台轮询、定时任务)请使用 Go 插件**(工具链编译的 `.so`/`.dll`,可自行启动 goroutine参见 webui/cli 插件。Lua 插件的等价做法是事件驱动:注册工具/阶段钩子/通道由内核回调,或经 `sdk.http` 与外部进程交互。
### 插件结构 ### 插件结构
```lua ```lua