+
+
+
+{{template "shellBottom"}}
diff --git a/cmd/mavweb/main.go b/cmd/mavweb/main.go
index e6c8c0c..69bcf58 100644
--- a/cmd/mavweb/main.go
+++ b/cmd/mavweb/main.go
@@ -75,6 +75,15 @@ var morningHTML string
//go:embed events.html
var eventsHTML string
+//go:embed tools.html
+var toolsHTML string
+
+//go:embed routines.html
+var routinesHTML string
+
+//go:embed chat.html
+var chatPageHTML string
+
// shellHTML — the shell partial every page is wrapped in: "shellTop", the
// "sidebar" it calls, and "shellBottom". It used to be two Go string constants
// with the sidebar assembled by a strings.Builder, which is the one piece of
@@ -672,92 +681,6 @@ var toolsTmpl = template.Must(template.New("tools").Funcs(func() template.FuncMa
return m
}()).Parse(shellHTML + toolsHTML))
-const toolsHTML = `{{template "shellTop" "tools"}}
-
maven drafted these from acts she couldn't run. Fill the command (argv, space-separated) and enable. A row in an mcp: scope came from an MCP server and already knows what it calls — check the command, then enable.
-
name
scope
from utterance
enable as
-{{range .Proposed}}
-
{{.Name}}
{{.Scope}}
{{.Utterance}}
-
-
-
{{end}}
-{{else}}
-
-
no proposed tools
-
maven will propose tools here when she needs help running an action
-
{{end}}
-
-
-
enabled {{len .Enabled}}
-{{if .Enabled}}
name
scope
command
-{{range .Enabled}}
{{.Name}}
{{.Scope}}
{{join .Cmd " "}}
-
{{if .Destructive}}destructive{{end}}
-
{{end}}
-{{else}}
-
-
no tools enabled
-
enable proposed tools above, or ask maven to configure one
-
{{end}}
-
-
-
MCP servers {{len .MCP}}
-{{if .MCP}}
servers she connects OUT to. Their tools appear above as proposals — a configured server is a place she may look, not a capability she has. A stdio target is a process on this box; an http one on a loopback or LAN address is inside the network, so treat its tools accordingly.
add an mcp.servers block to mavend.json to let her use an external tool server
-
{{end}}
-
-{{template "shellBottom"}}`
-
-// routinesHTML — proposed routine review surface. One row per thing maven
-// noticed, in her words, with at most two actions: accept or dismiss.
-const routinesHTML = `{{template "shellTop" "routines"}}
-
Routines
-{{if .Msg}}
{{.Msg}}
{{end}}
-
-
noticed {{len .Proposed}}
-{{if .Proposed}}
maven noticed
when
-{{range .Proposed}}
-
{{.Phrase}}
{{.Noticed}}
-
-
-
{{end}}
-{{else}}
-
-
no proposed routines
-
maven will propose routines here when she detects a recurring pattern
-
{{end}}
-
-{{template "shellBottom"}}`
-
var historyTmpl = template.Must(template.New("history").Funcs(shellFuncs()).Parse(shellHTML + historyHTML))
var notificationsTmpl = template.Must(template.New("notifications").Funcs(shellFuncs()).Parse(shellHTML + notificationsHTML))
@@ -770,6 +693,8 @@ var voiceTmpl = template.Must(template.New("voice").Funcs(shellFuncs()).Parse(sh
var tasksTmpl = template.Must(template.New("tasks").Funcs(shellFuncs()).Parse(shellHTML + tasksHTML))
+// routinesTmpl — the proposed-routine review surface. One row per thing maven
+// noticed, in her words, with at most two actions: accept or dismiss.
var routinesTmpl = template.Must(template.New("routines").Funcs(shellFuncs()).Parse(shellHTML + routinesHTML))
var traceTmpl = template.Must(template.New("trace").Funcs(func() template.FuncMap {
@@ -1095,9 +1020,10 @@ func fmtTaskDate(t *time.Time) string {
return t.Local().Format("02 Jan")
}
-// routineRow is one line on the page: what maven noticed, in her words, and
-// how long ago she noticed it.
-type routineRow struct {
+// routineView is one line on the page: what maven noticed, in her words, and
+// how long ago she noticed it. A view model, not a database row — the template
+// never formats an interval or a timestamp itself.
+type routineView struct {
ID int64
Phrase string
Noticed string
@@ -1159,23 +1085,23 @@ func handleRoutines(w http.ResponseWriter, r *http.Request, core ipc.CoreAPI, se
w.Header().Set("Content-Type", "text/html; charset=utf-8")
if err := routinesTmpl.Execute(w, struct {
Msg string
- Proposed []routineRow
- }{msg, routineRows(proposed)}); err != nil {
+ Proposed []routineView
+ }{msg, toRoutineViews(proposed)}); err != nil {
log.Printf("routines render: %v", err)
}
}
-// routineRows turns the wire rows into display rows. The phrase comes from
+// toRoutineViews turns the wire rows into view models. The phrase comes from
// pattern.PhraseRoutine so the page says the same thing maven's voice says.
-func routineRows(rs []ipc.ProposedRoutine) []routineRow {
- out := make([]routineRow, 0, len(rs))
+func toRoutineViews(rs []ipc.ProposedRoutine) []routineView {
+ out := make([]routineView, 0, len(rs))
for _, r := range rs {
p := pattern.ProposedRoutine{Action: r.Action, Object: r.Object, IntervalDays: r.IntervalDays}
noticed := "just now"
if r.CreatedTs > 0 {
noticed = time.Since(time.UnixMilli(r.CreatedTs)).Round(time.Minute).String() + " ago"
}
- out = append(out, routineRow{ID: r.ID, Phrase: pattern.PhraseRoutine(&p), Noticed: noticed})
+ out = append(out, routineView{ID: r.ID, Phrase: pattern.PhraseRoutine(&p), Noticed: noticed})
}
return out
}
@@ -1574,31 +1500,6 @@ func handlePTT(w http.ResponseWriter, r *http.Request, voiceAddr string, session
// and the handler redirects back to /chat with the response.
var chatTmpl = template.Must(template.New("chat").Funcs(shellFuncs()).Parse(shellHTML + chatPageHTML))
-const chatPageHTML = `{{template "shellTop" "chat"}}
-
maven drafted these from acts she couldn't run. Fill the command (argv, space-separated) and enable. A row in an mcp: scope came from an MCP server and already knows what it calls — check the command, then enable.
+
name
scope
from utterance
enable as
+{{range .Proposed}}
+
{{.Name}}
{{.Scope}}
{{.Utterance}}
+
+
+
{{end}}
+{{else}}
+
+
no proposed tools
+
maven will propose tools here when she needs help running an action
+
{{end}}
+
+
+
enabled {{len .Enabled}}
+{{if .Enabled}}
name
scope
command
+{{range .Enabled}}
{{.Name}}
{{.Scope}}
{{join .Cmd " "}}
+
{{if .Destructive}}destructive{{end}}
+
{{end}}
+{{else}}
+
+
no tools enabled
+
enable proposed tools above, or ask maven to configure one
+
{{end}}
+
+
+
MCP servers {{len .MCP}}
+{{if .MCP}}
servers she connects OUT to. Their tools appear above as proposals — a configured server is a place she may look, not a capability she has. A stdio target is a process on this box; an http one on a loopback or LAN address is inside the network, so treat its tools accordingly.