Stale-merge recovery now calls back into ProjectEngine's auto-merge queue
directly instead of waiting on the 15s polling sweep — wired via a new
InProcessRuntime.setMergeEnqueuer hook so SelfHealingManager can re-enqueue
without leaking engine internals.
createWorktree mirrors the merge-time rebase: when worktreeRebaseBeforeMerge
is enabled, the new task branch is rebased onto <remote>/<defaultBranch>
right after creation, so executors start from origin's tip with local main
replayed on top. Best-effort — fetch/rebase failures abort cleanly and
leave the merge-time rebase as the backstop.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Redesign the task Routing tab with effective-node summary rows, unhealthy node signaling, and direct per-task override selection
- Add robust override update handling (loading/saving states, stale-task guards, clear override action, and in-progress lock messaging)
- Extend TaskCard execution time indicator behavior to in-review cards and add focused regression coverage
- Refresh dashboard tests and styling for routing and node-status presentation, and remove an unused remote settings API import
- Add a reusable ProjectNodeSelector component and hook RoutingTab to it for per-task node overrides
- Move default node and unavailable-node policy controls into the dedicated Node Routing settings section
- Add descriptive routing guidance text and project-level note in SettingsModal
- Expand dashboard tests for routing tab behavior and node routing settings UX
- Remove the separate "Activate Provider" action from SettingsModal and rely on save-only provider configuration
- Ensure saving remote settings enables the selected active provider and keeps provider flags consistent
- Seed remoteAccess defaults in remote settings routes when project settings are missing instead of returning conflicts
- Expand dashboard tests to cover first-use/default remote settings behavior and updated provider lifecycle expectations
- Move the check-for-updates refresh button into the settings header actions group for consistent placement
- Keep update check behavior unchanged, including loading state, disabled state, and aria labeling
- Set the refresh icon size explicitly to match surrounding header controls
- Simplify mobile CSS by removing obsolete settings-update-check wrap overrides
- Add formatElapsedDurationDone to render done task elapsed time with ceiling-based minute/hour/day rounding
- Keep in-progress time indicator logic on existing floor-based formatElapsedDuration behavior
- Route done-card time indicator rendering through the new done-specific formatter
- Expand TaskCard tests to cover done rounding semantics and preserve in-progress rounding expectations
- Reset merge metadata, verification counters, and workflow results when tasks move from in-review/done back to in-progress
- Reopen verification-related steps (or the last step fallback) so re-verification runs from a pending state
- Add execute-time guard to clear stale mergeDetails on in-progress tasks before continuing
- Prevent resumeOrphaned fast-path recovery when completed in-progress tasks still carry merge metadata
- Add targeted executor and TaskForm tests covering FN-2883 regression paths
- Add webhook settings fields and defaults for enablement, URL, format, and event filtering
- Implement WebhookNotificationProvider with payload formatting support for generic, Slack, and Discord endpoints
- Extend NotificationService to manage both ntfy and webhook providers with live settings sync
- Export webhook notification types/providers through engine notification entry points
- Add planning-module documentation explaining current ntfy helper flow and future NotificationService migration
- Detect NotificationService export availability during helper initialization and emit diagnostic info logging
- Add regression test coverage that verifies planning notifications still use ntfy helper functions when NotificationService is present
- Preserve planning awaiting-input notification behavior and click URL/event gating expectations
- Wire onRetryTask from App through Board/Column/WorktreeGroup/ListView into TaskCard
- Add a Retry button with loading/disabled state to failed task error boxes in TaskCard
- Update failed-card styles to use design tokens and add retry button visual states
- Add TaskCard tests covering retry visibility, callback invocation, loading, and error toast behavior
- Add a patch changeset for @runfusion/fusion documenting the dashboard retry shortcut
- Resolve squash conflicts across dashboard and TUI files by preserving current mainline behavior
- Keep node-routing status UI and quick-chat default-model flows intact during conflict resolution
- Confirm no net code changes were required from fusion/fn-2868 after replay
- Run mandatory verification commands: pnpm test and pnpm build
- Add notification service module with provider abstractions and ntfy provider implementation
- Refactor NtfyNotifier into a compatibility wrapper that delegates task-event delivery to NotificationService
- Initialize and stop NotificationService from ProjectEngine while preserving gridlock notifications via NtfyNotifier
- Export notification APIs from engine index and add focused unit coverage for provider, service, and project-engine wiring
- Assert default-model auto-selection initializes a model session with project-scoped context
- Verify quick chat input stays disabled until default-model session bootstrap completes
- Add parity coverage for default-model initialization when agents are present
- Allow session initialization to retry when the same target key is selected but no active session exists
- Gate duplicate-init short-circuit behind activeSession/sessionsLoading so model-mode startup can recover
- Expand the effect dependency list to track session readiness inputs used by the retry guard
The live number-key handler hard-coded [3]→utilities, [4]→stats and
returned early, masking a parallel NUMBER_KEY_ORDER table. Update the
live mapping and remove the dead duplicate handler + constant.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Add node status indicators and labels to task creation, quick entry, task form, and settings node selectors
- Surface selected node health in list bulk-edit controls with status dot styling for online/connecting/offline/error states
- Update dashboard component CSS and shared styles for consistent node status presentation
- Include changeset documenting unavailable-node routing policy and default node behavior
- Remove stdout header overlay patching and related frame recovery hooks from the dashboard TUI controller
- Keep panel switching logic lightweight by relying on normal state updates without forced recover cycles
- Adjust status footer and utility/system panel rendering to maintain a single-line, truncation-friendly layout
- Add explicit number-key panel mapping while preserving existing tab/cycle panel order
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>
Replace lazy `await import("./pi.js")` and `require("./pi.js")` calls in
runtime-resolution, agent-session-helpers, agent-heartbeat, and
cron-runner with top-level static imports. These dynamic imports were
documented as plugin-decoupling, but pi.js is already eagerly loaded
through index.ts re-exports and static imports in executor/merger/
reviewer/triage/mission-execution-loop, so the deferral never paid off
in practice.
The deferral did, however, introduce a TOCTOU race: a tsc rebuild that
momentarily emptied dist/pi.js would let the engine load fine and only
fail minutes later when the first session was created (e.g. FN-2860
errored two minutes into execution while pi.js was being rewritten).
With static imports, a missing/half-built dist now fails immediately at
process startup with a clear stack — verified by `mv dist/pi.js
dist/pi.js.bak` reproducing ERR_MODULE_NOT_FOUND on the first import of
runtime-resolution.js.
Also drops the DefaultPiRuntime.describeModelFn cache, which only
existed to paper over the require-on-first-call latency.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
When a dependency task merges and its branch is deleted, self-healing nulls
the dependent task's baseBranch. Both resolveDiffBase (dashboard) and
resolveTaskDiffBaseRef (merger) defaulted to "main" in that case, widening
the diff range to merge-base(HEAD, main) and surfacing unrelated history —
e.g. FN-2855 reported 108 changed files instead of 16. Skip the merge-base
step when baseBranch is unset and a baseCommitSha is recorded; fall back to
"main" only for legacy tasks lacking both hints.
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.
- Tighten background task indicator pill padding to reduce vertical footprint
- Lower line-height to keep icon/text alignment after the size reduction
- Reduce mobile min-height so the footer pill no longer appears oversized
- Add effective node routing fields to task types/store, persist them in SQLite, and expand regression coverage for node override guard behavior
- Add dashboard and API support for manual memory dream processing/trigger actions plus expanded memory regression tests
- Improve task creation and task detail model/node UX, including quick chat default model selection and workflow/settings UI polish
- Apply mobile/dashboard UX fixes (form input zoom prevention, expand toggle styling, input layout tweaks) and update extension/docs/changelogs for the release
- Add ProjectEngine memory dreams wiring tests for startup ordering, settings-change resync, and unrelated-setting no-op behavior
- Cover degraded-mode startup and settings-update failure paths to ensure sync errors are logged without stopping the engine
- Extend MemoryView Dream Now tests for success, failure toast handling, and disabled loading-state behavior
- Add POST /api/memory/dream route that runs project and agent dream processing with AI prompt execution
- Expose triggerMemoryDreams() in dashboard legacy API client for direct dream invocation
- Switch SettingsModal and useMemoryData Dream Now actions from automation lookup to the new endpoint
- Update dashboard route, hook, and settings modal tests to cover success and error handling
- Add a patch changeset for @runfusion/fusion documenting the new endpoint and client helper
- Extend /models API responses to include optional defaultProvider/defaultModelId from global settings, including empty and error paths
- Update QuickChatFAB to prefer the configured default model on load and fall back to first-model selection only when no agents exist
- Move quick chat model tag/title-wrap inline styles into QuickChatFAB.css using dashboard design tokens
- Add QuickChatFAB tests covering default-model auto-selection with and without agents and legacy behavior when no default is configured
- Add a Learn more link to the update-available banner alongside release notes
- Refactor SettingsModal update-result rendering into a shared helper and include the infusion.ai link when updates exist
- Add dedicated SettingsModal link styling with hover and focus-visible states using dashboard tokens
- Update banner and settings tests to assert the new Learn more link behavior
- Add a patch changeset for @runfusion/fusion documenting the update notice link addition
- Add dedicated styles for the workflow result expand icon button with token-based sizing and alignment
- Add hover and focus-visible states for clearer interaction feedback and keyboard accessibility
- Increase mobile touch target sizing for both workflow edit and expand toggles using design tokens
- Add global `touch-action: manipulation` on html/body to reduce gesture-triggered zoom
- Set mobile input font-size to 16px for terminal, nodes, and scripts modal form fields
- Extend mobile CSS regression tests to assert the global touch-action rule
- Extend useMemoryData with triggerDreamNow and dreamRunning state by locating and invoking the Memory Dreams automation
- Add Dream Now actions to MemoryView and SettingsModal memory settings with loading UI, success/error toasts, and file refresh in MemoryView
- Expand hook and component tests to cover dream-trigger visibility and execution flows in both views
- Update terminal mobile keyboard layout CSS contract expectations for the current mobile modal width and min-height rules
- 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
- WorkflowStepManager: fix React error #310 ("Rendered more hooks than during
the previous render") that broke the workflow steps panel from loading.
`useOverlayDismiss` was being called after `if (!isOpen) return null`, so
the hook count differed between open/closed renders. Move the hook above
the early return.
- ModelOnboardingModal: API-key input + Save button now span the full card
width on mobile via negative inline margins that bleed past the card's
horizontal padding, so the form sits flush to the card edges instead of
picking up a chunky left indent from the icon-row's flex start position.
- TerminalModal: same desktop-min-width-pinning bug as the onboarding modal.
Reset min-width/min-height to 0 on mobile with `!important` so persisted
desktop sizes from useModalResizePersist cannot re-pin the modal at 480×320
on smaller phones. Also add `!important` to the keyboard-overlap height/
max-height so the visual-viewport adjustment wins against the new
fullscreen rule — without this the terminal stayed at 100dvh while the
mobile keyboard covered the bottom of the screen.
- Add 0.7.1 changeset covering the full mobile polish + paperclip CLI parity
+ plugin runtime registry fallback + SCHEMA_VERSION bump series.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
On mobile the dialog was rendering with its top hidden behind the in-page
\"Agents\" header. The dialog wasn't actually positioned wrong — its overlay
is `position: fixed; inset: 0`. The problem was that NewAgentDialog
rendered as a child of `.agents-view` (which has `overflow: hidden` and
`position: relative`), and an ancestor stacking context combined with the
relative+overflow parent prevented the fixed overlay from escaping above
the page header in the painter's order.
Render the dialog through `createPortal(..., document.body)` so the
overlay attaches at the document root, escaping every parent stacking
context. This is the standard React modal pattern.
All 9639 dashboard tests still pass — React Testing Library queries
traverse portals transparently.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ModelOnboardingModal:
- API-key row was forced to flex-direction: column on mobile, stacking the
input above the Save button and doubling the vertical space inside the
already-cramped provider card. Switch to flex-direction: row with the
input growing (flex: 1, left-aligned) and Save shrunk to its label
(right-aligned). Tighten input/button min-height to 32px and shrink the
button's inline padding.
- Tighten surrounding form: gap → --space-xs, label font-size → 11px with
no margin-bottom, helper paragraphs → 11px / line-height 1.35.
NewAgentDialog:
- Top of the dialog was cut off under the iOS notch / status bar. Added
env(safe-area-inset-top) to the mobile header padding-top, and
env(safe-area-inset-bottom) to the footer padding-bottom so the home
indicator doesn't cover the action buttons.
- Body wasn't scrolling because the flex child kept its default
min-height: auto, making the dialog grow past the viewport and never
trigger overflow-y: auto. Added min-height: 0 + flex: 1 1 auto on the
body, and flex-shrink: 0 on the header/footer/steps so only the body
gives up height.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Previous mobile rule forced .onboarding-provider-card to flex-direction:
column with --space-lg padding, so the icon, body, and actions each took
their own full-width row and every card rendered ~140px tall on a phone.
Keep the icon inline beside the name + description (the row layout the
desktop already uses, just tighter), shrink the icon container to
list-item-bullet size, drop name/description font sizes a notch, and rely
on the existing flex-wrap so the API-key form / action buttons still drop
to their own row underneath. Also evenly split simple action rows (Connect
/ Skip) across the full width for easier tap targets.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- ModelOnboardingModal: the desktop base set min-width: 640px / min-height:
480px and the mobile media query only reset max-width — but min-width
always wins over max-width in size resolution, so the modal stayed pinned
at 640px and overflowed any phone narrower than that. Compounding it,
useModalResizePersist writes inline width/height from saved desktop
sessions (e.g. 1100px), and inline styles beat the media query. Reset
min-width/min-height to 0 in the mobile rule and force fullscreen
(100vw/100dvh) with !important so the persisted desktop size cannot
re-pin the modal off-screen. Also disable resize on mobile.
- NewAgentDialog: had no mobile media query at all. Added a max-width: 768px
block that drops the overlay padding, fills 100vw/100dvh, removes the
border-radius, tightens header/footer/steps padding, locks body scroll
with overscroll-behavior: contain + -webkit-overflow-scrolling: touch
(so iOS doesn't bubble the scroll up and trap users above the footer),
and stacks the footer buttons full-width. Also switched the desktop
max-height from 100vh to 100dvh so iOS Safari's collapsing URL bar
doesn't push the footer under the address bar.
- SettingsModal auth panel: reduced .auth-panel-body padding-inline from
--space-xl (24px) to --space-md (12px) so each provider card gets more
horizontal room — the cards are dense enough that the wider gutter
wasted visible width without any visual benefit.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Migration 49 (`ALTER TABLE tasks ADD COLUMN nodeId TEXT`) was added with
SCHEMA_VERSION still pinned to 48. Existing DBs at version 48 hit the
`if (version >= SCHEMA_VERSION) return;` early exit, so the column was never
created — `TaskStore.listTasks` then crashed at startup with
`no such column: nodeId` and the dashboard exited before initialization.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Use bundled Nous Research SVG (inverted) on the Hermes runtime card
instead of the generic ProviderIcon.
- Lock GitHub-star and Help buttons in the settings header to a uniform
26px height so the differing icon sizes don't misalign them.
- Drop the inline Delete button from the idle/terminated agent-card
states — deletion stays available from the agent detail view.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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>
- packages/dashboard/src/routes.ts: hermes/openclaw runtime metadata declares
`version` as `string | undefined`, but BUNDLED_PLUGIN_RUNTIMES requires
`string`. Coalesce to "0.0.0" so the bundled fallback list type-checks.
- packages/dashboard/app/components/__tests__/NodeStatusIndicator.test.tsx:
the file had been reduced to a stub ("placeholder") which the test runner
parsed as an undefined identifier. Restore the original 155-line suite from
fc23e522a; the underlying NodeStatusIndicator component is unchanged.
All 9639 dashboard tests pass; pnpm typecheck is clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Merge metadata for the three example runtime plugins bundled as workspace
dependencies of @fusion/dashboard with pluginLoader.getPluginRuntimes(), so
the NewAgentDialog "Plugin Runtime" dropdown populates without requiring
an explicit `fn plugin install`. Installed plugins override the bundled
fallback by runtimeId.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The Paperclip runtime card's Local CLI tab previously only derived an apiUrl
from the local config and then made HTTP calls itself, so the Test action and
the company/agent pickers ignored the user's onboarded CLI auth context.
Add CLI-backed variants for every Paperclip call that has a `paperclipai`
counterpart, and route through them when transport=cli — both from the
settings card and from the runtime adapter's prompt path.
- New plugin functions spawning `paperclipai … --json`:
* probePaperclipViaCli, listCompaniesViaCli, listCompanyAgentsViaCli
(settings card test + pickers)
* createIssueViaCli, getIssueViaCli, agentsMeViaCli (runtime hot path)
- New dashboard routes: /providers/paperclip/cli-status, /cli-companies,
/cli-agents (read-only façades over the plugin's CLI helpers)
- PaperclipRuntimeCard: branches on transport=cli to use the cli-* fetchers
- PaperclipRuntimeAdapter: stores transport on the session and routes
createIssue/getIssue + identity derivation through CLI variants in CLI mode;
raises a clear error when agentId is unset in CLI mode (paperclipai has no
/agents/me equivalent)
- getIssueComments / wakeAgent / getRunEvents stay on HTTP (no matching
paperclipai subcommands) and continue to use the apiKey discovered from
the local paperclipai config, so CLI mode still works end-to-end
- Tests: 9 new paperclip-client tests covering each CLI variant + 5 new
adapter tests for the Local-CLI transport branch (64/64 plugin tests pass)
- Update routes.test for the existing BUNDLED_PLUGIN_RUNTIMES fallback so
the bundled hermes/openclaw/paperclip entries are expected alongside
installed plugins
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>