- AI Setup: connected providers now render first; 'Skip for now' hides
once a provider is connected; footer buttons share one size.
- GitHub step: state-driven (no install/pitch content when connected),
one type scale, real <code> literals, per-OS gh instructions behind a
disclosure, single skip affordance; gh/OAuth status revalidates on
window focus and OAuth relogin so later steps stop showing stale
'not connected'.
- Project step: onboarding-driven opens keep 'Step 3 of 5' context;
runtime-node picker no longer lists 'Local node' and 'local (local)'
duplicates and hides itself when only the local node exists;
isolation-mode cards no longer render a stretched native radio or
uppercased descriptions.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The GitLab Configuration disclosure was the only .settings-content
child without the form-group horizontal gutter, so its bordered box and
right-flushed checkbox leaked to the pane edge. The footer action rail
was a no-wrap flex with zero slack, clipping Save whenever extra footer
content appeared; it now wraps on desktop (mobile scroll rail intact).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The connection status pill rendered the host kind twice ('Desktop
Desktop local mode') with mismatched font sizes. The kind is now folded
once into the summary ('Desktop · Local mode') across all pill states.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Grok CLI chat failed two different ways depending on the surface:
1. Default (no-project) chat errored with "requires the bundled Grok CLI
runtime". The default ChatManager was handed a bare PluginLoader, but Grok
routing (deriveGrokRuntimeHintForNoVisibleKey -> resolveRuntime) needs a
PluginRunner's getRuntimeById/createRuntimeContext; the unguarded call threw
"getRuntimeById is not a function". New resolveChatManagerPluginRunner()
prefers the engine's PluginRunner (same runner the project-scoped path uses),
falling back to the loader only in UI-only mode.
2. Project-scoped chat returned empty replies. The CLI-bundled Grok plugin
(packages/cli/dist/plugins/.../bundled.js, gitignored) was stale vs the
FN-7796 single-JSON adapter source; the running server loads that bundle,
not the plugin's own dist. `pnpm build` regenerates it. Noted in the
changeset that the freshness guard only warns and the dev prebuild does not
rebuild the CLI tsup bundle.
Verified end-to-end on a live dashboard: both default and project-scoped
grok-cli/grok-4.5 chats now stream thinking + text.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The Grok stale-dist bug was possible because the dev/build path never
refreshed plugin dist:
- The `client` prebuild (default `pnpm dev dashboard`) rebuilt only
@fusion/core + @fusion/engine + @fusion/dashboard, never plugins.
- The FN-6638 stale-dist startup warning only scanned packages/, never
plugins/, so a source-ahead plugin dist ran phantom-old with no warning.
Changes:
- build-workspace.mjs: add `--plugins-only` to plan/build just the plugins
that changed, reusing the existing content-hash skip cache (cheap no-op when
unchanged).
- scripts/dev-prebuild-client.mjs: new orchestrator — fast core/engine/
dashboard build, then incremental changed-plugin rebuild. The `client`
prebuild now runs this single cross-platform command.
- dist-freshness.mjs: scan plugin roots (plugins/, plugins/examples/) so a
stale plugin dist is warned like a stale package dist; the warning names the
plugin dir.
Verified: --plugins-only plans only plugins, skips unchanged on the second
run, and re-plans exactly the one plugin whose source changed. All script and
CLI lib tests pass.
Fusion-Task-Id: FN-7779
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The running dashboard loads the compiled plugin dist, which was stale and
invoked `grok --prompt <text> --format json --directory <cwd>` — flags grok
0.2.93 rejects ("unexpected argument '--prompt'"), yielding a non-zero exit,
no JSON, and an empty "No message" bubble. The source already switched to the
valid `grok -p <text> --output-format json [-m <model>] [--cwd <dir>]`
contract (FN-7790/FN-7796); this rebuilds dist to match.
Also reconcile the FN-7779 test suite: a genuinely empty response is a parsed
`{text:"",stopReason:"EndTurn"}` object, not zero stdout bytes, so the
"stays silent" test now models that shape instead of contradicting the
FN-7796 zero-stdout wrong-binary diagnostic. All 64 plugin tests pass.
Fusion-Task-Id: FN-7779
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Narrative: the streaming-json headless contract intermittently emitted only thought events then stopReason:Cancelled with zero text, leaving Chat replies silently empty; the adapter now spawns grok with --output-format json, buffers stdout, and parses the single JSON response on process close, with streaming-json parsing kept only as a diagnostic fallback.
- Change grok CLI invocation from --output-format streaming-json to --output-format json (cli-stream.ts)
- Add GrokCliJsonResponse type ({text, stopReason, sessionId, requestId, thought}) and parseJsonOutput() to stream-parser.ts, keeping legacy NDJSON line parsing for fallback/diagnostics
- Rework runtime-adapter.ts to buffer full stdout, parse it via parsePromptOutput (JSON object first, NDJSON fallback), and surface a formatTerminalNoTextDiagnostic when a non-EndTurn stopReason yields no assistant text
- Rename first-line/inactivity timeout bookkeeping from line-based to output/chunk-based (FIRST_OUTPUT_TIMEOUT_MS, firstOutputReceived, firstStdoutChunk) since stdout is no longer consumed via readline
- Update cli-stream/runtime-adapter/stream-parser tests to cover the JSON response path and the Cancelled/no-text diagnostic
- Update docs/grok-cli-contract.md and plugin README to document the json output-format contract and diagnostics
- Add changeset fn-7796-grok-cli-reliable-headless.md (patch, fix)
Files changed:
.changeset/fn-7796-grok-cli-reliable-headless.md | 7 +
docs/grok-cli-contract.md | 108 ++++++++-----
plugins/fusion-plugin-grok-runtime/README.md | 16 +-
.../src/__tests__/cli-stream.test.ts | 4 +-
.../src/__tests__/runtime-adapter.test.ts | 73 ++++++++-
.../src/__tests__/stream-parser.test.ts | 80 +++++----
.../fusion-plugin-grok-runtime/src/cli-stream.ts | 14 +-
.../src/runtime-adapter.ts | 180 ++++++++++++---------
.../src/stream-parser.ts | 65 ++++++--
plugins/fusion-plugin-grok-runtime/src/types.ts | 13 +-
10 files changed, 373 insertions(+), 187 deletions(-)
Fusion-Task-Id: FN-7796
Fusion-Task-Lineage: c920fcf0-98f8-42ec-867a-7f76c0aca1b7
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Adds a per-lane thinking-level selector to every fallback model picker across global, project, and workflow Settings surfaces, wiring them into the existing null-as-delete save paths.
- Add inline thinking-level dropdowns to the global Fallback Model, workflow-declared planning/validator fallback lanes, and the project-scoped Title Summarizer fallback picker via CustomModelDropdown's `showThinkingLevel`.
- Route `planningFallbackThinkingLevel`/`validatorFallbackThinkingLevel` through workflow settings PATCH and `titleSummarizerFallbackThinkingLevel` through project settings save-split, both with null-as-delete semantics on reset.
- Move Title Summarizer fallback out of the workflow-declared model pairs into a dedicated project-scoped lane in ProjectModelsSection so its thinking companion isn't tied to workflow settings.
- Update WorkflowSettingsPanel to surface the new fallback thinking companion keys.
- Extend/adjust tests (settings-save-split, settings-sections, SettingsModal.models-auth, WorkflowSettingsPanel, core settings-migration) to cover the new selectors and save routing.
- Document the fallback thinking-level runtime behavior in docs/settings-reference.md and docs/dashboard-guide.md.
- Add a minor changeset describing the new fallback thinking-level selectors.
Files changed:
.changeset/fn-7795-fallback-thinking-selectors.md | 7 +
docs/dashboard-guide.md | 4 +-
docs/settings-reference.md | 10 +-
packages/core/src/__tests__/settings-migration.test.ts | 14 +-
packages/dashboard/app/__tests__/settings-save-split.test.ts | 35 +++++
packages/dashboard/app/__tests__/settings-sections.test.tsx | 163 ++++++++++++++++++++-
packages/dashboard/app/components/WorkflowSettingsPanel.tsx | 6 +-
packages/dashboard/app/components/__tests__/SettingsModal.models-auth.test.tsx | 11 +-
packages/dashboard/app/components/__tests__/WorkflowSettingsPanel.test.tsx | 38 +++++
packages/dashboard/app/components/settings/save-split.ts | 9 +-
packages/dashboard/app/components/settings/sections/GlobalModelsSection.tsx | 8 +-
packages/dashboard/app/components/settings/sections/ProjectModelsSection.tsx | 58 ++++++--
12 files changed, 328 insertions(+), 35 deletions(-)
Fusion-Task-Id: FN-7795
Fusion-Task-Lineage: ec990d47-defe-4717-993a-56988afe8d7d
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Adds fallbackThinkingLevel plumbing so, when Fusion swaps from a primary model to a configured fallback model (executor, validator/reviewer, merger, planning, title-summarizer, heartbeat, and workflow-step lanes), the fallback's own configured thinking level is applied instead of silently reusing the primary lane's level.
- Add fallbackThinkingLevel option to AgentRuntimeOptions (agent-runtime.ts), AgentOptions (pi.ts), and ReviewOptions (reviewer.ts)
- Add per-lane resolvers: resolveExecutorFallbackThinkingLevel, resolvePlanningFallbackThinkingLevel, resolveValidatorFallbackThinkingLevel, resolveTitleSummarizerFallbackThinkingLevel, resolveMergerFallbackThinkingLevel (agent-session-helpers.ts), each following fallback-provider precedence and falling back to the primary lane/default thinking level when unset
- Export new resolvers from packages/engine/src/index.ts
- Apply the resolved fallback thinking level in createFnAgent's applyThinkingLevelIfSupported once a session has swapped to the fallback model (pi.ts)
- Wire fallbackThinkingLevel through executor session creation (workflow-step, task validator, child-agent, and main executor session paths), merger session creation, and heartbeat session creation
- Promote the fallback thinking level alongside the fallback model/provider when the no-visible-key Grok CLI fallback is promoted to primary, so the cleared fallback pair doesn't leave the session on the superseded primary's thinking level
- Route workflow-step fallback thinking level by which fallback candidate (validatorFallback vs globalFallback) actually matched
- Document fallbackThinkingLevel runtime-swap behavior in docs/settings-reference.md
- Add minor changeset for @runfusion/fusion
- Add regression tests covering fallback thinking-level resolution and application (agent-session-helpers.test.ts, pi.test.ts) and a shared test helper (executor-test-helpers.ts)
Files changed:
.changeset/fn-7794-fallback-thinking-level.md | 7 ++
docs/settings-reference.md | 3 +
.../src/__tests__/agent-session-helpers.test.ts | 38 ++++++
.../engine/src/__tests__/executor-test-helpers.ts | 23 ++++
packages/engine/src/__tests__/pi.test.ts | 136 +++++++++++++++++++++
packages/engine/src/agent-heartbeat.ts | 3 +-
packages/engine/src/agent-runtime.ts | 5 +
packages/engine/src/agent-session-helpers.ts | 54 ++++++++
packages/engine/src/executor.ts | 31 ++++-
packages/engine/src/index.ts | 5 +
packages/engine/src/merger.ts | 7 +-
packages/engine/src/pi.ts | 16 ++-
packages/engine/src/reviewer.ts | 6 +
13 files changed, 327 insertions(+), 7 deletions(-)
Fusion-Task-Id: FN-7794
Fusion-Task-Lineage: c94d621a-ccbd-42b2-9fe6-cb619418ad90
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Image attachments added via TaskStore.addAttachment now surface as first-class image artifacts, reusing the existing artifact listing/SSE/media pipeline instead of duplicating bytes.
- addAttachment() registers a URI-only "image" artifact (metadata.source: "attachment") pointing at the already-written attachments/<file> path whenever an image mimeType is attached; registration is best-effort and swallows the archived/soft-deleted-task rejection so addAttachment keeps its always-succeeds contract for valid images.
- deleteAttachment() now removes any bridged artifact rows for a filename before deleting the attachment file, so /api/artifacts/:id/media can never point at a deleted attachment.
- register-task-workflow-routes.ts's resolveArtifactMediaPath now accepts task-scoped attachments/<file> URIs (in addition to artifacts/<file>) so the media route can stream bridged image-attachment artifacts; task-less artifacts remain restricted to .fusion/artifacts/.
- docs/storage.md documents the attachment→artifact bridge behavior and the media route's accepted URI prefixes.
- Added a changeset (@runfusion/fusion: minor) describing the user-facing Artifacts view change.
- Extended store-attachments and artifacts-route-integration tests to cover the new bridging and deletion behavior.
Files changed:
.changeset/fn-7791-image-attachments-artifacts.md | 7 +++
docs/storage.md | 3 +-
packages/core/src/__tests__/store-attachments.test.ts | 59 +++++++++++++++++++++-
packages/core/src/store.ts | 58 ++++++++++++++++++++-
packages/dashboard/src/routes/__tests__/artifacts-route-integration.test.ts | 40 +++++++++++++++
packages/dashboard/src/routes/register-task-workflow-routes.ts | 9 +++-
6 files changed, 172 insertions(+), 4 deletions(-)
Fusion-Task-Id: FN-7791
Fusion-Task-Lineage: 4df47880-6161-4a8b-933a-2f6fc2fed953
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Align the Grok CLI runtime plugin adapter with the real xAI grok CLI stream contract so tool responses are no longer silently dropped, and update tests/docs to match.
- Rework stream-parser.ts to parse the actual grok CLI event/message shape instead of the previously assumed schema
- Trim runtime-adapter.ts and types.ts down to the fields the real CLI contract emits, removing speculative/unsupported fields
- Update cli-stream.ts to match the corrected event handling
- Rewrite runtime-adapter, stream-parser, and cli-stream test suites to exercise the real CLI contract end-to-end
- Update docs/grok-cli-contract.md and plugin README to document the verified contract
- Add changeset for the grok-runtime plugin fix
Files changed:
.changeset/fn-7790-grok-cli-real-contract.md | 7 +
docs/grok-cli-contract.md | 432 +++++++--------------
plugins/fusion-plugin-grok-runtime/README.md | 149 ++-----
.../src/__tests__/cli-stream.test.ts | 22 +-
.../src/__tests__/runtime-adapter.test.ts | 250 ++++--------
.../src/__tests__/stream-parser.test.ts | 108 ++----
.../fusion-plugin-grok-runtime/src/cli-stream.ts | 22 +-
.../src/runtime-adapter.ts | 109 ++----
.../src/stream-parser.ts | 27 +-
plugins/fusion-plugin-grok-runtime/src/types.ts | 104 +----
10 files changed, 338 insertions(+), 892 deletions(-)
Fusion-Task-Id: FN-7790
Fusion-Task-Lineage: 377e86c4-c005-46a5-9eb4-69e858c38b79
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Task execution sessions previously ignored the assigned permanent agent's
runtimeConfig model whenever the executor was handed an agents-less
worktree AgentStore, silently drifting to the pi runtime's built-in
default model instead of the configured one.
- Add TaskExecutor.getAuthoritativeAssignedAgent(): falls back to the
authoritative project `.fusion` AgentStore when the live executor's
worktree AgentStore has no record of the assigned agent, so
runtimeConfig resolution matches chat-session behavior.
- Replace direct `this.options.agentStore.getAgent(...)` lookups across
step-session, workflow-graph, and legacy execution paths with the new
authoritative lookup helper.
- Warn and audit (`noModelResolved` / `runtimeBuiltInFallbackModel`) when
a non-mock, non-test-mode session resolves no provider/model pair and
falls back to the runtime's built-in default, so the drift is visible
instead of silent.
- Add regression tests covering assigned-agent runtime-config resolution
and the new runtime-resolved audit fields.
- Add changeset (patch) and update docs/settings-reference.md and
AGENTS.md.
Files changed:
.changeset/fuzzy-fable-fallback.md | 7 +++
AGENTS.md | 1 +
docs/settings-reference.md | 2 +-
.../executor-assigned-agent-runtime-config.test.ts | 68 ++++++++++++++++++++++
.../run-audit-session-runtime-resolved.test.ts | 44 ++++++++++++++
packages/engine/src/agent-session-helpers.ts | 31 +++++++---
packages/engine/src/executor.ts | 43 +++++++++-----
7 files changed, 174 insertions(+), 22 deletions(-)
Fusion-Task-Id: FN-7787
Fusion-Task-Lineage: 40fccad5-2e67-4ee2-8199-4548ce9025c6
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Fixes the residual "Grok CLI still returns no message immediately" case where a headless run exits code 0 but never emits any parsed NDJSON event, previously treated as a silent success.
- Detect a code-0 close with zero parsed NDJSON events and surface a diagnostic explaining the likely cause (wrong/unsupported grok binary falling into interactive mode and hitting EOF on stdin).
- Track and emit assistant text/diagnostics via a new appendMessage/emitDiagnosticText path so onText and session.state.errorMessage stay in sync, including on spawn failure and inactivity/first-line timeouts.
- Add first-line/inactivity timeout diagnostics with concrete elapsed-time messaging instead of silent kills.
- Add regression coverage in runtime-adapter.test.ts and grok-runtime-routing.test.ts for the zero-NDJSON exit path.
- Document the contract update in docs/grok-cli-contract.md.
- Add a patch changeset for @runfusion/fusion.
Files changed:
$(cat /tmp/diffstat_fn7788.txt)
Fusion-Task-Id: FN-7788
Fusion-Task-Lineage: dbb238a9-9601-47fc-8a88-40817d749337
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Rescopes the Thinking Level <select> dark-theme CSS to the createPortal dropdown container so it renders styled everywhere CustomModelDropdown is used, not just under the trigger wrapper.
- Change .thinking-level-select CSS selectors from .model-combobox to .model-combobox-dropdown scope (base, hover, focus, disabled, option, optgroup rules)
- Update test regexes/assertions to match the new .model-combobox-dropdown scope and assert the old .model-combobox scope no longer appears
- Add assertion that the thinking select renders inside .model-combobox-dropdown
- Add changeset (patch) documenting the fix
Files changed:
.changeset/fn-7789-thinking-level-select-portal-scope.md | 7 +++++++
packages/dashboard/app/components/CustomModelDropdown.css | 15 +++++++++------
.../app/components/__tests__/CustomModelDropdown.test.tsx | 6 ++++--
3 files changed, 20 insertions(+), 8 deletions(-)
Fusion-Task-Id: FN-7789
Fusion-Task-Lineage: 5c3addff-a672-42b1-94a9-11c0f235bb57
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Estimated cost on the dashboard could render empty because team/workflow analytics priced rows using the legacy task.modelProvider/modelId columns, which can be NULL even when a durable tokenUsageModelProvider/tokenUsageModelId snapshot exists on the row.
- Select tokenUsageModelProvider/tokenUsageModelId alongside the legacy model columns in the team-analytics and workflow-analytics task token queries
- Price each row using the token-usage model snapshot first, falling back to the legacy model columns, so cost survives model-resolution drift and empty legacy columns
- Add regression coverage in team-analytics, workflow-analytics, and model-pricing tests, plus a dashboard TaskDetailModal summary-tab test asserting estimated cost renders
- Add a patch changeset documenting the fix for @runfusion/fusion
Files changed:
.changeset/fn-7786-estimated-cost.md | 7 +++++
packages/core/src/__tests__/model-pricing.test.ts | 10 +++++++
packages/core/src/__tests__/team-analytics.test.ts | 34 ++++++++++++++++++++--
.../core/src/__tests__/workflow-analytics.test.ts | 33 +++++++++++++++++++--
packages/core/src/team-analytics.ts | 15 ++++++++--
packages/core/src/workflow-analytics.ts | 15 ++++++++--
.../__tests__/TaskDetailModal.summary-tab.test.tsx | 34 ++++++++++++++++++++++
7 files changed, 140 insertions(+), 8 deletions(-)
Fusion-Task-Id: FN-7786
Fusion-Task-Lineage: dab32809-4bb8-42c0-aed0-a0c1131ec641
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Fix Chat header showing thread controls (session switcher, back button, room header) while the conversation list is still displayed on mobile after re-entering Chat, since restored session/room state no longer implied the detail pane was visible.
- Derive mobileThreadPaneOpen from actual sidebar visibility (!sidebarVisible) combined with active thread/room state instead of relying solely on restored session/room presence.
- Gate showMobileSessionSwitcher, showMobileDirectThreadHeaderControls, and new showMobileRoomThreadHeaderControls off the corrected mobileThreadPaneOpen signal.
- Wrap the room thread header in showMobileRoomThreadHeaderControls so it only renders when the detail pane is actually shown.
- Add regression coverage in ChatView.mobile.test.tsx and ChatView.swipe-back.test.tsx for the list-shown-after-remount case.
- Add changeset documenting the fix.
Files changed:
.changeset/fn-7784-chat-header-list-consistency.md | 7 +
packages/dashboard/app/components/ChatView.tsx | 18 ++-
.../components/__tests__/ChatView.mobile.test.tsx | 141 +++++++++++++++++++--
.../__tests__/ChatView.swipe-back.test.tsx | 74 +++++++++--
4 files changed, 214 insertions(+), 26 deletions(-)
Fusion-Task-Id: FN-7784
Fusion-Task-Lineage: e2571efa-dff9-43ef-af09-f7d2ce32788b
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Fixes plugin skills silently disappearing when the fn daemon is started outside the project that enabled the contributing plugin, by making skill resolution project-aware instead of scoped to the daemon's root PluginLoader.
- getPluginSkills now resolves per requesting rootDir against project_plugin_states rather than the daemon-root PluginLoader scope
- Plugins skipped as disabled are now logged at load time for visibility
- Wired the new project-aware resolution through dashboard.ts, serve.ts, and daemon.ts CLI commands
- Added regression coverage in plugin-loader.test.ts and skills-adapter.test.ts
- Documented the project-scoped behavior in docs/PLUGIN_AUTHORING.md and docs/agents.md
- Added a patch changeset for @runfusion/fusion
Files changed:
.changeset/fn-7778-plugin-skills-project-scope.md | 7 +++
docs/PLUGIN_AUTHORING.md | 2 +
docs/agents.md | 2 +-
packages/cli/src/commands/daemon.ts | 68 +++++++++++++++++++--
packages/cli/src/commands/dashboard.ts | 71 ++++++++++++++++++++--
packages/cli/src/commands/serve.ts | 68 +++++++++++++++++++--
packages/core/src/__tests__/plugin-loader.test.ts | 69 +++++++++++++++++++++
packages/core/src/plugin-loader.ts | 29 ++++++---
.../dashboard/src/__tests__/skills-adapter.test.ts | 29 +++++++++
packages/dashboard/src/skills-adapter.ts | 19 ++++--
10 files changed, 337 insertions(+), 27 deletions(-)
Fusion-Task-Id: FN-7778
Fusion-Task-Lineage: 5d9a8ff2-ed0e-4859-bf9c-a16f715b081d
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Root-causes the Grok CLI empty-response bug: readline close no longer finalizes the session before the subprocess close event can attach exit code/stderr diagnostics, so failures were silently swallowed as empty assistant messages.
- Wait for subprocess close/error (not readline close) to finalize the Grok CLI session, so non-zero exits can attach stderr before callers inspect the result
- Add GrokSession.state.errorMessage to carry concrete diagnostics (spawn failure, process error, non-zero exit + stderr, or NDJSON error event) through the resolve-never-reject runtime contract
- Track whether any text was received so error diagnostics are only recorded when the run actually produced nothing
- Add a changeset documenting the fix for @runfusion/fusion
- Extend runtime-adapter tests to cover spawn failure, process error, non-zero exit with/without stderr, and NDJSON error-event diagnostics
Files changed:
.changeset/fn-7782-grok-cli-no-response.md | 7 ++
.../src/__tests__/runtime-adapter.test.ts | 98 ++++++++++++++++++++--
.../src/runtime-adapter.ts | 75 +++++++++++++----
plugins/fusion-plugin-grok-runtime/src/types.ts | 1 +
4 files changed, 161 insertions(+), 20 deletions(-)
Fusion-Task-Id: FN-7782
Fusion-Task-Lineage: c2907a70-0556-488f-bda3-132657b64071
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Moves the agent-created badge out of the task card header's meta-badges row into its own bottom row so it no longer causes header wrapping.
- Moved .card-agent-created-badge out of .card-meta-badges into a new .card-agent-badge-row in TaskCard.tsx
- Updated hasCardMetaBadges guard logic and TaskCard.css to support the new bottom row layout
- Added TaskCard.badge-wrap.test.tsx regression coverage and extended TaskCard.test.tsx
- Updated docs/dashboard-guide.md
- Added changeset fn-7780-agent-badge-bottom-row.md (patch, fix category)
Files changed:
.changeset/fn-7780-agent-badge-bottom-row.md | 7 +++
docs/dashboard-guide.md | 3 +-
packages/dashboard/app/components/TaskCard.css | 12 ++++
packages/dashboard/app/components/TaskCard.tsx | 29 ++++++----
.../__tests__/TaskCard.badge-wrap.test.tsx | 66 ++++++++++++++++++++++
.../app/components/__tests__/TaskCard.test.tsx | 34 ++++++++---
6 files changed, 131 insertions(+), 20 deletions(-)
Fusion-Task-Id: FN-7780
Fusion-Task-Lineage: 6a6cd9f6-a9ce-488f-969d-520459c8631b
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Adds dark-theme CSS styling for the inline Thinking Level <select> so it no longer renders as an OS-default white control across model-picker surfaces, including the quick-add QuickEntryBox and InlineCreateCard popups.
- Add .thinking-level-select rule set in CustomModelDropdown.css mirroring the canonical dark select tokens (background, border, color, focus ring, disabled state, option/optgroup styling)
- Add a custom dropdown chevron indicator via .model-combobox-thinking::after and make the container position: relative
- Add a regression test asserting the select and option rules use the dark theme CSS tokens
- Add a patch changeset for @runfusion/fusion documenting the fix
Files changed:
.changeset/fn-7774-thinking-level-select-styling.md | 7 +++
packages/dashboard/app/components/CustomModelDropdown.css | 59 ++++++++++++++++++++++
packages/dashboard/app/components/__tests__/CustomModelDropdown.test.tsx | 16 ++++++
3 files changed, 82 insertions(+)
Fusion-Task-Id: FN-7774
Fusion-Task-Lineage: 9ef9bf07-dd18-499c-b04d-1b137d200689
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Empty final assistant chat messages (e.g. Grok CLI runs that finish with no text) now show a muted "No message" placeholder instead of a blank bubble, in both Chat and Planner Chat via the shared StandardChatSurface component.
- Add isEmptyAssistantMessage check in StandardChatMessageItem: only applies to final persisted assistant messages with no content, tool calls, thinking output, attachments, or failure info
- Render a new .chat-message-content--empty block with the "No message" i18n string when the check matches
- Add shared CSS rule combining --waiting and --empty muted/italic styling, switching to var(--font-size-sm)
- Add "chat.noMessage" translation key to en/app.json and regenerate resources.d.ts
- Document the new behavior in docs/dashboard-guide.md
- Add a patch changeset for @runfusion/fusion
- Add StandardChatSurface.empty-message.test.tsx covering empty/whitespace content, populated content, tool calls, thinking output, attachments, failure info, non-assistant roles, and streaming waiting/thinking states
Files changed:
$(cat /tmp/diffstat_fn7779.txt)
Fusion-Task-Id: FN-7779
Fusion-Task-Lineage: d3ae068e-acba-4b4c-85d6-a788aa24a53b
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Tightens the mobile Settings modal footer rail so Version/Help, Import/Export/Reset, and Save no longer overlap or crowd on small viewports.
- Split modal-header and modal-actions padding rules so the mobile footer uses tighter --space-xs block padding independently of the header
- Center-align modal-actions-left/right, footer version, update-check, and version-check-button on the mobile footer rail
- Make the version text and version-check button non-wrapping inline elements with normalized line-height so they stop overlapping neighboring controls
- Add a settings-modal-version rule as a non-wrapping inline-flex box
- Extend settings-mobile.test.tsx with regression coverage for the tightened mobile footer layout
- Add a patch changeset documenting the fix
Files changed:
.changeset/fn-7773-mobile-settings-footer.md | 7 +++
packages/dashboard/app/components/SettingsModal.css | 55 +++++++++++++++----
packages/dashboard/app/components/__tests__/settings-mobile.test.tsx | 62 +++++++++++++++++-----
3 files changed, 103 insertions(+), 21 deletions(-)
Fusion-Task-Id: FN-7773
Fusion-Task-Lineage: ea45e7bb-2560-4d17-89dd-9dbc7a307351
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Fix useArtifacts fetching/subscribing only when a projectId is present, which left the Artifacts tab stuck at 0 on single-project dashboards where currentProject is unset at mount.
- useArtifacts now builds a cache key and fetches/subscribes even without a projectId, scoping the cache under a __default__ key
- SSE subscription omits the projectId query param when unset (default/unscoped /api/events) and only filters incoming events by projectId when one is set
- Added/updated tests covering the default-scope fetch, cache, and SSE subscription paths
- Added a changeset documenting the fix
Files changed:
.changeset/fn-7767-artifacts-default-scope.md | 7 ++++
.../app/hooks/__tests__/useArtifacts.test.ts | 42 +++++++++++++++++---
packages/dashboard/app/hooks/useArtifacts.ts | 37 ++++++------------
.../__tests__/artifacts-route-integration.test.ts | 45 ++++++++++++++++++++++
4 files changed, 100 insertions(+), 31 deletions(-)
Fusion-Task-Id: FN-7767
Fusion-Task-Lineage: b4ea9b1f-2908-4f5b-bf75-d6fdc45f9340
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Fix a "Response failed" crash for plugin CLI runtime chats (grok/droid/cursor) whose sessions expose top-level `messages` and stream via `onText` without a pi-shaped `session.state`.
- Read messages/errorMessage null-safely from `session.state`, falling back to top-level `session.messages` when state is absent, in both the room responder and streaming response extraction paths
- Keep `state.errorMessage` optional so successful streams from state-less sessions no longer throw TypeErrors, while pi/openclaw/hermes provider errors still surface correctly
- Add regression tests covering state-less plugin CLI sessions in chat-manager.test.ts
- Add changeset for the fix
Files changed:
.changeset/fn-7765-grok-cli-chat-crash.md | 7 ++
packages/dashboard/src/__tests__/chat-manager.test.ts | 90 ++++++++++++++++++++++
packages/dashboard/src/chat.ts | 35 ++++++---
3 files changed, 121 insertions(+), 11 deletions(-)
Fusion-Task-Id: FN-7765
Fusion-Task-Lineage: 80e33a97-e971-4aec-a4cf-29d97c5c5e62
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Extend artifact test coverage to pin creation, listing, and viewing across every artifact type and payload variant on both the agent/dashboard-chat tool surface and the dashboard artifacts route.
- Add a route-level integration test covering list/serve for all artifact types (document, image, video, audio, other) across inline content, uri reference, and binary data payloads, including task-scoped filtering, registry-level (task-less) artifacts, and 404 behavior for uri-only artifacts requested via /media.
- Add an engine-level real-TaskStore test exercising fn_artifact_register/list/view (agent tools) and the dashboard-chat artifact tool for every artifact type and content/uri/dataBase64 variant, asserting list and view output correctness.
- Factor out shared PNG_IMAGE_BYTES fixture and per-type MIME/binary fixtures to keep new assertions concise.
Files changed:
.../__tests__/artifacts-route-integration.test.ts | 150 ++++++++++++++++++++-
.../src/__tests__/agent-artifact-tools.test.ts | 142 ++++++++++++++++++-
2 files changed, 287 insertions(+), 5 deletions(-)
Fusion-Task-Id: FN-7764
Fusion-Task-Lineage: 187b3f0f-d1b4-42fe-9658-1ee67870b524
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Broadens regression coverage for the npm-release update-check invariant so it holds across every consuming surface, not just the reported repro.
- Replace the update-check route/service semver spot-checks with a parametrized case matrix (equal, newer, older, prerelease/build metadata, short/long version segments) to close false-positive/false-negative gaps.
- Add dedicated route-level tests asserting the update-check API route surfaces the same invariant.
- Add CLI update command tests covering notification rendering across version-comparison cases.
- Add desktop native update-check tests covering the same invariant on the desktop shell.
- Add dashboard useUpdateCheck hook tests verifying consistent notification behavior for the hook consumers.
Files changed:
packages/cli/src/commands/__tests__/update.test.ts | 59 ++++++++++++++++++
.../app/hooks/__tests__/useUpdateCheck.test.ts | 25 ++++++++
.../src/__tests__/update-check-route.test.ts | 71 ++++++++++++++++++++++
.../dashboard/src/__tests__/update-check.test.ts | 42 +++++++------
packages/desktop/src/__tests__/native.test.ts | 27 ++++++++
5 files changed, 206 insertions(+), 18 deletions(-)
Fusion-Task-Id: FN-7762
Fusion-Task-Lineage: 6ab34312-fb4e-487a-aefc-2ab133bf79af
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Packaged fn serve/daemon/dashboard hosts previously failed with a misleading missing-API-key error for grok-cli agents even though the operator was already logged in via the Grok CLI. This fixes routing so those hosts eagerly ensure the bundled Grok Runtime plugin is installed/loaded before session creation, and no longer silently falls back to the key-requiring direct endpoint when no key is visible.
- Eagerly ensure the bundled fusion-plugin-grok-runtime in serve, daemon, and dashboard commands before loadAllPlugins() so runtime id "grok" is available on fresh installs without manual plugin-settings setup.
- agent-session-helpers.ts: deriveGrokRuntimeHintForNoVisibleKey now throws an actionable error (naming both remediations: install/enable the Grok CLI runtime plugin, or set GROK_API_KEY) instead of silently falling through to the key-requiring pi/openai-completions path when the runtime can't be loaded.
- Update docs/grok-cli-contract.md to document the FN-7761 packaged-host wiring and new no-silent-fallback behavior.
- Add regression tests for the packaged bootstrap behavior and bundled-plugin install path.
- Add changeset for @runfusion/fusion (patch, category: fix).
Files changed:
.changeset/fn-7761-grok-cli-packaged-routing.md | 7 +++++
docs/grok-cli-contract.md | 19 +++++++++----
.../__tests__/grok-runtime-bootstrap.test.ts | 31 ++++++++++++++++++++++
packages/cli/src/commands/daemon.ts | 17 +++++++++++-
packages/cli/src/commands/dashboard.ts | 20 +++++++++++++-
packages/cli/src/commands/serve.ts | 19 +++++++++++--
.../__tests__/bundled-plugin-install.test.ts | 17 ++++++++++++
.../src/__tests__/grok-runtime-routing.test.ts | 17 ++++++------
packages/engine/src/agent-session-helpers.ts | 15 +++++++++--
9 files changed, 142 insertions(+), 20 deletions(-)
Fusion-Task-Id: FN-7761
Fusion-Task-Lineage: 3be5f054-965c-4e8a-ad91-6e61d4dc4a42
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Adds an explicit touch-scroll contract to the portaled model combobox list so it remains scrollable on mobile despite the global mobile lockdown that hides body/root overflow and defaults gestures to vertical panning.
- Add -webkit-overflow-scrolling: touch, overscroll-behavior: contain, and touch-action: pan-y to .model-combobox-list so the fixed-position dropdown owns its own touch scrolling on mobile.
- Add regression tests covering the mobile scroll contract for CustomModelDropdown.
- Add a patch changeset documenting the fix for release notes.
Files changed:
.changeset/fn-7760-mobile-model-dropdown-scroll.md | 7 +++
packages/dashboard/app/components/CustomModelDropdown.css | 7 +++
packages/dashboard/app/components/__tests__/CustomModelDropdown.test.tsx | 70 ++++++++++++++++++++++
3 files changed, 84 insertions(+)
Fusion-Task-Id: FN-7760
Fusion-Task-Lineage: e135ff47-275b-4606-aef2-c9859aeaa418
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Fix Grok CLI 'missing API key' false-positive by extending the no-visible-key routing invariant to configured fallback models, not just the default provider.
- deriveGrokRuntimeHintForNoVisibleKey now also triggers when the fallback provider is grok-cli
- new applyGrokCliNoKeyRuntimeOptions promotes a grok-cli fallback model into the primary session (stripping the provider-qualified model prefix) instead of leaving it as an unused fallback
- docs/grok-cli-contract.md updated to describe the fallback-routing contract
- added regression tests in grok-runtime-routing.test.ts, chat-manager.test.ts, and chat-manager-room-hybrid.test.ts
- added changeset fn-7758-grok-cli-no-key-routing.md (patch)
Files changed:
.changeset/fn-7758-grok-cli-no-key-routing.md | 7 ++
docs/grok-cli-contract.md | 29 +++--
.../src/__tests__/chat-manager-room-hybrid.test.ts | 36 +++++++
.../dashboard/src/__tests__/chat-manager.test.ts | 41 +++++++
packages/dashboard/src/chat.ts | 16 ++-
.../src/__tests__/grok-runtime-routing.test.ts | 118 +++++++++++++++++++++
packages/engine/src/agent-session-helpers.ts | 36 ++++++-
7 files changed, 266 insertions(+), 17 deletions(-)
Fusion-Task-Id: FN-7758
Fusion-Task-Lineage: 6b564b21-50ab-4c3e-b0d7-7fded2091d90
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Fixes the dashboard showing empty/dash estimated costs for runs on newer OpenAI Codex models, whose pricing was missing from the static model-pricing table.
- Add pricing entries for gpt-5.3-codex-spark, gpt-5.4, gpt-5.4-mini, and gpt-5.5 under the openai-codex provider, sourced from the pinned pi-ai 0.80.5 model catalog.
- Correct the previously-guessed gpt-5.6-luna/sol/terra rates to match their actual distinct published rates instead of all sharing the gpt-5.3-codex rate.
- Update/add tests across model-pricing, team-analytics, token-analytics, and workflow-analytics to cover the new/corrected pricing entries.
- Add dashboard tests (TaskSummaryTab prior attempts, CommandCenter mobile scroll, TokensArea, task-planner chat metrics) verifying costs render correctly instead of falling back to unavailable.
- Add a patch changeset documenting the estimated-cost fix.
Files changed:
$(cat /tmp/diffstat.txt)
Fusion-Task-Id: FN-7757
Fusion-Task-Lineage: e0f2e9d5-e922-4878-82d0-40c7d9899fdb
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Route grok-cli model selections through the grok CLI runtime when no Fusion-visible GROK_API_KEY is available.
- Add read-only isGrokApiKeyFusionVisible() in packages/core/src/grok-provider.ts, refactored to share user-settings-file reading with hydrateGrokApiKeyFromUserSettings without mutating process.env or logging key material.
- In packages/engine/src/agent-session-helpers.ts, auto-derive the existing "grok" runtimeHint when defaultProvider is grok-cli, no key is Fusion-visible, and the grok plugin runtime is registered; explicit runtime hints and mock/test-mode routing remain unchanged, and the provider-qualified model prefix is stripped before handoff.
- Normalize provider-qualified model ids (grok-cli/<id>, grok/<id>) in the grok-runtime plugin's runtime-adapter and CLI stream spawn so the concrete model reaches `grok --model`, with the historical grok/default fallback preserved for the no-model path.
- Update docs (grok-cli-contract.md, settings-reference.md, plugin README) and add/extend tests covering the new fallback behavior, model normalization, and CLI streaming.
- Add changeset fn-7753-grok-cli-no-key-fallback.md (patch, fix).
Files changed:
.changeset/fn-7753-grok-cli-no-key-fallback.md | 7 ++
docs/grok-cli-contract.md | 83 ++++++++++------
docs/settings-reference.md | 6 +-
.../__tests__/grok-provider-user-settings.test.ts | 46 +++++++++
packages/core/src/grok-provider.ts | 39 +++++++-
packages/core/src/index.gate.ts | 1 +
packages/core/src/index.ts | 1 +
.../src/__tests__/grok-runtime-routing.test.ts | 107 +++++++++++++++++++--
packages/engine/src/agent-session-helpers.ts | 52 +++++++++-
plugins/fusion-plugin-grok-runtime/README.md | 46 +++++----
.../src/__tests__/cli-stream.test.ts | 70 ++++++++++++++
.../src/__tests__/runtime-adapter.test.ts | 28 ++++++
.../fusion-plugin-grok-runtime/src/cli-stream.ts | 6 ++
.../src/runtime-adapter.ts | 24 ++++-
14 files changed, 443 insertions(+), 73 deletions(-)
Fusion-Task-Id: FN-7753
Fusion-Task-Lineage: 30ef7265-1ba9-47fd-8c4e-87b02f6a1d78
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Bumps the pi SDK dependencies to 0.80.6 across the CLI, dashboard, engine, and pi-claude-cli packages, and adapts the Claude CLI thinking-effort mapper for the new `max` ThinkingLevel.
- Bump @earendil-works/pi-ai and @earendil-works/pi-coding-agent from ^0.80.5 to ^0.80.6 in packages/cli, packages/dashboard, packages/engine, and packages/pi-claude-cli (dependency/peerDependency/devDependency entries)
- Regenerate pnpm-lock.yaml for the new SDK versions
- Map the new `max` ThinkingLevel in packages/pi-claude-cli/src/thinking-config.ts: non-Opus models downgrade to `high` (effort max unsupported), Opus models map to `max`
- Extend packages/pi-claude-cli/src/__tests__/thinking-config.test.ts with coverage for the `max` level
- Add .changeset/fn-7755-pi-sdk-bump.md (patch) documenting the SDK bump
Files changed:
.changeset/fn-7755-pi-sdk-bump.md | 7 ++
packages/cli/package.json | 4 +-
packages/dashboard/package.json | 2 +-
packages/engine/package.json | 4 +-
packages/pi-claude-cli/package.json | 8 +-
.../src/__tests__/thinking-config.test.ts | 12 +++
packages/pi-claude-cli/src/thinking-config.ts | 10 ++-
pnpm-lock.yaml | 92 +++++++++++-----------
8 files changed, 82 insertions(+), 57 deletions(-)
Fusion-Task-Id: FN-7755
Fusion-Task-Lineage: f6a9084b-dfb9-4ad5-bd99-4627dae4c666
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Wires the GPT-5.6 codenamed OpenAI Codex models (gpt-5.6-luna/sol/terra) into the engine pi model-registry seeding surface, mirroring the dashboard's /api/models supplemental merge so the models are no longer missing from pi.
- Call mergeSupplementalOpenAiCodexModels() in createFnAgent (packages/engine/src/pi.ts) alongside the existing Anthropic supplemental merge
- Add regression tests covering synthesis of missing GPT-5.6 rows and dedupe against pinned catalog entries
- Update docs/settings-reference.md to describe the additive surfacing on both /api/models and the engine/pi registry-seeding path
- Add a patch changeset for @runfusion/fusion
Files changed:
.changeset/fn-7754-openai-gpt-5-6-pi-surface.md | 7 +++
docs/settings-reference.md | 2 +-
.../src/__tests__/pi-create-fn-agent.test.ts | 63 ++++++++++++++++++++++
packages/engine/src/pi.ts | 6 +++
4 files changed, 77 insertions(+), 1 deletion(-)
Fusion-Task-Id: FN-7754
Fusion-Task-Lineage: b61b6812-c94b-46d8-b187-445ccdd6e4e9
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Squashes FN-7752, improving the mobile Settings modal layout to reduce chrome and simplify section navigation on small screens.
- Replace the mobile section-picker button row with a compact dropdown-only selector, keeping an accessible aria-label
- Slim down the header and footer, collapsing footer actions to a single row on mobile
- Tighten SettingsModal.css breakpoint rules (≤768px) for header/footer sizing and spacing
- Update settings-mobile tests to cover the new dropdown-only picker and single-row footer behavior
- Add changeset documenting the mobile layout fix
Files changed:
.changeset/fn-7752-mobile-settings-layout.md | 7 +++
.../dashboard/app/components/SettingsModal.css | 62 ++++++++++++++++------
.../dashboard/app/components/SettingsModal.tsx | 19 +++++--
.../components/__tests__/settings-mobile.test.tsx | 26 +++++++--
4 files changed, 90 insertions(+), 24 deletions(-)
Fusion-Task-Id: FN-7752
Fusion-Task-Lineage: 5dea597c-19f7-49c4-979a-7528d84fa6c5
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Relocates the mobile-only settings search icon toggle so it sits inline next to the section dropdown instead of its own row above it, tightening the mobile Settings header.
- Move the settings-search-toggle button out of the standalone .settings-search row into a new .settings-mobile-section-picker-control-row alongside the mobile section <select>.
- Preserve FN-7713 expand/hide toggle behavior and active-query preservation; desktop/tablet layout unaffected.
- Add CSS for .settings-mobile-section-picker-control-row to lay out the select and toggle button inline.
- Update settings-mobile tests to assert the toggle renders next to the section picker.
- Add changeset (patch) documenting the fix.
Files changed:
.../fn-7751-mobile-settings-search-inline.md | 7 ++
docs/dashboard-guide.md | 4 +-
.../dashboard/app/components/SettingsModal.css | 23 ++++--
.../dashboard/app/components/SettingsModal.tsx | 89 +++++++++++-----------
.../components/__tests__/settings-mobile.test.tsx | 38 ++++++++-
5 files changed, 105 insertions(+), 56 deletions(-)
Fusion-Task-Id: FN-7751
Fusion-Task-Lineage: 8bb9a32b-80f4-4b73-a366-d23e97106b73
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Fixes autoMerge=false being bypassed for engine-created branch-group member tasks whose branch group had already dissolved/finalized.
- Add isLiveSharedBranchGroupMemberIntegration(task, group) in @fusion/core, requiring the branch group's status be "open" before the shared-branch-member exemption bypasses the global/task autoMerge:false hold.
- Export the new helper from packages/core/src/index.ts and index.gate.ts.
- Thread the live-group check through packages/engine/src/project-engine.ts (allowInReviewMergeProcessing, enqueueEligibleInReviewTasks, merge-confirmed fast-path branch routing, and merge handoff paths).
- Add TaskExecutor.isLiveSharedBranchGroupMember helper in packages/engine/src/executor.ts and use it in retryable pre-merge remediation, no-op finalize, benign pause-abort classification, and merge-processing gates.
- Keep self-healing.ts's solo no-op finalize predicate on the pure branchContext-shape check (isSharedBranchGroupMemberIntegration) intentionally, so stale shared-group members stay excluded from solo finalize regardless of group liveness.
- Add regression tests covering the executor and project-engine auto-merge-hold behavior for stale/dissolved branch groups.
- Add a patch changeset documenting the fix.
Files changed:
.../fn-7750-automerge-hold-stale-branch-group.md | 7 ++
packages/core/src/__tests__/task-merge.test.ts | 42 +++++++++--
packages/core/src/index.gate.ts | 1 +
packages/core/src/index.ts | 1 +
packages/core/src/task-merge.ts | 13 +++-
...cutor-live-branch-group-auto-merge-hold.test.ts | 85 ++++++++++++++++++++++
.../engine/src/__tests__/project-engine.test.ts | 37 +++++++++-
packages/engine/src/executor.ts | 22 ++++--
packages/engine/src/project-engine.ts | 32 +++++---
packages/engine/src/self-healing.ts | 1 +
10 files changed, 214 insertions(+), 27 deletions(-)
Fusion-Task-Id: FN-7750
Fusion-Task-Lineage: d61f8847-0b09-49b5-b66a-00018c8738bb
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>