mirror of
https://github.com/theniceboy/.config.git
synced 2026-02-22 21:05:57 +08:00
agent tracker updates
This commit is contained in:
parent
689cc061cd
commit
bb2a53206b
13 changed files with 375 additions and 106 deletions
14
agent-tracker/README.md
Normal file
14
agent-tracker/README.md
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
# Agent Tracker
|
||||
|
||||
Tmux-aware agent task and note tracker.
|
||||
|
||||
## Build, Install & Restart
|
||||
|
||||
```bash
|
||||
./scripts/install_brew_service.sh
|
||||
```
|
||||
|
||||
This script:
|
||||
1. Builds `tracker-server` from source
|
||||
2. Installs it via Homebrew
|
||||
3. Restarts the brew service
|
||||
|
|
@ -603,7 +603,7 @@ func runUI(args []string) error {
|
|||
ic, hasIC := parseTimestamp(notes[i].CreatedAt)
|
||||
jc, hasJC := parseTimestamp(notes[j].CreatedAt)
|
||||
if hasIC && hasJC && !ic.Equal(jc) {
|
||||
return ic.After(jc)
|
||||
return ic.Before(jc)
|
||||
}
|
||||
if hasIC != hasJC {
|
||||
return hasIC
|
||||
|
|
|
|||
|
|
@ -425,6 +425,9 @@ func (s *server) handleCommand(env ipc.Envelope) error {
|
|||
}
|
||||
|
||||
func (s *server) startTask(target tmuxTarget, summary string) error {
|
||||
if target.SessionID == "" || target.WindowID == "" {
|
||||
return fmt.Errorf("cannot create task: missing session or window ID")
|
||||
}
|
||||
now := time.Now()
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
|
@ -441,6 +444,9 @@ func (s *server) startTask(target tmuxTarget, summary string) error {
|
|||
}
|
||||
|
||||
func (s *server) finishTask(target tmuxTarget, note string) error {
|
||||
if target.SessionID == "" || target.WindowID == "" {
|
||||
return nil // silently ignore - pane likely died
|
||||
}
|
||||
now := time.Now()
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
|
@ -458,7 +464,8 @@ func (s *server) finishTask(target tmuxTarget, note string) error {
|
|||
if note != "" {
|
||||
t.CompletionNote = note
|
||||
}
|
||||
t.Acknowledged = false
|
||||
// Auto-acknowledge if user is currently in this pane
|
||||
t.Acknowledged = isActivePane(target.PaneID)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -1217,16 +1224,19 @@ func (s *server) buildStateEnvelope() *ipc.Envelope {
|
|||
visible := s.visible
|
||||
pos := s.pos
|
||||
copies := make([]*taskRecord, 0, len(s.tasks))
|
||||
for _, task := range s.tasks {
|
||||
taskKeys := make([]string, 0, len(s.tasks))
|
||||
for key, task := range s.tasks {
|
||||
copy := *task
|
||||
copies = append(copies, ©)
|
||||
taskKeys = append(taskKeys, key)
|
||||
}
|
||||
s.mu.Unlock()
|
||||
|
||||
now := time.Now()
|
||||
tasks := make([]ipc.Task, 0, len(copies))
|
||||
var staleKeys []string
|
||||
nameCache := make(map[string][2]string)
|
||||
for _, t := range copies {
|
||||
for i, t := range copies {
|
||||
started := ""
|
||||
if !t.StartedAt.IsZero() {
|
||||
started = t.StartedAt.Format(time.RFC3339)
|
||||
|
|
@ -1242,14 +1252,24 @@ func (s *server) buildStateEnvelope() *ipc.Envelope {
|
|||
if duration < 0 {
|
||||
duration = 0
|
||||
}
|
||||
// Auto-timeout: in_progress tasks older than 30 minutes
|
||||
if t.Status == statusInProgress && duration > 30*time.Minute {
|
||||
staleKeys = append(staleKeys, taskKeys[i])
|
||||
continue
|
||||
}
|
||||
var names [2]string
|
||||
if cached, ok := nameCache[t.WindowID]; ok {
|
||||
if cached[0] == "" && cached[1] == "" {
|
||||
staleKeys = append(staleKeys, taskKeys[i])
|
||||
continue
|
||||
}
|
||||
names = cached
|
||||
} else {
|
||||
sessName, winName, err := tmuxNamesForWindow(t.WindowID)
|
||||
if err != nil {
|
||||
sessName = t.SessionID
|
||||
winName = t.WindowID
|
||||
if err != nil || (sessName == "" && winName == "") {
|
||||
nameCache[t.WindowID] = [2]string{"", ""}
|
||||
staleKeys = append(staleKeys, taskKeys[i])
|
||||
continue
|
||||
}
|
||||
names = [2]string{sessName, winName}
|
||||
nameCache[t.WindowID] = names
|
||||
|
|
@ -1271,6 +1291,15 @@ func (s *server) buildStateEnvelope() *ipc.Envelope {
|
|||
})
|
||||
}
|
||||
|
||||
// Clean up stale tasks (windows that no longer exist)
|
||||
if len(staleKeys) > 0 {
|
||||
s.mu.Lock()
|
||||
for _, key := range staleKeys {
|
||||
delete(s.tasks, key)
|
||||
}
|
||||
s.mu.Unlock()
|
||||
}
|
||||
|
||||
activeNotes, archived := s.notesForState()
|
||||
|
||||
s.mu.Lock()
|
||||
|
|
@ -1406,6 +1435,23 @@ func runTmux(args ...string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func isActivePane(paneID string) bool {
|
||||
clients, err := listClients()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
for _, client := range clients {
|
||||
output, err := tmuxDisplay(client, "#{pane_id}")
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if strings.TrimSpace(output) == paneID {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func tmuxOutput(args ...string) (string, error) {
|
||||
cmd := exec.Command("tmux", args...)
|
||||
output, err := cmd.CombinedOutput()
|
||||
|
|
|
|||
|
|
@ -14,9 +14,10 @@ fi
|
|||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
SERVER_BIN="$ROOT_DIR/bin/tracker-server"
|
||||
|
||||
if [[ ! -x "$SERVER_BIN" ]]; then
|
||||
echo "Error: tracker-server binary not found at $SERVER_BIN" >&2
|
||||
echo "Build it with: (cd $ROOT_DIR && ./install.sh)" >&2
|
||||
echo "Building tracker-server..." >&2
|
||||
mkdir -p "$ROOT_DIR/bin"
|
||||
if ! (cd "$ROOT_DIR" && go build -o bin/tracker-server ./cmd/tracker-server); then
|
||||
echo "Error: go build failed" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue