ScuttleBot

fix: mirror loop retries indefinitely instead of failing after timeout The mirror now loops on session discovery instead of giving up after 60 seconds. If the session file doesn't exist yet (idle agent) or the tail is lost, it waits and retries. No more "mirror failed" messages for agents that just haven't started their first task yet. Closes #59

lmata 2026-04-04 03:33 trunk
Commit 321167eca720bcc2d2e589ca80c2d657bedc974df1a097f68ec5b50652ad199d
1 file changed +24 -14
--- cmd/claude-relay/main.go
+++ cmd/claude-relay/main.go
@@ -266,27 +266,37 @@
266266
}
267267
268268
// --- Session mirroring ---
269269
270270
func mirrorSessionLoop(ctx context.Context, relay sessionrelay.Connector, cfg config, startedAt time.Time) {
271
- sessionPath, err := discoverSessionPath(ctx, cfg, startedAt)
272
- if err != nil {
273
- if ctx.Err() == nil {
274
- _ = relay.Post(context.Background(), fmt.Sprintf("mirror failed: %v — session activity not visible in IRC", err))
271
+ for {
272
+ if ctx.Err() != nil {
273
+ return
274
+ }
275
+ sessionPath, err := discoverSessionPath(ctx, cfg, startedAt)
276
+ if err != nil {
277
+ if ctx.Err() != nil {
278
+ return
279
+ }
280
+ // Session not found yet — wait and retry instead of giving up.
281
+ time.Sleep(10 * time.Second)
282
+ continue
283
+ }
284
+ if err := tailSessionFile(ctx, sessionPath, cfg.MirrorReasoning, func(text string) {
285
+ for _, line := range splitMirrorText(text) {
286
+ if line == "" {
287
+ continue
288
+ }
289
+ _ = relay.Post(ctx, line)
290
+ }
291
+ }); err != nil && ctx.Err() == nil {
292
+ // Tail lost — retry discovery.
293
+ time.Sleep(5 * time.Second)
294
+ continue
275295
}
276296
return
277297
}
278
- if err := tailSessionFile(ctx, sessionPath, cfg.MirrorReasoning, func(text string) {
279
- for _, line := range splitMirrorText(text) {
280
- if line == "" {
281
- continue
282
- }
283
- _ = relay.Post(ctx, line)
284
- }
285
- }); err != nil && ctx.Err() == nil {
286
- _ = relay.Post(context.Background(), fmt.Sprintf("mirror lost: %v — session activity no longer visible in IRC", err))
287
- }
288298
}
289299
290300
func discoverSessionPath(ctx context.Context, cfg config, startedAt time.Time) (string, error) {
291301
root, err := claudeSessionsRoot(cfg.TargetCWD)
292302
if err != nil {
293303
--- cmd/claude-relay/main.go
+++ cmd/claude-relay/main.go
@@ -266,27 +266,37 @@
266 }
267
268 // --- Session mirroring ---
269
270 func mirrorSessionLoop(ctx context.Context, relay sessionrelay.Connector, cfg config, startedAt time.Time) {
271 sessionPath, err := discoverSessionPath(ctx, cfg, startedAt)
272 if err != nil {
273 if ctx.Err() == nil {
274 _ = relay.Post(context.Background(), fmt.Sprintf("mirror failed: %v — session activity not visible in IRC", err))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
275 }
276 return
277 }
278 if err := tailSessionFile(ctx, sessionPath, cfg.MirrorReasoning, func(text string) {
279 for _, line := range splitMirrorText(text) {
280 if line == "" {
281 continue
282 }
283 _ = relay.Post(ctx, line)
284 }
285 }); err != nil && ctx.Err() == nil {
286 _ = relay.Post(context.Background(), fmt.Sprintf("mirror lost: %v — session activity no longer visible in IRC", err))
287 }
288 }
289
290 func discoverSessionPath(ctx context.Context, cfg config, startedAt time.Time) (string, error) {
291 root, err := claudeSessionsRoot(cfg.TargetCWD)
292 if err != nil {
293
--- cmd/claude-relay/main.go
+++ cmd/claude-relay/main.go
@@ -266,27 +266,37 @@
266 }
267
268 // --- Session mirroring ---
269
270 func mirrorSessionLoop(ctx context.Context, relay sessionrelay.Connector, cfg config, startedAt time.Time) {
271 for {
272 if ctx.Err() != nil {
273 return
274 }
275 sessionPath, err := discoverSessionPath(ctx, cfg, startedAt)
276 if err != nil {
277 if ctx.Err() != nil {
278 return
279 }
280 // Session not found yet — wait and retry instead of giving up.
281 time.Sleep(10 * time.Second)
282 continue
283 }
284 if err := tailSessionFile(ctx, sessionPath, cfg.MirrorReasoning, func(text string) {
285 for _, line := range splitMirrorText(text) {
286 if line == "" {
287 continue
288 }
289 _ = relay.Post(ctx, line)
290 }
291 }); err != nil && ctx.Err() == nil {
292 // Tail lost — retry discovery.
293 time.Sleep(5 * time.Second)
294 continue
295 }
296 return
297 }
 
 
 
 
 
 
 
 
 
 
298 }
299
300 func discoverSessionPath(ctx context.Context, cfg config, startedAt time.Time) (string, error) {
301 root, err := claudeSessionsRoot(cfg.TargetCWD)
302 if err != nil {
303

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button