a73x

23114045

feat: wire watcher → scanner → mcp → rewriter in main

a73x   2026-04-29 05:59

Commit message
feat: wire watcher → scanner → mcp → rewriter in main

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

cmd/filewatch-mcp/main.go
Old New
@@ -1,7 +1,101 @@
1 package main 1 package main
2 2
3 import "fmt" 3 import (
4 "context"
5 "flag"
6 "log"
7 "os"
8 "os/signal"
9 "strconv"
10 "syscall"
11 "time"
12
13 "github.com/google/uuid"
14
15 "github.com/xanderle/claudealong/internal/ignore"
16 "github.com/xanderle/claudealong/internal/mcp"
17 "github.com/xanderle/claudealong/internal/rewriter"
18 "github.com/xanderle/claudealong/internal/scanner"
19 "github.com/xanderle/claudealong/internal/watcher"
20 )
4 21
5 func main() { 22 func main() {
6 fmt.Println("filewatch-mcp") 23 root := flag.String("root", ".", "project root to watch")
24 debounce := flag.Duration("debounce", 500*time.Millisecond, "per-file debounce window")
25 flag.Parse()
26
27 log.SetOutput(os.Stderr)
28 log.SetFlags(log.Ltime | log.Lshortfile)
29
30 ig, err := ignore.New(*root)
31 if err != nil {
32 log.Fatalf("ignore: %v", err)
33 }
34 w, err := watcher.New(*root, ig, *debounce)
35 if err != nil {
36 log.Fatalf("watcher: %v", err)
37 }
38 defer w.Close()
39
40 srv := mcp.New()
41
42 ctx, cancel := context.WithCancel(context.Background())
43 defer cancel()
44
45 sigCh := make(chan os.Signal, 1)
46 signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
47 go func() { <-sigCh; cancel() }()
48
49 if err := w.Start(ctx); err != nil {
50 log.Fatalf("watcher start: %v", err)
51 }
52 go consume(ctx, w, srv)
53
54 if err := srv.Run(ctx); err != nil {
55 log.Fatalf("mcp run: %v", err)
56 }
57 }
58
59 func consume(ctx context.Context, w *watcher.Watcher, srv *mcp.Server) {
60 for {
61 select {
62 case <-ctx.Done():
63 return
64 case ev, ok := <-w.Events():
65 if !ok {
66 return
67 }
68 handle(ctx, ev.Path, srv)
69 }
70 }
71 }
72
73 func handle(ctx context.Context, path string, srv *mcp.Server) {
74 markers, err := scanner.Scan(path)
75 if err != nil {
76 log.Printf("scan %s: %v", path, err)
77 return
78 }
79 stamps := make(map[int]string, len(markers))
80 for _, m := range markers {
81 if m.Tagged {
82 continue
83 }
84 id := "fw-" + uuid.NewString()[:8]
85 stamps[m.Line] = id
86 if err := srv.SendChannel(ctx, mcp.ChannelMeta{
87 Source: "filewatch",
88 File: path,
89 Line: strconv.Itoa(m.Line),
90 ReplyTo: id,
91 }, m.Text); err != nil {
92 log.Printf("send: %v", err)
93 }
94 }
95 if len(stamps) == 0 {
96 return
97 }
98 if err := rewriter.StampUUIDs(path, stamps); err != nil {
99 log.Printf("stamp %s: %v", path, err)
100 }
7 } 101 }
go.mod
Old New
@@ -4,6 +4,7 @@ go 1.26.2
4 4
5 require ( 5 require (
6 github.com/fsnotify/fsnotify v1.9.0 // indirect 6 github.com/fsnotify/fsnotify v1.9.0 // indirect
7 github.com/google/uuid v1.6.0 // indirect
7 github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06 // indirect 8 github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06 // indirect
8 golang.org/x/sys v0.13.0 // indirect 9 golang.org/x/sys v0.13.0 // indirect
9 ) 10 )
go.sum
Old New
@@ -1,6 +1,8 @@
1 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 1 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
2 github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= 2 github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
3 github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= 3 github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
4 github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
5 github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
4 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 6 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
5 github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06 h1:OkMGxebDjyw0ULyrTYWeN0UNCCkmCWfjPnIA2W6oviI= 7 github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06 h1:OkMGxebDjyw0ULyrTYWeN0UNCCkmCWfjPnIA2W6oviI=
6 github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06/go.mod h1:+ePHsJ1keEjQtpvf9HHw0f4ZeJ0TLRsxhunSI2hYJSs= 8 github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06/go.mod h1:+ePHsJ1keEjQtpvf9HHw0f4ZeJ0TLRsxhunSI2hYJSs=