FN-7704: fix fn agent stop/start hanging up to 60s due to unclosed store handles

Fix CLI process exit so `fn agent stop`/`fn agent start` no longer hang up to 60s and eventually time out on repeated retries against the same agent.

- Root cause: `resolveProject()` cached an unclosed `TaskStore`, and `createAgentStore()` never closed the `AgentStore` it opened, leaving SQLite handles alive after the command's real work was done.
- Add `resolveProjectPathOnly`/`closeProjectStore` helpers in `project-context.ts` so path-only callers never leak a `TaskStore`.
- Explicitly close `AgentStore` on every exit/return path in `agent.ts`, since `process.exit()` skips pending `finally` blocks.
- Add a bounded fast-fail timeout around the state-store write (default 10s, overridable via `FUSION_AGENT_CMD_TIMEOUT_MS`) so a genuinely stuck operation fails fast with a clear error and non-zero exit instead of hanging.
- Add regression tests covering process-exit/store-closing behavior and update CLI reference docs.
- Add changeset for the patch release.

Files changed:
 .changeset/fn-7704-agent-cmd-hang-fix.md           |   7 +
 docs/cli-reference.md                              |   3 +
 .../commands/__tests__/agent-process-exit.test.ts  | 114 +++++++++++
 packages/cli/src/commands/__tests__/agent.test.ts  | 111 +++++++++-
 packages/cli/src/commands/agent.ts                 | 223 ++++++++++++++++-----
 packages/cli/src/project-context.ts                |  44 ++++
 6 files changed, 444 insertions(+), 58 deletions(-)

Fusion-Task-Id: FN-7704
Fusion-Task-Lineage: 4679d1a0-3ab8-48ce-86b7-5919bba805fb
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
This commit is contained in:
gsxdsm
2026-07-08 19:52:51 -07:00
parent 22e7d75a07
commit 55dae49b37
6 changed files with 444 additions and 58 deletions

View File

@@ -795,11 +795,13 @@ Pause a running/active agent by transitioning its state to `paused`.
- If the agent is already paused, this is a no-op and prints `Agent <id> is already paused`.
- Invalid state transitions are rejected with `Cannot stop agent <id> — current state '<state>' cannot transition to 'paused'`.
- On success, prints `✓ Agent <id> stopped`.
- The command always closes its store connections and exits promptly on every path (success, already-paused, not-found, invalid-transition) — it never hangs. The underlying state-store write is bounded by a fast-fail deadline (default 10s, override via `FUSION_AGENT_CMD_TIMEOUT_MS`); if it cannot complete in time, the command prints a clear error naming the agent and operation and exits non-zero instead of hanging. Safe to drive from an automated recovery watcher.
**Examples:**
```bash
fn agent stop AGENT-001
fn agent stop AGENT-001 --project my-project
FUSION_AGENT_CMD_TIMEOUT_MS=5000 fn agent stop AGENT-001 # tighter fast-fail deadline
```
### `fn agent start`
@@ -817,6 +819,7 @@ Resume a paused agent by transitioning its state to `active`.
- If the agent is already `active` or `running`, this is a no-op and prints `Agent <id> is already running (<state>)`.
- Invalid state transitions are rejected with `Cannot start agent <id> — current state '<state>' cannot transition to 'active'`.
- On success, prints `✓ Agent <id> started`.
- Same deterministic-exit and fast-fail-timeout behavior as `fn agent stop` (see above) — the command always closes its store connections and exits promptly, and the state-store write is bounded by `FUSION_AGENT_CMD_TIMEOUT_MS` (default 10s).
**Examples:**
```bash