local function tool_status(name) name = name or "?" return "tool:" .. name:sub(1, 27) end return { name = "herdr", activate = function() local pane_id = os.getenv("HERDR_PANE_ID") if not pane_id or pane_id == "" then return end local panto = require("panto") local uv = require("luv") -- Herdr orders reports by source and sequence. Seed each process from -- wall time so a restarted panto cannot be shadowed by the prior -- process's larger sequence numbers. local seq = os.time() * 1000000 local last_state local last_status local function spawn(args) local handle pcall(function() handle = uv.spawn("herdr", { args = args, stdio = { nil, nil, nil } }, function() if handle then handle:close() end end) end) end local function report(state, status) if state == last_state and status == last_status then return end last_state, last_status = state, status seq = seq + 1 local args = { "pane", "report-agent", pane_id, "--source", "panto:extension", "--agent", "panto", "--state", state, "--seq", tostring(seq), } if status then args[#args + 1] = "--message" args[#args + 1] = status end spawn(args) end local function release() seq = seq + 1 spawn({ "pane", "release-agent", pane_id, "--source", "panto:extension", "--agent", "panto", "--seq", tostring(seq), }) end panto.ext.on("session_start", function() report("idle") end) panto.ext.on("session_ready", function() report("idle") end) panto.ext.on("user_message", function() report("working", "thinking") end) panto.ext.on("thinking", function() report("working", "thinking") end) panto.ext.on("compaction", function() report("working", "compacting") end) panto.ext.on("tool_details", function(event) report("working", tool_status(event.tool_name)) end) panto.ext.on("assistant_text", function() report("working", "responding") end) panto.ext.on("assistant_text_complete", function() report("idle") end) panto.ext.on("session_end", release) end, }