Skip to content
This repository was archived by the owner on Apr 2, 2026. It is now read-only.
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions cmd/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,10 +226,13 @@ func runHandler(cmd *cobra.Command, args []string) error {
}(dbPath, proj.Hash, proj.Name, proj.RootDir)
}

// If no cache or forced refresh, fetch from API
// If no cache or forced refresh, fetch from API.
// Use a short timeout so the Stop hook never blocks a Claude Code session
// for more than ~90 seconds during an API outage. Long-running first-time
// fetches for large repos are handled by the background pregen hook.
if graph == nil || forceRefresh {
logFn("[debug] fetching from Supermodel API...")
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
ctx, cancel := context.WithTimeout(context.Background(), 90*time.Second)
Comment on lines +229 to +235
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

The 90s cap only applies to the fetch phase, not the whole Stop hook.

Right now the command can still spend up to 5s in project.Detect, 15s in GetWorkingMemory, and then another 90s here, so the real wall-clock cap is still closer to ~110s. If the PR goal is a true end-to-end Stop-hook limit, give the whole run path a parent deadline and derive these sub-contexts from it.

Possible shape of the fix
 func runHandler(cmd *cobra.Command, args []string) error {
+	runCtx, runCancel := context.WithTimeout(context.Background(), 90*time.Second)
+	defer runCancel()
+
 	...
-	gitCtx, gitCancel := context.WithTimeout(context.Background(), 5*time.Second)
+	gitCtx, gitCancel := context.WithTimeout(runCtx, 5*time.Second)
 	defer gitCancel()

 	...
-	wmCtx, wmCancel := context.WithTimeout(context.Background(), 15*time.Second)
+	wmCtx, wmCancel := context.WithTimeout(runCtx, 15*time.Second)
 	defer wmCancel()

 	...
-	ctx, cancel := context.WithTimeout(context.Background(), 90*time.Second)
+	ctx, cancel := context.WithTimeout(runCtx, 90*time.Second)
 	defer cancel()

You'd want to thread that same parent context into runWithoutCache too.

Also applies to: 475-479

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cmd/run.go` around lines 229 - 235, The current 90s timeout only wraps the
Supermodel fetch and doesn't bound the full Stop hook; create a single parent
context with a total deadline for the run path (e.g., in the function that calls
runWithoutCache) and pass that parent ctx into runWithoutCache so all
sub-operations (project.Detect, GetWorkingMemory, and the Supermodel fetch)
derive sub-contexts from it (use context.WithTimeout/WithDeadline on the parent
to create shorter child contexts where needed and replace the local
context.WithTimeout in the Supermodel fetch with a child of the parent). Ensure
functions like runWithoutCache, project.Detect, and GetWorkingMemory accept and
use the passed parent context so the whole end-to-end Stop hook is capped by the
single parent deadline.

defer cancel()

zipData, skipReport, err := zip.RepoZip(ctx, proj.RootDir)
Expand Down Expand Up @@ -469,8 +472,10 @@ func runLocalMode(logFn func(string, ...interface{})) error {
}

// runWithoutCache attempts an API fetch with no cache fallback.
// Uses a short timeout so the Stop hook never blocks a Claude Code session
// for more than ~90 seconds during an API outage.
func runWithoutCache(cfg *config.Config, proj *project.Info, wm *project.WorkingMemory, snap *snapshot.SessionSnapshot, postCompact bool, logFn func(string, ...interface{})) error {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
ctx, cancel := context.WithTimeout(context.Background(), 90*time.Second)
defer cancel()

zipData, skipReport, err := zip.RepoZip(ctx, proj.RootDir)
Expand Down