Cleanup list navigates; spend bars; office writes the missing scaffold; memory read-out per agent
This commit is contained in:
@@ -717,6 +717,9 @@ func (m agentsModel) settingLines(width int) []string {
|
||||
}
|
||||
out = append(out, mark+style.Render(fmt.Sprintf("%-14s %s", f.label, value)))
|
||||
}
|
||||
out = append(out, "", " "+mutedStyle2().Render("memory and extensions"))
|
||||
out = append(out, " "+lipgloss.NewStyle().Foreground(lipgloss.Color(active.Text)).Render(m.memoryLine(agent.ID)))
|
||||
out = append(out, " "+dimStyle().Render(" read from the agent's command and the global pi settings; nothing is set here yet"))
|
||||
out = append(out, "")
|
||||
out = append(out, dimStyle().Render(" a model change applies to that agent's next run, never to one in flight."))
|
||||
out = append(out, dimStyle().Render(" p pause · P resume · w wake: they act on the agent chosen here."))
|
||||
@@ -1239,3 +1242,57 @@ func (m agentsModel) extensionLines(width int) []string {
|
||||
out = append(out, dimStyle().Render(" and passed to Paperclip as this agent's command."))
|
||||
return out
|
||||
}
|
||||
|
||||
// memoryLine says what an agent's context is configured to use: whether it runs
|
||||
// a wrapper (per-agent extensions), and which memory or compression packages the
|
||||
// global Pi settings carry. It reads, and claims nothing it has not seen.
|
||||
func (m agentsModel) memoryLine(agentID string) string {
|
||||
parts := []string{}
|
||||
if wrapped := wrapperExtensions(agentID); len(wrapped) > 0 {
|
||||
var names []string
|
||||
for name := range wrapped {
|
||||
names = append(names, name)
|
||||
}
|
||||
sort.Strings(names)
|
||||
parts = append(parts, "extensions: "+strings.Join(names, ", "))
|
||||
} else {
|
||||
parts = append(parts, "extensions: the global set")
|
||||
}
|
||||
full, err := m.client.AgentRaw(agentID)
|
||||
if err == nil {
|
||||
if cfg, ok := full["adapterConfig"].(map[string]any); ok {
|
||||
if cmd, ok := cfg["command"].(string); ok && cmd != "" && cmd != "pi" {
|
||||
parts = append(parts, "command: "+filepath.Base(cmd))
|
||||
}
|
||||
}
|
||||
}
|
||||
home, _ := os.UserHomeDir()
|
||||
if b, err := os.ReadFile(filepath.Join(home, ".pi", "agent", "settings.json")); err == nil {
|
||||
var settings struct {
|
||||
Packages []any `json:"packages"`
|
||||
}
|
||||
if json.Unmarshal(b, &settings) == nil {
|
||||
var mem []string
|
||||
for _, p := range settings.Packages {
|
||||
switch v := p.(type) {
|
||||
case string:
|
||||
if strings.Contains(v, "memctx") || strings.Contains(v, "engram") || strings.Contains(v, "headroom") {
|
||||
mem = append(mem, strings.TrimPrefix(v, "npm:"))
|
||||
}
|
||||
case map[string]any:
|
||||
if src, ok := v["source"].(string); ok {
|
||||
if strings.Contains(src, "engram") || strings.Contains(src, "headroom") {
|
||||
mem = append(mem, src)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(mem) > 0 {
|
||||
parts = append(parts, "memory: "+strings.Join(mem, ", "))
|
||||
} else {
|
||||
parts = append(parts, "memory: none in the global pi settings")
|
||||
}
|
||||
}
|
||||
}
|
||||
return strings.Join(parts, " · ")
|
||||
}
|
||||
|
||||
@@ -383,11 +383,23 @@ func (m projectModel) costLines() []string {
|
||||
}
|
||||
total := 0
|
||||
runs := 0
|
||||
out := []string{"", dimStyle().Render(fmt.Sprintf("%-10s %-10s %8s %6s", "task", "state", "cents", "runs"))}
|
||||
peak := 1
|
||||
for _, c := range m.costs {
|
||||
if c.Cents > peak {
|
||||
peak = c.Cents
|
||||
}
|
||||
}
|
||||
out := []string{"", dimStyle().Render(fmt.Sprintf("%-10s %-10s %6s %5s %s", "task", "state", "cents", "runs", "share of the largest"))}
|
||||
for _, c := range m.costs {
|
||||
total += c.Cents
|
||||
runs += c.Runs
|
||||
out = append(out, fmt.Sprintf("%-10s %-10s %8d %6d", c.Identifier, c.Status, c.Cents, c.Runs))
|
||||
bars := int(float64(c.Cents) / float64(peak) * 24)
|
||||
bar := strings.Repeat("█", bars)
|
||||
if c.Cents > 0 && bars == 0 {
|
||||
bar = "▏"
|
||||
}
|
||||
out = append(out, fmt.Sprintf("%-10s %-10s %6d %5d %s", c.Identifier, c.Status, c.Cents, c.Runs,
|
||||
lipgloss.NewStyle().Foreground(lipgloss.Color(active.Accent)).Render(bar)))
|
||||
}
|
||||
out = append(out, "")
|
||||
out = append(out, m.row("total, recent", fmt.Sprintf("%d cent(s) over %d run(s)", total, runs)))
|
||||
|
||||
@@ -297,9 +297,26 @@ func (m repairModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
}
|
||||
return m, nil
|
||||
case "up", "k":
|
||||
if m.tab == 3 {
|
||||
if m.sessAt > 0 {
|
||||
m.sessAt--
|
||||
}
|
||||
m.scroll = max(0, min(m.scroll, m.sessAt-2))
|
||||
return m, nil
|
||||
}
|
||||
m.scroll--
|
||||
return m, nil
|
||||
case "down", "j":
|
||||
if m.tab == 3 {
|
||||
if m.sessAt < len(m.sessions)-1 {
|
||||
m.sessAt++
|
||||
}
|
||||
visible := max(3, m.height-6)
|
||||
if m.sessAt > m.scroll+visible-3 {
|
||||
m.scroll = m.sessAt - visible + 3
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
m.scroll++
|
||||
return m, nil
|
||||
case "esc":
|
||||
@@ -507,10 +524,10 @@ func (m repairModel) cleanupLines(width int) []string {
|
||||
r.lastUsed.Format("2 Jan 15:04"), state)
|
||||
mark := " "
|
||||
if m.ticked[r.name] {
|
||||
mark = "▸ "
|
||||
mark = "* "
|
||||
}
|
||||
if i == m.sessAt {
|
||||
out = append(out, selectedStyle2().Render(padTo(mark+line, width)))
|
||||
out = append(out, selectedStyle2().Render(padTo("▸"+line[1:], width)))
|
||||
continue
|
||||
}
|
||||
out = append(out, mark+line)
|
||||
|
||||
Reference in New Issue
Block a user