mirror of
https://gitcode.com/JianFeeeee/homeagent-sdk.git
synced 2026-10-15 12:15:11 +00:00
SDK 仓已迁到 GitHub 作为权威源,go module 路径同步: `gitcode.com/JianFeeeee/homeagent-sdk` → `github.com/JianFeeeee/homeagentsdk` ## 范围 74 个文件:71 个 Go 源码 + go.mod/go.sum + hmapdev 模板 + CI 与打包脚本。 主仓(HomeAgent)侧对应改动是 6d38a164。本仓这些文件当时**不在工作树上** (见下),所以那次的批量替换扫不到它们——这里是补偿。 ## 为何这批文件当时不在工作树上(事故与恢复) 10-08 07:58 主仓做 checkout/cherry-pick 序列时,把本仓工作树的 20 个文件 误清理了(`example/*/plugin.go` + `plg.json`,10 个示例)。 根因是**结构误判**:本仓是「一目录两仓库」结构下主仓 `third_party/` 里的 **独立 git 仓库**,而主仓 .gitignore 忽略了 `example/`,于是它在主仓 `git status` 里不可见 —— 看着像「不受跟踪的构建产物」,实际是本仓受跟踪的源码。 已全部恢复(`git checkout -- <D 文件>`,只恢复删除、不动迁移改动), 20 个文件与 HEAD 逐字节一致。 **破坏的连锁后果**:恢复出来的 `plugin.go` 仍写着旧 module 路径, 因为迁移时它们已不在工作树上。所以这次补偿是必须的,不是可选优化。 ## 保留 gitcode 引用 以下位置的 `gitcode` **有意保留**,不要"顺手清掉": - README.md / docs 里「二进制实际分发地址目前是 gitcode」的说明 - mkdocs.yml 的 gitcode 镜像链接(国内直连更快) - `tools/hmapdev/templates.go` 里「SDK 已从 gitcode 迁到 GitHub」的注释 gitcode 仍是**只读镜像**(源码同步;release 附件暂时仍在那边)。 ## 验证 - 本仓根 module:`go build ./...` + `go test ./...` 全通过 - 全部 20 个 example:`go vet` 通过(补偿前 10 个因旧 module 路径失败) - example/qq:`go test` 通过,且能从源码 build 出可用 plugin 产物
194 lines
5.1 KiB
Go
194 lines
5.1 KiB
Go
package main
|
||
|
||
import (
|
||
"fmt"
|
||
"os"
|
||
"os/exec"
|
||
"path/filepath"
|
||
"strings"
|
||
|
||
"github.com/JianFeeeee/homeagentsdk/tools/hmapdev/yaegi"
|
||
)
|
||
|
||
// tmplLuaDebug is the temporary Lua debug script template
|
||
const tmplLuaDebug = `-- HomeAgent Lua Plugin Debug
|
||
-- Generated by hmapdev debug --lua
|
||
-- sdk.lua 优先用激活 SDK 的权威 mock(HMAPDEV_SDK_LUA),否则回退项目内副本,
|
||
-- 避免拿一份过期的 sdk.lua 调试出“本地能跑、内核报 nil”的假象。
|
||
local sdk_path = os.getenv("HMAPDEV_SDK_LUA")
|
||
if sdk_path and sdk_path ~= "" then
|
||
sdk = dofile(sdk_path)
|
||
else
|
||
sdk = require("sdk")
|
||
end
|
||
local ok, plugin = pcall(dofile, "main.lua")
|
||
if not ok then
|
||
print("[debug] ERROR loading main.lua: " .. tostring(plugin))
|
||
os.exit(1)
|
||
end
|
||
if type(plugin) == "table" then
|
||
print("[debug] Plugin: " .. tostring(plugin.name or "unnamed"))
|
||
if plugin.start then
|
||
print("[debug] Calling plugin.start(sdk) ...")
|
||
local ok, err = pcall(plugin.start, sdk)
|
||
if ok then
|
||
print("[debug] plugin.start() OK")
|
||
else
|
||
print("[debug] plugin:start() ERROR: " .. tostring(err))
|
||
end
|
||
end
|
||
end
|
||
print("")
|
||
print("=== Interactive REPL ===")
|
||
print("sdk, plugin globals are available")
|
||
local function repl()
|
||
while true do
|
||
io.write("> ")
|
||
io.flush()
|
||
local line = io.read()
|
||
if line == nil or line == "exit" or line == "quit" then break end
|
||
if line == "help" then
|
||
print(" help - this help")
|
||
print(" exit/quit - exit debug")
|
||
print(" sdk - SDK API table")
|
||
print(" plugin - loaded plugin table")
|
||
else
|
||
local fn, err = (loadstring or load)(line)
|
||
if fn then
|
||
local ok, result = pcall(fn)
|
||
if ok and result ~= nil then print(tostring(result)) end
|
||
if not ok then print("Error: " .. tostring(result)) end
|
||
else
|
||
print("Error: " .. tostring(err))
|
||
end
|
||
end
|
||
end
|
||
end
|
||
repl()
|
||
`
|
||
|
||
type DebugConfig struct {
|
||
Dir string
|
||
Replaces []string
|
||
}
|
||
|
||
func cmdDebug(args []string) {
|
||
cfg := DebugConfig{Dir: "."}
|
||
for i := 0; i < len(args); i++ {
|
||
switch args[i] {
|
||
case "--replace", "-R":
|
||
if i+1 < len(args) {
|
||
cfg.Replaces = append(cfg.Replaces, args[i+1]); i++
|
||
}
|
||
default:
|
||
if !strings.HasPrefix(args[i], "-") {
|
||
cfg.Dir = args[i]
|
||
}
|
||
}
|
||
}
|
||
|
||
dir := cfg.Dir
|
||
luaPath := filepath.Join(dir, "main.lua")
|
||
sdkPath := filepath.Join(dir, "sdk.lua")
|
||
hasGo := false
|
||
|
||
entries, _ := os.ReadDir(dir)
|
||
for _, e := range entries {
|
||
if !e.IsDir() && strings.HasSuffix(e.Name(), ".go") && !strings.HasSuffix(e.Name(), "_test.go") {
|
||
hasGo = true
|
||
break
|
||
}
|
||
}
|
||
|
||
// Merge plg.json replaces with CLI --replace overrides
|
||
var replaces []string
|
||
if plg, err := readPlgJSON(filepath.Join(dir, "plg.json")); err == nil {
|
||
replaces = plg.ReplacesToSlice()
|
||
}
|
||
replaces = append(replaces, cfg.Replaces...)
|
||
|
||
if _, err := os.Stat(luaPath); err == nil {
|
||
debugLua(dir, sdkPath, luaPath)
|
||
} else if hasGo {
|
||
debugGo(dir, replaces)
|
||
} else {
|
||
fmt.Println("error: no main.lua or .go files found in", dir)
|
||
os.Exit(1)
|
||
}
|
||
}
|
||
|
||
func debugLua(dir, sdkPath, luaPath string) {
|
||
// check lua interpreter
|
||
luaBin, err := exec.LookPath("lua")
|
||
if err != nil {
|
||
fmt.Println("error: lua interpreter not found in PATH")
|
||
fmt.Println(" install Lua 5.1+ or use hmapdev build to compile your plugin")
|
||
os.Exit(1)
|
||
}
|
||
|
||
fmt.Printf("[debug] Lua interpreter: %s\n", luaBin)
|
||
fmt.Printf("[debug] Plugin dir: %s\n", dir)
|
||
|
||
// check if sdk.lua exists
|
||
if _, err := os.Stat(sdkPath); os.IsNotExist(err) {
|
||
fmt.Println("warning: sdk.lua not found, debug SDK mock will not be available")
|
||
}
|
||
|
||
// 优先用激活 SDK 里的权威 mock,避免调试用的是项目里可能过期的副本。
|
||
env := os.Environ()
|
||
if root := tryActiveSDKRoot(); root != "" {
|
||
canonical := filepath.Join(root, "sdk", "lua", "sdk.lua")
|
||
if _, err := os.Stat(canonical); err == nil {
|
||
env = append(env, "HMAPDEV_SDK_LUA="+canonical)
|
||
fmt.Printf("[debug] SDK mock: %s\n", canonical)
|
||
}
|
||
}
|
||
|
||
// write temporary debug script
|
||
debugScript := filepath.Join(dir, "_debug.lua")
|
||
if err := os.WriteFile(debugScript, []byte(tmplLuaDebug), 0644); err != nil {
|
||
fmt.Printf("error: write debug script: %v\n", err)
|
||
os.Exit(1)
|
||
}
|
||
defer os.Remove(debugScript)
|
||
|
||
cmd := exec.Command(luaBin, filepath.Base(debugScript))
|
||
cmd.Dir = dir
|
||
cmd.Env = env
|
||
cmd.Stdin = os.Stdin
|
||
cmd.Stdout = os.Stdout
|
||
cmd.Stderr = os.Stderr
|
||
|
||
fmt.Println("[debug] Starting Lua debug session...")
|
||
fmt.Println()
|
||
if err := cmd.Run(); err != nil {
|
||
if exitErr, ok := err.(*exec.ExitError); ok {
|
||
os.Exit(exitErr.ExitCode())
|
||
}
|
||
fmt.Printf("[debug] error: %v\n", err)
|
||
os.Exit(1)
|
||
}
|
||
}
|
||
|
||
func debugGo(dir string, replaces []string) {
|
||
debug, err := yaegi.NewYaegiDebugger(dir, replaces)
|
||
if err != nil {
|
||
fmt.Printf("error: %v\n", err)
|
||
os.Exit(1)
|
||
}
|
||
|
||
fmt.Printf("[debug] Plugin dir: %s\n", dir)
|
||
|
||
if err := debug.LoadPlugin(); err != nil {
|
||
fmt.Printf("[debug] load plugin: %v\n", err)
|
||
os.Exit(1)
|
||
}
|
||
|
||
if err := debug.StartREPL(); err != nil {
|
||
fmt.Printf("[debug] repl error: %v\n", err)
|
||
os.Exit(1)
|
||
}
|
||
}
|
||
|
||
|