mirror of
https://github.com/mark3labs/kit.git
synced 2026-06-13 19:20:06 +00:00
53ae47a1bd
Extensions can now place persistent header (above stream) and footer (below status bar) regions via ctx.SetHeader/SetFooter. Single-instance per slot, reuses WidgetContent/WidgetStyle types and WidgetUpdateEvent for notifications. Includes thread-safe Runner storage, SDK methods, UI rendering with height distribution, and example extension.
121 lines
3.1 KiB
Go
121 lines
3.1 KiB
Go
//go:build ignore
|
|
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
|
|
"kit/ext"
|
|
)
|
|
|
|
// Init demonstrates the custom header/footer system. The header shows
|
|
// project context (branch, CWD) and the footer shows a running summary
|
|
// of agent activity. Slash commands toggle them on/off.
|
|
func Init(api ext.API) {
|
|
var turnCount int
|
|
var lastResponse string
|
|
|
|
// Show a custom header with project context when the session starts.
|
|
api.OnSessionStart(func(_ ext.SessionStartEvent, ctx ext.Context) {
|
|
ctx.SetHeader(ext.HeaderFooterConfig{
|
|
Content: ext.WidgetContent{
|
|
Text: fmt.Sprintf("Project: %s | Model: %s | %s",
|
|
ctx.CWD, ctx.Model, time.Now().Format("Jan 2, 15:04")),
|
|
},
|
|
Style: ext.WidgetStyle{
|
|
BorderColor: "#89b4fa",
|
|
},
|
|
})
|
|
|
|
ctx.SetFooter(ext.HeaderFooterConfig{
|
|
Content: ext.WidgetContent{
|
|
Text: "Ready | 0 turns",
|
|
},
|
|
Style: ext.WidgetStyle{
|
|
BorderColor: "#a6e3a1",
|
|
},
|
|
})
|
|
})
|
|
|
|
// Update footer after each agent turn with activity summary.
|
|
api.OnAgentEnd(func(ae ext.AgentEndEvent, ctx ext.Context) {
|
|
turnCount++
|
|
lastResponse = ae.Response
|
|
if len(lastResponse) > 60 {
|
|
lastResponse = lastResponse[:57] + "..."
|
|
}
|
|
|
|
ctx.SetFooter(ext.HeaderFooterConfig{
|
|
Content: ext.WidgetContent{
|
|
Text: fmt.Sprintf("Turns: %d | Last: %s | %s",
|
|
turnCount, ae.StopReason, time.Now().Format("15:04:05")),
|
|
},
|
|
Style: ext.WidgetStyle{
|
|
BorderColor: "#a6e3a1",
|
|
},
|
|
})
|
|
})
|
|
|
|
// /header-off — remove the custom header.
|
|
api.RegisterCommand(ext.CommandDef{
|
|
Name: "header-off",
|
|
Description: "Remove the custom header",
|
|
Execute: func(_ string, ctx ext.Context) (string, error) {
|
|
ctx.RemoveHeader()
|
|
return "Header removed.", nil
|
|
},
|
|
})
|
|
|
|
// /header-on — restore the custom header.
|
|
api.RegisterCommand(ext.CommandDef{
|
|
Name: "header-on",
|
|
Description: "Restore the custom header",
|
|
Execute: func(_ string, ctx ext.Context) (string, error) {
|
|
ctx.SetHeader(ext.HeaderFooterConfig{
|
|
Content: ext.WidgetContent{
|
|
Text: fmt.Sprintf("Project: %s | Model: %s | %s",
|
|
ctx.CWD, ctx.Model, time.Now().Format("Jan 2, 15:04")),
|
|
},
|
|
Style: ext.WidgetStyle{
|
|
BorderColor: "#89b4fa",
|
|
},
|
|
})
|
|
return "Header restored.", nil
|
|
},
|
|
})
|
|
|
|
// /footer-off — remove the custom footer.
|
|
api.RegisterCommand(ext.CommandDef{
|
|
Name: "footer-off",
|
|
Description: "Remove the custom footer",
|
|
Execute: func(_ string, ctx ext.Context) (string, error) {
|
|
ctx.RemoveFooter()
|
|
return "Footer removed.", nil
|
|
},
|
|
})
|
|
|
|
// /footer-on — restore the custom footer.
|
|
api.RegisterCommand(ext.CommandDef{
|
|
Name: "footer-on",
|
|
Description: "Restore the custom footer",
|
|
Execute: func(_ string, ctx ext.Context) (string, error) {
|
|
ctx.SetFooter(ext.HeaderFooterConfig{
|
|
Content: ext.WidgetContent{
|
|
Text: fmt.Sprintf("Turns: %d | %s", turnCount, time.Now().Format("15:04:05")),
|
|
},
|
|
Style: ext.WidgetStyle{
|
|
BorderColor: "#a6e3a1",
|
|
},
|
|
})
|
|
return "Footer restored.", nil
|
|
},
|
|
})
|
|
|
|
// Clean up on shutdown.
|
|
api.OnSessionShutdown(func(_ ext.SessionShutdownEvent, ctx ext.Context) {
|
|
ctx.RemoveHeader()
|
|
ctx.RemoveFooter()
|
|
})
|
|
}
|