uttrflow / uttrflow/uttrflow-swift

The AI suggestions command lookups never time out: the program's output is read to the end before the 0.5 s / 2 s deadline is checked

Open
#663 0 comments 0 reactions 0 assignees View on GitHub
area:ai-suggestions bug P2
Dominant language
Swift
Stars
4
Forks
17
Avg merge
3h 32m
Merged PRs (30d)
277

Description

## What happens

To suggest subcommands, branches and aliases in a terminal, `SystemEnvironmentReader.run` launches programs (`Sources/UttrflowPredict/EnvironmentReading+System.swift:205-236`):

- `git` with `-C `;
- ` --help`, `cargo --list`, `brew commands --quiet` or `npm help`, run in the terminal's working directory (`:163-171`, `:216`).

The deadline is `timeoutInSeconds = 0.5`, or `helpTimeoutInSeconds = 2.0` for help output (`:6`, `:9`). But the output is read with a blocking `readToEnd()` *before* the deadline loop (`:227-228`):

```swift
let produced = try? output.fileHandleForReading.readToEnd()
let deadline = Date().addingTimeInterval(timeout)
while process.isRunning && Date() < deadline { … }
```

`readToEnd()` returns only when every writer has closed the pipe. A program that hangs (waits on a lock, a network call, or a prompt despite `GIT_TERMINAL_PROMPT=0`), or that keeps a child process holding stdout, blocks this task indefinitely. The deadline starts only after that. A program that prints without end fills memory, because nothing caps the read. `terminate()` sends SIGTERM to the direct child only, so grandchildren survive.

This is the same pattern as #579 in the clipboard formatter, in a different file that runs without any click: as a person types in a terminal.

## Why it matters

Each lookup is awaited on a suggestion turn. A hung `git` (for example, on a network file system, or a repository whose fsmonitor hook stalls) or a slow `--help` holds a task and a child process per lookup for as long as it hangs, and repeated keystrokes can start more. The documented bounds (0.5 s, 2 s) are what a reader relies on to judge whether launching programs while typing is safe.

## How to reproduce

In a unit test or throwaway harness, call `run` on a script that sleeps 10 s before printing, with `within: 0.5`. It returns after 10 s, not 0.5 s. A script that forks `sleep 30 &` with inherited stdout and exits returns only after 30 s.

## Acceptance criteria

- Output is read concurrently (a `readabilityHandler`, or a detached read) with a byte cap, and the deadline starts at launch.
- On timeout, the process group is killed, and the call returns `nil` within about the timeout plus 100 ms.
- A test in `Tests/UttrflowPredictTests` covers a hanging child and a child that leaves a grandchild holding the pipe. The fix shares a helper with #579 if one is written.

Contributor guide

Open the contributing guide

Research direction

Start in Sources/UttrflowPredict/EnvironmentReading+System.swift:205-236 and inspect SystemEnvironmentReader.run, especially the blocking readToEnd() and deadline loop. Reproduce the issue with a script that sleeps or leaves a grandchild holding stdout, then inspect Tests/UttrflowPredictTests for the appropriate test location. Done means capped concurrent reading, process-group cleanup, and nil returned within the stated timeout bounds.

Written by the indexing model from the issue text.

Assessment

Tech stack
swift
Domain
tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
65/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.