Merge branch 'main' into fix-monitor

Amp-Thread-ID: https://ampcode.com/threads/T-7bbd9558-2eb4-483a-bf7b-c61ea9c22092
Co-authored-by: Amp <amp@ampcode.com>
This commit is contained in:
Steve Yegge
2025-11-20 12:34:30 -05:00
12 changed files with 612 additions and 176 deletions

View File

@@ -210,7 +210,10 @@ func (s *Server) handleConnection(conn net.Conn) {
Success: false,
Error: fmt.Sprintf("invalid request: %v", err),
}
s.writeResponse(writer, resp)
if err := s.writeResponse(writer, resp); err != nil {
// Connection broken, stop handling this connection
return
}
continue
}
@@ -220,15 +223,32 @@ func (s *Server) handleConnection(conn net.Conn) {
}
resp := s.handleRequest(&req)
s.writeResponse(writer, resp)
if err := s.writeResponse(writer, resp); err != nil {
// Connection broken, stop handling this connection
return
}
}
}
func (s *Server) writeResponse(writer *bufio.Writer, resp Response) {
data, _ := json.Marshal(resp)
_, _ = writer.Write(data)
_ = writer.WriteByte('\n')
_ = writer.Flush()
func (s *Server) writeResponse(writer *bufio.Writer, resp Response) error {
data, err := json.Marshal(resp)
if err != nil {
return fmt.Errorf("failed to marshal response: %w", err)
}
if _, err := writer.Write(data); err != nil {
return fmt.Errorf("failed to write response: %w", err)
}
if err := writer.WriteByte('\n'); err != nil {
return fmt.Errorf("failed to write newline: %w", err)
}
if err := writer.Flush(); err != nil {
return fmt.Errorf("failed to flush response: %w", err)
}
return nil
}
func (s *Server) handleShutdown(_ *Request) Response {

View File

@@ -8,6 +8,7 @@ import (
"fmt"
"os"
"path/filepath"
"runtime"
"strings"
"sync/atomic"
"time"
@@ -113,6 +114,15 @@ func New(path string) (*SQLiteStorage, error) {
if isInMemory {
db.SetMaxOpenConns(1)
db.SetMaxIdleConns(1)
} else {
// For file-based databases in daemon mode, limit connection pool to prevent
// connection exhaustion under concurrent load. SQLite WAL mode supports
// 1 writer + unlimited readers, but we limit to prevent goroutine pile-up
// on write lock contention (bd-qhws).
maxConns := runtime.NumCPU() + 1 // 1 writer + N readers
db.SetMaxOpenConns(maxConns)
db.SetMaxIdleConns(2)
db.SetConnMaxLifetime(0) // SQLite doesn't need connection recycling
}
// For file-based databases, enable WAL mode once after opening the connection.
@@ -1134,11 +1144,11 @@ func (s *SQLiteStorage) findAllDependentsRecursive(ctx context.Context, tx *sql.
if err != nil {
return nil, err
}
defer rows.Close()
for rows.Next() {
var depID string
if err := rows.Scan(&depID); err != nil {
_ = rows.Close()
return nil, err
}
if !result[depID] {
@@ -1147,10 +1157,8 @@ func (s *SQLiteStorage) findAllDependentsRecursive(ctx context.Context, tx *sql.
}
}
if err := rows.Err(); err != nil {
_ = rows.Close()
return nil, err
}
_ = rows.Close()
}
return result, nil

View File

@@ -37,6 +37,14 @@ func ParseIssueID(input string, prefix string) string {
// - No issue found matching the ID
// - Multiple issues match (ambiguous prefix)
func ResolvePartialID(ctx context.Context, store storage.Storage, input string) (string, error) {
// Fast path: if the user typed an exact ID that exists, return it as-is.
// This preserves behavior where issue IDs may not match the configured
// issue_prefix (e.g. cross-repo IDs like "ao-izl"), while still allowing
// prefix-based and hash-based resolution for other inputs.
if issue, err := store.GetIssue(ctx, input); err == nil && issue != nil {
return input, nil
}
// Get the configured prefix
prefix, err := store.GetConfig(ctx, "issue_prefix")
if err != nil || prefix == "" {
@@ -63,7 +71,7 @@ func ResolvePartialID(ctx context.Context, store storage.Storage, input string)
normalizedID = prefixWithHyphen + input
}
// First try exact match
// First try exact match on normalized ID
issue, err := store.GetIssue(ctx, normalizedID)
if err == nil && issue != nil {
return normalizedID, nil