Commit Graph

4955 Commits

Author SHA1 Message Date
gsxdsm
8eb5c3dc60 refactor(agents): remove terminated AgentState; collapse to paused/error
Drops "terminated" from AGENT_STATES. The agent lifecycle now runs through
idle | active | running | paused | error. paused (carrying a pauseReason)
absorbs every former terminated use case — manual stop, heartbeat run
termination, spawned-child cleanup. Run status (agentRuns.status) is
unchanged: "terminated" stays a valid run-status value.

AGENT_VALID_TRANSITIONS allows direct any→idle transitions so resetAgent
no longer needs the intermediate hop.

Stack-wide:
- core/agent-store: lastError clearing + resetAgent simplified.
- engine/agent-heartbeat, executor, in-process-runtime: terminated state
  writes → paused; halt-state listener fires on paused/error.
- dashboard: AgentsView/AgentListModal/AgentDetailView lose the Terminated
  badge/option/state-block; agent pickers no longer filter terminated;
  agentHealth drops the Terminated branch; routes/state cast widened to
  the new AgentState union.

Tests across core and engine updated to assert paused for AgentState and
left "terminated" intact for run-status assertions.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 20:47:38 -07:00
gsxdsm
7d41271601 feat(dashboard): make agent card row click-anywhere and Run Now optimistic
- Run Now now optimistically stamps the agent's state to "running" before
  the startAgentRun API call so the card reacts immediately. Rolls back on
  error, mirroring the handleStateChange pattern.
- Whole .agent-card body is clickable (role=button, Enter/Space, focus ring)
  and bails when the click landed on an action button, select, or the
  role-icon so those keep their dedicated behaviors.
- Renamed the card's "View Details" button to "Details" and switched
  .agent-card-actions to flex-wrap: nowrap so Run Now / Pause / Details
  stay on one row regardless of card width.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 20:47:37 -07:00
gsxdsm
d47501feeb fix(engine): unstick agents in running and clean up ephemeral worker pile-up
Two related leaks in the agent lifecycle plus a refactor:

- Governance-skip paths in executeHeartbeat (budget/global-pause/engine-paused)
  were leaving agents permanently stuck in `running` because they ran startRun
  first and then short-circuited with skipStateTransition: true. Removed the
  flag from those four paths so they flow through running → active. Added
  HeartbeatMonitor.reconcileOrphanedRunningAgents() on start to recover any
  rows already trapped in this state.
- Ephemeral task-workers piled up across runtime restarts because taskAgentMap
  was in-memory only and the startup sweep ignored ephemerals with no taskId.
  Now: spawn dedup via findAgentByName before create, on-disk fallback in
  finalize when the in-memory map is empty, and the sweep deletes any
  ephemeral not bound to an in-progress task.
- Extracted the lifecycle into EphemeralWorkerManager
  (packages/engine/src/ephemeral-worker-manager.ts). InProcessRuntime drops
  ~140 lines and delegates via onTaskStart/onTaskComplete/onTaskError/
  attachStateChangeListener/reconcileOrphaned. ChildProcessRuntime and
  RemoteNodeRuntime inherit the fix because they delegate execution to a
  worker that runs InProcessRuntime.

Durable assigned agents now return to `active` after task completion (was
`terminated` in the old contract).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 20:47:37 -07:00
Fusion
9d8589a149 fix(FN-3531): consolidate file browser css and document terminal input reliability
- Refactor FileBrowser.css to consolidate duplicated rules and align styling with shared design tokens
- Remove redundant/obsolete file browser style blocks while preserving behavior under mainline-safe merge constraints
- Add Step 4 documentation note in dashboard guide for terminal single-input reliability

Fusion-Task-Id: FN-3531
2026-05-05 20:47:37 -07:00
Fusion
bb6169a89b feat(FN-3530): add modal-based agent error details and UI/docs updates
- Add AgentErrorDetailsModal and wire agent list/detail views to open full error diagnostics while keeping inline errors compact
- Add line-number gutter toggle in FileEditor and Files modal with dashboard persistence coverage
- Align project memory scope guidance across core logic, CLI tool docs, and dashboard docs
- Add regression coverage for runtime plugin alias behavior and update related engine/heartbeat tests
- Include changesets for FN-3530 UI improvements and FN-3485 memory guidance updates

Fusion-Task-Id: FN-3530
2026-05-05 20:47:37 -07:00
Fusion
ff66c20417 feat(FN-3485): align memory scope guidance and dashboard tooling
- Clarify task memory scope behavior across core types, project memory logic, engine tool prompts, and related docs
- Add regression coverage for memory scope and runtime plugin alias handling in core/dashboard/engine tests
- Add agent avatar API routes and dashboard UI support for avatar display and storage documentation
- Add line-number gutter toggle support in FileEditor and Files modal with accompanying component tests
- Include changeset for @runfusion/fusion documenting memory scope guidance update

Fusion-Task-Id: FN-3485
2026-05-05 20:47:37 -07:00
Fusion
c5039eb52f feat(FN-3528): add line-number gutter toggle to FileEditor and Files modal
This merge adds a line-number toggle to the Files modal with persisted preference, introduces an AgentAvatar component with server-side avatar storage routes, and adds documentation for both the toggle and avatar storage. It also includes a regression test for runtime plugin alias behavior and updat

Fusion-Task-Id: FN-3528
2026-05-05 20:47:37 -07:00
Fusion
dfbaee1e93 feat(FN-3298): add regression test for runtime plugin alias
Adds a regression test for runtime plugin alias functionality (FN-3298 Step 3), covering 25 lines of test coverage for this feature.

Fusion-Task-Id: FN-3298
2026-05-05 20:47:37 -07:00
Fusion
e30fe5d245 feat(FN-3118): document avatar storage in agents and architecture
Added avatar storage and field documentation to the agents guide, with a minor reference added to the architecture docs.

Fusion-Task-Id: FN-3118
2026-05-05 20:47:37 -07:00
gsxdsm
21bedd89a0 Merge pull request #45 from timothyjlaurent/fix/quick-chat-init-race-condition
fix(dashboard): prevent quick chat init race condition and infinite retry loop
2026-05-05 17:09:27 -07:00
Timothy Laurent
2746015fc7 test(dashboard): add regression tests for quick chat init fixes
Six new tests covering the three bugs fixed in the previous commit:

- Retry limit: stops showing toasts after 3 consecutive failures,
  resets counter on success
- Skip flag: startFreshSession sets/clears skipNextSessionInitRef,
  creates new session even when existing one exists
- Ref stability: switchSession reads activeSession from ref so it
  correctly detects "same session" and skips re-initialization

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-05 16:43:54 -07:00
Timothy Laurent
5e5b40079a fix(dashboard): prevent quick chat init race condition and infinite retry loop
Three interacting bugs caused "Failed to initialize chat" toast spam and
prevented fresh session creation:

1. Race condition in handleCreateFreshSession — setting chatMode/
   selectedAgentId before startFreshSession triggered the session-init
   useEffect, which called switchSession and resumed the old session
   instead of creating a new one. Fixed with skipNextSessionInitRef.

2. Infinite retry loop — shouldRetrySessionInit retried indefinitely
   when initializeSession failed, producing unbounded toast spam.
   Fixed with a 3-retry cap (initRetryCountRef).

3. Cascading re-renders — switchSession depended on activeSession in
   its closure, getting a new identity on every state change and
   re-triggering the consumer's useEffect. Fixed by reading
   activeSession from a ref instead.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-05 16:31:49 -07:00
gsxdsm
58a0eff09a chore(release): v0.21.0
Version bump via changesets.
2026-05-05 15:31:33 -07:00
gsxdsm
035911409c Merge pull request #44 from timothyjlaurent/timothyjlaurent/browser-back-button-spa-integration
feat: enable browser back-button navigation within the SPA dashboard
2026-05-05 15:29:47 -07:00
gsxdsm
e6fd593c40 fix(dashboard): distinguish CLI update vs install banner
When the local fn/fusion CLI is on the wrong version, the banner now
says "Update the Fusion CLI", shows installed vs expected versions,
and labels the action "Update with npm" instead of the generic install
copy.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 15:09:56 -07:00
gsxdsm
dc8863dbcb feat(dashboard): add 'blocked' to FeatureStatus with mission-blocked colors
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 15:09:00 -07:00
gsxdsm
2e29d447ed Merge pull request #43 from timothyjlaurent/timothyjlaurent/broken-insights
fix(insights): add missing lifecycle column compatibility check
2026-05-05 15:08:45 -07:00
Timothy Laurent
5c16e095e2 fix: fix flaky PlanningModeModal test — use findByText for async rendering
The test clicked 'Medium' and 'Continue' synchronously without waiting
for the scope question options to fully render. Use findByText/findByRole
to wait for elements to appear before interacting, and add a timeout to
the final waitFor for the second question.
2026-05-05 15:06:50 -07:00
Timothy Laurent
7250b450de fix(FN-002): tighten pushState assertions to be action-specific per PR feedback 2026-05-05 15:06:17 -07:00
Timothy Laurent
85eabbc533 fix(FN-002): update integration tests for desktop back-button support
Tests previously asserted desktop does NOT push history entries.
Now that back-button nav is enabled for desktop too, flip the assertions.
2026-05-05 15:06:17 -07:00
Timothy Laurent
0eea0d02f1 fix(FN-002): fix lint — prefix unused vars with underscore 2026-05-05 15:06:17 -07:00
Timothy Laurent
ac74cb0d6d feat(FN-002): enable browser back-button navigation within the SPA dashboard
Previously the back button left the dashboard page entirely because
useNavigationHistory was only enabled for mobile viewports. Now it's
enabled for all viewports — desktop and mobile — so the browser back
button dismisses modals and reverts view changes within the SPA.

Changes:
- Enable useNavigationHistory for desktop (enabled: true instead of enabled: isMobile)
- Remove all isMobile ? historyAwareHandler : plainHandler ternaries
- Always use navigation-aware handlers (openDetailTask, openSettingsWithNav, etc.)
- Update JSDoc to reflect desktop support
2026-05-05 15:06:17 -07:00
gsxdsm
8a57d3fa96 feat(tui): up/down cycle sections on Main; Enter on Logs releases mouse for text selection
Up/Down arrows now cycle the focused panel on the Main page (mirroring
Left/Right), except on the Logs panel where they keep their existing
role of navigating log entries. Expanding a log entry with Enter now
also disables xterm mouse reporting so the user can click-drag to
select the message text; closing the expanded view restores wheel
scrolling.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 15:03:45 -07:00
gsxdsm
61dac2801d fix(cli): declare node-pty as runtime dep so npx runfusion.ai terminal works on clean install
node-pty was previously only present transitively via the workspace
@fusion/dashboard devDependency, which is stripped at publish time. Fresh
users running `npx runfusion.ai` hit a 503 "PTY module could not be loaded"
when opening the dashboard terminal. Tightened the package-config guard so
this regression is caught next time.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 15:02:41 -07:00
gsxdsm
b41396de4b chore(release): v0.20.0
Version bump via changesets.
2026-05-05 14:56:34 -07:00
gsxdsm
045f94b98c chore: silence node:sqlite ExperimentalWarning in tests, fix QR mock type
Patch process.emitWarning in the shared vitest setup to drop the
"SQLite is an experimental feature" notice; align the test mock for
getQrPayload with the canonical RemoteQrPayload signature.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 14:33:26 -07:00
gsxdsm
ca432feaea Update packages/core/src/__tests__/insight-store.test.ts
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2026-05-05 14:31:53 -07:00
gsxdsm
cfca41dae7 Merge pull request #40 from timothyjlaurent/timothyjlaurent/stuck-spinners
fix: add global spinner animation to prevent stuck loaders
2026-05-05 14:29:38 -07:00
gsxdsm
4677612f23 Merge branch 'main' into timothyjlaurent/broken-insights 2026-05-05 14:18:45 -07:00
gsxdsm
dd09f7c8d6 Merge branch 'main' into timothyjlaurent/stuck-spinners 2026-05-05 14:17:58 -07:00
gsxdsm
d253e01b3f fix: quiet noisy store poll and skill-resolver info logs
Raise checkForChanges slow-poll warn threshold from 100ms to 750ms so
warnings only fire when cycles approach the 1s poll interval, and route
skill-resolver info diagnostics through log() instead of warn().

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 14:16:30 -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
Timothy Laurent
b09f7d0602 fix: add listMissions to MissionStore mock to prevent flaky test
The MissionLoop calls this.missionStore.listMissions() during startup
recovery, but the mock TaskStore's getMissionStore() return value didn't
include this method. When the runtime startup sequence raced ahead, it
would hit "listMissions is not a function" — making the test flaky.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-05 13:55:35 -07:00
Timothy Laurent
8f47e8ddd8 ci: re-trigger checks — flaky in-process-runtime test (unrelated to CSS change)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-05 13:50:02 -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
Fusion
511c0c5442 feat(FN-3502): add comment-triggered retriage when task is in triage status
Merged four commits implementing comment-driven retriage: triage rules now respond to specific comment patterns (Step 1) and surface needs-replan feedback inputs in the UI (Step 2), with documentation for the new behavior and a bug fix restoring workspace typecheck defaults. Changes span the core ta

Fusion-Task-Id: FN-3502
2026-05-05 13:32:10 -07:00
Fusion
7d373286d9 feat(FN-3470): prefer source aliases for runtime plugins and add test artif
Merges FN-3470 in two steps: first, runtime plugins now prefer source path aliases over build artifacts, with hardening tests for vitest alias resolution and plugin view registry updates; second, a new `ensure-test-artifacts.mjs` bootstrap script guarantees required test files exist before test runs

Fusion-Task-Id: FN-3470
2026-05-05 13:25:02 -07:00
Fusion
0aef085f13 feat(FN-3368): tighten research view test coverage and resolve dashboard ty
This merge introduces an eval automation domain store with persistence schema and a plugin dashboard view registry (FN-3512/FN-3513), adds scheduled eval batch architecture documentation (FN-3388), and includes substantial test coverage for Research routes and hooks (FN-3368 steps 1-3). The branch a

Fusion-Task-Id: FN-3368
2026-05-05 13:05:57 -07:00
Timothy Laurent
053ad59d42 fix: suppress pre-existing no-explicit-any lint in chat.ts test mock
The options parameter in __setCreateFnAgent's inline arrow already
uses any to match the module-level let (which has its own suppress
comment). Add the missing eslint-disable-next-line so CI passes.

Unrelated to the spinner fix — pre-existing on main.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-05 13:03:03 -07:00
Timothy Laurent
06cbb744ff fix(lint): suppress no-explicit-any in chat.ts mock assignment
Pre-existing lint error on main — the `any` cast in __setCreateFnAgent
mirrors the eslint-disable already on the adjacent variable declarations.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-05 12:53:45 -07:00
Timothy Laurent
b0c10849d2 test(insights): add regression test for ensureInsightRunsSchemaCompatibility
Simulates a database where project_insight_runs exists without lifecycle
and cancelledAt columns (the state that caused the original bug), then
verifies that re-opening the database adds the columns and creating a run
succeeds.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-05 12:51:32 -07:00
Fusion
c36d30f517 feat(FN-3388): document scheduled eval batch architecture
Added 3 lines documenting the scheduled eval batch architecture in the architecture docs as part of FN-3388 Step 4.

Fusion-Task-Id: FN-3388
2026-05-05 12:49:01 -07:00
Fusion
0e3eaf063f feat(FN-3512): add eval domain store with persistence schema, plugin dashbo
This merge adds three major features: a new **eval domain store** (`eval-store.ts`, `eval-types.ts`) for AI evaluation data with persistence schema and a `PluginDashboardViewHost` for extensibility; a **plugin dashboard view registry** with navigation integration that lets plugins register custom vi

Fusion-Task-Id: FN-3512
2026-05-05 12:37:25 -07:00
Fusion
30f6381ec0 feat(FN-3513): add eval domain store, plugin dashboard view registry, and G
This merge adds three major features: an eval domain (`eval-store.ts`, `eval-types.ts`) with persistence schema for evaluation data; a plugin dashboard view registry with navigation integration for third-party dashboard extensions; and GitHub source metadata traceability that locks and enforces issu

Fusion-Task-Id: FN-3513
2026-05-05 12:25:50 -07:00
Fusion
d7880c66b0 feat(FN-3157): add plugin dashboard view registry with nav integration
Merged FN-3157 to add a plugin dashboard views system, including a plugin view registry with lazy loading, navigation integration for Header and MobileNavBar, a usePluginDashboardViews hook with cache and refetch support, and tests covering the no-loader path. Also added documentation in `docs/PLUGI

Fusion-Task-Id: FN-3157
2026-05-05 12:14:20 -07:00
Fusion
c87c9e2e1f feat(FN-3387): add eval domain with store and persistence schema
Introduced a new evaluation persistence layer in `@fusion/core` with domain contracts, SQLite-backed storage APIs, and retention/window-rollup support, wired through the core store and documented in the architecture and storage docs.

Fusion-Task-Id: FN-3387
2026-05-05 12:01:53 -07:00
Timothy Laurent
c68bfff4f5 fix: move spinner keyframes outside :root selector block
The @keyframes spin and .animate-spin rules were incorrectly placed
inside the first :root {} block, which is invalid CSS — @keyframes
cannot be nested inside selector blocks. Browsers silently ignore
them in that position, so the spinners would still get stuck on pages
without component CSS loaded.

Moves the rules to the stylesheet top level between the two :root
blocks. Also fixes the mobile-css regression test that parses the
first :root block with a non-greedy regex.

Addresses review feedback from Greptile (P1) and CodeRabbit on PR #40.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-05 12:01:14 -07:00
Timothy Laurent
74821803c9 fix: add global spinner animation to prevent stuck loaders
The `.animate-spin` CSS utility class and `@keyframes spin` were only
defined in TaskCard.css but used by 25+ components (~60 instances).
On pages without a TaskCard rendered, the class didn't exist in the
stylesheet, causing all spinners to appear frozen.

Moves both the keyframes and utility class to the global styles.css
so they're available from the first paint regardless of which
components are loaded.

Closes Runfusion/Fusion#39

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-05 12:01:14 -07:00
Fusion
b4bc105726 feat(FN-3481): clean up ephemeral runtimes and spawned agents immediately o
Merges three major changesets: ephemeral agent cleanup for FN-3481 (runtime and spawned agent teardown), a fix for planning-mode refine continuation flow (FN-3209) plus a new local startup script, and chat SSE broadcast isolation with QuickChat backend unification. Key components affected include th

Fusion-Task-Id: FN-3481
2026-05-05 11:43:33 -07:00