Skip to content

Commit de6fa76

Browse files
committed
fix(tui): address code review feedback from PR #38
- Security: set socket permissions to 0600 after creation - Fix CloseAgentListener to use pointer receiver - Increase agent timeout from 60s to 120s (match documented socat -t 120) - Cache filter history in memory to avoid disk reads on every keystroke - Replace synthetic tea.KeyCtrlE with dedicated AgentAutoExecMsg - Trim design doc from 902 lines to ~70 lines of design rationale
1 parent 3293b8a commit de6fa76

6 files changed

Lines changed: 75 additions & 885 deletions

File tree

cmd/mxcli/tui/agent_listener.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ func NewAgentListener(socketPath string, sendMsg func(tea.Msg), autoProceed bool
3636
if err != nil {
3737
return nil, err
3838
}
39+
// Restrict socket access to current user only
40+
if err := os.Chmod(socketPath, 0600); err != nil {
41+
ln.Close()
42+
return nil, fmt.Errorf("chmod socket: %w", err)
43+
}
3944

4045
al := &AgentListener{
4146
socketPath: socketPath,
@@ -150,7 +155,7 @@ func (al *AgentListener) handleConnection(conn net.Conn) {
150155
select {
151156
case resp := <-responseCh:
152157
encoder.Encode(resp)
153-
case <-time.After(60 * time.Second):
158+
case <-time.After(120 * time.Second):
154159
encoder.Encode(AgentResponse{ID: req.ID, OK: false, Error: "timeout waiting for TUI response"})
155160
}
156161
}

cmd/mxcli/tui/agent_msgs.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ type AgentCreateModuleMsg struct {
4242
ResponseCh chan<- AgentResponse
4343
}
4444

45+
// AgentAutoExecMsg triggers automatic MDL execution in ExecView
46+
// without simulating a keystroke. Used by auto-proceed mode.
47+
type AgentAutoExecMsg struct{}
48+
4549
// Ensure messages satisfy tea.Msg.
4650
var (
4751
_ tea.Msg = AgentExecMsg{}
@@ -50,4 +54,5 @@ var (
5054
_ tea.Msg = AgentNavigateMsg{}
5155
_ tea.Msg = AgentDeleteMsg{}
5256
_ tea.Msg = AgentCreateModuleMsg{}
57+
_ tea.Msg = AgentAutoExecMsg{}
5358
)

cmd/mxcli/tui/app.go

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ func (a *App) StartAgentListener(prog *tea.Program, socketPath string, autoProce
149149
}
150150

151151
// CloseAgentListener stops the agent listener if running.
152-
func (a App) CloseAgentListener() {
152+
func (a *App) CloseAgentListener() {
153153
if a.agentListener != nil {
154154
a.agentListener.Close()
155155
}
@@ -469,10 +469,7 @@ func (a App) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
469469
ev := NewExecViewWithContent(a.mxcliPath, a.activeTabProjectPath(), a.width, a.height, msg.MDL)
470470
a.views.Push(ev)
471471
if a.agentAutoProceed {
472-
// Auto-trigger execution (like pressing Ctrl+E)
473-
return a, func() tea.Msg {
474-
return tea.KeyMsg{Type: tea.KeyCtrlE}
475-
}
472+
return a, func() tea.Msg { return AgentAutoExecMsg{} }
476473
}
477474
return a, nil
478475

cmd/mxcli/tui/execview.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,14 @@ func (ev ExecView) Update(msg tea.Msg) (View, tea.Cmd) {
315315
ev.textarea.SetHeight(msg.Height - 6)
316316
return ev, nil
317317

318+
case AgentAutoExecMsg:
319+
mdlText := strings.TrimSpace(ev.textarea.Value())
320+
if mdlText == "" {
321+
return ev, nil
322+
}
323+
ev.executing = true
324+
return ev, ev.executeMDL(mdlText)
325+
318326
case tea.KeyMsg:
319327
if ev.executing {
320328
return ev, nil

cmd/mxcli/tui/filterhistory.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,23 @@ import (
1212

1313
const maxFilterHistory = 50
1414

15+
// filterHistoryCache holds the in-memory cache of filter history entries.
16+
// Loaded once from disk, updated in memory and written back on mutation.
17+
var filterHistoryCache []string
18+
var filterHistoryCacheLoaded bool
19+
1520
func filterHistoryPath() string {
1621
home, _ := os.UserHomeDir()
1722
return filepath.Join(home, ".mxcli", "tui-filter-history.json")
1823
}
1924

2025
// LoadFilterHistory returns recent filter queries, most recent first.
26+
// Uses an in-memory cache to avoid disk reads on every keystroke.
2127
func LoadFilterHistory() []string {
28+
if filterHistoryCacheLoaded {
29+
return filterHistoryCache
30+
}
31+
filterHistoryCacheLoaded = true
2232
data, err := os.ReadFile(filterHistoryPath())
2333
if err != nil {
2434
return nil
@@ -28,6 +38,7 @@ func LoadFilterHistory() []string {
2838
Trace("filterhistory: unmarshal error: %v", err)
2939
return nil
3040
}
41+
filterHistoryCache = entries
3142
return entries
3243
}
3344

@@ -43,6 +54,9 @@ func AddFilterHistoryEntry(query string) {
4354
if len(entries) > maxFilterHistory {
4455
entries = entries[:maxFilterHistory]
4556
}
57+
// Update in-memory cache
58+
filterHistoryCache = entries
59+
// Persist to disk
4660
if err := os.MkdirAll(filepath.Dir(filterHistoryPath()), 0755); err != nil {
4761
Trace("filterhistory: mkdir error: %v", err)
4862
return

0 commit comments

Comments
 (0)