Commit Graph

3545 Commits

Author SHA1 Message Date
Fusion
91acccc85d fix(FN-2650): align dashboard createFnAgent aliases with static engine import
- Replace namespace engine imports with a named createFnAgent import in planning and chat modules
- Alias imported createFnAgent to engineCreateFnAgent and wire local createFnAgent binding to it
- Preserve existing injectable createFnAgent variable pattern while avoiding dynamic namespace access pitfalls
2026-04-27 00:13:06 -07:00
Fusion
cf36a83d41 feat(FN-2640): align planning labels across agent log and tests
- Rename Planning/Triage label to Planning in Agent Log model metadata and related assertions
- Map triage agent badge display name to Plan while preserving existing labels for other agent roles
- Update TaskDetailModal and AgentLogViewer tests to match the revised planning terminology
- Stabilize dashboard TUI QR payload test by waiting for label and payload text separately with explicit timeouts
2026-04-27 00:09:53 -07:00
Fusion
2df8831a92 fix(FN-2646): restore quick chat render toggle visibility
- Remove generic btn btn-icon classes from quick chat render toggles so component-specific visibility styles apply
- Increase toggle icon size and adjust default muted color for clearer eye/eye-off affordance in assistant messages
- Add explicit focus-visible ring styling for keyboard accessibility on the render toggle control
- Extend QuickChatFAB regression coverage to assert class usage, SVG icon presence, and plain/rendered toggle state transitions
2026-04-27 00:02:35 -07:00
gsxdsm
bfe824619e fix(tui): recover frame on dim-poll divergence under tmux+ssh
The 2s dim-poll fallback relied on _refreshSize() emitting a 'resize'
event to trigger recovery, which doesn't always propagate under tmux+ssh
— leaving Ink's frame buffer pinned to the old layout until the user
resized again. Extract the recovery body and call it directly whenever
OS-reported dims differ from the last recovered size.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 00:00:26 -07:00
Fusion
e1f764d0e6 feat(FN-2647): constrain board header width behavior
- Add desktop CSS constraints so column headers and titles can shrink without expanding board columns
- Prevent auto-merge toggle controls from shrinking to preserve stable header layout
- Add board CSS regression tests for the 6-column minmax grid template and header truncation rules
2026-04-26 23:53:22 -07:00
Fusion
bddecf14a2 feat(FN-2648): merge fusion/fn-2648 2026-04-26 23:51:25 -07:00
gsxdsm
84572f396a feat(dashboard): clarify version-update loader copy
Update the version-hash reload loader message to "Updating to a new
frontend version..." so users understand it refers to the dashboard UI,
not a server/runtime upgrade.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 23:47:22 -07:00
gsxdsm
77b6a28e7c feat(dashboard): default review level to auto triage when unset
Review level select now treats the empty option as undefined (auto — let
triage decide) rather than coercing to 0/None, and relabels the option
accordingly. Widens onReviewLevelChange to accept undefined.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 23:45:42 -07:00
gsxdsm
e1baaad120 fix(dashboard): align task card time indicator with stats tab
Done task cards now show agent execution time (sum of workflow step
durations) instead of wallclock time from creation to completion, matching
the Workflow runtime metric in the stats tab. Falls back to the previous
wallclock duration when no workflow timing data is available. Formatter
also updated to render sub-minute durations in seconds (e.g., 45.3s, 1m 30s)
to match the stats panel format.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 23:45:03 -07:00
Fusion
b4933d6f3f feat(FN-2631): revise task detail move split-button behavior
- Rework TaskDetailModal move controls to use split-button primary/secondary transitions with in-review-specific options
- Add dedicated split-button styling for divider, chevron menu, focus states, and mobile sizing using design tokens
- Keep in-review merge action visible while move options remain accessible through secondary menu actions
- Expand TaskDetailModal tests to cover split-button rendering, primary click behavior, and secondary transition menu contents
2026-04-26 23:43:11 -07:00
Fusion
5518c76789 feat(FN-2645): add desktop resize support for Quick Chat panel
- Add panel resize state and pointer-driven drag handling to QuickChatFAB
- Wire resize behavior into component layout so desktop users can adjust panel dimensions
- Style resize handles and interaction affordances in QuickChatFAB.css
- Expand QuickChatFAB tests to cover resize lifecycle, constraints, and persistence behavior
2026-04-26 23:39:27 -07:00
gsxdsm
58c6d4bf39 feat(dashboard): show "Updating to a new version..." on loader during version-hash reload
When the dashboard reloads because the build version hash changed, surface that
on the loading screen instead of the generic "Initializing dashboard..." so the
user understands why they bounced.

Carry the signal across the hard reload via a sessionStorage flag set in
versionCheck just before reloadOnce(), and consume-and-clear it once on the
loader's first render.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 23:35:18 -07:00
Fusion
dafbdfd062 feat(FN-2632): pin return-to-live control to bottom-right
- Update .agent-log-return-to-live to anchor on the right edge while staying sticky at the bottom
- Switch the control container to flex with fit-content width to keep compact button sizing
- Add mobile-specific right offset so spacing stays consistent at smaller breakpoints
2026-04-26 23:30:54 -07:00
Fusion
6b39e5d284 feat(FN-2636): add plugin runtime mode support to agent management
- Add plugin runtimes endpoint in dashboard routes and legacy API client support
- Add runtime mode controls to NewAgentDialog with plugin runtime selection UX
- Add runtime mode display and editing support in AgentDetailView with matching styles
- Expand dashboard tests to cover new routes, modal behavior, and mobile agent view flows
2026-04-26 23:25:17 -07:00
Fusion
2c50785882 feat(FN-2643): refine scheduled tasks modal header and toolbar layout
- Restructure ScheduledTasksModal header markup to support updated title and actions grouping
- Add automation toolbar styling updates in ScriptsModal.css to match the new modal header layout
- Update ScheduledTasksModal tests to assert the revised header structure and action placement
2026-04-26 23:21:25 -07:00
Vhailors
794700d133 fix(core): prevent FirstRunDetector from walking into OS temp directory
`FirstRunDetector.detectExistingProjects()` walks ancestor directories
looking for `.fusion/` projects, stopping only at `homedir()` and the
filesystem root. On systems where a prior Fusion session has left a
`/tmp/.fusion/fusion.db` (e.g. running tests, ephemeral dashboards,
crashed processes), the walk crosses into `/tmp` and incorrectly
"discovers" that stale state as a project.

This was caught by tests in packages/core/src/__tests__/store.test.ts
that intermittently failed when a real Fusion session had been run
on the same box. The walk would find the test's tmp dir AND the host's
real `/tmp/.fusion/fusion.db`, polluting the project-detection invariants.

Fix: import `tmpdir` from `node:os` and add it as a third walk-stop
boundary alongside `homedir()` and `/`. The OS temp directory is a
shared system surface and should never itself host a project.

The bug affected any user with a stale `/tmp/.fusion/` from a previous
session — invisible most of the time, but caused FirstRunDetector to
misclassify project state.

Tested: 4 previously-flaky tests in packages/core now pass deterministically.
2026-04-26 23:13:31 -07:00
gsxdsm
9c6706bbb1 fix: dismiss background tasks even when session lock-conflicted
The X button in the footer's Background Tasks popover silently failed when
ai_sessions.lockedByTab pointed to a stale/closed tab: cancelPlanning et al.
returned 409, dismissSession set lockConflict and bailed before calling
deleteAiSession. Always proceed to delete; the dismissal tombstone already
prevents stale SSE/sync from resurrecting the session.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 23:13:08 -07:00
Fusion
d1b3679897 feat(FN-2637): align usage window hide/show controls
- Remove the per-row eye toggle for already hidden usage windows so hidden rows no longer show a show/hide button
- Keep hide controls visible for active rows and preserve existing hide interactions
- Update UsageIndicator tests to assert hidden rows omit hide buttons and visible rows still render hide controls
- Drop obsolete per-row unhide test now that restoring hidden windows is handled through the provider-level show hidden flow
2026-04-26 23:07:56 -07:00
Fusion
7b5c78b68b feat(FN-2635): add optimistic agent state updates across dashboard
- Apply optimistic start/stop state transitions in AgentsView and AgentDetailView action handlers
- Add optimistic behavior to AgentListModal while preserving rollback on API failure
- Expand unit test coverage for optimistic transitions and failure recovery in all three agent views
- Update dashboard TUI test expectation to align with the new agent state update flow
2026-04-26 22:59:45 -07:00
Fusion
59587b289a feat(FN-2642): reorganize Dev Server layout for responsive preview
- Move preview panel markup to support a two-column desktop structure
- Add desktop-specific grid styling for configuration and preview panes
- Preserve existing mobile stacking behavior with responsive CSS overrides
2026-04-26 22:50:51 -07:00
Fusion
b963ed5e5f feat(FN-2633): anchor usage popover to header trigger
- Track and thread usage trigger bounds from Header through modal management to UsageIndicator
- Render desktop usage details as an anchored popover while preserving existing modal wiring behavior
- Extract usage indicator styling into a dedicated UsageIndicator.css and remove planning-mode style duplication
- Expand header and usage indicator tests to cover anchor rect propagation and popover behavior
- Stabilize CLI bundle output sqlite assertion for workspace test reliability
2026-04-26 22:33:06 -07:00
Fusion
57784cc763 fix(FN-2634): remove surface-hover fallback usage in dashboard CSS
- Replace hover background fallbacks with direct var(--surface-hover) in QuickChatFAB and SettingsModal styles
- Tighten status-colors theme test to forbid var(--surface-hover, ...) fallback syntax
- Preserve token-based hover styling contract while preventing stale fallback patterns from reappearing
2026-04-26 22:29:50 -07:00
gsxdsm
7c3e5dde29 feat(FN-2628): merge fusion/fn-2628 2026-04-26 22:21:18 -07:00
Fusion
6d2cf27410 feat(FN-2621): guard execution for non-git project directories
- Add isGitRepository utility in worktree-pool using git rev-parse checks
- Fail fast in TaskExecutor with actionable non-git errors before worktree creation starts
- Classify not-a-git-repository worktree add failures as non-retryable in recovery flows
- Warn from in-process runtime startup when the working directory is not a Git repository
- Expand executor and worktree-pool tests to cover non-git, missing-dir, and conflict-classification paths
2026-04-26 22:20:17 -07:00
Fusion
da97ba667f feat(FN-2630): add vertical offset to project selector
- Update ProjectSelector styles to include a vertical offset adjustment
- Align selector positioning with the FN-2630 Step 1 UI layout requirement
2026-04-26 22:17:19 -07:00
Fusion
323e151e3a feat(FN-2629): stabilize terminal modal font-size refit
- Enforce terminal xterm root height fill so inline fit heights do not collapse the modal terminal area
- Defer font-size-driven fit to the next animation frame and coalesce pending fits via pendingFitRef
- Remove eager refit calls from zoom keyboard/button handlers and rely on shared font-size effect scheduling
- Expand TerminalModal tests to assert font-size controls and keyboard zoom continue to trigger xterm refits
2026-04-26 22:14:03 -07:00
Fusion
debc532c1c fix(FN-2577): preserve Todos access and TodoView interaction behavior
- Keep the view overflow trigger available when Todos is supported so the Todos view remains reachable
- Update TodoView list rows to use an explicit select button and align active-state assertions with the new structure
- Restore keyboard focus styling and mobile action visibility in TodoView CSS for accessibility and usability
- Harden CLI extension test cleanup with retry logic for transient ENOTEMPTY/EBUSY tempdir removal errors
2026-04-26 22:07:43 -07:00
Fusion
081984a64d feat(FN-2613): tokenize standalone mobile footer spacing
- Replace hardcoded mobile footer offset with --executor-footer-height in MobileNavBar content padding
- Move standalone display-mode behavior to a :root token override and remove global #root standalone padding
- Scope standalone bottom-gap application to mobile layout containers (project content and executor status bar)
- Update mobile nav and PWA CSS tests to assert tokenized spacing and scoped standalone rules
2026-04-26 22:00:36 -07:00
Fusion
a208723cbc feat(FN-2620): add plugin test-time engine resolution stubs
- Add engine-guard-stub test modules for hermes, openclaw, and paperclip runtime plugins to fail fast on unmocked @fusion/engine imports
- Update each plugin Vitest config to alias @fusion/engine to the local guard stub during test runs
- Keep setup-engine-guard behavior while removing dependency on built engine dist artifacts for plugin-local tests
2026-04-26 21:49:47 -07:00
Fusion
c62e1d7595 feat(FN-2624): surface task token usage on task cards
- Render a compact token usage indicator in TaskCard footer with accessible labeling and token-aware styling
- Track token usage fields in the TaskCard memo comparator and expose a comparator test helper for regression coverage
- Add TaskCard tests for token usage rendering behavior and comparator invalidation on token usage updates
- Configure runtime plugin Vitest setups with an @fusion/engine source alias for reliable workspace test resolution
- Keep restart integration child_process spawn mocking aligned with execSync-driven merge verification behavior
2026-04-26 21:45:46 -07:00
gsxdsm
39ff80d540 feat(FN-2625): merge fusion/fn-2625 2026-04-26 21:36:23 -07:00
Fusion
a6ddce1a11 feat(FN-2626): make task detail logs responsive to terminal width
- Add narrow-log helper formatting to compact task detail log output on small terminals
- Implement responsive log panel layout that adapts between narrow and wide views
- Preserve readable wide-terminal formatting while reducing wrapping in constrained widths
- Add app-level tests covering narrow and wide log formatting behavior
2026-04-26 21:32:03 -07:00
gsxdsm
5162531275 chore(release): v0.6.0
Version bump via changesets.
2026-04-26 21:27:49 -07:00
gsxdsm
fdf8ca904e feat(cli): rebrand splash and surface version in dashboard
Splash now reads "multi node agent orchestrator" / runfusion.ai / v<version>.
System panel and status bar also display the running CLI version.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 21:27:04 -07:00
gsxdsm
245a79353d fix(core): bump SCHEMA_VERSION to 48 so v48 migration actually runs
migrate() short-circuits via 'if (version >= SCHEMA_VERSION) return',
so my prior commit's v48 block (adding tasks.verificationFailureCount)
never executed against existing v47 databases. App startup then failed
with 'no such column: verificationFailureCount' on first task SELECT.

Bumping the constant to 48 lets the migration body run on next init.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 21:14:53 -07:00
gsxdsm
53decd1bd2 fix(engine): cap verification-failure bounces, reap unregistered worktrees, dedupe activity log
Three fixes for the worktree-overflow / stuck-task incident:

1. Cap deterministic-verification-failure bounces (fix #2)
   Auto-merge previously bounced an in-review task back to in-progress
   on every verification failure with no upper bound. A single flaky test
   could keep a task ping-ponging in-review→in-progress forever, holding
   its worktree and consuming agent slots. Adds verificationFailureCount
   on Task (DB migration v48), increments on each bounce, and after 3
   failures marks the task failed and creates a follow-up triage task
   so a fresh agent can investigate the underlying flake instead of
   re-running the same fix loop.

2. Reap unregistered orphan worktree dirs even when recycle is on (fix #3)
   cleanupOrphans previously bailed out entirely when recycleWorktrees
   was true, leaving stale dirs (clear-hawk-broken, *-bak, leftover
   crash debris) on disk forever. New reapUnregisteredOrphans pass
   removes only directories that aren't registered git worktrees, so
   the recycle pool keeps its warm worktrees but the trash gets cleared.

3. Idempotence guard on activity-log listener wiring (fix #6)
   setupActivityLogListeners() was registering handlers on every call.
   When init() ran twice, every task:created / task:moved event wrote
   N rows to activityLog, producing the duplicate entries visible in
   the DB. Added activityListenersWired flag so repeated calls no-op.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 21:09:28 -07:00
gsxdsm
07e86e696d test(engine): mock spawn so verification runner works under restart suite
9c7c8ee5 switched merger verification from exec to spawn-based
execWithProcessGroup, but restart.integration.test.ts only mocked
execSync/exec. spawn() returned undefined, so the merger crashed before
running the test command and any in-review merge test that hit the
verification path failed with VerificationError.

Adds a spawn mock that funnels through the existing execSync mock so a
single mockedExecSync.mockImplementation continues to control both git
calls and verification command outcomes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 21:01:27 -07:00
gsxdsm
330545d45c test(core,dashboard): expand in-memory SQLite to more store tests
Extends the inMemoryDb opt-in established in 4fc58e0bb to single-instance
TaskStore/AgentStore/RoutineStore/PluginStore tests that were still
opening disk-backed fusion.db files. Cross-instance persistence tests
(open store A, close, open store B on same dir) and migration tests that
seed via a sibling Database instance keep their disk-backed stores —
swapping those would silently drop data between instances.

Sites flipped:
- core: store.test.ts (RunMutationContext, memory-toggle, diagnostics
  blocks), store-sort, settings-export, backup, plugin-loader,
  agent-instructions, agent-instructions-bundle, mission-store (all 10
  triage subtests), mission-planning-context.integration
- dashboard: routes.test.ts (Messaging routes block),
  session-reconnect, session-cross-tab, planning

Sites left disk-backed (cross-instance or sibling-Database dependency):
- run-audit*, task-documents, fts5-guard (sibling Database at same dir)
- mission-integration, mission-factory-parity (taskStore2 reopens)
- agent-store checkout-leasing (TaskStore + AgentStore at same dir)
- routes.test.ts AgentStore seed pattern (route handler opens its own)
- cli/extension.test.ts (makeCtx opens its own TaskStore)

All disk-backed tests continue to write to mkdtemp temp dirs — no live-db
risk introduced. Wall-clock impact: core 149s → 19s.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 20:56:31 -07:00
gsxdsm
4ccc8aed11 fix(engine): make global pause actually stop in-flight verification
Hitting Stop (globalPause) disposed the AI merge agent session but left
the spawned `pnpm test` / `pnpm build` child processes running until
they finished naturally. With recurring flaky-test loops at Step 5,
that meant Stop had no visible effect — new test runs kept piling up
across multiple worktrees.

Two gaps:
- project-engine.ts onGlobalPause never called mergeAbortController.abort(),
  so subsequent verification commands (gated by the signal) weren't cancelled.
- merger.ts execWithProcessGroup only listened to its own internal
  timeout — passing an AbortSignal had no effect on the in-flight
  child process group.

Fix: abort the controller on global pause, and have execWithProcessGroup
SIGTERM/SIGKILL the detached process group when its signal aborts.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 20:51:40 -07:00
gsxdsm
b60bda82b0 test(core): use in-memory DB for logEntry truncation test
The logEntry()-bounds test does 1005 sequential SQLite writes and was
timing out at 20s on a disk-backed TaskStore. It doesn't exercise
cross-instance persistence, so flip on inMemoryDb to bring it under 8s.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 20:47:37 -07:00
gsxdsm
f0b8446c2f fix(dashboard): restore engine namespace import in chat/planning
The auto-resolved FN-2614 merge swapped `import * as engine` for a narrow
named import but left dangling `engine.X` references, breaking the
dashboard build. Restore the namespace import and drop the now-orphaned
engineExports/ntfy helper consts.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 20:32:22 -07:00
Fusion
32e7ce6f5f feat(FN-2614): merge fusion/fn-2614 (auto-resolved)
- fix(FN-2614): restore workspace green verification gates
2026-04-26 19:26:25 -07:00
gsxdsm
4fc58e0bba perf(core): opt-in in-memory SQLite for *-store tests
Adds an opt-in `inMemory` flag to `Database`/`ArchiveDatabase` (and
`{ inMemoryDb }` to TaskStore, AgentStore, RoutineStore,
AutomationStore, PluginStore) that swaps the on-disk fusion.db /
archive.db for SQLite's `:memory:` connection. Production callers
never set the flag, so behavior is unchanged.

Test files for each store now flip the flag in `beforeEach`. The
handful of tests that exercise cross-instance persistence (open store
A, close, open store B on same dir, expect data) construct disk-backed
stores explicitly inside the test body, marked with a comment at each
site.

Wall-clock impact:
- core:      69.4s → 18.5s  (3.7× faster, 3038 tests)
- dashboard: 156.6s → 30.0s (5.2× faster — improvement ripples through
                              any test that constructs a TaskStore)

The refactor eliminates the per-test SQLite open + WAL fsync + tmp
dir cleanup loop that dominated setup cost: ~50ms/test → ~5ms/test.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 18:45:14 -07:00
gsxdsm
6caab172ba feat(FN-2623): merge fusion/fn-2623 2026-04-26 18:11:09 -07:00
gsxdsm
f4d98ed717 feat(FN-2622): merge fusion/fn-2622 2026-04-26 17:56:18 -07:00
gsxdsm
b32f8ca275 feat(FN-2619): merge fusion/fn-2619 2026-04-26 17:56:09 -07:00
gsxdsm
e67c80011d fix(release): move plugin-sdk's @fusion/core dep out of peerDependencies
The v1.0.0 release-bump misfire (0.4.1 + one minor changeset → 1.0.0
instead of 0.5.0) traced to changesets' assemble-release-plan logic:

  1. getDependencyVersionRanges resolves "workspace:*" to the *exact*
     current version (not a wildcard).
  2. shouldBumpMajor escalates a dependent's bump to "major" whenever
     it has a peerDependency on a package whose new version falls
     outside the resolved range AND the bump is non-patch.
  3. plugin-sdk listed "@fusion/core": "workspace:*" as a peer dep, so
     a minor on @fusion/core (triggered via the fixed group) escalated
     plugin-sdk to major; the fixed group then carried every package
     to 1.0.0.

Both packages are private:true workspace-only — the peer-dep semantic
had no runtime effect, only mis-shaped the changesets dependency graph.
Moving it to "dependencies" makes the determineDependents path fall
into the non-peer branch (caps at "patch", does not escalate), so the
fixed group bumps as intended (verified: 0.5.0 + minor → 0.6.0).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 17:36:56 -07:00
gsxdsm
1dddf3252c chore(release): v0.5.0
Manual version bump to 0.5.0 (changeset version produced 1.0.0 from a
single minor changeset against 0.4.1; that release was rolled back and
the 1.0.0 npm version deprecated).

Aggregates: status terminology refresh (planning/replan), Reviewer
rename, in-review pause behavior, dashboard-tui resize hardening,
dev-server experimental toggle fix, version reporting fix.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 17:31:46 -07:00
gsxdsm
45002257fd Revert "chore(release): v1.0.0"
This reverts commit 26e09c7aa0.
2026-04-26 17:26:56 -07:00
gsxdsm
26e09c7aa0 chore(release): v1.0.0
Version bump via changesets.
2026-04-26 17:25:49 -07:00