Commit Graph

19 Commits

Author SHA1 Message Date
Fusion
ff3412637b feat(FN-3539): remove duplicate todos entry and update navigation docs
Merged branch removes the duplicate desktop "Todos" nav entry from the Header, syncs the `allowParallelExecution` runtime toggle into `AgentDetailView`, and updates the corresponding docs (agents.md, settings-reference.md, todo-view.md, dashboard-guide.md) to reflect the navigation change. Tests wer

Fusion-Task-Id: FN-3539
2026-05-06 03:52:18 -07:00
gsxdsm
7d569670c1 test: cover concurrent startRun race in heartbeat recovery sweep
Documents the race called out in code review: when recovery samples a
stale run id and a fresh run is spawned for the same agent before
endHeartbeatRun() lands, only the sampled id is terminated — never the
freshly-spawned run.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 14:14:56 -07:00
gsxdsm
9b01c0a369 fix: auto-recover orphaned heartbeat runs from crashed processes
When the dashboard crashes mid-heartbeat, the agentRuns row is left in
status='active' forever. HeartbeatTriggerScheduler.onTimerTick treats
any active run as "still running" and skips every subsequent tick, so
agents go silent indefinitely (observed: 6+ hours). The existing
in-memory missed-heartbeat watchdog can't help — its trackedAgents map
is wiped on process restart.

SelfHealingManager.recoverStaleHeartbeatRuns now reconciles these on
startup and during periodic maintenance: terminates active runs whose
processPid does not match the current process, has no recorded pid, or
has been active for more than 6 hours.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 14:13:07 -07:00
Fusion
c67e786f48 feat(FN-3498): add self-healing and ownership-aware done-task merge reconci
The merge completes FN-3498 across three steps: adds ownership-aware done-task reconciliation to the merger, prevents branch-missing head SHA pollution during merge operations, and restores workspace typecheck compatibility. Core changes touch the merger (103 lines) and self-healing module (67 lines

Fusion-Task-Id: FN-3498
2026-05-05 13:42:39 -07:00
gsxdsm
df20edb61f fix: skip auto-archive when done task has active dependents
Auto-archive previously wiped .fusion/tasks/{id}/ for stale done tasks
even while downstream agents (triage/todo/in-progress/in-review) still
needed to read those sibling specs from disk. Now the sweep skips any
done task that has an active dependent. The executor prompt also
instructs the agent to fall back to fn_task_show when sibling spec
files are missing on disk (e.g., manually archived deps).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 07:19:30 -07:00
Fusion
a9a1f4c209 feat(FN-3323): recover orphaned agents and add reports health section to he
The merge lands FN-3323's self-healing system: a new "reports health" prompt section and `agent-heartbeat.ts` module that detect orphaned agents and recover their state (clearing stale error states and re-enabling heartbeat execution). The engine's `self-healing.ts` was expanded with wired recovery

Fusion-Task-Id: FN-3323
2026-05-04 17:22:21 -07:00
Fusion
44cc899eb9 feat(FN-3185): preserve progress on task reset with explicit confirmation d
This merge implements a "preserve progress" option for task resets across the system. FN-3185 adds a `preserveProgress` flag to `moveTask` that keeps status/history when resetting tasks back to `todo`, with required explicit confirmation dialogs to prevent accidental resets. The feature is wired thr

Fusion-Task-Id: FN-3185
2026-05-02 10:20:44 -07:00
gsxdsm
222e11c2f8 fix(FN-3175): reduce dashboard log stalls 2026-05-02 08:05:33 -07:00
gsxdsm
31195374d4 fix(FN-XXXX): quiet pi-claude-cli MCP config refresh log
Demote the refresh message from console.error to debugMcp so it no
longer appears as an error in normal output.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 22:58:00 -07:00
Fusion
1747d6fc43 feat(FN-3050): preserve failed review tasks during recovery to prevent loop
The merge strengthens task recovery logic to prevent in-review tasks from entering merge-recovery loops and preserves failed review tasks during retry sweeps instead of incorrectly resetting them. It adds targeted test coverage for these edge cases in the self-healing and project engine modules.

Fusion-Task-Id: FN-3050
2026-05-01 02:07:43 -07:00
gsxdsm
208345e872 feat(self-healing): add ghost-review fallback recovery
Add recoverGhostReviewTasks as a final-fallback scan in the maintenance
loop. Catches any in-review task that fell through every more-specific
recovery scan and has been idle past taskStuckTimeoutMs, kicks it back
to todo with transient status cleared. Worktree state is intentionally
ignored — the executor recreates as needed. Preserves human-handoff and
active-merge statuses; rate-limited naturally by updatedAt refresh.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 04:41:56 -07:00
gsxdsm
7f42c7fe42 fix(engine): respect autoMerge and mergeStrategy in recover-mergeable-review sweep
The periodic maintenance job `recover-mergeable-review` was silently merging
in-review tasks regardless of `autoMerge` and `mergeStrategy` settings,
defeating the PR-based review flow for users with `autoMerge: false` and
`mergeStrategy: "pull-request"`.

Gate the sweep on `settings.autoMerge` (and globalPause/enginePaused for
consistency with other merge entry points) and route through the engine's
merge queue via the existing `enqueueMerge` callback so `mergeStrategy ===
"pull-request"` is honored. Falls back to the direct `store.mergeTask` path
only when no enqueue callback is wired (standalone/tests).

Closes https://github.com/Runfusion/Fusion/issues/21

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 13:26:05 -07:00
gsxdsm
86a1232fa9 fix(engine): make stale-merge recovery robust to includeTaskIdInCommit=false
recoverInterruptedMergingTasks searched for landed commits by grepping
commit subjects for the task ID. Users with includeTaskIdInCommit=false
have commit subjects like `feat: ...` (no task ID), so if the merger
crashed after committing but before storing mergeDetails, recovery would
silently fail to find the commit and incorrectly retry the merge.

Three layered defenses:

1. Emit a Fusion-Task-Id: <id> trailer in every Fusion-managed merge
   commit body. The 4 fallback commit invocations now include
   `-m "Fusion-Task-Id: ..."`. After the AI agent commits, an
   idempotent ensureTaskIdTrailerOnHead() amends the trailer in via
   `git interpret-trailers` (no-op if already present).

2. findLandedTaskCommit now tries three sources in order:
   a. task.mergeDetails.commitSha (if reachable from HEAD)
   b. Fusion-Task-Id trailer grep (anchored regex)
   c. Subject grep (legacy commits)

3. Trailer grep uses an anchored regex `^Fusion-Task-Id: <id>$` so
   it doesn't false-match task IDs appearing as substrings.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 17:32:30 -07:00
gsxdsm
4f2f728350 fix(engine): paused-task guard for merged + misclassified review recovery
Two recovery scans operated on in-review tasks without checking
!task.paused:

- recoverMergedReviewTasks would move a paused task whose merge was
  already confirmed to done, against user intent.
- recoverMisclassifiedFailures would clear the error on a paused failed
  task, defeating the user's intent to investigate manually.

Add the paused guard to both, matching the pattern used by all other
recovery scans. Completes the pause-vs-stuck audit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 17:20:04 -07:00
gsxdsm
105a4dfef6 fix(engine): skip paused tasks in interrupted-merge recovery
recoverInterruptedMergingTasks was the one self-healing scan that didn't
guard !task.paused. A user who paused a task mid-merge (status=merging,
column=in-review) would still see the recovery scan finalize or unblock
the merge once the stuck timeout elapsed, violating their pause intent.

The other 12 self-healing recovery scans either explicitly skip paused
tasks or operate on terminal/metadata-only state where pause is moot.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 16:59:55 -07:00
Fusion
79ce48c51e feat(FN-2608): merge fusion/fn-2608 (auto-resolved)
- feat(FN-2608): complete Step 6 — verify lint test build gates
- feat(FN-2608): complete Step 5 — resume auto-merge on in-review unpause
- feat(FN-2608): complete Step 4 — pause-aware self-healing recovery
- feat(FN-2608): complete Step 3 — interrupt active merges on pause
- feat(FN-2608): complete Step 2 — guard auto-merge for paused review tasks
- feat(FN-2608): complete Step 1 — pause status for in-review tasks
2026-04-26 13:39:27 -07:00
Fusion
bbc872cee9 feat(FN-2603): merge fusion/fn-2603 (auto-resolved)
- test(FN-2603): update downstream tests for planning label expectations
- test(FN-2603): complete Step 6 — update engine tests for planning terminology
- feat(FN-2603): complete Step 5 — rename self-healing planning APIs
- feat(FN-2603): complete Step 4 — rename needs-respecify status to needs-replan
- feat(FN-2603): complete Step 3 — rename specifying and re-specification text
- feat(FN-2603): complete Step 2 — rename triageLog usages to planLog
- feat(FN-2603): complete Step 1 — rename triage logger to plan logger
- feat(FN-2602): complete Step 7 — add release changeset
- test(FN-2602): complete Step 6 — align migration and schema tests
- test(FN-2602): complete Step 5 — update store status assertions
- feat(FN-2602): complete Step 4 — rename triage prompt labels
- feat(FN-2602): complete Step 3 — add status rename migration
- feat(FN-2602): complete Step 2 — rename respecify status literals
- feat(FN-2602): complete Step 1 — rename triage display labels
2026-04-26 12:45:05 -07:00
Fusion
c039af066c feat(FN-2408): merge fusion/fn-2408 2026-04-24 22:54:44 -07:00
gsxdsm
bce7dbd96f chore: consolidate test files into __tests__/ dirs and clean stray engine artifacts
- Move all co-located *.test.* files into sibling __tests__/ directories so the
  layout is consistent across packages (159 renames + content-rewrite moves).
  Updates relative imports, vi.mock specifiers, and __dirname/import.meta.url
  path resolutions where tests read fixtures from disk.
- Drop tracked tsc-emit alongside engine .ts sources (auth-storage/logger/
  skill-resolver/context-limit-detector/pi.{js,d.ts,*.map}). These were
  accidentally committed in a merge and the stale pi.js was masking a real
  test-mock vs source mismatch (tests imported "../pi.js" and vite preferred
  the stale build over pi.ts).
- Add packages/engine/.gitignore to block future src/*.{js,d.ts,map}.
- Refactor plugin pi-module seams (openclaw/paperclip/hermes) to ESM-import
  createFnAgent / promptWithFallback / describeModel from @fusion/engine
  instead of require()-ing packages/engine/src/pi.js. Adds @fusion/engine to
  the two plugin package.jsons that were missing it; exports describeModel
  from the engine public API.
- Fix engine test mocks now that they run against current pi.ts: add
  ModelRegistry.create static to mocks in pi.test.ts and pi-create-fn-agent
  .test.ts; switch three boundary-result toEqual assertions to toMatchObject
  so the new content/isError fields don't trip exact-match comparison.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 19:39:20 -07:00