Cleans up lint and type errors in the engine by removing unused imports from executor and merger, and replacing `any` types with proper type annotations in verification-utils.
Fusion-Task-Id: FN-3345
Heartbeat read non-existent split modelProvider/modelId fields while the
dashboard saves runtimeConfig.model as combined "provider/modelId", so
sessions fell through to pi's default model and failed with
"No API key for provider: openai-codex". Add extractRuntimeModel helper
that prefers the combined string and use it from heartbeat.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
A task whose previous run exhausted its merge budget (mergeRetries=MAX)
could land back in in-review with status=null, where the merger refused
it (canMergeTask false) and the ghost-review fallback bounced it back to
todo every taskStuckTimeoutMs (10 min) — beating the 30 min merge
cooldown reset. Each fresh execution now starts with mergeRetries=0.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The merge adds an auto-reload setting (FN-3334) with UI controls in the settings modal, documentation, and a new version-check module, while also fixing a bug (FN-3338) where extension providers incorrectly resolved the project root when invoked from git worktrees — moving the project-root resolutio
Fusion-Task-Id: FN-3338
Merges FN-3335 (worktree project resolution) and FN-3333 (spurious version reloads). The engine's `createFnAgent` now resolves project root from the worktree's cwd rather than the parent process, with `resolveProjectRoot` added to skill-resolver for consistency. The dashboard's `versionCheck` was up
Fusion-Task-Id: FN-3335
The verification-fix agent prompt previously forbade modifying files
unrelated to the failure, which blocked the natural fix when
deterministic merge verification failed because of stale/missing
plugin `dist/` outputs in sibling workspace packages (e.g.
`Failed to resolve import "./cli-spawn.js"` from
`fusion-plugin-hermes-runtime/dist`).
- Add explicit guidance to detect stale-artifact failure signatures
and rebuild the affected package(s) before editing source.
- Allow the agent to fix pre-existing breakage on the base branch,
preferring the smallest change that makes verification green.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Enriched agent heartbeat callbacks with a `reason` parameter propagated through the engine, in-process runtime, and dashboard components (AgentDetailView, AgentListModal, AgentsView). Added a new `agentHealth.tsx` utility and corresponding test file to surface the reason in UI health status, with te
Fusion-Task-Id: FN-3319
TS2352: Direct conversion from AuthStorage to Record<string|symbol, unknown>
no longer overlaps. Route through `unknown` so the proxy set trap continues
to forward writes to the underlying target.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The merge restores Claude usage tracking by introducing a Proxy-based auth storage with a fallback resolver that falls back to `models.json` API keys when the primary auth store lacks credentials. It also adds planning improvements with corresponding tests and a context limit detector enhancement, a
Fusion-Task-Id: FN-3305
Restores Claude usage tracking across the dashboard by integrating with Fusion Anthropic auth storage, and adds detection and testing for the `model_context_window_exceeded` stop reason to handle context limit errors gracefully. The work spans planning logic, usage tracking, mission management UI, a
Fusion-Task-Id: FN-3302
Merges FN-2999 research hardening (idempotent cancel/retry routes, aligned SSE event wiring, and cleaned status handling in the core research store and orchestrator) plus UI improvements to AgentDetailView header actions and planning disclosure UX in the modal, with a CSS token fallback fix in Scrip
Fusion-Task-Id: FN-2999
Merged FN-3207 and FN-3242: streamlined the memory backend by removing the runtime side-load pattern in `project-memory.ts` (simplified from 25+ lines), added regression tests across core, engine, and CLI bundle to catch the import issue at build time, and updated ChatView with a CSS fix for file me
Fusion-Task-Id: FN-3207
pi-coding-agent sets Skill.name to the parent directory (e.g. 'web-research'),
while Fusion uses two-segment names everywhere (e.g. 'web-research/SKILL.md')
from extractSkillName(), normalizeAgentSkills(), and toggleExecutionSkill().
The previous fix (c9043519) correctly switched matching from skill.filePath to
skill.name, but that only works when both sides use the same format. Since they
don't, all pattern/requested-name comparisons still failed, producing the
spurious 'not found in discovered skills' warnings.
Fix: add bareSkillName() helper that strips the /SKILL.md suffix before
comparison. Applied to all five comparison points in skill-resolver.ts:
- skillNameMatches() (pattern filtering)
- requestedSkillNames set lookup (name filtering)
- hasDiscoveredMatch() (configured-pattern diagnostic)
- discoveredBareNamesLower (requested-name diagnostic)
- excluded-path discovery check
`TriageProcessor.finalizeApprovedTask` (added in FN-3056) called
`store.updateTask({title})` while the task was still in column='triage',
which triggered a pre-existing regen path in `TaskStore.updateTask` that
overwrote the agent's just-written specification with the bootstrap stub
(`# {id}: {title}\n\n{description}\n`). Tasks shipped to `todo` (and
through to `done`) with empty 70–200 byte specs while the executor only
saw the original one-line user description. The same regen path also
silently dropped `## Review Level` / `## Frontend UX Criteria` and any
section outside a fixed whitelist whenever a non-triage task's title or
description was edited.
Replaces the regen with wrapper-shape-exact stub detection (compare to
the bytes `createTask` would have written for the pre-update title and
description) plus surgical edits for real specs: title changes splice
only the leading `# ...` heading, description changes rewrite only the
body of `## Mission`, and every other section is preserved verbatim.
`finalizeApprovedTask` now applies the prompt-declared title after
`moveTask("todo")` as defense in depth. New regression tests cover real
specs surviving title sync, long bootstrap stubs, stubs whose body
contains `##` markdown or `**Created:**` text, and the end-to-end
triage finalize sequence on a real `TaskStore`.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three related bugs that prevent agent skills from loading:
1. **Doubled "skills/" prefix in discovery** (skills-adapter.ts)
`discoverSkills()` unconditionally prepends "skills/" to the relative
path, but `baseDir` points to the parent of the skills directory
(e.g. `~/.fusion/agent`), so `relative()` already returns a path
starting with "skills/". Result: IDs like
`auto::skills/skills/web-research/SKILL.md` instead of
`auto::skills/web-research/SKILL.md`.
Fix: only prepend "skills/" when the relative path does not already
start with it.
2. **normalizeAgentSkills does not extract name from full ID**
(session-skill-context.ts)
The dashboard saves full skill IDs (e.g.
`"auto::skills/web-research/SKILL.md"`) into agent
`metadata.skills`. The runtime matches these against
`skill.name` (e.g. `"web-research/SKILL.md"`) — they never match,
so agent skills silently fail to load.
Fix: when an entry contains "::", parse out the skill name (last
two path segments) before matching.
3. **Pattern matching uses absolute filePath instead of skill name**
(skill-resolver.ts)
Settings patterns written by `toggleExecutionSkill()` are relative
(e.g. `"web-research/SKILL.md"`), but the resolver compares them
against `skill.filePath` which is absolute. Patterns can never
match, producing spurious "not found in discovered skills" warnings.
Fix: match patterns against `skill.name` (case-insensitive) with
fallback to exact `skill.filePath` match for backward compatibility.
Merges FN-3008 to add a "fallback-used" notification system: the engine now emits events when AI model fallbacks are triggered, dispatches notifications via ntfy/webhook providers, surfaces a session banner in the dashboard, and exposes a settings toggle to enable or disable these alerts.
Fusion-Task-Id: FN-3008
- pnpm build now excludes @fusion/desktop and @fusion/mobile by default
(recursive build still available as pnpm build:all). Saves time on
workspace-wide builds that don't need the native shells.
- Hoist the per-package max-worker computation into a shared
packages/core/src/__test-utils__/vitest-workers.ts util. Every
vitest.config.ts now calls computeMaxWorkers(), which honors
VITEST_MAX_WORKERS, FUSION_TEST_TOTAL_WORKERS, and a per-config
defaultCap, clamped to cpus-1.
- pnpm test sets VITEST_MAX_WORKERS=2 so the workspace run keeps total
fan-out modest with --workspace-concurrency=2.
- Switch dashboard vitest pool from forks to threads so jsdom/React
suites share a V8 heap instead of duplicating ~500MB per worker.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Refreshes the built-in model catalog feeding ModelRegistry with the
latest entries upstream pi-ai generates from models.dev (Anthropic,
OpenAI, Codex, Bedrock, etc.). No Fusion-side API changes; upgrades
applied in cli, dashboard, and engine package.json plus lockfile.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three merger fallback commit paths (auto-resolve-all-conflicts,
-X theirs/ours side strategy, AI-agent-didn't-commit) hard-coded
`feat(FN-XXXX): merge fusion/fn-xxxx` as the subject and never used
the AI subject summarizer. Route them through buildDeterministicMergeMessage
so they pick up aiSubject when available.
When the AI subject summarizer returns null, derive the subject from
the branch's first step commit (with conventional-commit prefix
stripped, plus `(+N more)` for multi-commit branches) instead of the
bare `merge <branch>` template.
Bump DEFAULT_COMMIT_SUBJECT_TIMEOUT_MS 15s → 30s so slow-first-token
providers complete instead of silently falling back.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This merge delivers the full draft planning feature (FN-3106) — API routes for planning subtasks, the AiSessionStore backend for draft sessions, a draft planning API client, auto-creation of planning drafts from user input, and corresponding UI polish in PlanningModeModal with accessibility-focused
Fusion-Task-Id: FN-3106
This merge brings FN-3155's plugin `createAiSession` API (types, DI hooks, engine adapter, context wiring, docs, and tests), FN-3056's task title sanitization, and FN-3129's tokenized footer and mobile initialization for MissionManager. It also adds CentralCore Docker node management, a new AddNodeM
Fusion-Task-Id: FN-3155
This merge ships several feature and infrastructure improvements across the codebase. Task title validation is strengthened in triage with stricter rejection of malformed titles and preference for prompt-declared titles (FN-3056), while task creation now preserves priority settings (FN-3210). The Mi
Fusion-Task-Id: FN-3056
- Add scheduler logic to create dependency-linked follow-up tasks when actionable PR feedback remains after a PR is merged or closed
- Update engine runtime/project wiring to support manual PR create flows and branch publish behavior for fusion/<task-id>
- Add dashboard route coverage for manual PR creation/linking behavior and corresponding engine/runtime tests
- Document manual PR branch conventions and follow-up behavior in task management and dashboard docs
Fusion-Task-Id: FN-3202
This merge implements a "preserve progress" option for task resets across the system. FN-3185 adds a `preserveProgress` flag to `moveTask` that keeps status/history when resetting tasks back to `todo`, with required explicit confirmation dialogs to prevent accidental resets. The feature is wired thr
Fusion-Task-Id: FN-3185
The merge restores the engine's unpause merge sweep logic in `project-engine.ts` and documents the soft-pause merge resume behavior across architecture and settings reference docs, with associated test coverage added.
Fusion-Task-Id: FN-3201
Merged FN-3076 introducing an auto completion-doc mode that automates task completion documentation. The feature adds a new setting to the settings schema and types, surfaces it in the dashboard Settings UI, provides triage-stage guidance to suggest completion documentation, and is documented in the
Fusion-Task-Id: FN-3076
Merges FN-3122's agents workspace redesign (split-pane layout, mobile responsiveness) and FN-3193's test infrastructure stabilization. The AgentsView and AgentDetailView components received major style and layout updates, with corresponding test coverage added. Several vitest config entries were con
Fusion-Task-Id: FN-3193
Documents the layered agent memory access system in the agents documentation, with a minor update to the engine tools reference guide to reflect the documented behavior.
Fusion-Task-Id: FN-3179
This release (v0.15.0) brings significant plugin system enhancements including a new dependency graph plugin with dashboard view, plugin skills in session selection, and extended plugin UI slot metadata. Database improvements add SQLite WAL tuning, integrity checks, and batch writes for agent logs.
Fusion-Task-Id: FN-3117
This merge brings FN-3173's SQLite stability improvements: WAL tuning pragmas for better concurrency, periodic integrity checks with self-healing recovery, and batched agent log writes to reduce I/O overhead. It also includes a new cron-runner for scheduled maintenance tasks, TUI mouse wheel scrolli
Fusion-Task-Id: FN-3173
Two follow-ups to the in-process backup interception:
- Previously the matcher only allowed a bare `npx` prefix, so the
canonical zero-install form `npx -y runfusion.ai backup --create`
(and any `npx --yes` / `-p <pkg>` / `--package=<pkg>` variant) fell
through to the legacy shell-out path. The matcher now consumes any
number of npx flags before the binary token so all canonical
invocations route through the in-process executor.
- Previously the matcher accepted arbitrary text after `--create` and
the runner silently dropped it. Authors writing
`fn backup --create && notify-send done` or
`fn backup --create | tee log` reasonably expected the trailing
side effect to fire. The matcher now refuses any command containing
shell continuations / redirections / substitutions
(`&&`, `||`, `|`, `;`, `>`, `<`, backticks, `$()`), and rejects
trailing positional arguments. Such commands shell out as the user
wrote them.
The matcher is now a small tokenizer rather than a regex collection,
so the contract is easier to read and the unit-test grid covers each
permitted prefix combination plus all the previously-unhandled shell
forms.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Demote the refresh message from console.error to debugMcp so it no
longer appears as an error in normal output.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two follow-up corrections to the in-process auto-backup interception:
- The matcher previously hijacked any `fn backup …` / `fusion backup …` /
`runfusion.ai backup …` form. The in-process replacement only knows how
to do `--create` + cleanup, so scheduling `--list`, `--cleanup`, or
`--restore <file>` would have silently executed a create instead of the
requested operation. The matcher is now anchored to `backup --create`
(with optional trailing flags), with positive/negative unit tests.
- Step-based automations (`AutomationStep` with `type: "command"`) also
shell out — the legacy-command interception alone left that path
vulnerable. `executeCommandStep` now applies the same in-process backup
detour, factored through a shared `runBackupActionInProcess` helper.
Independently, `runProbe` in fn-binary now spawns with `cwd: tmpdir()`.
The dashboard's `/system/fn-binary/status` route runs `<bin> --version`
on whatever fusion binary happens to be on PATH — older releases (e.g.
v0.13.0) initialise an engine and create a fresh `.fusion/<project>/
.fusion/` tree as a side effect. Pinning the probe's cwd to the OS temp
directory keeps any such artefacts off the developer's project.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The backup automation was scheduled with `npx runfusion.ai backup --create`, which spawns whatever fusion binary is on PATH. On developer machines that's usually an older globally-installed runfusion.ai (v0.13.0 at time of writing) which still carries the pluginStore-rootDir bug — every backup tick recreated `<project>/.fusion/.fusion/` with a fresh empty TaskStore.
Cron-runner and routine-runner now intercept any command matching `fn backup`, `fusion backup`, or `npx runfusion.ai backup` and call `runBackupCommand` directly via the engine's open TaskStore. The interception also handles existing schedules persisted with the old npx command, so users do not need to manually update their automation rows.
The default command for newly created backup schedules is also simplified to `fn backup --create` — both forms route through the same in-process executor.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
PluginStore expects a project-root path and appends `.fusion` itself, but the in-process runtime was handing it the already-resolved `.fusion` directory — producing a spurious `.fusion/.fusion/fusion.db` on every engine startup.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Merged feat(FN-3059) which aligns provider metadata and documentation across the codebase, updating README and getting-started docs plus refinements to the CustomProviderForm and ProviderIcon dashboard components.
Fusion-Task-Id: FN-3059
This merge adds readonly custom tool preservation (FN-3140) with new plugin SDK types and documentation, fixes PluginManager responsive overflow (FN-3093), and integrates the fn-3065 branch with enhanced plugin authoring capabilities. The core plugin-types module was significantly expanded with 230+
Fusion-Task-Id: FN-3140