Subtask, mission-interview, and milestone/slice-interview sessions could pin
their `generating` state forever when the underlying provider stream stalled
silently or a tool call hung. Wrap each `agent.session.prompt()` in a new
GenerationGuard helper (per-session AbortController + timer) so a stuck turn
becomes a bounded error users can retry. Adds matching `stop*Generation`
exports and threads abort through cleanup so dismissing a modal cancels the
in-flight call instead of leaking it.
Also closes the gh-cli tool hang vector: `runGhAsync` / `runGhJsonAsync` now
accept `{ signal, timeoutMs }` (default 30s). Github-touching extension tools
forward the AI tool's signal so an aborted agent kills the `gh` child instead
of orphaning it.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Add an effective node resolver with task override, project default, and local fallback precedence.
- Wire scheduler dispatch to persist effectiveNodeId/effectiveNodeSource and log resolved node routing.
- Add coverage for effective node resolution and scheduler node routing integration behavior.
- Stabilize workspace test resolution by adding @fusion/core and @fusion/plugin-sdk aliases across Vitest configs.
- Add a core node-override-guard module, export it from @fusion/core, and enforce conflicts in store updates
- Add API route and CLI extension safeguards so nodeId override updates are blocked when ownership would conflict
- Wire node override routing and validation through dashboard quick-create, list, modal, settings, and task form/detail surfaces
- Add focused unit and integration tests for core guard logic, workflow routes, and dashboard node override UX
Replace process.env.HOME fallbacks with os.homedir() in dashboard usage
probes and the hermes plugin profile resolver so unset HOME no longer
yields literal "~" paths. Skip POSIX process-group semantics on Windows
in engine/merger and dashboard-tui's pgrep-based vitest killer. Add
shell: true to npx spawns in CLI skills/extension so .cmd shims resolve
on Windows, and route test:build-exe through cross-env.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- ModelOnboardingModal: native CSS resize with persisted size via
useModalResizePersist; default ~1100px wide; modal scrolls inside
the content area instead of clipping.
- Provider cards flex-wrap so the API-key form drops to a full-width
row instead of being squished into a fixed side column. Connected
badge no longer stretches the full body width.
- Step changes now reset content scrollTop so each page lands at the
top.
- GitHub step: prominent GitHub mark via ProviderIcon; when gh CLI is
authenticated the intro reads as 'you are all set', primary CTA
becomes 'Continue with gh CLI auth', and a secondary
'Connect OAuth (optional)' button is offered.
- CustomModelDropdown: highlight init runs once per open session, and
filter changes reset highlight to top + scrollTop=0, fixing the
scroll-fight when filtering models.
- TUI dashboard: at >=150 cols, Stats panel sits to the left of Logs;
bottom row drops to Utilities + Settings.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Previously the spacer kicked in at cols<68 (top of Logs border was
covered at 68-70) then was widened to cols<72 (which added a gap at 71
where Yoga's flex-column placed the panel correctly without help).
cols<71 is the precise boundary: 68-70 need the 1-row compensation
spacer, 71+ does not.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Update-check frequency (end-to-end)
- Add `updateCheckFrequency: "manual" | "on-startup" | "daily" | "weekly"`
to GlobalSettings (default: "daily").
- Backend `performUpdateCheck` honors the frequency: TTL = day/week,
`manual` returns cache or empty without hitting npm, `on-startup`
refreshes once per process lifetime then serves cache. `/refresh`
route forces network regardless.
- Settings → Updates surfaces a working `<select>` for the cadence,
disabled when auto-checks are off entirely.
- Tests: 4 new cases covering ttlForFrequency mapping, weekly window,
manual semantics, on-startup once-per-process behavior.
TUI update notice
- Read cached update result synchronously on TUI startup. When an
update is available, render a yellow notice line on the splash and
a colored ● next to the version in the status bar.
Settings modal header polish
- Add "Star on GitHub" pill (icon + Star + cached star count from the
GitHub API, 1h localStorage TTL) and "Help" button (opens project
Discussions). Both link to the Runfusion/Fusion repo.
- Star button auto-hides after the user clicks it (intent = star),
tracked in localStorage `fusion:github-star-clicked`.
- Settings → General gets a "Show Star on GitHub button" checkbox so
users can hide it preemptively. New global setting
`showGitHubStarButton: boolean` (default true) gates rendering.
More resizable modals
- Task Detail modal: 85vh default, resize: both, persisted via
useModalResizePersist (key `fusion:task-detail-modal-size`).
- Quick Chat FAB: full 8-direction resize (4 corners + 4 edges) via
pointer-event handlers; persisted to
`fusion:quick-chat-size-<projectId>`. Each handle has the right
cursor + role="separator" for accessibility.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Header was disappearing in tmux at narrow widths under Logs/Utilities
panels because Yoga's flex-column placed the panel body at y=0 instead
of y=1, overdrawing the header. Synthetic tests at every width show the
layout as correct, but real-tmux log-update tracking drifts over many
state updates and the header gets scrolled off.
- Paint header as an ANSI overlay after every Ink frame write (DECSC/
DECRC cursor save/restore) — guaranteed at terminal row 1 regardless
of any layout drift. Skipped during splash so the loading screen is
uncluttered.
- StatusModeGrid: full-width System on top (4-row pinned, chips wrap if
needed) + Logs filling the middle + Stats/Utilities/Settings as
equal-width bottom row. Stats now shows just Process/System rows.
- StatusModeSingle: 1-row spacer only at cols<68 (Yoga edge case at
very narrow widths shifts content up); 68+ has no spacer per UX.
- Panel/LogsPanel/UtilitiesPanel inner content boxes pinned with
flexShrink=1 + overflow=hidden so panel intrinsic height can't push
the frame past terminal rows.
- Each Logs entry wrapped in height={1} Box (when wrap is off) — Yoga
was sometimes measuring nested Text as taller than 1 row at narrow
widths.
- Tab "Explorer" → "Files" with shortcut "e" → "f" (preserves
filter-cycle on Logs panel; switches to Files view elsewhere).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The task card timer chip previously fell back through several metrics
(timed duration → workflow runtime → wallclock), so cards showed only a
subset of execution time. For FN-2714 this rendered <1m on the card while
the stats tab reported >2m of workflow runtime.
The chip now reports the sum of [timing]-tagged log events and workflow
step runtime (matching the new "Total execution time" metric in the stats
panel), with live elapsed for in-progress workflow steps. When neither
metric is recorded, the chip is hidden rather than falling back to
wallclock.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
When the worktree-recycle pool reassigned a path to a new task, the old
task's diff endpoints kept reading the new task's branch state — surfacing
unrelated commits as the original task's "files changed" list.
- Clear task.worktree/branch in the merger after the worktree is released
to the pool or removed, so the path no longer points anywhere.
- Validate the worktree's current branch matches task.branch in the three
worktree-backed diff endpoints; on mismatch return empty rather than
diffing against a foreign branch.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Load configured plugins during dashboard startup before launching the UI flow
- Load plugins during serve and daemon startup so runtime hooks are available immediately
- Add targeted CLI command tests for dashboard, serve, and daemon auto-load behavior at startup
- Add a changeset documenting the plugin runtime startup fix for @runfusion/fusion
- Add TodoView controls to create todo tasks directly and optionally assign an agent
- Style the TodoView agent picker dropdown for desktop and mobile interactions
- Add TodoView tests covering todo task creation and agent assignment behavior
- Simplify dashboard TUI status grid sizing to use flexible panel layout
- Add CLI plugin install tests that reproduce and guard the getRootDir path-resolution regression
- Validate plugin installation behavior in the regression scenario to prevent future breakage
- Add a patch changeset for @runfusion/fusion documenting the plugin install getRootDir fix
- Add getRootDir() to the plugin command mock TaskStore used by createPluginLoader
- Ensure fn plugin install can resolve project root expectations without runtime failures
- Add a patch changeset for @runfusion/fusion documenting the CLI fix
In StatusModeSingle (cols<80 || rows<20), an active panel whose
intrinsic content exceeds the container could push the frame past
terminal rows under tmux, scrolling the header off the top. Yoga
defaults flexShrink to 0 (unlike CSS), so panels refused to shrink
when wrapped Text grew them vertically.
- Default Panel flexShrink to 1 so panels collapse to fit container
- Pin StatusModeSingle's three rows to explicit heights with
overflow:hidden, eliminating overflow paths entirely
- Pass availableRows to LogsPanel from the capped middleHeight so
its rowBudget matches the actual height instead of stdout.rows-11
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Improve automation startup diagnostics and route handling for manual execution steps
- Add support for full manual automation step execution in dashboard and engine flows
- Expand due-schedule coverage in automation store and dashboard route tests
- Add cron runner regression tests for edge cases and document the automation execution fix via changeset
- Add global updateCheckEnabled setting to core schema/types and wire dashboard command to cache update checks in the CLI
- Implement dashboard server update-check cache module plus REST routes for status and refresh behavior
- Add dashboard client hook, legacy API helpers, and UpdateAvailableBanner UI to show cached CLI update notices
- Cover update-check server routes, hook behavior, banner rendering, and route registration with focused tests
- Document update-check configuration and API behavior in architecture and settings reference docs
- Set explicit column widths in the dashboard TUI logs panel to prevent width jitter during log updates
- Add a regression test covering logs panel width stability across rerenders
- Keep existing layout behavior while eliminating shifting in the logs view
- 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
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>
- 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
- 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
- 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
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>
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>
Raise per-test timeout to 30s in extension and provider-settings suites
where parallel FS load (or worker-pool starvation) can push pure-sync
tests past vitest's 5s default. Skip the fn pi extension and agent-export
suites whose coverage is duplicated by command-level tests but cost ~62s
and ~3.3s respectively on every run.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Debounce SIGWINCH bursts (50ms trailing edge), wipe the alt-screen before
Ink redraws so shrunk frames don't leave stale rows, and add a 2s dim-poll
fallback for environments that drop SIGWINCH. LogsPanel now reads stdout
rows itself so timer-driven renders always see live dimensions, and the
layoutKey includes a resizeTick so Yoga's cached layout is invalidated
even when cols×rows lands back on the same string.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- test(FN-2618): harden process-manager fs/tmpdir mocks
- fix(cli): mark react-devtools-core external in bun compile
- fix(pty): switch to @homebridge/node-pty-prebuilt-multiarch fork
Bun's --compile binary previously crashed at startup because:
1. node:sqlite isn't implemented in Bun 1.3.8 (require returns
undefined; import throws "No such built-in module")
2. ink imports react-devtools-core inside its reconciler; even though
gated by isDev(), the bundled module path failed to resolve at
runtime
Fixes:
- Add packages/core/src/sqlite-adapter.ts: a thin DatabaseSync wrapper
that picks bun:sqlite under Bun and node:sqlite under Node via
createRequire (so the bundler doesn't statically pull in either).
Drop-in for the three core files that import DatabaseSync.
- Install react-devtools-core as a workspace devDependency so it
resolves at bundle time. The dev-only code path is still gated by
DEV=true, so it stays inert in production.
- Revert the prior --external react-devtools-core flag (no longer
needed and was causing a different runtime error).
- Mark node-pty external in tsup so esbuild stops choking on the
homebridge fork's conditional native require()s
(build/Release/conpty.node etc.) when bundling for the npm package.
- Update bundle-output test: the bundle now contains both
bun:sqlite and node:sqlite specifiers (loaded via createRequire).
Verified end-to-end: dist/fn dashboard -p 0 starts cleanly (no PTY,
sqlite, or devtools errors). Core tests 3038/3038, CLI tests 826/826
(up from 822/826 baseline).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ink@6 has a devtools.js module that imports react-devtools-core. It is
only loaded at runtime when DEV=true, but Bun's static bundler still
tries to resolve it at compile time and fails with "Could not resolve".
Marking it external lets the compile succeed; the dynamic import path
is never taken in production.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Resolves "Failed to load PTY module" install errors on Linux/macOS by
aliasing node-pty to the homebridge fork, which ships prebuilds for
linux x64/arm64/arm/ia32 across many Node ABIs and uses prebuild-install
for darwin/windows binaries on install.
- Aliased dep so all "node-pty" import specifiers (and vi.mock calls)
keep working unchanged.
- Removed darwin chmod postinstall hack (fork handles permissions).
- Updated cli/build.ts to dynamically resolve node-pty install root and
pick prebuilds by ABI for Linux cross-compile; warn-and-skip for
darwin/windows cross-compile (host-only there, as before).
- Added type shim because the fork's bundled typings declare module
'@homebridge/node-pty-prebuilt-multiarch', not 'node-pty'.
Verified: pnpm install clean, dashboard typecheck clean, native module
loads and spawns shell via fork, host + linux-x64 cross-compile staging
both produce dist/runtime/<plat>/pty.node.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Remove the standalone remoteEnabled setting from CLI, core settings defaults/types, and dashboard settings APIs/UI
- Treat remote access as enabled when an active provider is selected and that provider is configured as enabled
- Update remote auth and engine lifecycle checks to gate on provider activation instead of a global flag
- Adjust tests and add a changeset documenting the remote access configuration simplification