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
- 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
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