Three orthogonal fixes bundled together so they re-land as a unit after
earlier worktree-based reverts kept wiping them individually.
1. `--no-auth` flag now actually disables auth. Previously a stale
FUSION_DAEMON_TOKEN in .env silently re-armed bearer-token auth despite
the CLI flag. Added a `noAuth` option to ServerOptions; auth-middleware's
isDaemonAuthActive/getDaemonToken short-circuit to false/undefined when
set; CLI plumbs opts.noAuth through both createServer call sites.
2. Workflow review failures no longer reset every completed step. Previously
a single CSS nit from a workflow reviewer could drag 5+ already-approved
steps back through plan review, code review, and re-execution because
determineRevisionResetStart fuzzy-matched feedback tokens against step
names. handleWorkflowRevisionRequest, handleWorkflowStepFailure, and
sendTaskBackForFix now call a new reopenLastStepForRevision helper that
flips only the last non-pending step back to pending (with currentStep
rewind via a newly-accepted updateTask field) — all earlier done steps
stay done, and the agent applies the feedback as an in-place patch per
the updated PROMPT.md instructions. determineRevisionResetStart stays
exported as @deprecated so existing unit tests still link.
3. Heartbeat scheduling is now state-driven. Previously a non-ephemeral
agent with a stale runtimeConfig.enabled=false on disk would never tick
and the Pause/Resume button couldn't arm the timer without also flipping
that hidden flag. HeartbeatTriggerScheduler's watchAgentLifecycle now
registers on transitions into active/running and clears on transitions
out; the tick and assignment-trigger guards key off state + ephemeral
classification. InProcessRuntime's created/updated listeners and startup
scan mirror the same semantics. runtimeConfig.enabled is only retained
for ephemeral (task-worker) opt-out.
Tests updated: agent-heartbeat.test.ts — one test renamed from "skips
registration when enabled is false" (obsolete behavior) to
"registers regardless of the legacy enabled flag"; 4 assignment-watching
tests now pass a realistic `state: "active"` on mock agents. 207 heartbeat
tests + 330 executor tests pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The bearer-token middleware was mounted globally on the Express app, so
the initial GET /?token=<token> request for index.html was rejected with
401 before the frontend JS could even load and capture the token from
the URL. The server-side query-string fallback only accepts fn_token=,
while the banner URL uses ?token= (which only the frontend captures), so
the bootstrap request had no valid auth path.
Fix: gate auth on /api/* only. The SPA shell (index.html, /assets/*,
favicon) is public — it contains no secrets, and the frontend auth.ts
module captures the token into localStorage and installs a fetch wrapper
that injects Authorization: Bearer on every /api/* call.
Also: add .env / .env.local to .gitignore so local FUSION_DAEMON_TOKEN
values don't accidentally get committed.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pre-release polish. Two related changes bundled because they both land the
project on public-release footing:
Dashboard auth
- fn dashboard now gates the HTTP API + terminal/badge WebSockets behind a
bearer token by default. Token resolution order: --token flag,
FUSION_DASHBOARD_TOKEN env, FUSION_DAEMON_TOKEN env (back-compat), or an
auto-generated fn_<32 hex>. --no-auth disables. The startup banner prints
a click-to-open URL with ?token=<token> embedded.
- Auth middleware now also accepts fn_token=<token> as a query-string
fallback so EventSource and WebSocket clients (which can't set custom
headers) still authenticate.
- setupTerminalWebSocket / setupBadgeWebSocket now refuse unauthenticated
upgrades with a proper 401 + socket close.
- Frontend: new auth.ts module captures ?token= off the URL into
localStorage (key fn.authToken), strips it from the visible URL via
replaceState, and installs a window.fetch wrapper that injects
Authorization: Bearer <token> on every same-origin /api/* request.
EventSource/WebSocket URL builders (api.ts, sse-bus.ts, useTerminal,
useBadgeWebSocket) route through appendTokenQuery().
MIT license
- LICENSE file at repo root.
- license: "MIT" on root package.json and every packages/*/package.json,
plus description/bugs metadata on the CLI package.
Docs
- docs/cli-reference.md documents --token / --no-auth / FUSION_DASHBOARD_TOKEN
and the click-to-open auth flow.
- docs/getting-started.md, docs/docker.md, README.md point at the new flow
and the CLI reference section.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
When the engine restarts mid-step, an in-progress step may have already
passed plan + code review but not yet been flipped to done by the agent's
next task_update call. Previously, the next executor pass re-entered the
step and replayed both reviews — measured at 5-20 min of pure waste per
restart (observed in FN-2215 Step 1 and FN-2207 Step 6).
recoverApprovedStepsOnResume scans the task log for any in-progress step
whose most recent "code review Step N: APPROVE" entry is newer than its
most recent "Step N → pending" transition, and marks those steps done
before execute() runs. Safely skips steps that were reset after approval
(e.g. by a workflow revision) or only received REVISE verdicts.
Called from both the engine-restart path (resumeOrphaned) and the
unpause path, matching the two places the task log shows as vulnerable
to this race.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Replace the silent stale-session eviction catch with a terminal error log in setupTerminalWebSocket
- Add regression tests that assert evictStaleSessions runs on each 60s interval tick
- Verify eviction errors are logged without stopping future ticks and interval cleanup runs on server close
- Introduce DevServerStore and DevServerProcessManager with a simplified store API contract
- Add dev-server script detection and route legacy manager behavior through the new process manager
- Add a dedicated dev-server router with start/stop/status/log endpoints and SSE event streaming
- Wire dev-server routes into the main route table and hook manager shutdown into server teardown
- Expand tests and architecture docs for store, process, route, detection, and SSE coverage
- Add a durable dev-server store and manager with persisted state/log history, process reconciliation, and SSE event buffering
- Wire new backend lifecycle APIs for status/history/start/stop/restart/stream and initialize/shutdown manager handling in server startup
- Add dashboard Dev Server view, hook-based hydration/stream handling, nav integration, and supporting styles
- Expand coverage with backend persistence/route tests and frontend DevServerView/useDevServer tests
- Document the dev-server persistence architecture in docs/architecture.md
- Add DevServerManager service to start/stop/restart dev processes, persist state, stream logs, and detect preview URLs
- Add dev server candidate detection across root/workspace package scripts with caching and invalidation helpers
- Expose /api/dev-server routes for candidates, status, lifecycle actions, manual preview URL, and SSE log/status stream
- Initialize and tear down dev server managers from dashboard server lifecycle
- Add unit and route tests covering detection, manager lifecycle, URL parsing/fallback probes, and API validation
- Emit chat:session:updated from ChatStore when message deletion mutates a session and cover deleteMessage false returns
- Pass ChatStore into SSE setup and forward chat session update events to connected clients
- Update useChat to consume SSE updates in real time with safer EnrichedChatSession typing
- Add core and dashboard tests for chat-store emissions, SSE forwarding, route wiring, and hook behavior
- Add Memory section controls for enabling auto-summarize with threshold and cron schedule inputs
- Wire ProjectEngine to sync auto-summarize automation on startup and when related settings change
- Reuse a single startup settings snapshot when syncing insight extraction and auto-summarize automations
- Add SettingsModal and ProjectEngine tests covering auto-summarize UI persistence and automation re-sync behavior
- Add agent memory support to instruction resolution and introduce/export buildAgentChatPrompt for identity-aware prompt assembly with optional project memory
- Wire ChatManager to AgentStore so chat sessions can enrich system prompts per agent and include recent conversation context in prompt payloads
- Update server chat wiring to provide an AgentStore for prompt enrichment and keep graceful fallback behavior when agent context is unavailable
- Enrich HeartbeatMonitor system prompts with resolved agent instructions/ratings while preserving base-prompt fallback paths
- Expand dashboard and engine tests to cover prompt enrichment, fallback behavior, conversation context assembly, and AgentStore route mocks
- Wire MessageStore into the in-process executor runtime and project engine
- Forward MessageStore events through dashboard SSE infrastructure for mailbox updates
- Close mailbox pipeline gaps across API routes, server wiring, and mailbox UI components
- Add regression coverage for messaging routes, SSE forwarding, and agent tool behavior
- Document the MessageStore SSE wiring pattern in .fusion/memory.md
- Expose getAgentStore from runtime and engine packages
- Add includeSystem filter to getOrgTree API endpoint
- Wire AgentStore into SSE endpoint for event forwarding
- Forward agent events through the SSE pipeline
- Exclude ephemeral agents from org tree API and UI
- Filter ephemeral agents in useAgents hook
- Update AgentsView test to expect includeSystem filter
- Document agent SSE event forwarding architecture
- Add skills discovery API (GET /api/skills/discovered) to list available skills with enabled state
- Add skills execution toggle API (PATCH /api/skills/execution) for enabling/disabling skills with project-scoped persistence
- Add skills catalog API (GET /api/skills/catalog) with resilient fallback to fetch skills.sh catalog
- Skills are stored in project settings (.fusion/settings.json) with support for both top-level and package-scoped skills
- Add SkillsAdapter runtime class for skills discovery, catalog fetching, and execution toggle
- Add comprehensive tests for all skills API endpoints
- Update dashboard, serve, and provider-settings commands with skills adapter integration
- Skip flaky streamChatResponse test (matches main branch behavior)
- ProjectEngineManager.startReconciliation() polls for newly registered
projects every 30s and starts their engines without requiring UI access
- Expose global concurrency limit in dashboard settings
- Fix SettingsModal test cleanup
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove the anti-pattern where the cwd project was treated as "primary" with a
special engine, and other projects got "secondary" engines through a separate
code path. Every project now gets an identical ProjectEngine created through
ProjectEngineManager.
Key changes:
- Add ProjectEngineManager class to @fusion/engine for uniform engine lifecycle
- Replace manual engine maps in dashboard.ts and serve.ts with engineManager
- Add engineManager to ServerOptions for per-project engine resolution
- Add getProjectContext() helper in routes.ts (replaces 199 getScopedStore calls)
- Merge and automation routes now resolve engine subsystems per-request
- SSE endpoint uses engine's store when available (same EventEmitter)
- Fix tsx not found in dev-with-memory.mjs startup script
- Add invalidateAllGlobalSettingsCaches for cross-project settings sync
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Tasks in projects other than the primary (cwd) project were never triaged
because only one ProjectEngine was started. When a project is accessed via
?projectId= API/SSE, getOrCreateProjectStore created a TaskStore but left
the Scheduler, TriageProcessor, and TaskExecutor unstarted.
Fix: introduce setOnProjectFirstCreated callback in project-store-resolver
so the dashboard server is notified when any new project is first accessed.
dashboard.ts creates a ProjectManager that lazily starts an InProcessRuntime
(Scheduler + TriageProcessor + TaskExecutor) for each project the first time
it is accessed — works for any number of registered projects.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Implemented:
- POST /api/missions/features/:featureId/validate - triggers validation run
- GET /api/missions/features/:featureId/validation-loop - returns loop snapshot
- GET /api/missions/features/:featureId/validation-runs - returns run history with pagination
- GET /api/missions/validation-runs/:runId - returns run detail with assertion results
- POST /api/missions/recover - triggers recovery of active missions
- SSE events for milestone:validation:updated via assertion CRUD and link/unlink
All 4xx/5xx responses use consistent {"error": "message"} format.
Uses existing badRequest, notFound, internalError helpers.
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
- Add RoutineRunner class for routine execution via heartbeat system
- Add RoutineScheduler class for cron-based routine polling
- Add triggerManual and triggerWebhook methods for API and webhook triggers
- Wire RoutineScheduler into InProcessRuntime lifecycle
- Add routine trigger and webhook API endpoints
- Fix type mismatches between PROMPT and actual FN-1519 types
- Add ChatStore mock to all dashboard route tests that mock @fusion/core,
since server.ts now instantiates ChatStore(store.getFusionDir(), ...)
- Add getFusionDir to createMockStore in server.test.ts
- Gate AI session cleanup scheduling behind shouldScheduleAiSessionCleanup()
(returns false in test env) to prevent open handle warnings
- Fix desktop tests: DASHBOARD_URL is now exported as a function alias,
update assertions to call DASHBOARD_URL() instead of using as string
- Add node:os mocks to system-metrics.test.ts for deterministic results
- Replace hardcoded maxWorkers=16 with availableParallelism()-based
calculation in all vitest configs to prevent OOM on 2-core CI runners
- Add --workspace-concurrency=2 to pnpm test commands
- Fix TaskCard tests: update mission badge title assertions to full titles
- Remove unused /api/mesh/state route
- Fix plugin-auto-label: add isError field, async onTaskCreated, "tests" keyword
- Fix plugin-ci-status: add module-level logger, tighten test assertions
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add PluginLifecycleEvent type and relay infrastructure in sse.ts
- Emit plugin lifecycle events (install, uninstall, enable, disable) via dashboard SSE
- Wire up plugin events in server.ts to broadcast to connected clients
- Add comprehensive tests for SSE plugin event relay and server integration
- Add .fusion/memory.md with plugin lifecycle documentation
- Add routineStore to ServerOptions for dependency injection
- Implement CRUD API routes for routines (create, list, get, update, delete)
- Add frontend API functions for routine management
- Include comprehensive route tests for all routine endpoints
- Update memory documentation with webhook HMAC testing pattern
- Add ChatManager class for managing chat sessions with AI agent integration
- Implement SSE streaming for real-time chat responses
- Add chat API routes for creating sessions, sending messages, and streaming responses
- Wire ChatStore and ChatManager into server initialization
- Add comprehensive test suite for all chat routes
- Add BlockedStateSnapshot typing/export and AgentStore persistence APIs for last blocked heartbeat state
- Deduplicate blocked-task heartbeat comments using blockedBy + context hash, and clear blocked snapshots when tasks are no longer blocked
- Thread triggeringCommentIds/triggeringCommentType through heartbeat execution, wake context, scheduler assignment triggers, and runtime wiring
- Trigger immediate heartbeat runs from task/steering comment routes for assigned immediate-response agents, with validation for comment wake fields on /api/agents/:id/runs
- Expand core, engine, and dashboard tests to cover blocked dedup logic, comment-triggered wakes, validation, and skip scenarios
- Enhance AiSessionStore cleanup logic to handle stale generating/awaiting_input sessions and remove expired records consistently
- Add a dedicated API route to trigger AI session cleanup and return cleanup results
- Wire scheduled server-side cleanup startup/shutdown behavior using configurable interval and TTL settings
- Expand dashboard tests to cover cleanup logic, route behavior, and cleanup endpoint scenarios
- Re-engage MissionAutopilot when a paused mission is resumed with autopilot enabled
- Wire mission autopilot into dashboard route setup so resume flows can trigger watcher start
- Extend mission e2e tests to cover autopilot mock shape and resume re-engagement behavior
- Add a patch changeset documenting the mission resume autopilot fix
- Add heartbeat stopRun support in the engine and wire it into the dashboard server lifecycle
- Add an agent run stop API route and client helper with route-level test coverage
- Add stop controls in AgentDetailView and AgentRunHistory with updated UI tests
- Add a changeset for @gsxdsm/fusion documenting the new stop run feature
- Replace dashboard calls to local getCurrentGitHubRepo helpers with getCurrentRepo from @fusion/core
- Update engine scheduler PR-monitor startup paths to use shared core repo resolution
- Remove duplicated remote parsing implementations from dashboard and engine packages
- Mark gap analysis finding 6.3 as resolved after centralizing parsing logic
- Update executor, triage, and merger prompt strings to identify the product as "fn"
- Align branch/worktree documentation examples with fusion/fn-* naming conventions
- Rename dashboard websocket attachment guard from __kbWebSocketsAttached to __fnWebSocketsAttached
- Refresh engine tests, dashboard utility comments, and TUI header text to remove stale kb wording
- Rename all pi extension tool registrations from kb_* to fn_* across task, mission, and agent tool families
- Update extension and skill-sync tests plus Fusion skill docs/workflows to assert and document the new fn_* tool names
- Align product-identity strings across core, dashboard, and CLI references, including GitHub import examples, User-Agent headers, and terminal TERM_PROGRAM
- Add a @gsxdsm/fusion minor changeset describing the extension tool-prefix rename
- Add shared ApiError class and response helpers for consistent error shape
- Migrate routes and mission-routes handlers to use standardized API errors
- Update server error middleware, rate limiter, and node metrics error handling to use shared helpers
- Expand dashboard tests with ApiError coverage and standardized response assertions
- Add a changeset documenting the @gsxdsm/fusion patch for API error shape standardization
- Add a new serve command implementation that runs the dashboard server in headless mode and exposes a health endpoint
- Register the serve command in CLI routing and extend bin command coverage for dispatch behavior
- Add comprehensive serve command tests for startup flow, options handling, and health-check responses
- Fix mission event ordering in MissionStore to keep health snapshots deterministic under concurrent updates
- Include a changeset for @gsxdsm/fusion documenting the new fn serve capability
- Add recoverable-session querying in AiSessionStore and cover it with targeted store tests
- Persist resume context (ip, initial plan, mission metadata) and rebuild planning/subtask/mission sessions from SQLite rows
- Rehydrate recoverable sessions at server startup and resume planning/mission interviews by recreating agents with replayed conversation context
- Update API flows to pass project root context and clean in-memory sessions when persisted sessions are deleted, with comprehensive regression tests
- Add aiSessionTtlMs and aiSessionCleanupIntervalMs project settings with defaults and bounds for cleanup scheduling
- Extend AiSessionStore cleanup to expire stale in-progress sessions, emit deletion events, and support start/stop scheduled cleanup loops
- Wire server startup/shutdown to load cleanup settings and manage the scheduled ai_sessions sweep lifecycle
- Align planning, subtask breakdown, and mission interview in-memory session retention to a 7-day TTL with shared deletion-driven cleanup
- Update schema/tests/docs for migration v15 ai_sessions indexing and end-to-end cleanup/TTL behavior stability
- Harden core AgentStore lifecycle behavior and heartbeat runtime integration paths
- Align dashboard agent APIs, server routes, and agent UI flows with the updated contract
- Tighten CLI agent/message command routing and validate payload handling semantics
- Expand test coverage across core, dashboard, engine, and CLI for route, heartbeat, and instruction regressions
- Wire heartbeatMonitor into ServerOptions and pass through to API routes
- Add POST /api/agents/:id/runs route to trigger heartbeat execution with optional source/triggerDetail
- Update API client startAgentRun to accept optional source and triggerDetail parameters
- Add Run Heartbeat button to AgentsView and enhance AgentDetailView RunsTab with execution details and polling
- Add route handler tests for agent runs and UI static analysis tests
- Support run history display with status, duration, trigger type, and result details
- Add heartbeat tolerance window to prevent false idle disconnects on terminal connections
- Increase client heartbeat interval from 30s to 45s for better idle tolerance
- Add session staleness detection on reconnect with idle state logging
- Add tests for heartbeat tolerance and client interval configuration
- Add changeset for patch release