package main import ( "fmt" "os" "os/exec" "path/filepath" "strings" ) // tmplLuaDebug is the temporary Lua debug script template const tmplLuaDebug = `-- HomeAgent Lua Plugin Debug -- Generated by plugindev debug --lua sdk = require("sdk") 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() ` func cmdDebug(args []string) { dir := "." if len(args) > 0 && args[0] != "" { dir = args[0] } luaPath := filepath.Join(dir, "main.lua") goPath := filepath.Join(dir, "main.go") sdkPath := filepath.Join(dir, "sdk.lua") if _, err := os.Stat(luaPath); err == nil { debugLua(dir, sdkPath, luaPath) } else if _, err := os.Stat(goPath); err == nil { debugGo(dir, goPath) } else { fmt.Println("error: no main.lua or main.go 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 plugindev 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") } // 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.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, goPath string) { fmt.Println("Go debug mode: use standard Go tooling") fmt.Println() fmt.Println(" go test -v ./... # run tests") fmt.Println(" go build -o plugin.so -buildmode=plugin . # build plugin") fmt.Println(" plugindev build # package as .hmap") fmt.Println() fmt.Println("For interactive Go debugging, use your IDE or dlv:") fmt.Println(" dlv debug # Delve debugger") } var _ = strings.TrimSpace