From d9b9d828fbc86eccdf536d8abc8cec37cf50d2b9 Mon Sep 17 00:00:00 2001 From: David Chen Date: Sat, 29 Nov 2025 10:55:42 -0800 Subject: [PATCH] feat: add 's' hotkey to cycle note scope --- agent-tracker/cmd/tracker-client/main.go | 38 ++++++++++++++++++++---- agent-tracker/cmd/tracker-server/main.go | 16 ++++++---- 2 files changed, 43 insertions(+), 11 deletions(-) diff --git a/agent-tracker/cmd/tracker-client/main.go b/agent-tracker/cmd/tracker-client/main.go index 3528e2a..78102e8 100644 --- a/agent-tracker/cmd/tracker-client/main.go +++ b/agent-tracker/cmd/tracker-client/main.go @@ -683,10 +683,11 @@ func runUI(args []string) error { }) } - updateNote := func(id, text string) error { + updateNote := func(id, text, scope string) error { text = strings.TrimSpace(text) - if text == "" { - return fmt.Errorf("note text required") + scope = strings.TrimSpace(scope) + if text == "" && scope == "" { + return fmt.Errorf("note text or scope required") } if strings.TrimSpace(id) == "" { return fmt.Errorf("note id required") @@ -694,9 +695,26 @@ func runUI(args []string) error { return sendCommand("note_edit", func(env *ipc.Envelope) { env.NoteID = id env.Summary = text + env.Scope = scope }) } + cycleNoteScope := func(n ipc.Note) error { + current := noteScopeOf(n) + var next noteScope + switch current { + case scopeWindow: + next = scopeSession + case scopeSession: + next = scopeAll + case scopeAll: + next = scopeWindow + default: + next = scopeWindow + } + return updateNote(n.ID, "", string(next)) + } + toggleNote := func(id string) error { if strings.TrimSpace(id) == "" { return fmt.Errorf("note id required") @@ -802,7 +820,7 @@ func runUI(args []string) error { case promptAddNote: err = addNote(text) case promptEditNote: - err = updateNote(prompt.noteID, text) + err = updateNote(prompt.noteID, text, "") } prompt.active = false if prompt.mode == promptEditNote { @@ -1265,7 +1283,7 @@ func runUI(args []string) error { if helpVisible { helpLines := []string{ - "t: toggle Tracker/Notes | n/N: scope (Notes) | Alt-A: archive view | Shift-A: archive note", + "t: toggle Tracker/Notes | s/S: scope (Notes) | Alt-A: archive view | Shift-A: archive note", "a/k: add note | i: edit note | Enter/c: complete (Tracker/Notes) | p: focus task", "Shift-D: delete | Shift-C: show/hide completed | Esc: close | ?: toggle help", } @@ -1484,6 +1502,16 @@ func runUI(args []string) error { } draw(time.Now()) } + case 's': + if mode == viewNotes { + notes := getVisibleNotes() + if len(notes) > 0 && noteList.selected < len(notes) { + if err := cycleNoteScope(notes[noteList.selected]); err != nil { + st.message = err.Error() + } + } + draw(time.Now()) + } case 'u': switch mode { case viewTracker: diff --git a/agent-tracker/cmd/tracker-server/main.go b/agent-tracker/cmd/tracker-server/main.go index 63207ab..5593e44 100644 --- a/agent-tracker/cmd/tracker-server/main.go +++ b/agent-tracker/cmd/tracker-server/main.go @@ -314,7 +314,7 @@ func (s *server) handleCommand(env ipc.Envelope) error { s.statusRefreshAsync() return nil case "note_edit": - if err := s.editNote(strings.TrimSpace(env.NoteID), env.Summary); err != nil { + if err := s.editNote(strings.TrimSpace(env.NoteID), env.Scope, env.Summary); err != nil { return err } s.broadcastStateAsync() @@ -466,18 +466,22 @@ func (s *server) addNote(target tmuxTarget, scope, summary string) error { return s.saveNotesLocked() } -func (s *server) editNote(id, summary string) error { +func (s *server) editNote(id, scope, summary string) error { summary = strings.TrimSpace(summary) - if summary == "" { - return fmt.Errorf("note summary required") - } + scope = normalizeScope(scope) + s.mu.Lock() defer s.mu.Unlock() n, ok := s.notes[id] if !ok { return fmt.Errorf("note not found") } - n.Summary = summary + if summary != "" { + n.Summary = summary + } + if scope != "" { + n.Scope = scope + } now := time.Now() n.UpdatedAt = now return s.saveNotesLocked()