5ff7a20738dbff400a730050a4ec6013b8d87682
2357 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
5ff7a20738 |
FN-7976: fix mailbox artifact open and view-task popups
Fix Mailbox/Artifacts media auth and ensure View task always opens a usable popup. - Add artifactMediaUrlWithToken for authenticated img/video/audio/link loads while keeping artifactMediaUrl token-free for fetch and HTML previews - Load script-capable HTML artifact previews via Authorization + revocable blob URL so tokens never reach allow-scripts iframes - Keep non-board/list task popups (Mailbox, Documents) visible even when board/list-only popup gating is enabled - Upgrade duplicate popOut entries so reopening a task refreshes snapshot and origin - Document the behavior and add a patch changeset Files changed: .changeset/fn-7976-mailbox-artifact-fixes.md | 7 +++ docs/dashboard-guide.md | 2 +- packages/dashboard/app/App.tsx | 15 +++-- .../app/__tests__/App.taskPopupViewGating.test.tsx | 10 ++- .../dashboard/app/__tests__/api-artifacts.test.ts | 12 +++- .../api/__tests__/legacy-artifact-media.test.ts | 27 ++++++++ packages/dashboard/app/api/legacy.ts | 21 +++++-- .../dashboard/app/components/ArtifactsGallery.tsx | 72 ++++++++++++++++++---- .../dashboard/app/components/DocumentsView.tsx | 4 +- .../app/components/MailboxArtifactAttachment.tsx | 6 +- .../dashboard/app/components/TaskDocumentsTab.tsx | 6 +- .../components/__tests__/DocumentsView.test.tsx | 31 ++++++---- .../__tests__/MailboxArtifactAttachment.test.tsx | 24 ++++---- .../app/components/__tests__/MailboxView.test.tsx | 8 +-- .../components/__tests__/TaskDocumentsTab.test.tsx | 16 ++--- .../app/hooks/__tests__/usePoppedOutTasks.test.ts | 9 ++- packages/dashboard/app/hooks/usePoppedOutTasks.ts | 17 +++-- 17 files changed, 206 insertions(+), 81 deletions(-) Fusion-Task-Id: FN-7976 Fusion-Task-Lineage: 4c25b3a6-5836-4629-b33e-647f213e3261 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
667f4c8a55 |
FN-7987: expose shared fusion toolset to chat agents and Grok CLI
Give dashboard chat and room responders the same safe coordination/productivity tools as other agent lanes, including via the Grok MCP bridge. - Export chat coordination tool factories from @fusion/engine for public use - Assemble createChatFusionToolset with board, delegation, web, goal, memory, and research tools - Wire the shared toolset into model-loop chat and room-responder sessions - Exclude destructive agent-lifecycle tools and fn_memory_append from chat - Cover chat fusion parity and Grok bridge tool preservation with tests - Document chat Grok tool parity and add a minor changeset Files changed: .changeset/fn-7987-chat-fusion-toolset.md | 7 ++ docs/agents.md | 1 + docs/grok-cli-contract.md | 2 +- packages/dashboard/src/__tests__/chat-manager.test.ts | 52 +++++++++++- packages/dashboard/src/chat.ts | 95 +++++++++++++++++++++- packages/engine/src/__tests__/agent-session-helpers.test.ts | 15 ++++ packages/engine/src/index.ts | 26 ++++++ plugins/fusion-plugin-grok-runtime/src/__tests__/tool-bridge.test.ts | 36 ++++++++ 8 files changed, 230 insertions(+), 4 deletions(-) Fusion-Task-Id: FN-7987 Fusion-Task-Lineage: 4d8d3dbc-10b8-4b56-9b63-79fe85a13755 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
d9843f75bc |
FN-7983: colocate project summarization model with summarization settings
Move the Project Summarization model lane and title-summarizer fallback next to the AI title/commit summarization controls in Project Models. - Extract shared project-lane renderer and keep default/merger/import-translate in the general Model Lanes list - Render summarization + title-summarizer fallback inside the AI summarization section with the same models-available guard - Add regression tests for colocation and empty-models guard - Update settings reference docs and add a patch changeset Files changed: .changeset/fn-7983-summarization-lane-colocation.md | 7 ++ docs/settings-reference.md | 6 +- .../app/__tests__/settings-sections.test.tsx | 61 ++++++++++ .../settings/sections/ProjectModelsSection.tsx | 126 ++++++++++++--------- 4 files changed, 142 insertions(+), 58 deletions(-) Fusion-Task-Id: FN-7983 Fusion-Task-Lineage: c473ba61-f003-401d-bc66-86f2078ba047 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
10b80453c4 |
FN-7978: share GitHub import dedup via sourceIssue-first helper
Unify GitHub issue import deduplication so prior imports stay marked after description edits or owner/repo casing changes. - Extract shared buildGitHubIssueSource and isGitHubIssueAlreadyImported helpers in dashboard github.ts (sourceIssue-first, case-insensitive repo, sourceMetadata + description URL fallbacks) - Route CLI import paths, extension tools, and dashboard single/batch import through the shared helpers - Drop local description-URL-regex-only importedUrls dedup; list existing tasks with slim:false for full provenance - Add regression coverage and changeset for the operator-facing fix Files changed: .changeset/fn-7978-github-import-dedup.md | 7 ++ docs/gitlab-parity-inventory.md | 2 +- packages/cli/src/__tests__/extension.test.ts | 12 ++-- .../task-command-github-import-tracking.test.ts | 6 ++ packages/cli/src/commands/__tests__/task.test.ts | 36 +++++++--- packages/cli/src/commands/task.ts | 82 +++++++++------------- packages/cli/src/extension.ts | 35 ++------- packages/dashboard/src/__tests__/github.test.ts | 22 +++++- .../dashboard/src/__tests__/routes-github.test.ts | 8 +-- packages/dashboard/src/github.ts | 62 +++++++++++++++- packages/dashboard/src/index.ts | 2 +- .../dashboard/src/routes/register-git-github.ts | 33 +-------- 12 files changed, 174 insertions(+), 133 deletions(-) Fusion-Task-Id: FN-7978 Fusion-Task-Lineage: 44f3d555-49fb-41e2-87d0-0a722462f132 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
f9c19f9f3a |
FN-7967: accept custom triage workflow IDs and honor project default
Allow triageDefaultWorkflowId and triageDecisionOnlyWorkflowId to accept custom workflow IDs so project default workflows are honored at triage time. - Change triage workflow settings from enum to string; empty triageDefaultWorkflowId inherits config.settings.defaultWorkflowId - Render triage prompt default from project settings unless an explicit stored override exists - Only pass stored triageDefaultWorkflowId into triage policy settings so declaration defaults do not clobber project defaults - Document settings behavior and add core/engine regression coverage - Add patch changeset for @runfusion/fusion Files changed: .changeset/fn-7967-triage-default-workflow.md | 7 +++++++ docs/settings-reference.md | 4 ++-- packages/core/src/__tests__/builtin-workflow-settings-triage.test.ts | 43 +++++++++++++++++++++++++++++++++++++++++-- packages/core/src/builtin-workflow-settings.ts | 35 ++++++++++++++++++++--------------- packages/engine/src/__tests__/triage.test.ts | 41 +++++++++++++++++++++++++++++++++++++++++ packages/engine/src/triage.ts | 28 ++++++++++++++++++++++++---- 6 files changed, 135 insertions(+), 23 deletions(-) Fusion-Task-Id: FN-7967 Fusion-Task-Lineage: e42ea061-889c-4bdd-8a9d-f56f34fc0c89 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
a75b2f4bb8 |
FN-7980: dismiss mobile task popups on swipe/back without leaving board
Register mobile task popups on the Fusion nav stack so browser Back, iOS edge-swipe, and Android Back close the popup and keep the board/list visible. - Push a modal nav entry when opening a mobile task popup and clean it up on close - Route FloatingWindow and shortcut closes through nav-aware popup close - Add swipe-back tests for board and list popup dismissal - Document popup Back behavior in the dashboard guide Files changed: docs/dashboard-guide.md | 3 +- packages/dashboard/app/App.tsx | 35 +++++++-- .../__tests__/TaskDetail.swipe-back.test.tsx | 84 +++++++++++++++++++++- 3 files changed, 114 insertions(+), 8 deletions(-) Fusion-Task-Id: FN-7980 Fusion-Task-Lineage: e321a1df-e271-41c0-81af-3560d759f7bb Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
0863c0fb58 |
feat(dashboard): auto-translate foreign-language GitHub issues on import (#2141)
## Why The Import Tasks panel routinely lists issues in languages the operator cannot read. Translation already shipped in #2128, but deliberately **opt-in and preview-only** — its header comment read *"Translation is opt-in (never automatic) so import provenance stays faithful until the operator asks."* This reverses that decision **behind a default-off setting**, so operators who never opt in keep byte-faithful import provenance. The superseded comment is kept and annotated rather than deleted, so the reason the rule changed stays in the code. ### The structural gap #2128 left `POST /github/issues/import` accepts only `{owner, repo, issueNumber}` and **re-fetches the issue server-side**. A translation held in React state could never reach the created task, and the in-memory cache died with the modal. That is why the cache here is server-side rather than in the hook — it's what makes "imported issues carry the translated version" actually true. ## What operators get Auto-translate is **off by default**. When enabled: - The **50 most recent OPEN** foreign-language issues translate on panel load — **list titles**, not just the preview, so the list reads in your language before you click anything. - Translations show **by default**, with a toggle back to the original (hover a translated list title to see the original). - Translations **persist until the issue closes**, so re-opening the panel neither waits nor re-bills. - **Both single and batch import** carry the translation, so the created task reads like the preview you approved. - A **target language** setting (unset = follow the dashboard language) and a dedicated **model lane**, so you can pin a cheap/fast model without dragging the summarization lane onto it. ## Notable decisions | Decision | Why | |---|---| | Detect **before** the model | An issue already in the target language is never sent. Without this, an English repo with the setting on would bill every issue to return its input unchanged. | | Detection moved to `@fusion/core` | The panel and the server must not disagree about which issues are foreign; two copies of a heuristic drift. | | Own rate-limit budget | Translation shared a 10/hour budget with refine/goal-draft. Fanning out per-issue would fail partway **and** starve refine for the hour. | | Cache keyed on a **source hash** | An edited issue misses the cache and re-translates instead of serving stale prose. | | Import is **cache-read only** | A miss imports the original. Import must never block on, or fail because of, translation. | | `project_id` leads the cache PK + full RLS contract | All projects share one flat `project` schema. `verification_cache`'s PK predates that discipline; this table does not copy that mistake. | ## Verification - ✅ `pnpm lint`, `@fusion/core` + `@fusion/dashboard` typecheck - ✅ `pnpm verify:fast` — build + scoped typecheck + real boot smoke (`/api/health`) - ✅ `pnpm test:gate` — 479 tests - ✅ 19 new tests covering the billing invariants (off/closed/same-language ⇒ **no model call**), cache hit/miss-on-edit, the 50 cap, and per-item fail-soft - ✅ `schema-applier` real-Postgres suite (46 tests) exercises migration `0010` and its isolation invariant **Pre-existing failures NOT touched** (confirmed red on `HEAD` before this branch): `AppearanceSection`'s task-popup test, and two PG-cutover keys (`sqliteMigrationNotice`, `postgresMigrationInboxMessageSentAt`) missing description mappings. I left the latter rather than guess an allowlist entry that could mask a real coverage gap. ## Reviewer notes - Short Latin-script prose (a one-line Spanish title) rates only *medium* confidence and won't auto-translate — the existing heuristic is deliberately conservative so English issues are never billed. CJK detects regardless of length. The threshold is the knob if you'd rather bias toward translating. - The RLS/isolation contract in migration `0010` is the part most worth a careful look. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
05151a25db |
feat: faster dashboard and serve startup (#2132)
## Summary Speeds up **time-to-HTTP-ready** for `fn dashboard` and `fn serve` after the PostgreSQL cutover without reintroducing the historical 3s cwd-engine race that degraded webhooks. - **Dashboard store share (serve parity):** inject the factory-booted `TaskStore` as `externalTaskStore` so cwd `ensureEngine` does not open a second pool; share only when store root matches project working directory (multi-project safe). - **Serve multi-project:** stop awaiting `startAll()` before listen; await only the primary engine; background the rest + reconciliation. - **Defer non-route-critical engine work:** ordered OAuth (refresh → monitor), automation schedule syncs, and auto-merge **enqueue** after the engine handle is returnable. - **Critical-path merge status clear:** still clear stale `merging`/`merging-pr` before ready so manual merge is not blocked after crash. - **Serve `--paused`:** apply `enginePaused` before `ensureEngine`/`startAll` (dashboard ordering). - **Stop safety:** generation counter so deferred tails cannot resume after `stop()` clears `shuttingDown`. - **Phase timing:** shared `phaseTime` helper, factory substep logs, serve time-to-listen. Plan: `docs/plans/2026-07-14-001-feat-faster-startup-plan.md` ## Test plan - [x] `packages/engine` — `project-engine-manager.test.ts` (path-matched external store) - [x] `packages/engine` — `project-engine-deferred-startup.test.ts` (status clear, OAuth order, stop generation) - [x] `packages/cli` — `startup-phase.test.ts` - [x] `packages/cli` — `serve.test.ts` (60 tests, including `--paused`) - [ ] Local: warm `fn dashboard` / `fn serve` and compare `startup phase *` / `time-to-listen` logs - [ ] `pnpm smoke:boot` (real serve `/api/health` on ephemeral port) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Performance** * Improved dashboard and serve startup times, including faster time-to-listen and time-to-ready. * Moved non-essential background initialization off the critical startup path. * Parallelized dashboard service initialization where possible. * **Reliability** * Improved multi-project startup handling and project selection. * Prevented cross-project task-store sharing. * Added safer shutdown behavior for partially completed startup. * **Diagnostics** * Added startup phase timing logs to help identify performance bottlenecks. * **Tests** * Expanded coverage for deferred startup, shutdown, project isolation, and startup timing. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
599a509d22 |
refactor: package code organization (god-file peels, wave 1) (#2139)
## Summary
First wave of package-internal code organization: split oversized
modules into domain-named files/folders while preserving public import
paths via re-exports, and refresh the line-count ratchet scoreboard.
- **Plan:**
`docs/plans/2026-07-14-001-refactor-package-code-organization-plan.md`
(multi-wave program; this PR lands U1–U4 + first U3/U6 slices)
- **Core types:** peel `types.ts` into
`types/{board,merge-queue,execution-and-ui,merge-policy,workflow-steps}.ts`
with browser-safe Vite alias preserved
- **Core TaskStore:** rename `remaining-ops-9` →
`task-commit-associations` (domain-named, not ordinal dump)
- **Engine executor:** peel pure helpers into
`executor/{browser-probe,requeue-loop,pseudo-pause,workflow-step-failures}.ts`
- **Engine heartbeat:** peel system prompts/procedures into
`agent-heartbeat-prompts.ts`
- **Ratchet:** one-time baseline truth-up + ratchet-down for touched
files
### Deferred to follow-up PRs (plan U5, U7–U9 + remaining waves)
- Self-healing folder split
- Further remaining-ops domain peels
- Dashboard `legacy.ts` / routes / UI monofiles
- CLI extension + TUI peels
## Test plan
- [x] `pnpm --filter @fusion/core exec tsc --noEmit`
- [x] `pnpm --filter @fusion/engine exec tsc --noEmit`
- [x] Focused vitest: `detect-pseudo-pause`,
`executor-browser-verification`, `clear-terminal-workflow-step-failures`
- [x] `node scripts/check-file-line-count.mjs` clean against updated
baseline
- [ ] CI merge gate (lint/typecheck/build/gate)
- [ ] Browser smoke: N/A for this PR (no dashboard UI route changes)
## Residual Review Findings
None. Review autofix applied dual-home wiring for
`clearTerminalWorkflowStepFailures` only.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added configurable heartbeat procedures for task and no-task scenarios
(including patrol-aware rendering).
* Improved agent-browser availability verification with clearer
availability/status reporting.
* Added detection for pseudo-pauses and review-handoff requests.
* Expanded core configuration/contract options for
execution/UI/localization, merges, merge queues, and workflow steps.
* **Bug Fixes**
* Improved handling of transient execute-requeue and workflow-step
retry/cleanup behavior, including better Windows path support.
* Preserved existing public interfaces during internal restructuring.
* **Documentation**
* Added a multi-phase roadmap for future package reorganization.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
|
||
|
|
85f8b1f909 |
feat: shared Postgres multi-node — retire mesh data-plane replication (#2130)
## Summary - Treat **shared PostgreSQL** (`DATABASE_URL`) as the multi-node durable data plane; mesh HTTP is membership + optional auth, not task/settings replication. - **Peer exchange**: under Postgres backend mode, write queue is **topology/auth-only**; non-topology pending rows fail rather than replaying multi-leader task/settings payloads. - **Mesh routes**: task-ID reserve/commit/abort always hit local shared allocator rows (ignore remote `coordinatorNodeId`); mesh sync ignores settings and only exchanges `authMaterial`. - **Docs**: rewrite multi-project runbook, shared cluster protocol, and architecture mesh sections for shared-Postgres + claims/leases. ## Context Follows the SQLite→Postgres cutover. Multiple Fusion nodes can share one external Postgres while keeping **per-node execution** (worktrees, processes, claims via `central.task_claims`). Explicit non-goals remain: scheduler failover and live process migration. Plan: `docs/plans/2026-07-15-001-refactor-mesh-shared-postgres-multinode-plan.md` ## Test plan - [x] `pnpm --filter @fusion/engine exec vitest run src/__tests__/peer-exchange-service.test.ts` - [x] `pnpm --filter @fusion/dashboard exec vitest run src/__tests__/mesh-routes.test.ts` - [x] `pnpm --filter @fusion/core exec vitest run src/__tests__/shared-mesh-state.test.ts` - [ ] CI gate (lint/typecheck/build/gate) - [ ] Manual (optional): two processes, same `DATABASE_URL`, create task on A visible on B; settings change without mesh settings sync; claim exclusivity ## Operator note Multi-node shared board requires **external** `DATABASE_URL` on every node. Default embedded Postgres is still single-host. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Improved multi-node deployments using shared PostgreSQL as the durable source of execution state. * Task ID reservation/commit/abort now run locally (no remote coordinator forwarding). * Mesh syncing now prioritizes topology visibility and authentication material; settings replication is disabled in shared-Postgres mode. * **Bug Fixes** * Prevented task/settings replication over mesh HTTP in shared-Postgres deployments. * Refined lease ownership, recovery, and reconciliation to converge via shared-database primitives. * **Documentation** * Updated architecture and shared-mesh protocol guidance, including multi-node setup and lease/task-ID allocation behavior. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
3e978e1540 |
fix: quiet per-poll scheduler hold-release and routing log spam
Both lines fired on every scheduler poll while nothing changed: a held card re-attempts release each sweep, and every dispatch candidate logged its resolved node. On a busy board that filled the operator log pane with "Hold release for FN-XXXX deferred" and "routed to node=local" within seconds, burying real scheduler events. Add a Logger.debug() level, off by default and opted into per subsystem via FUSION_DEBUG, and demote both lines to it. Routing to a remote node stays at info since it explains where work actually went; only the local default is demoted. Lines reporting a real transition (capacity rejection, racing sweep, release failure) are untouched. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
d893a026df |
FN-7971: hide GitLab import tab when GitLab is disabled
Hide the Import Tasks GitLab provider affordance when gitlabEnabled is off, coerce restored GitLab state to GitHub, and document the behavior. - Gate GitLab provider tab visibility on effective gitlabEnabled and wait for settings before replaying persisted GitLab auto-load - Coerce disabled GitLab provider preference to GitHub without firing GitLab fetch/import requests - Cover hide/show/coerce paths in GitHubImportModal tests and update dashboard guide copy - Add patch changeset for the published package Files changed: .changeset/fn-7971-hide-gitlab-when-disabled.md | 7 +++ docs/dashboard-guide.md | 4 +- .../dashboard/app/components/GitHubImportModal.tsx | 27 ++++++++-- .../__tests__/GitHubImportModal.test.tsx | 62 +++++++++++++++++++--- 4 files changed, 88 insertions(+), 12 deletions(-) Fusion-Task-Id: FN-7971 Fusion-Task-Lineage: e645a4a7-85e0-4635-8dad-f5839390e5c5 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
6e3a338cac |
FN-7968: defer slow cleanup off task deletion critical path
Make soft-delete return after the DB mutation while branch and agent cleanup run in the background. - Schedule cleanupBranchForTask after the soft-delete transaction instead of awaiting it under withTaskLock - Persist cleaned-branch log entries on the deleted row asynchronously; warn on deferred failures - Respond from DELETE /tasks/:id after deleteTask and schedule execution-agent binding release off the HTTP path - Add core and dashboard regression tests for non-blocking delete cleanup - Document the fast-path contract in architecture.md and add a patch changeset Files changed: .changeset/fn-7968-task-delete-latency.md | 7 + docs/architecture.md | 1 + .../task-delete-nonblocking-cleanup.test.ts | 160 +++++++++++++++++++++ packages/core/src/task-store/archive-lifecycle.ts | 57 +++++++- .../routes-task-delete-nonblocking.test.ts | 139 ++++++++++++++++++ .../src/routes/register-task-workflow-routes.ts | 19 ++- 6 files changed, 370 insertions(+), 13 deletions(-) Fusion-Task-Id: FN-7968 Fusion-Task-Lineage: f218a91e-aee3-46c9-a80f-182751b3ccc4 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
de25e32eac |
FN-7963: add plannerHeartbeatPatrolEnabled to gate idle heartbeat task creation
Add a workflow setting that disables idle/no-task heartbeat proactive task creation without turning off planner overseer stuck-task recovery. - Declare plannerHeartbeatPatrolEnabled (default true) in BUILTIN_OVERSIGHT_SETTINGS - Resolve the flag via resolveEffectivePlannerHeartbeatPatrolEnabled and wire it into agent-heartbeat/triage prompts - Render patrol-off instruction when disabled; keep FN-7962 outage backoff lines when patrol stays enabled - Cover setting defaults, prompt builders, and heartbeat executor paths with tests - Document the setting in settings-reference and add a changeset Files changed: .changeset/fn-7963-planner-heartbeat-patrol.md | 7 ++ docs/settings-reference.md | 11 +- packages/core/src/__tests__/agent-prompts.test.ts | 29 +++++ .../builtin-workflow-settings-triage.test.ts | 21 ++++ .../plannerHeartbeatPatrolEnabled-default.test.ts | 64 ++++++++++ packages/core/src/agent-prompts.ts | 55 +++++++-- packages/core/src/builtin-workflow-settings.ts | 14 +++ packages/core/src/index.gate.ts | 5 + packages/core/src/index.ts | 5 + packages/core/src/workflow-settings-resolver.ts | 15 ++- .../src/__tests__/heartbeat-executor.test.ts | 59 ++++++++- packages/engine/src/agent-heartbeat.ts | 135 +++++++++++++++++++-- packages/engine/src/triage.ts | 8 +- 13 files changed, 402 insertions(+), 26 deletions(-) Fusion-Task-Id: FN-7963 Fusion-Task-Lineage: c5e7a382-52c1-4cc1-8b21-aba7dc7d2b97 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
7a4a9c8229 |
fix(engine): auto-recover false-positive heartbeat-model-unavailable parks
Admit under-budget paused/heartbeat-model-unavailable agents to the shared heartbeatErrorRecovery budget so timer, self-healing, and startup paths retry without a manual Retry. Keep the pause reason when the budget is exhausted so operators still see credential guidance. |
||
|
|
e9f14bf024 |
perf: speed up local pnpm build and cap stacked verifications (#2134)
## Summary - Extend the workspace content-hash skip cache to **all** packages (not just plugins), with `--force` / `--full` flags - Default local CLI packaging to a **fast mode** (bin/extension + migrations only); full desktop/plugin/DTS staging runs on CI or `pnpm build:full` - Enable TypeScript `incremental` builds for warm recompiles - Add `maxConcurrentVerifications` (default **1**) so concurrent tasks cannot stack monorepo typecheck/build and peg CPU Warm `pnpm build` measured ~**126s → ~0.8s** when nothing changed. ## Test plan - [x] `node --test scripts/__tests__/build-workspace.test.mjs` (12 pass) - [x] `pnpm --filter @fusion/engine exec vitest run src/__tests__/verification-concurrency.test.ts` - [x] `pnpm --filter @fusion/core exec vitest run src/__tests__/settings-parity.test.ts` - [x] Local: first `pnpm build` rebuilds as needed; second warm `pnpm build` skips all packages (~0.8s) - [x] Fast CLI packaging logs skip of desktop/plugin staging without `FUSION_CLI_FULL_PACKAGE` - [ ] CI: `pnpm build` still full-packages under `CI=true` (plugin staging / release surfaces) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added a Scheduling setting to limit concurrent verification tasks from 1–8, with a default of 1. * Verification tasks now support cancellation while waiting or running. * Added options for forced and full workspace builds. * **Performance** * Local builds can skip unchanged packages and use incremental compilation for faster rebuilds. * Local CLI packaging is faster by default, while full packaging remains available when needed. * **Documentation** * Updated the settings reference with the new verification concurrency option. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
bc2d22df6e |
feat(dashboard): offer AI translation in Import Tasks preview (#2128)
## Summary Import Tasks can now offer on-demand AI translation when a selected GitHub or GitLab issue/PR title and body appear to be in a different language than the active dashboard locale. - Detect foreign-language content with a conservative client heuristic (Unicode scripts + Latin stopwords) - Show an opt-in banner: **Translate**, then **Show original / Show translation**, plus **Dismiss** - Call new `POST /api/ai/translate-text` (shared AI-helper rate limit with refine/draft) - Translation is **display-only** in the preview; imported task text stays the original source language ## Why Operators working in a non-English dashboard (or reading non-dashboard-language issues) needed a way to understand import candidates without leaving the preview or changing what gets imported. ## Test plan - [x] Unit tests for language detection (`detectContentLanguage`) - [x] Unit tests for translate request validation, response parsing, and AI agent path - [x] GitHub import modal: French content shows translate controls; English content does not - [x] Dashboard typecheck clean for app + server packages - [ ] Manual: open Import Tasks with dashboard language English, select a French/Korean issue, translate and toggle original - [ ] Manual: confirm Import still creates the task with original title/body - [ ] Manual: dismiss banner for a selection and confirm it stays dismissed for that item ## Notes - Comments are not translated (title + body only) - zh-CN / zh-TW share a CJK family so Chinese content does not prompt translation when the UI is either Chinese locale - Secondary locale catalogs have empty placeholders for the new `git.translate*` keys (runtime falls back to English) |
||
|
|
a242f1b449 |
fix(FN-7952): migrate bundled plugins to PostgreSQL (#2111)
## Summary Bundled plugins now persist shared runtime state in project-scoped PostgreSQL tables instead of maintaining independent SQLite authority. Reports, CLI Printing Press, Compound Engineering, Roadmap, Even Realities, and WhatsApp all follow the same ownership and startup contract as Fusion core. ## Design decisions - Plugin schema hooks run through the host’s PostgreSQL owner and enforce project isolation. - The SDK exposes the host contract needed by bundled plugins without importing engine internals. - Legacy Roadmap ownership fixtures use the supported empty-owner sentinel, preserving current composite primary/foreign keys while exercising backfill behavior. - The lockfile travels with the Even Realities PostgreSQL dependency so packaged installs remain reproducible. ## Validation - All six affected plugin builds pass. - Affected plugin suites pass: 773 tests across Printing Press, Compound Engineering, Even Realities, Reports, Roadmap, and WhatsApp. - `pnpm test:gate` passes all 478 gate tests. - This PR changes 40 files. ## Stack - Depends on #2110 → #2109 → #2108. - The documentation/release PR completes the stack. Related: #2105 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Breaking Changes** * PostgreSQL is now required for runtime storage; SQLite files are used only as one-time migration inputs. * The legacy `FUSION_NO_EMBEDDED_PG` fallback has been removed. * **New Features** * Added project-isolated PostgreSQL storage for plugins, reports, tasks, notifications, and other plugin data. * Added agent tools for reports and CLI service drafts. * Added PostgreSQL schema initialization support for plugin authors. * **Bug Fixes** * Improved migration and recovery of legacy plugin state. * Prevented cross-project data access and strengthened transactional schema updates. * **Documentation** * Updated storage, migration, deployment, plugin authoring, CLI, and dashboard guidance for PostgreSQL. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
4f037679ad |
feat: planner overseer session advisor (OMP advisor parity) (#2082)
## Summary Adds a **session advisor** to the planner overseer so Fusion can review live executor transcripts the way [oh-my-pi’s advisor](https://github.com/can1357/oh-my-pi/tree/main/packages/coding-agent/src/advisor) does — without replacing the existing lifecycle supervisor (stage watch, retry, merge confirmation, human-control withhold). ### What ships - **Emission guard** (`OverseerEmissionGuard`) — content-free phrase filter, session dedupe with severity-rank escalation, one accept per advisor update - **Session delta runtime** — queues agent-log deltas, drains through an advisor agent, drops backlog after 3 failures - **Session advisor service** — model gate, level matrix (`observe` / `steer` / `autonomous`), human-control re-check at inject, `[session-advisor]` steering comments - **OVERSEER.md / WATCHDOG.md** discovery for project review priorities - **AgentLogger `onEntriesFlushed`** + poll-backed agent-log cursor for durable deltas - Workflow settings: `plannerOverseerAdvisorProvider` + `plannerOverseerAdvisorModelId` (both required; empty = soft-disabled for cost safety) - Docs + changeset ### What does not ship (deferred) - Multi-advisor YAML roster, mutating advisor tools, reviewer/merger shadowing, true tool-abort interrupt ### Plan `docs/plans/2026-07-13-001-feat-overseer-advisor-parity-plan.md` ## Enablement 1. Set workflow **Session advisor model provider** + **Session advisor model id** 2. Oversight level `observe` (log only), `steer`, or `autonomous` (inject) 3. Optional: add `OVERSEER.md` or `WATCHDOG.md` in the project ## Test plan - [x] `pnpm --filter @fusion/core exec vitest run src/__tests__/overseer-emission-guard.test.ts` - [x] `pnpm --filter @fusion/engine exec vitest run` overseer-* unit tests (21 tests) - [x] Related planner-overseer / intervention regression tests - [x] `@fusion/engine` + `@fusion/core` typecheck - [ ] Manual: configure advisor model, run an executor task, confirm `[session-advisor]` inject + timeline metadata when concern is raised ## Residual Review Findings None from autofix pass (log-cursor ordering fix already committed). <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added an off-by-default “session advisor” that can review live execution activity and provide severity-based guidance. * Added project and per-task controls to enable it, including a default enable switch and Quick Add / Task Detail toggles. * Enhanced advisor prompting by discovering and incorporating `OVERSEER.md`/`WATCHDOG.md` review files. * **Documentation** * Added architecture and settings documentation for the new session-advisor parity behavior. * **Bug Fixes** * Improved fail-soft handling so advisor behavior won’t disrupt execution. * Fixed concurrent PostgreSQL migration startup failures. * **Tests** * Added coverage for advice parsing, emission guarding, runtime behavior, and watchdog discovery. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
9bdbdc5f16 |
FN-7955: stage bundled plugin skills
Ensure bundled Compound Engineering skills are present in published CLI packages. - Copy plugin src/skills directories into dist/plugins/<id>/skills during CLI packaging. - Add bundle-output coverage that verifies Compound Engineering SKILL.md files stage and resolve from the plugin root. - Document runtime-read bundled plugin asset staging and add a patch changeset for @runfusion/fusion. Files changed: .changeset/fn-7955-ce-skills-published.md | 7 ++++ docs/PLUGIN_AUTHORING.md | 3 ++ packages/cli/src/__tests__/bundle-output.test.ts | 51 ++++++++++++++++++++++++ packages/cli/tsup.config.ts | 14 +++++++ 4 files changed, 75 insertions(+) Fusion-Task-Id: FN-7955 Fusion-Task-Lineage: 32c4ad31-4f3a-478b-996f-ce6bcafd1e27 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
d0ce7829c0 |
FN-7953: fix mobile OAuth code submit taps
Submit Anthropic OAuth manual codes on the first mobile tap instead of requiring keyboard dismissal first. - Add a reusable touch action gesture hook that handles touch/pointer activation before synthetic clicks. - Wire the OAuth manual code Submit button to invoke submission on the first touch while preventing duplicate click handling. - Cover the mobile double-tap regression and document the UI bug pattern for future fixes. Files changed: .../oauth-manual-code-mobile-double-tap-submit.md | 60 +++++++++++ .../app/components/OAuthManualCodeForm.tsx | 31 +++++- .../__tests__/OAuthManualCodeForm.test.tsx | 110 +++++++++++++++++++++ .../hooks/__tests__/useTouchActionGesture.test.ts | 110 +++++++++++++++++++++ .../dashboard/app/hooks/useTouchActionGesture.ts | 89 +++++++++++++++++ 5 files changed, 399 insertions(+), 1 deletion(-) Fusion-Task-Id: FN-7953 Fusion-Task-Lineage: d387cdbd-25a7-4b7d-add6-27a1ded5cbea Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
dff864e098 |
feat: harden permanent-agent heartbeat instructions (#2081)
## Summary Hardens permanent-agent operating law while keeping the heartbeat/executor split: - **Critical Rules** in task-scoped and no-task heartbeat system prompts (survive custom `HEARTBEAT.md`) - Stronger default procedures: disposition checklist, scoped-wake, blocked dedup, progress note style - **Wake Delta multi-assign inventory** (ranked, cap 8, coordination-only framing) + `checkout_conflict` regression test - Standing instructions six-section template for blank custom create / empty detail insert - Onboarding interview guidance to prefer structured `instructionsText` - Playbooks, CONCEPTS, agents.md accuracy; remove stale agent gap-analysis doc Plan: `docs/plans/2026-07-12-001-feat-permanent-agent-heartbeat-instructions-plan.md` ## Test plan - [x] `pnpm --filter @fusion/core exec vitest run src/__tests__/assigned-task-ranking.test.ts` - [x] `pnpm --filter @fusion/engine exec vitest run src/__tests__/agent-heartbeat-procedures.test.ts src/__tests__/heartbeat-executor.test.ts -u` - [x] `pnpm --filter @fusion/dashboard exec vitest run app/components/__tests__/standing-instructions-template.test.ts` - [ ] CI gate green on PR ## Residual Review Findings None recorded at open (inline review; no residual sink). <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added ranked multi-assignment context to agent heartbeat wake-ups, including task status, ownership, and lease details. * Added standing-instructions templates for creating and editing permanent agents. * Improved onboarding guidance with a consistent six-section instruction structure. * Added clearer heartbeat handling for blocked tasks, no-task runs, and checkout conflicts. * **Documentation** * Added permanent-agent heartbeat playbooks and expanded coordination glossary entries. * Updated documentation indexes and heartbeat behavior guidance. * **Tests** * Added coverage for task ranking, instruction templates, wake-up context, and conflict handling. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
b563b12662 |
feat: add Oh My Pi (omp) ACP runtime plugin (#2083)
## Summary - Add `fusion-plugin-omp-runtime` so Fusion agents can run through operator-installed **Oh My Pi (`omp`)** over the [Agent Client Protocol](https://omp.sh/docs/acp) (`omp acp`). - Wire staged/bundled install, Settings → Authentication card (enable + binary path), model discovery (`omp models` → `omp-cli/*`), and MCP eligibility for runtime id `omp`. - Forward Fusion `systemPrompt` via ACP `session/new` `_meta.systemPromptOverride`. ## How operators use it 1. Install/auth `omp` (credentials under `~/.omp`). 2. Enable **Oh My Pi — via omp ACP** in Settings → Authentication (optional binary path). 3. Set agent **Runtime Source → OMP Runtime** (`runtimeHint: "omp"`), or pick an `omp-cli/*` model when enabled. ## Known v1 gaps - No Grok-style Fusion `fn_*` loopback tool bridge yet (operator MCP is forwarded; in-process custom tools are not). - Model is fixed at spawn (`omp --model … acp`); no mid-session Fusion model switch. ## Test plan - [x] `pnpm --filter @fusion-plugin-examples/omp-runtime test` (unit + live ACP when `omp` is on PATH) - [x] Auth routes: `POST /api/auth/omp-cli`, `GET /api/providers/omp-cli/status` - [x] Engine `runtimeSupportsMcp("omp")` - [ ] Manual: enable card in dashboard, select OMP runtime on an agent, run a short chat turn <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added Oh My Pi (OMP) CLI support as an ACP-backed runtime and model provider, including model discovery and probing. * Added dashboard auth/status controls to enable OMP, check readiness, and configure the local binary path (with validation). * Exposed OMP custom `fn_*` tools via an MCP loopback bridge, plus optional filesystem capabilities and stricter tool permission gating. * **Documentation** * Added/expanded OMP runtime contract and integration docs (including the ACP session/handshake flow). * **Tests** * Added Vitest coverage for settings wiring, provider status, model discovery, runtime sessions, permissions, MCP bridging, and live connectivity. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
03966ecb79 |
Fix multi-project branch-group route store scoping (#2085)
## Summary Conflict resolution for closed [#2074](https://github.com/Runfusion/Fusion/pull/2074) (FN-001 multi-project branch-group store scoping), rebased onto current `main`. #2074 closed when its fork head was briefly reset to `main` during a ref update; maintainer write access to the fork head only works while the PR is open, so that PR could not be reopened without new fork commits. This branch carries the same fix: - Request-scoped `TaskStore` for branch-group list/read/assign/promote/abandon - Integrated reconcile/close uses the request store for cwd + persistence - Compatible with async branch-group store APIs and main’s CentralProjectIdentity (`projectId` trim) - Postgres durable FN-7438 tests + padded `projectId` regression ## Verification - `FUSION_DASHBOARD_DEEP=1 pnpm --filter @fusion/dashboard exec vitest run --project dashboard-api src/__tests__/routes-branch-groups.test.ts src/__tests__/integrated-routers-group-pr-token.test.ts src/__tests__/routes-context-project-identity.test.ts --silent=passed-only --reporter=dot` — 3 files, 41 tests passed. --------- Co-authored-by: Tchorizo <295840812+Tchorizo@users.noreply.github.com> Co-authored-by: Fusion <noreply@runfusion.ai> |
||
|
|
c15c78feeb |
feat: migrate storage from SQLite to PostgreSQL (#1793)
# Migrate storage from SQLite to PostgreSQL — full dashboard cutover Migrates Fusion's storage layer to the embedded PostgreSQL `AsyncDataLayer` (the default backend) and **completes the satellite-store + feature cutover** so every dashboard and Command Center surface works in PG mode. ## Status — every surface works in embedded-PG mode Verified live against a running embedded-Postgres dashboard (all **200**, zero 5xx) and gate-tested (**23 files / 99 tests** on embedded PG, plus engine-core 294 and ci-shape 63 in the blocking merge gate; core/engine/cli/dashboard typecheck clean). | Area | Surfaces | State | |---|---|---| | Satellite stores | workflows, todos, insights, research, missions, goals, mailbox | ✅ | | Views | artifacts, documents, evals | ✅ | | Command Center | activity, productivity, team, tokens, tools, **workflows**, **github**, **signals**, **plugin-activations**, **live** (all 10) | ✅ | | Run execution | insight generation, research run execution | ✅ (store-path; AI step needs a provider) | | Live updates | SSE push for mission/research/insight events | ✅ | | Workflow editing | create / update / delete / select (+ id counter) | ✅ | | Engine | mission autopilot, incident-signal ingestion, regression storm-guard, agent wake-on-message | ✅ | | Core | tasks, agents, secrets, automations, memory, chat, usage, PRs, git | ✅ | ## Approach Each satellite store gets an `Async<Store>` wrapper exposing the sync store's method names over the existing `async-*-store.ts` helpers; `get<Store>Store()` returns a `Sync | Async` union; consumers `await` (harmless on sync), and engine/CLI paths that can't convert use `instanceof Sync` graceful fallback. Analytics aggregators branch on `"ping" in dbOrLayer` to run schema-qualified raw SQL over `project.*` (snake_case) in PG. Executors/orchestrators/autopilot are await-converted to drive the union store; the async store wrappers extend `EventEmitter` so SSE live-push fires in both backends. Not-yet-ported capabilities degrade gracefully (never 500) and are individually called out in commits. ## Sync with main The branch is kept continuously merged with `main` (currently through FN-7845, 2026-07-12); the earlier "final rebase deferred" note no longer applies. Use **Create a merge commit** (or squash) to land it — GitHub's rebase-merge cannot replay a merge-maintained branch. ## Residual Review Findings Multi-agent code review of the PostgreSQL satellite-store ports (U1–U5) applied 3 safe fixes (see `fix(review): apply autofix feedback`). The following are **real but gated** — recorded here as follow-up work rather than auto-applied. All are SQLite→PostgreSQL **concurrency/atomicity regressions**: the sync stores were immune only by SQLite's single-writer, single-threaded-handler execution; the async ports open multi-await read-modify-write windows. **Reachability is low today** because the execution engines that generate concurrent same-run mutations (insight run executor, research orchestrator/dispatcher) are `instanceof`-gated to sync mode in PG. No process-crash class survived (all engine fallbacks correctly guard the sync store). - **[P1] Research `appendResearchEvent` dual-write is non-atomic** (`packages/core/src/async-research-store.ts`, corroborated: adversarial + reliability). The `research_run_events` insert (own transaction) and the `run.events` jsonb update are separate writes — a crash between them, or two concurrent appends, splits the table count from the jsonb array. **Fix:** perform the seq-insert and the jsonb update in one `layer.transactionImmediate`. - **[P1] Research run terminal-reversion via stale full-row persist** (`async-research-store.ts` `persistResearchRun`/`updateResearchStatus`). Concurrent `PATCH /runs/:id/status` + `POST /runs/:id/events` can revert a terminal run to `running` by overwriting the whole row, bypassing the transition guard. **Fix:** scoped column `UPDATE`s with a `WHERE status …` guard, or optimistic version column. - **[P2] `updateResearchRun`/`updateInsightRun` read-then-write TOCTOU** — concurrent PATCHes last-writer-wins on the lifecycle merge. **Fix:** `SELECT … FOR UPDATE` / enclosing transaction. - **[P2] `upsertRun`/`createRunOrThrowConflict` check-then-create race** (`async-insight-store.ts`) — two callers can each create an "active" run. **Fix:** partial unique index on `(projectId, trigger) WHERE status IN ('pending','running')`. - **[P3] `createResearchRetryRun` return-value divergence** — sync returns the pre-update `queued` snapshot; async returns the reloaded `retry_waiting` run (persisted state is identical). Pick one side for cross-backend parity. - **[P2/perf] Mission `getMissionWithHierarchy`/`getMissionHealth` N+1 fan-out** — O(milestones×slices) sequential round-trips hold one pool slot per request; can starve the pool for large hierarchies. **Fix:** batched/joined reads. - **Testing gaps:** no PG-mode concurrency tests (interleaved status/event mutations), no sync↔async parity assertion for the lifecycle-error codes, and no mission status/health rollup parity test vs the sync `MissionStore`. ~~Out of scope (deferred): AI run *execution* (insight/research) + mission autopilot + live SSE mission events remain sync-gated/degraded in PG mode.~~ **Since ported** — insight/research run execution, mission autopilot, and SSE live push all run on the async layer now, which also makes the concurrency findings above genuinely reachable; they remain open follow-ups. --- ## Update — 2026-07-12: production-readiness hardening & live acceptance Everything below landed on this branch since the description above was written: **Production blockers from review — fixed** - `recoverStaleTransitionPending` ported to the async layer (backend moves write + clear the crash-safe marker; startup/maintenance sweeps no longer throw). - Lost-update class fixed: `atomicWriteTaskJson`/`WithAudit` write changed columns only (full-row upserts silently resurrected stale fields across concurrent store instances — the "task stuck unplanned forever" bug). - First-boot **auto-migration**: booting the PG backend over a project with a legacy `fusion.db` migrates it automatically (loud failure, SQLite kept as backup), and the dashboard shows a one-time **"your data was migrated" banner** with the backup paths and a Need-help Discord link. - `pg_dump`/`pg_restore` discovered from common install locations for embedded-mode backups. - The PG suite is part of the blocking merge gate (`test:pg-gate`). **Multi-project isolation (PR #2007, merged into this branch)** - `project_id` partition key on tasks / archived tasks / config, `taskProjectScope` threaded through every scan/claim/count, per-project config rows, layer bound to the project at startup. - Review P1 follow-up: the shared cold-storage `archive.archived_tasks` table is also partitioned and all archived-board reads/counts/searches are scoped. - Schema drift self-heal generalized to schema-qualified columns so existing databases upgrade in place. **Other changes** - Node settings sync **removed** in PG mode (409 `settings-sync-disabled-postgres`) — nodes share state by connecting to the same database; auth sync kept (per-machine file). - Perf (review findings): `listTasks` pushes column filter + ORDER BY + LIMIT/OFFSET into SQL; `getConversation` capped to the most recent 200 messages. - Fixed a false "operator action required" pause-abort log fired on every successfully auto-merged task. **Live acceptance — PASSED (2026-07-12)** A sandboxed instance (isolated HOME, embedded PG, real Opus executor) ran a task through the complete cycle: create → triage (AI spec) → execute → in-review → AI squash-merge landed on the project's `main` → done. A write+read sweep of every data surface (settings, comments, documents, attachments + artifact bridge + artifact edit, chat with real generation, goals, missions, agent mail, secrets, workflows, memory, CC analytics) was green on embedded PG. **Known remaining work** - The per-project `config` PK re-key has no upgrade path for pre-isolation embedded-PG databases (needs a real `DROP CONSTRAINT`/re-key migration; fresh databases are fine). - `pg_dump`/`pg_restore` binaries are not yet bundled in release artifacts (PATH/common-location discovery only). - The satellite-store concurrency findings listed above. --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: Phil Larson <hello@phillarson.xyz> Co-authored-by: fusion-merge <fusion-merge@local> |
||
|
|
6e0fde860c |
FN-7949: fix deleted planning-mode session resurrecting after in-flight generation completes
Adds a bounded-TTL delete tombstone to AiSessionStore so a straggling post-delete generation write can never resurrect a session the user explicitly deleted. - AiSessionStore now records a 10-minute delete tombstone (id -> deletion timestamp) in delete(), deleteByIdAndType(), and bulk cleanup paths (cleanupOld/cleanupStaleSessions/emitDeletedSessions). - upsert() checks the tombstone first and drops (no-ops) any write for a tombstoned id without touching SQLite or emitting ai_session:updated, fixing the root cause once in the shared store rather than per-producer (planning.ts, subtask-breakdown.ts, mission-interview.ts, milestone-slice-interview.ts). - Tombstone entries are pruned lazily on check and piggyback on the existing cleanupStaleSessions() cadence so the in-memory map cannot grow unbounded. - Adds a changeset (patch) documenting the user-facing fix. - Updates docs/architecture.md and docs/storage.md with the new "AI session delete tombstones" behavior. - Adds regression tests covering the tombstone guard in ai-session-store.test.ts and routes-planning.test.ts. Files changed: .changeset/fn-7949-ai-session-delete-tombstone.md | 7 + docs/architecture.md | 2 +- docs/storage.md | 12 +- packages/dashboard/src/__tests__/ai-session-store.test.ts | 145 +++++++++++++++ packages/dashboard/src/__tests__/routes-planning.test.ts | 200 ++++++++++++++++++++- packages/dashboard/src/ai-session-store.ts | 83 +++++++++ 6 files changed, 446 insertions(+), 3 deletions(-) Fusion-Task-Id: FN-7949 Fusion-Task-Lineage: 8e509dae-0cc5-46cd-9c4b-9048cfda56d3 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
4e7e013d6f |
FN-7947: add Plan action to context menu for pre-execution task cards
Adds a Plan action to Board/List task context menus so triage/hold/intake cards can jump straight into Planning Mode without duplicating a task. - Add `onPlan` handler and `isPreExecutionHoldColumn` gate to `TaskContextMenu` so Plan only appears for pre-execution (triage/intake/hold) columns, and only when a host wires the handler - Wire the Plan action through `Board.tsx`, `Column.tsx`, `ListView.tsx`, and `WorktreeGroup.tsx` so both board and list views expose the new menu item - Surface the Plan entry point on `TaskCard.tsx` - Add test coverage in `TaskContextMenu.test.tsx`, `TaskCard.test.tsx`, and `ListView.test.tsx` for the new gating/wiring behavior - Document the new action in `docs/dashboard-guide.md` - Add a minor changeset for `@runfusion/fusion` Files changed: .changeset/fn-7947-plan-context-menu-action.md | 7 ++ docs/dashboard-guide.md | 10 ++- packages/dashboard/app/components/Board.tsx | 10 ++- packages/dashboard/app/components/Column.tsx | 4 + packages/dashboard/app/components/ListView.tsx | 15 +++- packages/dashboard/app/components/TaskCard.tsx | 24 +++++- packages/dashboard/app/components/TaskContextMenu.tsx | 18 ++++ packages/dashboard/app/components/WorktreeGroup.tsx | 9 ++ packages/dashboard/app/components/__tests__/ListView.test.tsx | 21 +++++ packages/dashboard/app/components/__tests__/TaskCard.test.tsx | 96 ++++++++++++++++++++++ packages/dashboard/app/components/__tests__/TaskContextMenu.test.tsx | 32 ++++++++ 11 files changed, 236 insertions(+), 10 deletions(-) Fusion-Task-Id: FN-7947 Fusion-Task-Lineage: 41c759a2-e76b-4771-9421-c9805c4596e5 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
7cc622bed2 |
FN-7946: auto-retry stuck Planning Mode AI generation up to 3 times
Planning Mode now automatically retries a stuck or terminally-errored AI generation session up to three times before falling back to the permanent Retry/Dismiss error panel, reducing manual retries for transient failures. - Add a bounded (MAX_PLANNING_AUTO_RETRIES = 3) client-side auto-retry that reuses the existing /planning/:id/retry endpoint whenever the SSE stream's onError, a session reload, or the stuck-session poll observes a terminal "error" status. - Track the retry budget in refs (planningAutoRetryAttemptRef, planningAutoRetryInFlightRef) so async SSE/poll/loadSession handlers share a single in-flight guard, with the current attempt mirrored into state (isAutoRetrying/autoRetryAttempt) for the UI. - Reset the retry budget whenever the session makes real progress (reaches a new question or a completed summary), and surface the permanent Retry/Dismiss error view once the budget is exhausted. - Show a "Retrying... (attempt N of 3)" loading message while an automatic retry is in flight, distinct from the manual Retry button state. - Fix a stuck-poll edge case where a terminal error discovered only by the poll (missed SSE event) after the auto-retry budget was exhausted left the modal spinning on "Generating next question..." forever instead of showing the error view. - Document the new auto-retry behavior in docs/dashboard-guide.md and add a minor changeset for @runfusion/fusion. - Extend PlanningModeModal.planning-flow.test.tsx with coverage for the auto-retry budget, single-flight behavior, and the poll-discovered terminal-error fallback. Files changed: .changeset/fn-7946-planning-auto-retry.md | 7 + docs/dashboard-guide.md | 3 + .../dashboard/app/components/PlanningModeModal.tsx | 339 ++++++++++++++------ .../PlanningModeModal.planning-flow.test.tsx | 353 ++++++++++++++++++--- 4 files changed, 567 insertions(+), 135 deletions(-) Fusion-Task-Id: FN-7946 Fusion-Task-Lineage: 42e911dc-9639-46ab-bb4f-bc9060413140 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
f0888d43c3 |
FN-7945: route List-view task opens through the movable popup when Open tasks as popups is on
Extends the existing board/right-dock "Open tasks as popups" routing so ordinary List row/card and keyboard opens use the same shared movable/resizable FloatingWindow instead of the docked split-pane/mobile detail. - Add openMobileTasksInPopup prop to ListView, threaded through App -> MainContent -> ListView (dashboard/types.ts) - handleRowClick routes to onPopOut (popOutTaskDetail) when the setting is on, on both desktop split-pane and mobile/tablet single-pane; docked behavior is preserved when the setting is off - Restore Enter/Space keyboard activation on list rows to invoke the same handleRowClick path, alongside existing context-menu key handling - Update docs/dashboard-guide.md and docs/settings-reference.md to describe List row/card opens as part of the popup routing surface, and refresh the Appearance settings help copy/FNXC comment accordingly - Add changeset (.changeset/fn-7945-list-view-task-popup.md, minor) describing the user-facing behavior - Extend ListView.test.tsx coverage for the new popup routing and restored keyboard activation Files changed: .changeset/fn-7945-list-view-task-popup.md | 7 ++ docs/dashboard-guide.md | 4 +- docs/settings-reference.md | 2 +- packages/dashboard/app/App.tsx | 1 + packages/dashboard/app/components/ListView.tsx | 48 +++++++++---- .../app/components/__tests__/ListView.test.tsx | 80 +++++++++++++++++++++- .../app/components/dashboard/MainContent.tsx | 2 + .../dashboard/app/components/dashboard/types.ts | 1 + .../settings/sections/AppearanceSection.tsx | 4 +- 9 files changed, 127 insertions(+), 22 deletions(-) Fusion-Task-Id: FN-7945 Fusion-Task-Lineage: 784cb4ee-c493-4ace-bf8b-0e3dbaaef9a3 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
7246df22f6 |
FN-7944: add setting to keep task popups attached to their Board/List view
Adds an opt-in project setting so open task-detail popups stay attached to the Board or List view where they were opened, instead of floating over every main-content view. - New project setting taskPopupsBoardListOnly (default: off) in settings-schema.ts and ProjectSettings type, with default preserved via settings-defaults tests. - usePoppedOutTasks now stores each popup's originating TaskView alongside its task snapshot (PoppedOutTaskEntry), keeping legacy tasks output for existing callers. - App.tsx adds isTaskPopupVisibleForView() gating helper and filters popped-out entries to the current view for rendering/keyboard-close handling, while hidden popups remain mounted in hook state (not cleared) so switching back to the originating view restores them with shared persisted geometry. - Settings -> Appearance gets a new "Keep task popups on their Board/List view" checkbox (AppearanceSection.tsx) with i18n strings and updated settings search text in SettingsModal. - Documentation updated in docs/dashboard-guide.md and docs/settings-reference.md to describe the render-only hide/restore behavior. - New/updated tests: App.taskPopupViewGating.test.tsx, usePoppedOutTasks.test.ts, AppearanceSection.test.tsx, settings-default-descriptions.test.tsx, settings-defaults.test.ts. Files changed: docs/dashboard-guide.md | 5 +- docs/settings-reference.md | 1 + .../core/src/__tests__/settings-defaults.test.ts | 13 +++ packages/core/src/settings-schema.ts | 5 + packages/core/src/types.ts | 7 ++ packages/dashboard/app/App.tsx | 49 +++++++-- .../app/__tests__/App.taskPopupViewGating.test.tsx | 113 +++++++++++++++++++++ .../dashboard/app/components/SettingsModal.tsx | 3 +- .../settings/sections/AppearanceSection.tsx | 8 ++ .../sections/__tests__/AppearanceSection.test.tsx | 21 ++++ .../settings-default-descriptions.test.tsx | 1 + .../app/hooks/__tests__/usePoppedOutTasks.test.ts | 14 +++ packages/dashboard/app/hooks/useAppSettings.ts | 4 + packages/dashboard/app/hooks/usePoppedOutTasks.ts | 27 +++-- packages/i18n/locales/en/app.json | 2 + 15 files changed, 255 insertions(+), 18 deletions(-) Fusion-Task-Id: FN-7944 Fusion-Task-Lineage: 4b8ced0e-1853-429f-8482-163821a35ae6 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
6b78633b07 |
FN-7943: keep Quick Chat open when portaled model/thinking-level dropdowns are clicked
Quick Chat's outside-pointer dismissal now recognizes body-portaled dropdown menus (model, thinking-level, agent, dependency, node, priority) as part of the panel instead of treating them as outside clicks. - Extend FloatingWindow's outside-pointerdown safe-surface selector to include the portaled dropdown classes used by model combobox, model nested menu, dependency, node picker, agent picker, and priority picker menus - Add regression tests covering pointerdown on each portaled dropdown surface and on a child element inside a portaled dropdown, asserting onClose is not called - Update dashboard-guide docs to describe that these portal dropdowns are treated as part of the Quick Chat panel for outside-click purposes Files changed: docs/dashboard-guide.md | 2 +- .../dashboard/app/components/FloatingWindow.tsx | 19 +++++++- .../components/__tests__/FloatingWindow.test.tsx | 50 ++++++++++++++++++++++ 3 files changed, 69 insertions(+), 2 deletions(-) Fusion-Task-Id: FN-7943 Fusion-Task-Lineage: fa91bd43-241c-48b0-8858-16521f383784 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
d4001ab0ee |
feat: make merger AI model configurable under Global and Project Models
Add a dedicated merger model lane (project + global provider/model/thinking) so merge-agent sessions no longer share only the default model, without inheriting executor/planner/reviewer lanes. |
||
|
|
e35620c9aa |
FN-7939: supervise heartbeat timer-audit interval and bound non-advancing zombie re-arms
Fixes agents silently going stale for hours even though the heartbeat repair audit process was running. - HeartbeatTriggerScheduler now runs an independent watchdog (armTimerAuditWatchdog/checkTimerAuditLiveness) that tracks the audit loop's last-run timestamp and re-arms + immediately re-runs the 60s audit interval if it goes stale beyond a bounded multiple of the cadence, so a silently dropped audit driver self-heals instead of leaving active agents unrepaired for hours. - Tracks consecutive non-advancing zombie-timer re-arms per agent (nonAdvancingRearmState) and escalates once the count crosses a threshold, recording consecutiveNonAdvancingRearms/nonAdvancingEscalated in agent.metadata.heartbeatTimerRepair and logging reason=heartbeat-rearm-nonadvancing-escalated instead of silently churning the same zombie-timer-rearmed repair forever. - Clears non-advancing rearm state on unregister, non-eligible agents, paused settings, and stale-run-reap skip paths so tracking never leaks stale per-agent counters. - Watchdog and its interval handle are armed in start() and cleared in stop() alongside the existing audit interval. - Adds a changeset (patch) describing the fix, and updates docs/agents.md and docs/architecture.md to document the FN-7939 audit watchdog and non-advancing escalation behavior. - Adds heartbeat-scheduler.test.ts coverage for watchdog re-arm/liveness and non-advancing escalation. Files changed: .changeset/fn-7939-heartbeat-audit-supervision.md | 7 + docs/agents.md | 8 +- docs/architecture.md | 1 + .../src/__tests__/heartbeat-scheduler.test.ts | 209 +++++++++++++++++++++ packages/engine/src/agent-heartbeat.ts | 128 ++++++++++++- 5 files changed, 341 insertions(+), 12 deletions(-) Fusion-Task-Id: FN-7939 Fusion-Task-Lineage: 9fa90240-4333-4588-b595-aef3811b1524 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
316d4fa034 |
FN-7941: anchor execute-requeue loop guard to monotonic terminal-step progress
Hardens the FN-7863 execute-node self-requeue loop guard so residual execute_loop_stall cases (#2043/#2045/#2046/#2047) can no longer reset the loop counter forever via non-terminal signature drift. - Change buildExecuteRequeueLoopSignature to track terminal step count (done/skipped) plus total step count instead of raw currentStep + every step status, so pending/in-progress oscillation no longer produces a "new" signature each cycle. - Add buildExecuteRequeueLoopHighWaterSignature, which derives current terminal-step progress via the shared signature parser (parseExecuteRequeueLoopProgressSignature) and only resets the streak on monotonic forward progress, keeping a high-water mark across cycles so decreases/oscillation below the high-water still count toward exhaustion. - Update executor.ts's execute self-requeue dispatch path to use the new high-water helper when deciding whether to reset (1) or increment executeRequeueLoopCount, replacing the previous raw signature-equality check. - Extend execute-requeue-loop-guard.test.ts with regression coverage: a drifting-signature case that oscillates step order/status with no terminal progress (still terminalizes at MAX_EXECUTE_REQUEUE_LOOP_CYCLES), a done/in-progress oscillation case bounded after the high-water stops increasing, and an updated "real progress never terminalizes" case driven by genuine monotonic done-step advancement. - Update docs/architecture.md's FN-7863/FN-7926 self-healing notes to describe the new terminal-step high-water signature and cross-reference FN-7941. Files changed: docs/architecture.md | 4 +- .../execute-requeue-loop-guard.test.ts | 83 +++++++++++++++++++++- packages/engine/src/executor.ts | 54 ++++++++++++-- 3 files changed, 130 insertions(+), 11 deletions(-) Fusion-Task-Id: FN-7941 Fusion-Task-Lineage: cbf1e536-d29b-40da-bdd8-8c34d8d6b1ca Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
281bb05161 |
FN-7936: alias @fusion/core to a runtime shim in bundled plugin outputs
Fix bundled example plugins (dependency-graph, grok-runtime, roadmap, acp-runtime, compound-engineering) crashing on enable with "Cannot find package '@fusion/core'" by aliasing the private import to a self-contained runtime shim during CLI bundling. - packages/cli/tsup.config.ts: drop @fusion/core from bundlePluginEntry's external list and alias it to the existing pluginSdkCoreRuntimeShim so bundled.js no longer references the private workspace package at runtime - packages/cli/src/__tests__/bundle-output.test.ts: add a regression test asserting every staged bundled plugin's bundled.js contains no bare @fusion/core import/reference - docs/PLUGIN_AUTHORING.md: document that bundled.js outputs must be self-contained and must not leak private @fusion/* workspace imports - .changeset/fn-7936-bundled-plugin-fusion-core-external.md: add a patch changeset for @runfusion/fusion describing the fix Files changed: .changeset/fn-7936-bundled-plugin-fusion-core-external.md | 7 +++++ docs/PLUGIN_AUTHORING.md | 3 +++ packages/cli/src/__tests__/bundle-output.test.ts | 30 ++++++++++++++++++++++ packages/cli/tsup.config.ts | 9 +++++-- 4 files changed, 47 insertions(+), 2 deletions(-) Fusion-Task-Id: FN-7936 Fusion-Task-Lineage: a8a391b2-9441-4a7c-92bc-f1675e1a8a0d Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
1f9dcea4b6 |
FN-7935: route mailbox artifact View task to the popped-out task-detail window
Mailbox artifact "View task" now opens the producing task in the same shared, movable/resizable floating task-detail window used elsewhere in the dashboard, instead of the docked task-detail modal. - MainContent's MailboxView onOpenTask handler now calls popOutTaskDetail(task) after fetchTaskDetail resolves, instead of openDetailTask(task), matching DocumentsView's artifact-task open path - add regression test verifying mailbox artifact "View task" clicks resolve the task and route to popOutTaskDetail (not openDetailTask) - update docs/dashboard-guide.md to describe the shared movable/resizable task-detail window behavior - add changeset (patch) documenting the fix for @runfusion/fusion Files changed: .changeset/fn-7935-mailbox-artifact-view-task-popout.md | 7 ++ docs/dashboard-guide.md | 2 +- packages/dashboard/app/components/dashboard/MainContent.tsx | 8 ++- .../MainContent.mailbox-view-task.test.tsx | 83 ++++++++++++++++++++++ 4 files changed, 97 insertions(+), 3 deletions(-) Fusion-Task-Id: FN-7935 Fusion-Task-Lineage: 51374962-aa36-4390-a6b5-b519e7fc2bf2 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
29560021d3 |
FN-7934: fix chat brain popup clipping in narrow floating windows
Fixes the in-chat model/thinking (Brain) popup being cut off inside a narrow floating Chat window or compact dock on a wide desktop viewport. - Key the popover's viewport-fitting inset layout on ChatView's .chat-view--narrow class (chat surface width) instead of only the @media (max-width: 768px) browser-viewport query, so narrow floating/docked chat surfaces get the fitted layout too. - Add narrow-surface CSS rules for .chat-thinking-level-root, .chat-thinking-popover, .chat-thinking-agent-list, and .chat-thinking-popover-list to constrain position/width/max-height to the chat surface. - Add a CSS-contract regression test asserting both the desktop popover sizing and the new narrow-surface rules stay in sync. - Update docs/dashboard-guide.md to describe the popup staying fitted to the chat surface for narrow floating Chat windows/compact docks, not just mobile/tablet viewports. - Add a patch changeset for @runfusion/fusion documenting the fix. Files changed: .changeset/fn-7934-chat-narrow-model-popup.md | 7 +++++ docs/dashboard-guide.md | 3 +- packages/dashboard/app/components/ChatView.css | 22 +++++++++++++++ .../__tests__/ChatThinkingLevelControl.test.tsx | 32 ++++++++++++++++++++++ 4 files changed, 63 insertions(+), 1 deletion(-) Fusion-Task-Id: FN-7934 Fusion-Task-Lineage: 30c461c5-a153-4005-8a8c-24f02916a934 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
9ba8a2e575 |
FN-7932: add per-lane Reviewer and Planning thinking-level overrides
Adds validatorThinkingLevel and planningThinkingLevel task fields so the Reviewer and Planning AI lanes can override reasoning effort independently of the shared task thinkingLevel, with dashboard UI, storage, and runtime fallback wiring. - Add validatorThinkingLevel and planningThinkingLevel to Task/TaskCreateInput types (packages/core/src/types.ts) - Persist the new fields in the SQLite schema and store read/write/replication paths (packages/core/src/db.ts, store.ts, mesh-task-replication.ts) - Wire executor and triage lanes to fall back per-lane thinking level -> task.thinkingLevel -> existing settings/lane fallback (packages/engine/src/executor.ts, triage.ts) - Add per-lane thinking-level selectors to the ModelSelectorTab UI, alongside the existing thinking-level control (packages/dashboard/app/components/ModelSelectorTab.tsx) - Expose the new fields through the legacy task API and task-workflow routes (packages/dashboard/app/api/legacy.ts, packages/dashboard/src/routes/register-task-workflow-routes.ts) - Document the new settings in dashboard-guide.md and settings-reference.md - Add a minor changeset and unit/integration test coverage for store persistence, routes, UI, and agent-session helpers Files changed: .changeset/per-lane-task-thinking.md | 7 ++ docs/dashboard-guide.md | 2 + docs/settings-reference.md | 2 +- .../src/__tests__/store-thinking-levels.test.ts | 43 +++++++ packages/core/src/db.ts | 15 ++- packages/core/src/mesh-task-replication.ts | 4 + packages/core/src/store.ts | 24 +++- packages/core/src/types.ts | 12 ++ packages/dashboard/app/api/legacy.ts | 2 + .../dashboard/app/components/ModelSelectorTab.tsx | 126 ++++++++++++++++++++- .../components/__tests__/ModelSelectorTab.test.tsx | 50 +++++++- .../src/__tests__/routes-tasks-ops.test.ts | 74 ++++++++++++ .../src/routes/register-task-workflow-routes.ts | 19 +++- .../src/__tests__/agent-session-helpers.test.ts | 15 +++ packages/engine/src/executor.ts | 16 ++- packages/engine/src/triage.ts | 8 +- 16 files changed, 395 insertions(+), 24 deletions(-) Fusion-Task-Id: FN-7932 Fusion-Task-Lineage: 4202f774-aab9-41d2-86a0-f5277dd0f848 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
967f3dd900 |
FN-7923: align task-card cost badge bottom-right with other footer chips
Narrative: Reworked TaskCard footer/meta layout so the cost badge (and its sibling footer-right chips) render inline at the bottom-right of the card-meta row when the footer has no leading content, instead of always sitting in a separate footer row beside the time badge. - Extracted the footer-right chip cluster (cost, time, retry, near-duplicate, undo-of, GitHub tracking) into a shared `footerRightCluster` render, computed once instead of duplicated inline. - Added `footerHasLeadingContent`/`footerRightHasContent`/`placeFooterRightInMeta` derivations so the cluster moves into `.card-meta` (bottom-right, inline with other tags) when there's no files-changed button or GitHub-import leading content, and the meta row is visible; otherwise it keeps the existing `.card-footer-row` placement for in-progress/tracked cards. - Updated dashboard-guide.md wording to describe the cost badge as appearing 'with the card's other footer/meta chips' rather than 'beside the execution-time badge'. - Extended TaskCard.test.tsx coverage for the new placement behavior. - Desktop local-runtime.ts: kept the previously-unused `reason` parameter on `requestRestart` explicitly referenced (void reason) for API parity/lint cleanliness, unrelated cosmetic cleanup carried in the same branch. Files changed: docs/dashboard-guide.md | 2 +- packages/dashboard/app/components/TaskCard.tsx | 242 +++++++++++---------- .../app/components/__tests__/TaskCard.test.tsx | 96 +++++++- packages/desktop/src/local-runtime.ts | 4 +- 4 files changed, 222 insertions(+), 122 deletions(-) Fusion-Task-Id: FN-7923 Fusion-Task-Lineage: 7e4c3109-f39e-45c0-af13-358ce54f945c Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
30d2e3660d |
FN-7927: fix Refine feedback modal self-dismissing immediately after opening
The task-detail Refine overlay used a raw onClick backdrop handler with a stopPropagation-wrapped inner modal, so the same click/touch sequence that opened Refine could bubble into the backdrop handler and close it right away; route it through the shared useOverlayDismiss contract instead so it behaves like every other dashboard modal. - Compute refineOverlayDismissProps via useOverlayDismiss(handleCloseRefineModal) and spread it onto the refine overlay instead of a plain onClick handler - Drop the redundant stopPropagation-only onClick from the inner .detail-refine-modal div now that the overlay itself no longer misfires on the opening interaction - Update docs/dashboard-guide.md to document that the Refine modal (Board and List entry points) stays open until an explicit close or an enabled backdrop dismissal - Add TaskDetailModal.refine.test.tsx regression coverage for the modal staying open across the opening interaction and honoring the dismiss-preference gate - Add a patch changeset summarizing the fix for @runfusion/fusion release notes Files changed: .changeset/fn-7927-refine-modal.md | 7 + docs/dashboard-guide.md | 8 +- .../dashboard/app/components/TaskDetailModal.tsx | 12 +- .../__tests__/TaskDetailModal.refine.test.tsx | 182 +++++++++++++++++++++ 4 files changed, 201 insertions(+), 8 deletions(-) Fusion-Task-Id: FN-7927 Fusion-Task-Lineage: c7e7cd4a-d103-47e6-93ce-6577147b4795 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
6dcecb0c34 |
FN-7926: park completed-but-blocked tasks instead of looping execute-requeue
Stops the execute → pause-abort → re-queue-to-todo infinite loop for tasks whose implementation work is done but a dependency/blockedBy blocker is still live, by diverting them into a dedicated parked state instead of feeding the FN-7863 no-progress backstop or looping forever. - Add TaskExecutor.parkCompletedBlockedTask(): when work is complete but getTaskCompletionBlocker() still reports a blocker, park the task in todo with pausedReason:"completed-work-blocked", status:"queued", preserved worktree/branch/steps, and a cleared execute-requeue signature. - Replace shouldFinalizeCompletedTask's boolean with getCompletedTaskFinalizationDecision() returning "finalize" | "blocked" | "incomplete" so both the paused-after-completion and finalization call sites can react to the new "blocked" outcome without re-entering execution. - Divert completed-but-blocked tasks before the FN-7863 execute-requeue-loop counter increments, so waiting-on-dependency states are no longer misclassified as EXECUTION_DISPATCH_LOOP_EXHAUSTED. - Add SelfHealingManager.reconcileCompletedBlockedTasks(): a bounded sweep (wired into both startup/maintenance and periodic self-healing passes) that clears the park and advances the task to review once getTaskCompletionBlockerForStore() resolves, guarded by auto-merge eligibility, user-pause, and live-execution checks; failed advances re-park rather than strand the row. - Add run-audit mutation types task:completed-blocked-parked and task:completed-blocked-advanced (ids/counts/outcomes-only metadata) plus AGENTS.md/docs/architecture.md entries documenting the new lifecycle. - Extend execute-requeue-loop-guard.test.ts with coverage for the park/advance flow, including the zero-step task edge case. Files changed: AGENTS.md | 1 + docs/architecture.md | 2 + .../execute-requeue-loop-guard.test.ts | 256 ++++++++++++++++++++- packages/engine/src/executor.ts | 85 ++++++- packages/engine/src/run-audit.ts | 4 + packages/engine/src/self-healing.ts | 95 ++++++++ 6 files changed, 432 insertions(+), 11 deletions(-) Fusion-Task-Id: FN-7926 Fusion-Task-Lineage: e47945f4-a816-447e-9ea1-7c13105d0ba9 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
e84fda936a |
FN-7918: make chat go-to-top contextual and inline edit pencil compact
Reworks chat message footer affordances: the scroll-to-top control now only becomes visible once a message's top is actually clipped above the visible thread viewport, and the edit pencil moves from a standalone action row into the timestamp footer beside user messages. - ChatView measures assistant message tops on scroll/message changes (rAF-scheduled) and tracks which message IDs are currently clipped above the `.chat-messages` container edge - StandardChatMessageItem accepts a new `isTopClipped` prop; the go-to-top button stays DOM-mounted (for tests/a11y) but is visually hidden via CSS until clipped - Merged the assistant thinking/copy/scroll-to-top actions into a single collapsible footer row instead of separate action rows - Moved the user-message edit pencil into an inline `chat-message-time-row` next to the relative timestamp instead of a standalone action row above it - Updated ChatView.css for the new inline layout, collapsed-row state, and hidden/visible scroll-to-top button states - Updated message-edit and scroll-to-top tests to cover the new inline placement and clipped-visibility behavior - Added changeset and docs/dashboard-guide.md note describing the new behavior Files changed: .changeset/fn-7918-chat-inline-icons.md | 7 ++ docs/dashboard-guide.md | 6 +- packages/dashboard/app/components/ChatView.css | 80 +++++++++++++++------- packages/dashboard/app/components/ChatView.tsx | 52 +++++++++++++- .../app/components/StandardChatSurface.tsx | 33 +++++++-- .../__tests__/ChatView.message-edit.test.tsx | 34 ++++++++- .../__tests__/ChatView.scroll-to-top.test.tsx | 75 +++++++++++++++++++- 7 files changed, 253 insertions(+), 34 deletions(-) Fusion-Task-Id: FN-7918 Fusion-Task-Lineage: 76206cd2-94a8-47be-b282-94943e184d01 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
2aefaad319 |
FN-7924: Add View task link to artifact-registration mail notifications
Artifact-registration mail messages now expose the task that produced the artifact so users can jump straight to it from the mailbox. - MailboxArtifactAttachment renders a "View task" button when message.metadata.taskId is present and an onOpenTask handler is supplied, alongside the existing Open artifact affordance - MailboxModal and MailboxView thread taskId metadata and onOpenTask through to MailboxArtifactAttachment for both the message-list and detail-pane renders - MainContent wires MailboxView's onOpenTask to the shared fetchTaskDetail -> openDetailTask path, with a toast on failure, so mailbox reuses the existing task-detail flow - docs/dashboard-guide.md documents the new View task affordance for artifact notifications - adds a minor changeset for @runfusion/fusion describing the new mail notification behavior - extends MailboxArtifactAttachment and MailboxView tests to cover the new taskId/onOpenTask wiring Files changed: .changeset/fn-7924-artifact-mail-view-task-link.md | 7 ++++ docs/dashboard-guide.md | 2 +- .../app/components/MailboxArtifactAttachment.tsx | 20 ++++++++++ packages/dashboard/app/components/MailboxModal.css | 2 +- packages/dashboard/app/components/MailboxModal.tsx | 6 +++ packages/dashboard/app/components/MailboxView.tsx | 6 +++ .../__tests__/MailboxArtifactAttachment.test.tsx | 35 ++++++++++++++++- .../app/components/__tests__/MailboxView.test.tsx | 45 +++++++++++++++++++++- .../app/components/dashboard/MainContent.tsx | 6 +++ 9 files changed, 124 insertions(+), 5 deletions(-) Fusion-Task-Id: FN-7924 Fusion-Task-Lineage: 800102e1-9025-40da-8130-9ab0e8acd747 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
313956df5a |
FN-7916: fix chat model selector dismissing before selection on mobile/tablet
Fix the in-chat Brain popup's model picker on touch viewports: pointerdown outside-close was treating the portaled CustomModelDropdown menu as outside the popup, dismissing it before the tap could register a model selection, and the mobile popover was mis-anchored off-screen. - ChatThinkingLevelControl: treat pointerdown targets inside the portaled `.model-combobox-dropdown--portal` menu as inside the popup so touch taps select the model instead of closing the popup first - ChatView.css: clamp the popover to the viewport width via max-width/max-inline-size, and on mobile anchor it to the chat input area with tokenized left/right gutters instead of a collapsing left:0 width - Add a portal-aware regression test covering pointerdown-inside-portal selection, genuine outside-pointerdown close, and the mobile CSS anchoring contract - Add changeset (patch) and update dashboard guide docs to describe mobile/tablet behavior Files changed: .changeset/fn-7916-chat-mobile-model-selector.md | 7 ++ docs/dashboard-guide.md | 3 +- .../app/components/ChatThinkingLevelControl.tsx | 10 ++- packages/dashboard/app/components/ChatView.css | 17 +++- .../ChatThinkingLevelControl.portal.test.tsx | 97 ++++++++++++++++++++++ 5 files changed, 130 insertions(+), 4 deletions(-) Fusion-Task-Id: FN-7916 Fusion-Task-Lineage: bcc2d9ad-0be6-4e23-b643-eebf93aae3c6 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
daf3f15fd1 |
FN-7909: add room-level thinking effort override for Chat Rooms
Adds a per-room thinking-effort (reasoning level) override for Chat Rooms so all room responders can share a consistent override instead of relying only on per-agent/global defaults. - Persist `chat_rooms.thinkingLevel` with a new core DB migration and store read/write support - Extend chat-store and chat-types with thinkingLevel plumbing for room create/update - Wire the dashboard chat room API/routes and legacy handlers to accept and return thinkingLevel - Add a ChatView room settings control (with CSS) and useChatRooms hook support for setting/clearing the override - Resolve room responder defaultThinkingLevel from the room override when present - Update docs (dashboard-guide, settings-reference) and add a minor changeset for the feature Files changed: .changeset/fn-7909-room-thinking-level.md | 7 +++ docs/dashboard-guide.md | 1 + docs/settings-reference.md | 2 +- packages/core/src/__tests__/chat-store.test.ts | 21 ++++++++ packages/core/src/__tests__/db-migrate.test.ts | 57 ++++++++++++++++++++++ packages/core/src/chat-store.ts | 12 ++++- packages/core/src/chat-types.ts | 10 ++++ packages/core/src/db.ts | 28 ++++++++++- packages/dashboard/app/api/__tests__/chat-rooms-api.test.ts | 8 +-- packages/dashboard/app/api/legacy.ts | 4 +- packages/dashboard/app/components/ChatView.css | 16 ++++++ packages/dashboard/app/components/ChatView.tsx | 29 ++++++++++- packages/dashboard/app/components/__tests__/ChatView.rooms.test.tsx | 24 +++++++++ packages/dashboard/app/hooks/__tests__/useChatRooms.test.ts | 22 +++++++++ packages/dashboard/app/hooks/useChatRooms.ts | 16 ++++++ packages/dashboard/src/__tests__/chat-room-routes.test.ts | 26 ++++++++++ packages/dashboard/src/__tests__/chat.rooms.test.ts | 42 ++++++++++++++++ packages/dashboard/src/chat.ts | 8 +++ packages/dashboard/src/routes/register-chat-room-routes.ts | 21 ++++++-- 19 files changed, 338 insertions(+), 16 deletions(-) Fusion-Task-Id: FN-7909 Fusion-Task-Lineage: 2741eca9-5305-4f6c-81bf-ae644a9fe307 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
1ea185daa5 |
FN-7911: add workflow validate dry-run command, tool, and API route
Adds a non-mutating `fn workflow validate` dry-run path across CLI, agent tools, and dashboard API so custom workflow IR can be checked before create/update. - Add `packages/cli/src/commands/workflow.ts` implementing `fn workflow validate <id> | --file <path>` with JSON/text output, wired into `bin.ts`. - Add `fn_workflow_validate` agent tool (`agent-tools.ts`, `index.ts`) reusing the existing parseWorkflowIr/trait/code-node/column-agent validation used by create/update, performing no persistence. - Add `POST /api/workflows/validate` route in `register-workflow-routes.ts` plus dashboard route test coverage. - Extend heartbeat tool-gating/exposure tests and gating classifications to include `fn_workflow_validate` alongside the other workflow tools. - Update CLI/agent extension docs (`docs/cli-reference.md`, `docs/agents.md`, `docs/workflow-steps.md`, fusion skill references) to document the new command/tool. - Add changeset `.changeset/fn-7911-workflow-validate.md` (minor) describing the new capability. Files changed: .changeset/fn-7911-workflow-validate.md | 7 ++ docs/agents.md | 5 +- docs/cli-reference.md | 13 ++ docs/workflow-steps.md | 3 +- packages/cli/skill/fusion/SKILL.md | 2 +- .../cli/skill/fusion/references/extension-tools.md | 10 ++ .../skill/fusion/references/fusion-capabilities.md | 1 + .../src/__tests__/extension-workflow-tools.test.ts | 1 + packages/cli/src/__tests__/extension.test.ts | 1 + .../src/__tests__/workflow-docs-current.test.ts | 1 + packages/cli/src/bin.ts | 22 ++++ packages/cli/src/commands/workflow.ts | 80 ++++++++++++ packages/cli/src/extension.ts | 10 ++ .../dashboard/src/__tests__/chat-manager.test.ts | 1 + .../dashboard/src/__tests__/chat.rooms.test.ts | 1 + .../planning-document-tools-exposure.test.ts | 1 + .../__tests__/workflow-validate-route.test.ts | 101 +++++++++++++++ .../src/routes/register-workflow-routes.ts | 27 +++- .../engine/src/__tests__/agent-action-gate.test.ts | 2 +- .../agent-workflow-tools-exposure.test.ts | 70 ++++++++++- .../src/__tests__/gating-classifications.test.ts | 3 +- .../src/__tests__/heartbeat-executor.test.ts | 37 +++--- .../src/__tests__/heartbeat-session-prompt.test.ts | 5 +- .../src/__tests__/permanent-agent-gating.test.ts | 2 +- packages/engine/src/agent-heartbeat.ts | 5 +- packages/engine/src/agent-tools.ts | 140 ++++++++++++++++++++- packages/engine/src/executor.ts | 6 + packages/engine/src/gating-classifications.ts | 2 + packages/engine/src/index.ts | 4 + 29 files changed, 532 insertions(+), 31 deletions(-) Fusion-Task-Id: FN-7911 Fusion-Task-Lineage: 903d15fe-a7ec-458f-aa34-8f2e895a9603 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
8835c6cb48 |
FN-7908: add in-chat model/agent switcher to brain-icon popup
Extend the chat brain-icon popup and its backing session PATCH route so an active Direct chat's model or agent can be switched mid-conversation instead of only being set at creation time. - Add a Model/Agent section to ChatThinkingLevelControl (the brain-icon popup) for picking a model provider/model or retargeting to a real agent without leaving the chat. - Extend PATCH /api/chat/sessions/:id to accept modelProvider/modelId (as a validated pair via the existing validateModelPair helper) and agentId, forwarding only the keys present in the body so omitted fields leave the session's stored target untouched. - Add chat-store updateSession support for the agentId clause alongside the existing model/thinkingLevel fields, and a useChat.setSessionModel hook for the dashboard to call the new PATCH capability. - Update i18n locale strings (en/es/fr/ko/zh-CN/zh-TW) and dashboard-guide.md docs for the new switcher UI. - Add unit/integration test coverage across chat-store, chat-manager, chat-routes, useChat, ChatThinkingLevelControl, and ChatView for the new model/agent switch behavior. - Add changeset fn-7908-chat-model-agent-switcher.md (minor, @runfusion/fusion). Files changed: .changeset/fn-7908-chat-model-agent-switcher.md | 7 + docs/dashboard-guide.md | 3 +- packages/core/src/__tests__/chat-store.test.ts | 21 ++ packages/core/src/chat-store.ts | 8 + packages/core/src/chat-types.ts | 2 + packages/dashboard/app/api/legacy.ts | 11 +- .../app/components/ChatThinkingLevelControl.tsx | 219 ++++++++++++++++++--- packages/dashboard/app/components/ChatView.css | 135 ++++++++++++- packages/dashboard/app/components/ChatView.tsx | 23 ++- .../__tests__/ChatThinkingLevelControl.test.tsx | 109 +++++++++- .../__tests__/ChatView.thinking-level.test.tsx | 67 ++++++- .../dashboard/app/hooks/__tests__/useChat.test.ts | 166 +++++++++++++++- packages/dashboard/app/hooks/useChat.ts | 56 ++++++ .../dashboard/src/__tests__/chat-manager.test.ts | 38 ++++ .../dashboard/src/__tests__/chat-routes.test.ts | 117 ++++++++++- .../dashboard/src/routes/register-chat-routes.ts | 48 ++++- packages/i18n/locales/en/app.json | 8 +- packages/i18n/locales/es/app.json | 8 +- packages/i18n/locales/fr/app.json | 8 +- packages/i18n/locales/ko/app.json | 8 +- packages/i18n/locales/zh-CN/app.json | 8 +- packages/i18n/locales/zh-TW/app.json | 8 +- 22 files changed, 1007 insertions(+), 71 deletions(-) Fusion-Task-Id: FN-7908 Fusion-Task-Lineage: b1104865-9b0c-4d77-973e-89152fe245e0 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
3326984a6d |
FN-7913: add fn plugin publish --dry-run preflight command
Adds a non-mutating `fn plugin publish` CLI command that preflights a plugin before manual pack/publish, giving external plugin authors an offline readiness check. - New `packages/cli/src/commands/plugin-publish.ts` with `runPluginPublish`, `collectPluginPreflight`, and `classifyVersionBump` (strict x.y.z semver bump classification), reusing `loadManifestFromPath` / `resolvePluginEntryFile` from the install path - Wire `fn plugin publish <path> [--dry-run] [--previous-version <semver>]` into `bin.ts` command routing, dynamic import list, and help text - Add test coverage in `plugin-publish.test.ts` and update `bin.test.ts` for the new subcommand - Update `docs/PLUGIN_AUTHORING.md`, `docs/cli-reference.md`, and `docs/plugins/external-authoring.md` to document the new preflight command - Add changeset `.changeset/fn-7913-plugin-publish-dry-run.md` (minor, @runfusion/fusion) Files changed: .changeset/fn-7913-plugin-publish-dry-run.md | 7 + docs/PLUGIN_AUTHORING.md | 9 +- docs/cli-reference.md | 5 +- docs/plugins/external-authoring.md | 14 +- packages/cli/src/__tests__/bin.test.ts | 2 +- packages/cli/src/__tests__/plugin-publish.test.ts | 197 ++++++++++++++++ packages/cli/src/bin.ts | 22 +- packages/cli/src/commands/plugin-publish.ts | 272 ++++++++++++++++++++++ 8 files changed, 521 insertions(+), 7 deletions(-) Fusion-Task-Id: FN-7913 Fusion-Task-Lineage: 27bdf937-3195-4619-9d01-b6af4fbba487 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
b85a6b8663 |
FN-7912: add quarantine-ledger deadline visibility check
Add a report-only script that surfaces flaky-test quarantine entries approaching their 14-day deletion clock, so maintainers can make deliberate rescue-or-expire decisions before entries silently expire. - Add scripts/check-quarantine-ledger.mjs: reads scripts/lib/test-quarantine.json, computes days-remaining against the existing 14-day deletion clock (shared DELETION_CLOCK_DAYS from scripts/test-velocity-baseline.mjs), and buckets each entry as expired/near/healthy/unknown - Support --warn-within=<days> (default 5) to tune the near-deadline window, --json for machine-readable output, and --strict as an opt-in local/CI gate (exits 1 on expired/near entries) while default mode stays exit-0 and non-blocking - Wire pnpm check:quarantine-ledger script in package.json - Add scripts/__tests__/check-quarantine-ledger.test.mjs covering deadline bucketing/sorting, empty/missing ledger handling, --strict behavior, and --json output shape - Document the new command and its flags in docs/testing.md under the quarantine ledger/deletion ratchet section Files changed: docs/testing.md | 10 + package.json | 1 + scripts/__tests__/check-quarantine-ledger.test.mjs | 159 ++++++++++++++++ scripts/check-quarantine-ledger.mjs | 202 +++++++++++++++++++++ 4 files changed, 372 insertions(+) Fusion-Task-Id: FN-7912 Fusion-Task-Lineage: c08e2e09-473a-4ad0-8c27-43cbc3355168 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
03bca1787b |
FN-7907: Add project chat default (model/agent) setting and New Chat default behavior
Adds a project-scoped Direct-chat default (model pair or durable agent) plus a New Chat behavior toggle (prompt vs. always-use-default), surfaced in Project Models settings using the standard model dropdown. - Add ProjectSettings fields: chatNewSessionMode, chatDefaultKind, chatDefaultAgentId, chatDefaultModelProvider, chatDefaultModelId, chatDefaultThinkingLevel - Extend settings-schema validation for the new chat default fields - Add a "Chat" subsection to ProjectModelsSection with New Chat behavior selector, model/agent target toggle, and the standard CustomModelDropdown for model selection - Update ChatView.tsx handleNewChat() flow to honor the configured default (prompt vs. immediate session creation) - Add i18n strings across en/es/fr/ko/zh-CN/zh-TW locales and regenerate resources.d.ts - Add changeset (@runfusion/fusion minor) and update docs/settings-reference.md and docs/dashboard-guide.md - Add settings-parity, ChatView new-chat-default, and ProjectModelsSection chatDefault test coverage Files changed: .changeset/fn-7907-chat-default.md | 7 + docs/dashboard-guide.md | 3 +- docs/settings-reference.md | 8 + packages/core/src/__tests__/settings-parity.test.ts | 20 ++ packages/core/src/settings-schema.ts | 6 + packages/core/src/types.ts | 15 + packages/dashboard/app/components/ChatView.tsx | 93 +++++- packages/dashboard/app/components/__tests__/ChatView.new-chat-default.test.tsx | 357 +++++++++++++++++++++ packages/dashboard/app/components/settings/sections/ProjectModelsSection.tsx | 77 +++++ packages/dashboard/app/components/settings/sections/__tests__/ProjectModelsSection.chatDefault.test.tsx | 193 +++++++++++ packages/i18n/locales/en/app.json | 20 +- packages/i18n/locales/es/app.json | 20 +- packages/i18n/locales/fr/app.json | 20 +- packages/i18n/locales/ko/app.json | 20 +- packages/i18n/locales/zh-CN/app.json | 20 +- packages/i18n/locales/zh-TW/app.json | 20 +- packages/i18n/src/resources.d.ts | 18 ++ 17 files changed, 899 insertions(+), 18 deletions(-) Fusion-Task-Id: FN-7907 Fusion-Task-Lineage: 86a81b9c-7e0c-4033-9e2a-6f7380810fe9 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |