Commit Graph

10988 Commits

Author SHA1 Message Date
gsxdsm
f7c6f560c0 FN-7753: route grok-cli execution through the grok CLI when no Fusion-visible GROK_API_KEY resolves
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>
2026-07-09 21:36:14 -07:00
gsxdsm
28c82331e7 FN-7755: upgrade bundled pi SDK to 0.80.6
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>
2026-07-09 21:32:59 -07:00
gsxdsm
d2c2a4cab1 FN-7754: seed OpenAI GPT-5.6 Codex models into pi createFnAgent registry
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>
2026-07-09 21:30:34 -07:00
gsxdsm
9ce0b49054 FN-7752: tighten mobile Settings modal layout
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>
2026-07-09 21:19:40 -07:00
gsxdsm
547740bb66 FN-7751: move mobile settings search toggle inline with section picker
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>
2026-07-09 20:13:20 -07:00
gsxdsm
eb377ba831 FN-7750: gate shared-branch-group auto-merge exemption on live groups
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>
2026-07-09 19:58:08 -07:00
gsxdsm
786a274ae6 FN-7749: fix benign pause/resume abort marking manual merge holds as failed
Fixes tasks in auto-merge-off manual merge hold getting incorrectly marked failed by a benign pause/resume abort, which blocked Merge & Close.

- Add isBenignManualMergeHoldPauseAbort classifier in executor.ts: recognizes a hard-cancel pause-abort at a merge-region node while auto-merge is off (or processing is disallowed) as benign, and preserves the in-review row instead of failing/re-enqueueing it.
- Clear stale pause-abort status/error and suppress the failure notification when this benign manual-hold case is detected, per FN-5147's no-backward-move/no-reenqueue contract.
- Extend self-healing.ts recovery to handle this manual-hold case alongside existing paused-abort recovery paths.
- Add/extend tests in merge-node-paused-abort-retryable.test.ts and self-healing-paused-abort-recovery.test.ts covering the new benign classification.
- Document the fix in docs/architecture.md.
- Add changeset (patch) describing the user-facing fix.

Files changed:
 .changeset/fn-7749-manual-merge-hold-false-failure.md                                   |  7 +++
 docs/architecture.md                                                                    |  4 +-
 packages/engine/src/__tests__/reliability-interactions/merge-node-paused-abort-retryable.test.ts | 50 +++++++++++++++++----
 packages/engine/src/__tests__/self-healing-paused-abort-recovery.test.ts                | 49 ++++++++++++++++++++-
 packages/engine/src/executor.ts                                                         | 51 +++++++++++++++++++++-
 packages/engine/src/self-healing.ts                                                     | 23 ++++++++--
 6 files changed, 168 insertions(+), 16 deletions(-)

Fusion-Task-Id: FN-7749
Fusion-Task-Lineage: 6d90adc3-6cd9-463d-b9d0-7a5c3069c1a5
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-09 19:58:08 -07:00
gsxdsm
6a13ad175e FN-7732: remove dangling release-authorization UI/i18n/docs scaffolding
Narrative: The triage release-authorization gate itself was already removed in b5b0458; this cleans up the leftover scaffolding it left behind — an unemitted activity type, a dead TaskCard badge/label/CSS, orphaned i18n keys across all 6 locales, and a stale solutions doc — so the codebase no longer references a gate that no longer exists.

- Drop the unused `task:release-authorization-required` ActivityEventType and its label/rendering in ActivityFeed.tsx and ActivityLogModal.tsx
- Remove the dead `isReleaseAuthorizationHold` badge logic and `.awaiting-release-authorization` CSS class from TaskCard.tsx/TaskCard.css
- Simplify TaskDetailModal.tsx comments/logic now that legacy release-authorization holds render as ordinary manual plan-approval holds
- Delete orphaned i18n keys `tasks.awaitingReleaseAuthorization` and `taskDetail.plan.releaseAuthorizationHold` across en/es/fr/ko/zh-CN/zh-TW locales and resources.d.ts
- Delete the stale docs/solutions/architecture-patterns/release-triage-requires-user-authorization.md doc
- Update docs/workflow-steps.md and docs/settings-reference.md to describe the gate as removed (superseded by FN-7732) instead of documenting still-active behavior
- Add changeset for @runfusion/fusion (patch/internal)

Files changed:
 .changeset/fn-7732-remove-release-authorization-block.md |  7 +++++
 docs/settings-reference.md                                |  2 +-
 docs/solutions/architecture-patterns/release-triage-requires-user-authorization.md | 33 ----------------------
 docs/workflow-steps.md                                    |  6 ++--
 packages/core/src/types.ts                                 |  8 ++++--
 packages/dashboard/app/components/ActivityFeed.tsx         |  5 ----
 packages/dashboard/app/components/ActivityLogModal.tsx     |  6 ----
 packages/dashboard/app/components/TaskCard.css             | 11 --------
 packages/dashboard/app/components/TaskCard.tsx              | 13 +++------
 packages/dashboard/app/components/TaskDetailModal.tsx       | 14 +++------
 packages/i18n/locales/en/app.json                           |  3 --
 packages/i18n/locales/es/app.json                           |  5 +---
 packages/i18n/locales/fr/app.json                           |  5 +---
 packages/i18n/locales/ko/app.json                           |  5 +---
 packages/i18n/locales/zh-CN/app.json                        |  5 +---
 packages/i18n/locales/zh-TW/app.json                        |  5 +---
 packages/i18n/src/resources.d.ts                            |  3 --
 17 files changed, 30 insertions(+), 106 deletions(-)

Fusion-Task-Id: FN-7732

Fusion-Task-Lineage: d4137bd8-9056-4062-9f2a-c6f5d47295f4

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-09 19:58:07 -07:00
gsxdsm
2c4052c76b FN-7746: Add thinking level selector to model pickers
Adds a thinking-level (reasoning-effort) selector to the quick-create model pickers, matching the levels already available in the full task pickers.

- ModelSelectionModal: adds optional thinking-level <select> (off/minimal/low/medium/high/xhigh) with a status badge, rendered only when onThinkingLevelChange is supplied
- QuickEntryBox: wires thinking-level state through to ModelSelectionModal and persists the override with quick-created tasks
- InlineCreateCard: same thinking-level wiring for the inline task creation card
- Adds i18n strings for the new thinking-level labels across en/es/fr/ko/zh-CN/zh-TW locale files
- Adds test coverage in InlineCreateCard.test.tsx, ModelSelectionModal.test.tsx, and QuickEntryBox.test.tsx for the new selector

Files changed:
 .../dashboard/app/components/InlineCreateCard.tsx  | 16 ++++-
 .../app/components/ModelSelectionModal.tsx         | 47 +++++++++++++-
 .../dashboard/app/components/QuickEntryBox.tsx     | 67 ++++++++++++++++++-
 .../components/__tests__/InlineCreateCard.test.tsx | 70 ++++++++++++++++++++
 .../__tests__/ModelSelectionModal.test.tsx         | 69 ++++++++++++++++++++
 .../components/__tests__/QuickEntryBox.test.tsx    | 75 ++++++++++++++++++++++
 packages/i18n/locales/en/app.json                  |  2 +
 packages/i18n/locales/es/app.json                  |  2 +
 packages/i18n/locales/fr/app.json                  |  2 +
 packages/i18n/locales/ko/app.json                  |  2 +
 packages/i18n/locales/zh-CN/app.json               |  2 +
 packages/i18n/locales/zh-TW/app.json               |  2 +
 12 files changed, 351 insertions(+), 5 deletions(-)

Fusion-Task-Id: FN-7746

Fusion-Task-Lineage: 4a221203-0222-47d6-93f8-632638bcfbfe

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-09 19:58:07 -07:00
gsxdsm
f9307904c2 FN-7745: add GPT-5.6 codenamed model variants to model selector
Registers the three GPT-5.6 codenamed OpenAI Codex model variants (luna, sol, terra) so they appear in the model picker, since pricing alone did not make them selectable.

- Add packages/core/src/openai-models.ts with SUPPLEMENTAL_OPENAI_CODEX_PROVIDER_REGISTRATION and mergeSupplementalOpenAiCodexModels(), mirroring the existing Anthropic supplemental-merge seam; additive and dedupe-safe against the pinned pi-ai catalog
- Wire mergeSupplementalOpenAiCodexModels into GET /api/models via packages/dashboard/src/routes/register-model-routes.ts, alongside the existing Anthropic supplemental merge
- Export new symbols from packages/core/src/index.ts and packages/core/src/index.gate.ts
- Add unit tests for the merge helper (packages/core/src/__tests__/openai-models.test.ts) and the route wiring (packages/dashboard/src/__tests__/register-model-routes-openai-codex-supplemental.test.ts)
- Document the new supplemental catalog entries in docs/settings-reference.md
- Add changeset .changeset/fn-7745-gpt-5-6-codenamed-model-selector.md (minor, @runfusion/fusion)

Files changed:
 .../fn-7745-gpt-5-6-codenamed-model-selector.md    |   7 +
 docs/settings-reference.md                         |   2 +
 packages/core/src/__tests__/openai-models.test.ts  | 134 +++++++++++++++++
 packages/core/src/index.gate.ts                    |   9 ++
 packages/core/src/index.ts                         |   9 ++
 packages/core/src/openai-models.ts                 | 166 +++++++++++++++++++++
 ...-model-routes-openai-codex-supplemental.test.ts | 143 ++++++++++++++++++
 .../dashboard/src/routes/register-model-routes.ts  |  10 +-
 8 files changed, 479 insertions(+), 1 deletion(-)

Fusion-Task-Id: FN-7745

Fusion-Task-Lineage: 74c83182-df81-4606-a4dc-0da3ee4cae83

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-09 19:58:07 -07:00
gsxdsm
0e90578122 FN-7737: Add file_scope agent permission category with default allow disposition
Introduces a new file_scope sensitive-action category to the agent permission policy model so file-scope-related FN tools are classified and gated distinctly from other categories, defaulting to allowed under the grant-all preset.

- Add file_scope to AGENT_PERMISSION_POLICY_ACTION_CATEGORIES in @fusion/core types
- Classify FILE_SCOPE_FN_TOOLS in both agent-action-gate and permanent-agent-gating with a uniform preset disposition (no review_gate_bypass-style override)
- Update AgentDetailView and AgentPermissionPolicyEditor to surface the new category in the dashboard UI
- Add/extend unit tests across core, engine, and dashboard packages covering the new category's resolution, gating, and UI rendering
- Update docs/agents.md and docs/settings-reference.md to document the new permission category
- Regenerate i18n locale strings (en/es/fr/ko/zh-CN/zh-TW) and resources.d.ts for the new category labels
- Add changeset for @runfusion/fusion (minor) describing the new File Scope permission category

Files changed:
 .../fn-7737-file-scope-permission-category.md      |   7 +
 docs/agents.md                                     |  10 +-
 docs/settings-reference.md                         |   8 +-
 .../agent-permission-policy-resolution.test.ts     |  13 +
 .../src/__tests__/agent-permission-policy.test.ts  |  45 +++
 packages/core/src/types.ts                         |   7 +
 .../dashboard/app/components/AgentDetailView.tsx   |   2 +
 .../app/components/AgentPermissionPolicyEditor.tsx |   8 +
 .../__tests__/AgentPermissionPolicyEditor.test.tsx |  37 +++
 .../engine/src/__tests__/agent-action-gate.test.ts |  46 +++
 .../src/__tests__/gating-classifications.test.ts   |  67 +++++
 .../src/__tests__/permanent-agent-gating.test.ts   |  41 +++
 packages/engine/src/agent-action-gate.ts           |   7 +
 packages/engine/src/gating-classifications.ts      |   6 +
 packages/engine/src/permanent-agent-gating.ts      |   6 +
 packages/i18n/locales/en/app.json                  |   4 +
 packages/i18n/locales/es/app.json                  |   4 +
 packages/i18n/locales/fr/app.json                  |   4 +
 packages/i18n/locales/ko/app.json                  |   4 +
 packages/i18n/locales/zh-CN/app.json               |   4 +
 packages/i18n/locales/zh-TW/app.json               |   4 +
 packages/i18n/src/resources.d.ts                   | 310 +++++++++++++++------
 22 files changed, 550 insertions(+), 94 deletions(-)

Fusion-Task-Id: FN-7737

Fusion-Task-Lineage: 7b161fb3-7dd9-4860-aa4d-0cb35f38ea5b

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-09 19:58:07 -07:00
gsxdsm
1fa4a69dde FN-7747: derive dashboard authStorage fallback from engine.getAuthStorage()
Fixes desktop provider API keys not persisting when a host wires an engine into createServer() but forgets to pass its own authStorage, which previously caused register-auth-routes.ts to throw "Authentication is not configured".

- Add ProjectEngine.getAuthStorage() exposing the OAuth subsystem's raw createFusionAuthStorage() instance
- In createServer(), derive options.authStorage from engine.getAuthStorage() when not explicitly provided (mirrors existing engine-derivation pattern for onMerge/automationStore/etc.); explicit authStorage still overrides
- Add regression tests covering the fallback-derivation and explicit-override behavior
- Add changeset (patch) documenting the fix for @runfusion/fusion

Files changed:
 .changeset/fn-7747-derive-authstorage-from-engine.md |   7 ++
 packages/dashboard/src/__tests__/server.test.ts      | 119 +++++++++++++++++++++
 packages/dashboard/src/server.ts                     |  28 ++++-
 packages/engine/src/project-engine.ts                |  25 +++++
 4 files changed, 178 insertions(+), 1 deletion(-)

Fusion-Task-Id: FN-7747

Fusion-Task-Lineage: f8e72b15-d084-4e8d-89db-47453d57b41b

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-09 19:58:07 -07:00
gsxdsm
2ff8e2e13e FN-7743: detect and recover stalled in-progress executor tasks in overseer
Fix the planner overseer's executor-stage stall detection so hung in-progress tasks get unstuck instead of being reported as progressing forever.

- Add configurable stuck-detection: the executor-stage overseer observation now emits signal: "stuck" once an in-progress task has been inactive past a new plannerOverseerExecutorStuckAfterMs threshold, feeding the existing decidePlannerRecovery -> bounded inject_guidance recovery path.
- Register the new plannerOverseerExecutorStuckAfterMs setting in builtin-workflow-settings.ts and export it via core index.ts/index.gate.ts.
- Preserve human-control withholds (user-paused / approval-blocked / autoMerge-off) taking precedence over stuck detection.
- Add/extend tests covering planner-overseer, planner-recovery-controller, planner-recovery, and builtin-workflow-settings-triage.
- Document the new setting in docs/architecture.md and docs/settings-reference.md.
- Add changeset fn-7743-overseer-executor-stall.md (patch).

Files changed:
 .changeset/fn-7743-overseer-executor-stall.md      |   7 +
 docs/architecture.md                               |  31 +++++
 docs/settings-reference.md                         |   3 +-
 .../builtin-workflow-settings-triage.test.ts       |  22 ++++
 .../core/src/__tests__/planner-recovery.test.ts    |  12 ++
 packages/core/src/builtin-workflow-settings.ts     |  26 ++++
 packages/core/src/index.gate.ts                    |   1 +
 packages/core/src/index.ts                         |   1 +
 .../engine/src/__tests__/planner-overseer.test.ts  | 146 +++++++++++++++++++++
 .../__tests__/planner-recovery-controller.test.ts  |  52 +++++++-
 packages/engine/src/planner-overseer.ts            |  88 ++++++++++++-
 packages/engine/src/project-engine.ts              |  11 +-
 12 files changed, 391 insertions(+), 9 deletions(-)

Fusion-Task-Id: FN-7743

Fusion-Task-Lineage: 791852a2-5b77-48de-955a-1b3916616dfa

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-09 19:58:07 -07:00
gsxdsm
9d7b087188 FN-7742: bump pi SDK to 0.80.5 and add GPT-5.6 codex-tier model pricing
Updates the @earendil-works/pi SDK dependency and adds pricing entries for the new GPT-5.6 codex-tier models so Command Center reports real cost instead of unavailable.

- Bump @earendil-works/pi-ai and @earendil-works/pi-coding-agent from ^0.80.3 to ^0.80.5 in packages/cli, packages/dashboard, packages/engine, and packages/pi-claude-cli
- Add openai-codex:gpt-5.6-luna, openai-codex:gpt-5.6-sol, and openai-codex:gpt-5.6-terra pricing entries to model-pricing.ts, mirroring the existing gpt-5.3-codex rate
- Bump pricingAsOf to 2026-07-09
- Add regression tests covering the new GPT-5.6 pricing entries
- Add changeset (minor) for @runfusion/fusion
- Update pnpm-lock.yaml for the dependency bump

Files changed:
 .changeset/fn-7742-pi-sdk-gpt-5-6.md              |   7 +
 packages/cli/package.json                         |   4 +-
 packages/core/src/__tests__/model-pricing.test.ts |  14 +
 packages/core/src/model-pricing.ts                |  35 ++-
 packages/dashboard/package.json                   |   2 +-
 packages/engine/package.json                      |   4 +-
 packages/pi-claude-cli/package.json               |   8 +-
 pnpm-lock.yaml                                    | 323 ++++++++++++----------
 8 files changed, 246 insertions(+), 151 deletions(-)

Fusion-Task-Id: FN-7742

Fusion-Task-Lineage: 2fae3ac1-0877-4d12-b08f-d53d261f2fea

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-09 19:58:07 -07:00
gsxdsm
4726af673a FN-7740: fix store-leak and no-retry-on-lock gaps in research/settings-import/agent-export/git/project CLI commands
Close leaked TaskStore/AgentStore handles and retry lock errors across fn research, settings import, agent export, git, and project CLI commands.

- fn research create/list/show/export/cancel/retry now close their resolved store on every exit path except the intentional fire-and-forget --wait-for-completion-less create, which stays open to avoid truncating the background run
- fn settings import retries importSettings through a momentary database-is-locked window and closes the store before every process.exit()
- fn agent export closes both the project TaskStore and the AgentStore it opens on every exit path, including the no-agents-to-export guard
- fn git status/fetch/pull/push and fn agent export switch to a path-only project resolution helper so no cached, never-closed TaskStore is left behind for these read/write-nothing-to-board commands
- fn project list/show compute per-project task counts against an uncached TaskStore that is now closed after every call, and the count read retries a momentary lock instead of silently reporting zero tasks
- Adds dedicated lock-retry regression tests for each touched command plus a changeset documenting the fix

Files changed:
 .changeset/fn-7740-cli-cmd-lock-retry.md           |   7 +
 docs/cli-reference.md                              |  28 +++
 .../__tests__/agent-export-lock-retry.test.ts      | 122 ++++++++++
 .../src/commands/__tests__/git-lock-retry.test.ts  | 129 +++++++++++
 packages/cli/src/commands/__tests__/git.test.ts    |  12 +
 .../commands/__tests__/project-lock-retry.test.ts  | 195 ++++++++++++++++
 .../cli/src/commands/__tests__/project.test.ts     |   8 +
 .../commands/__tests__/research-lock-retry.test.ts | 248 ++++++++++++++++++++
 .../cli/src/commands/__tests__/research.test.ts    |  16 +-
 .../__tests__/settings-import-lock-retry.test.ts   | 170 ++++++++++++++
 .../src/commands/__tests__/settings-import.test.ts |  34 +++
 packages/cli/src/commands/agent-export.ts          |  67 ++++--
 packages/cli/src/commands/git.ts                   |  18 +-
 packages/cli/src/commands/project.ts               |  40 +++-
 packages/cli/src/commands/research.ts              | 254 ++++++++++++++-------
 packages/cli/src/commands/settings-import.ts       |  61 ++++-
 16 files changed, 1284 insertions(+), 125 deletions(-)

Fusion-Task-Id: FN-7740

Fusion-Task-Lineage: 5c572332-b81c-4e16-9748-ce8639f53ff3

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-09 19:58:06 -07:00
gsxdsm
5304af8d0e FN-7739: retry locked store access in backup/mcp/db CLI commands
Audits and hardens `fn backup`, `memory-backup`, `mcp`, and `db vacuum` CLI commands so they retry a locked board database instead of hanging, and reliably close store handles on every exit path.

- Add retryOnLock + closeProjectStore/asLocalProjectContext pattern to backup.ts, memory-backup.ts, mcp.ts, and db.ts (following the FN-7731/FN-7738 pattern)
- Close cached, uncached CWD-fallback, and ad-hoc MCP secrets TaskStores on every exit path (success, error, early-return)
- Retry MCP settings writes and DB VACUUM on lock contention, honoring FUSION_CLI_LOCK_RETRY_MS
- Add lock-retry regression test suites for backup, db, mcp, and memory-backup commands
- Update docs/cli-reference.md with the new retry/lock behavior
- Add changeset (patch) documenting the fix

Files changed:
 .changeset/fn-7739-cli-cmd-lock-retry.md           |   7 +
 docs/cli-reference.md                              |  17 +
 .../commands/__tests__/backup-lock-retry.test.ts   | 202 +++++++++++
 packages/cli/src/commands/__tests__/backup.test.ts |  15 +
 .../src/commands/__tests__/db-lock-retry.test.ts   | 182 ++++++++++
 packages/cli/src/commands/__tests__/db.test.ts     |  15 +
 .../src/commands/__tests__/mcp-lock-retry.test.ts  | 234 ++++++++++++
 packages/cli/src/commands/__tests__/mcp.test.ts    |  14 +
 .../__tests__/memory-backup-lock-retry.test.ts     | 201 +++++++++++
 .../src/commands/__tests__/memory-backup.test.ts   |  15 +
 packages/cli/src/commands/backup.ts                | 252 +++++++++----
 packages/cli/src/commands/db.ts                    |  62 +++-
 packages/cli/src/commands/mcp.ts                   | 391 +++++++++++++++------
 packages/cli/src/commands/memory-backup.ts         | 179 +++++++---
 14 files changed, 1538 insertions(+), 248 deletions(-)

Fusion-Task-Id: FN-7739

Fusion-Task-Lineage: 6dbab086-2bf8-4cd4-950b-04fe39131933

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-09 19:58:06 -07:00
gsxdsm
bab42b40dd FN-7736: prevent recovery/oversight from resuming approval-blocked tasks
Introduces a canonical awaiting-approval pause reason and predicate so recovery and oversight paths treat approval-blocked tasks as terminal-until-approved instead of eligible for early rebound.

- Add isTaskBlockedOnApproval predicate and canonical "awaiting-approval" pause reason in @fusion/core (store.ts, task-merge.ts, index.ts/index.gate.ts)
- Exclude approval-blocked tasks from paused-scope-decay rebound in self-healing.ts
- Keep the planner overseer withholding oversight for approval-blocked tasks (overseer-human-control-policy.ts)
- Executor and agent-heartbeat now recognize the approval-blocked state and avoid resuming it
- Add regression tests across store-persistence, task-merge, overseer-human-control-policy, paused-scope-decay, and self-healing-paused-abort-recovery
- Update docs/architecture.md with the new approval-hold invariant
- Add changeset fn-7736-approval-hold.md (patch)

Files changed:
 .changeset/fn-7736-approval-hold.md                |  7 +++
 docs/architecture.md                               | 64 ++++++++++++++++++++--
 .../core/src/__tests__/store-persistence.test.ts   | 18 ++++++
 packages/core/src/__tests__/task-merge.test.ts     | 34 ++++++++++++
 packages/core/src/index.gate.ts                    |  2 +
 packages/core/src/index.ts                         |  2 +
 packages/core/src/store.ts                         | 18 +++++-
 packages/core/src/task-merge.ts                    | 34 ++++++++++++
 .../executor-approval-gate-suspend.test.ts         |  5 +-
 .../src/__tests__/heartbeat-executor.test.ts       |  5 +-
 .../overseer-human-control-policy.test.ts          | 44 +++++++++++++++
 .../paused-scope-decay.test.ts                     | 44 +++++++++++++++
 .../self-healing-paused-abort-recovery.test.ts     | 21 +++++++
 packages/engine/src/agent-heartbeat.ts             |  8 ++-
 packages/engine/src/executor.ts                    | 13 ++++-
 .../engine/src/overseer-human-control-policy.ts    | 45 +++++++++++----
 packages/engine/src/self-healing.ts                | 12 +++-
 17 files changed, 351 insertions(+), 25 deletions(-)

Fusion-Task-Id: FN-7736

Fusion-Task-Lineage: 67e05b7f-f621-4f9b-bc01-721ff05d715b

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-09 19:58:06 -07:00
gsxdsm
86bd434c11 FN-7738: retry locked board DB in fn branch-group/pr CLI commands
Audit non-task.ts CLI command families for store-leak / no-retry-on-lock gaps and fix branch-group.ts and pr.ts to match the FN-7731 retryOnLock + closeProjectStore pattern.

- Add retryOnLock handling (honoring FUSION_CLI_LOCK_RETRY_MS) around board DB access in branch-group.ts and pr.ts so a locked store retries and exits promptly instead of hanging.
- Ensure both cached and uncached CWD-fallback project stores are closed on every exit path (success, error, early return) to stop store leaks.
- Extend project-context.ts with shared helpers used by both commands.
- Add regression tests: branch-group-lock-retry.test.ts and pr-lock-retry.test.ts, plus additional coverage in branch-group.test.ts.
- Document the new lock-retry behavior in docs/cli-reference.md.
- Add a patch changeset for @runfusion/fusion describing the user-facing fix.

Files changed:
 .changeset/fn-7738-cli-cmd-lock-retry.md           |   7 +
 docs/cli-reference.md                              |  11 +
 .../__tests__/branch-group-lock-retry.test.ts      | 221 ++++++++
 .../src/commands/__tests__/branch-group.test.ts    |  10 +
 .../src/commands/__tests__/pr-lock-retry.test.ts   | 226 ++++++++
 packages/cli/src/commands/branch-group.ts          | 389 +++++++++-----
 packages/cli/src/commands/pr.ts                    | 575 +++++++++++++--------
 packages/cli/src/project-context.ts                |  26 +
 8 files changed, 1122 insertions(+), 343 deletions(-)

Fusion-Task-Id: FN-7738

Fusion-Task-Lineage: 0bbc8fa2-c4f9-49ed-adb6-7dab57eaee13

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-09 19:58:06 -07:00
gsxdsm
1e79a236b2 FN-7734: generalize lock-retry and store-close pattern across all fn task subcommands
Applies the FN-7731 retryOnLock + closeProjectStore pattern to the ~26 runTask* handlers in task.ts so every 'fn task' subcommand retries a momentarily locked board database and exits promptly instead of hanging or leaking a store handle.

- Generalize retryOnLock/closeProjectStore usage across all runTask* handlers in packages/cli/src/commands/task.ts
- Honor FUSION_CLI_LOCK_RETRY_MS for configurable retry timing
- Close both cached and uncached CWD-fallback stores on exit
- Multi-step flows (create/retry/delete/merge/imports) retry each discrete write independently instead of retrying the whole flow
- Add task-lock-retry.test.ts covering the new retry/close behavior across subcommands
- Update docs/cli-reference.md and task.test.ts for the new behavior
- Add changeset fn-7734-task-cmd-lock-retry-generalized.md (patch)

Files changed:
 .../fn-7734-task-cmd-lock-retry-generalized.md     |    7 +
 docs/cli-reference.md                              |   18 +-
 .../src/commands/__tests__/task-lock-retry.test.ts |  282 ++++
 packages/cli/src/commands/__tests__/task.test.ts   |    9 +-
 packages/cli/src/commands/task.ts                  | 1541 +++++++++++---------
 5 files changed, 1173 insertions(+), 684 deletions(-)

Fusion-Task-Id: FN-7734

Fusion-Task-Lineage: cd5c864b-8a33-4962-803e-bbb353a41085

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-09 19:58:06 -07:00
gsxdsm
21d1201de1 FN-7713: collapse mobile Settings search row behind an expand/hide toggle
Mobile Settings modal now hides the search row by default and exposes a toggle icon to expand/hide it, keeping desktop layout unchanged.

- Add mobile-only searchRowExpanded state and toggle affordance in SettingsModal.tsx
- Add toggle icon styling in SettingsModal.css
- Update dashboard-guide.md docs to describe the new mobile behavior
- Add/extend tests covering the collapsed-by-default state and toggle interaction
- Add changeset (feature, no release wording) for @runfusion/fusion

Files changed:
 .../fn-7713-mobile-settings-search-toggle.md       |   7 ++
 docs/dashboard-guide.md                            |   3 +
 .../dashboard/app/components/SettingsModal.css     |  31 ++++++
 .../dashboard/app/components/SettingsModal.tsx     | 112 ++++++++++++++-------
 .../__tests__/SettingsModal.general.test.tsx       |   7 ++
 .../components/__tests__/settings-mobile.test.tsx  |  69 +++++++++++++
 6 files changed, 192 insertions(+), 37 deletions(-)

Fusion-Task-Id: FN-7713

Fusion-Task-Lineage: 4ce90317-28ce-45b4-a1d7-8fd662a922ae

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-09 19:58:06 -07:00
gsxdsm
e4a59f7269 fix: remove over-firing triage release-authorization gate
The triage release-authorization gate (FN-6481/FN-6469) false-flagged any
spec that merely mentioned release tooling (scripts/release.mjs, pnpm release)
and, because non-user sources made the in-band authorization marker inert,
stranded ordinary tasks in awaiting-approval with no exit.

- Delete triage-release-authorization.ts + its test and the finalizeApprovedTask
  parking block; release-class specs now flow through triage normally.
- Remove the dashboard approve/reject-plan API guards and UI gating so tasks
  still carrying the legacy awaitingApprovalReason="release-authorization" hold
  render as ordinary manual plan-approval holds and can be resolved.
- Keep the awaitingApprovalReason field + activity label for backward-compat.
- Replace the engine gate with agent instruction (AGENTS.md -> Releasing):
  agents must never run a release from inside a Fusion task.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 19:58:06 -07:00
gsxdsm
7420abe80e FN-7731: add CLI-level lock retry for task show/move commands
Add bounded exponential-backoff retry above the DB layer so `fn task show`/`fn task move` ride out transient SQLite lock contention instead of failing outright or hanging.

- Add packages/cli/src/lock-retry.ts: retries a thunk on SQLite lock errors (via @fusion/core's isSqliteLockError) with exponential backoff capped by a wall-clock deadline (default 15s, override via FUSION_CLI_LOCK_RETRY_MS); non-lock errors propagate immediately; raises LockRetryExhaustedError on deadline exhaustion.
- Wire lock-retry into packages/cli/src/commands/task.ts for the show/move task-store operations, and close the resolved TaskStore for deterministic exit.
- Export isSqliteLockError from packages/core/src/index.ts for CLI reuse.
- Add packages/cli/src/commands/__tests__/task-lock-retry.test.ts covering retry/backoff/deadline/error-passthrough behavior; extend task.test.ts.
- Document the new behavior/env var in docs/cli-reference.md.
- Add changeset (@runfusion/fusion: patch).

Files changed:
 .changeset/fn-7731-task-cmd-lock-retry.md          |   7 +
 docs/cli-reference.md                              |   9 +
 .../src/commands/__tests__/task-lock-retry.test.ts | 430 +++++++++++++++++++++
 packages/cli/src/commands/__tests__/task.test.ts   |  11 +
 packages/cli/src/commands/task.ts                  | 117 +++++-
 packages/cli/src/lock-retry.ts                     | 117 ++++++
 packages/core/src/index.ts                         |   5 +
 7 files changed, 688 insertions(+), 8 deletions(-)

Fusion-Task-Id: FN-7731

Fusion-Task-Lineage: 85543164-10d6-4da9-8c3c-a84cd86827aa

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-09 19:58:05 -07:00
gsxdsm
badb86a965 FN-7726: unify fs.watch/poll logic between TaskStore and AgentStore
Extracted the duplicated file-watch-with-polling-fallback logic from TaskStore and AgentStore into a shared controller.

- Added packages/core/src/fs-watch-poll-controller.ts implementing a reusable fs.watch + polling-fallback controller
- Refactored packages/core/src/store.ts (TaskStore) to use the shared controller instead of its own watch/poll implementation
- Refactored packages/core/src/agent-store.ts (AgentStore) to use the shared controller instead of its own watch/poll implementation
- Added packages/core/src/__tests__/fs-watch-poll-controller.test.ts covering the new controller's behavior
- Updated docs/architecture.md to document the shared controller

Files changed:
 docs/architecture.md                               |   1 +
 .../src/__tests__/fs-watch-poll-controller.test.ts | 187 +++++++++++++++++++++
 packages/core/src/agent-store.ts                   |  66 +++-----
 packages/core/src/fs-watch-poll-controller.ts      | 123 ++++++++++++++
 packages/core/src/store.ts                         |  66 +++-----
 5 files changed, 364 insertions(+), 79 deletions(-)

Fusion-Task-Id: FN-7726
Fusion-Task-Lineage: 69be6dc3-5414-44f2-a3f1-3eb72c2d7391
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-09 19:58:05 -07:00
gsxdsm
5663067e62 FN-7733: remove GitLab browse tools from task_agent_mutation policy examples
Fixes a task_agent_mutation policy example drift: the read-only GitLab browse
tools were incorrectly listed as mutation examples even though they were
never part of ACTION_GATE_TASK_AGENT_MANAGEMENT_TOOLS and are already
classified read-only.

- Remove fn_task_browse_gitlab_project_issues, fn_task_browse_gitlab_group_issues,
  and fn_task_browse_gitlab_merge_requests from AGENT_PERMISSION_POLICY_CATEGORY_TOOL_EXAMPLES.task_agent_mutation
  in packages/core/src/types.ts, keeping the mutating fn_task_import_gitlab_* variants
- Add an FNXC:ToolGovernance comment documenting the invariant and rationale
- Add regression coverage asserting the browse tools are excluded from
  task_agent_mutation examples and are pinned as READONLY_FN_TOOLS

Files changed:
 .../src/__tests__/agent-permission-policy.test.ts     | 19 +++++++++++++++++++
 packages/core/src/types.ts                            |  6 ++----
 2 files changed, 21 insertions(+), 4 deletions(-)

Fusion-Task-Id: FN-7733

Fusion-Task-Lineage: 3a54faa1-89dd-48bc-978a-4a53f06706be

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-09 19:58:05 -07:00
gsxdsm
927741a8cf FN-7727: persist failed workflow step history across self-healing retries
Preserves prior failed pre-merge review attempts instead of overwriting them when self-healing re-runs a failed workflow step.

- Add optional bounded `priorAttempts?: WorkflowStepResult[]` field to `WorkflowStepResult` (capped at `MAX_WORKFLOW_STEP_PRIOR_ATTEMPTS`)
- Add shared pure `upsertWorkflowStepResult(existing, incoming, opts?)` helper in `@fusion/core` (packages/core/src/workflow-step-results.ts)
- Route the executor graph adapter's `recordWorkflowStepResult` and triage's `recordPlanReviewWorkflowResult` through the new helper so a self-healing recovery re-run snapshots the prior failed/advisory_failure attempt into `priorAttempts` instead of dropping it
- Selection logic (self-healing, merge-blocker, progress/timing) is unchanged and still reads only the current entry
- Surface prior failed attempts in the TaskDetailModal Summary tab's Workflow results list as a collapsed "previous failed attempts" disclosure
- Add core/engine/dashboard tests covering the upsert helper, self-healing recovery snapshotting, and the UI disclosure
- Document the behavior in docs/workflow-steps.md
- Add changeset for @runfusion/fusion (patch)

Files changed:
 .changeset/fn-7727-persist-failed-step-history.md  |   7 ++
 docs/workflow-steps.md                             |  15 +++
 .../src/__tests__/workflow-step-results.test.ts    | 138 +++++++++++++++++++++
 packages/core/src/index.gate.ts                    |   4 +
 packages/core/src/index.ts                         |   4 +
 packages/core/src/types.ts                         |  19 +++
 packages/core/src/workflow-step-results.ts         |  99 +++++++++++++++
 .../dashboard/app/components/TaskDetailModal.css   |  55 ++++++++
 .../dashboard/app/components/TaskSummaryTab.tsx    |  42 ++++++-
 .../TaskSummaryTab.prior-attempts.test.tsx         |  89 +++++++++++++
 .../clear-terminal-workflow-step-failures.test.ts  |  27 ++++
 packages/engine/src/__tests__/self-healing.test.ts |  50 ++++++++
 ...flow-step-results-self-healing-recovery.test.ts | 115 +++++++++++++++++
 packages/engine/src/executor.ts                    |  29 +++--
 packages/engine/src/triage.ts                      |  14 ++-
 15 files changed, 688 insertions(+), 19 deletions(-)

Fusion-Task-Id: FN-7727
Fusion-Task-Lineage: 7316fb18-bc92-426d-91f4-b1a4ad41c9b1
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-09 19:58:05 -07:00
gsxdsm
5a9f354e9a FN-7730: fix linked-worktree project-root resolution so board writes don't silently land in the wrong .fusion.db
Board mutations (fn_task_update, CEO override, direct SQL) issued from a pi-extension tool session could silently write into a task's throwaway, never-synced worktree-local .fusion/fusion.db instead of the true project root when git CLI resolution failed (missing git binary, Docker "dubious ownership" refusal, or a non-default settings.worktreesDir). This fixes root-cause resolution and adds regression coverage plus a docs writeup.

- getProjectRootFromGitLinkedWorktree now resolves a linked worktree's project root from git's own on-disk .git/commondir metadata via pure filesystem reads before falling back to the git rev-parse CLI, so writes no longer fall through to a local hydrated copy on git-invocation failure.
- Added getMainRepoRootFromGitFile and resolveCommonGitDirFromWorktreeGitFile helpers with FNXC:Storage comments documenting the FN-7730 root cause and fix rationale.
- Added packages/core/src/__tests__/pi-extensions-write-path-durability.test.ts regression coverage for the write-path durability invariant.
- Extended packages/core/src/__tests__/pi-extensions.test.ts with additional resolution-path assertions.
- Documented the failure mode and fix in docs/storage.md ("Silent board-mutation write loss (FN-7730)").
- Added a patch changeset for @runfusion/fusion describing the user-facing fix.

Files changed:
 .changeset/fn-7730-worktree-project-root-resolution.md              |   7 ++
 docs/storage.md                                                     |  54 ++++++++++
 packages/core/src/__tests__/pi-extensions-write-path-durability.test.ts | 98 ++++++++++++++++++
 packages/core/src/__tests__/pi-extensions.test.ts                   |  87 +++++++++++++++-
 packages/core/src/pi-extensions.ts                                  | 114 +++++++++++++++++++++
 5 files changed, 359 insertions(+), 1 deletion(-)

Fusion-Task-Id: FN-7730
Fusion-Task-Lineage: 00753a2d-a934-42cf-8fde-0f9b8ad98142
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-09 19:58:05 -07:00
gsxdsm
d44dbaab15 FN-7728: add review_gate_bypass RBAC category for fn_task_bypass_review
Introduces a dedicated review_gate_bypass permission-policy category so operators can govern who may bypass a failed pre-merge review gate independently of ordinary task-mutation permissions.

- Add review_gate_bypass as a new sensitive-action category in packages/core/src/types.ts, distinct from task_agent_mutation, with fn_task_bypass_review as its sole example tool
- Default review_gate_bypass to require-approval even under the unrestricted preset (stricter than the preset's uniform disposition) in packages/core/src/agent-permission-policy.ts, while approval-required/locked-down already cover it uniformly
- Classify fn_task_bypass_review into the new category via a shared REVIEW_GATE_BYPASS_FN_TOOLS set in packages/engine/src/gating-classifications.ts, consumed identically by both evaluateAgentActionGate and the permanent-agent gate to prevent path drift
- Render the new category as its own row in the dashboard's project-default and per-agent AgentPermissionPolicyEditor, surfaced in AgentDetailView
- Update docs/settings-reference.md and add unit tests across core/engine/dashboard covering the new category, its stricter default, and gate-classification alignment
- Add changeset (@runfusion/fusion: minor) documenting the new operator-facing permission category

Files changed:
 .changeset/fn-7728-review-gate-bypass-rbac.md      |  7 +++
 docs/settings-reference.md                         |  8 +--
 .../src/__tests__/agent-permission-policy.test.ts  | 54 ++++++++++++++++++-
 packages/core/src/agent-permission-policy.ts       | 12 ++++-
 packages/core/src/types.ts                         |  8 +++
 .../dashboard/app/components/AgentDetailView.tsx   |  2 +
 .../app/components/AgentPermissionPolicyEditor.tsx |  8 +++
 .../__tests__/AgentPermissionPolicyEditor.test.tsx |  5 ++
 .../engine/src/__tests__/agent-action-gate.test.ts | 45 ++++++++++++++++
 .../src/__tests__/gating-classifications.test.ts   | 63 ++++++++++++++++++++++
 .../src/__tests__/permanent-agent-gating.test.ts   | 41 ++++++++++++++
 packages/engine/src/agent-action-gate.ts           |  7 +++
 packages/engine/src/gating-classifications.ts      |  8 ++-
 packages/engine/src/permanent-agent-gating.ts      |  6 +++
 14 files changed, 266 insertions(+), 8 deletions(-)

Fusion-Task-Id: FN-7728

Fusion-Task-Lineage: 100c8563-2897-4d53-9546-5c2faa6ab7d8

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-09 19:58:05 -07:00
gsxdsm
1fc615d0da FN-7724: bridge Grok CLI tool_use NDJSON events in GrokRuntimeAdapter
Bridges Grok CLI tool execution events (tool_use start/result) from the NDJSON stream into the runtime adapter's onToolStart/onToolEnd callbacks, alongside existing text bridging.

- GrokRuntimeAdapter.promptWithFallback now parses and bridges tool_use NDJSON events into onToolStart/onToolEnd callbacks
- Tool name/args/result pass through unchanged (no Grok→pi tool-name mapping, since the verified contract doesn't pin a vocabulary)
- step_finish/error remain non-terminal per-step events, not bridged to any callback; only subprocess close/error finalizes (unchanged from FN-7722)
- Extended stream-parser.ts to recognize tool_use event shapes
- Added new types for tool event payloads in types.ts
- Updated docs/grok-cli-contract.md and plugin README to document tool event bridging
- Added changeset for @runfusion/fusion (minor)
- Added/extended tests in runtime-adapter.test.ts and stream-parser.test.ts (fixture-based, no live binary)

Files changed:
 .changeset/fn-7724-grok-cli-tool-bridging.md       |   7 ++
 docs/grok-cli-contract.md                          |  16 ++-
 plugins/fusion-plugin-grok-runtime/README.md       |  12 +++
 .../src/__tests__/runtime-adapter.test.ts          | 120 +++++++++++++++++++++
 .../src/__tests__/stream-parser.test.ts            |  33 ++++++
 .../src/runtime-adapter.ts                         |  83 +++++++++++---
 .../src/stream-parser.ts                           |  10 ++
 plugins/fusion-plugin-grok-runtime/src/types.ts    |  23 ++++
 8 files changed, 287 insertions(+), 17 deletions(-)

Fusion-Task-Id: FN-7724

Fusion-Task-Lineage: 73abbf2a-6dcd-44fb-86be-71d4788c92d2

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-09 19:58:05 -07:00
gsxdsm
e5c3ffbb39 FN-7725: wire Grok CLI runtime adapter routing end-to-end with tests and docs
Formalizes and tests the existing agent Runtime-mode picker path as the decided Grok CLI routing wiring.

- Add FNXC decision note at the extractRuntimeHint seam documenting the Grok CLI routing chain (agent-session-helpers.ts)
- Add routing test verifying runtimeHint="grok" resolves through resolveRuntime/resolvePluginRuntime to GrokRuntimeAdapter (grok-runtime-routing.test.ts)
- Update docs/grok-cli-contract.md with the wiring decision and documented limitations
- Update plugins/fusion-plugin-grok-runtime/README.md with routing guidance
- Add changeset for the new opt-in Grok CLI streaming runtime routing feature

Files changed:
 .changeset/fn-7725-grok-cli-routing.md             |   7 +
 docs/grok-cli-contract.md                          | 106 ++++++--
 .../src/__tests__/grok-runtime-routing.test.ts     | 275 +++++++++++++++++++++
 packages/engine/src/agent-session-helpers.ts       |  12 +
 plugins/fusion-plugin-grok-runtime/README.md       |  38 ++-
 5 files changed, 414 insertions(+), 24 deletions(-)

Fusion-Task-Id: FN-7725

Fusion-Task-Lineage: f5210793-59d0-4a0c-8152-4c5ef61ca737

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-09 19:58:04 -07:00
gsxdsm
626e00288c FN-7720: add operator review-lane bypass for stranded pre-merge review failures
Add a policy-gated review-lane bypass primitive so operators can unstick cards stranded by a failed pre-merge review step (e.g. the no-feedback review-engine defect), without exposing it to agent-driven lanes.

- Add `store.bypassFailedPreMergeReviewStep(id, { reason, actor })` in @fusion/core plus `getLatestFailedPreMergeReviewStep` in task-merge.ts, and new `bypassedBy`/`bypassedAt`/`bypassReason`/`bypassedFromStatus`/`bypassedFromVerdict` fields on `WorkflowStepResult`
- Add operator-only `fn_task_bypass_review` CLI/pi-extension tool; explicitly withheld from executor/reviewer/triage agent tool lists
- Add `POST /tasks/:id/bypass-review` dashboard API route and wire it through `register-task-workflow-routes.ts` and legacy API compatibility layer
- Add dashboard UI affordance (context menu action + task detail modal + right-dock controller wiring) to trigger the bypass with a reason
- Add i18n strings for the bypass action/labels across en/es/fr/ko/zh-CN/zh-TW locales
- Update `gating-classifications.ts` to recognize the bypassed state
- Add unit tests: `store-bypass-review.test.ts`, `task-merge-bypass.test.ts`, extension test coverage, and `useTasks` hook test coverage
- Update docs (`docs/workflow-steps.md`, `docs/dashboard-guide.md`, AGENTS.md, fusion skill references) to describe the new bypass tool/route
- Add changeset `.changeset/fn-7720-review-lane-bypass-primitive.md` (minor)

Files changed:
$(git diff --cached --stat)

Fusion-Task-Id: FN-7720

Fusion-Task-Lineage: 590b020a-ae02-4b51-8189-df8f54bf3044

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-09 19:58:04 -07:00
gsxdsm
e657d3b965 FN-7723: add cross-process agent state change notification bus
Adds opt-in cross-process change detection to AgentStore so the engine reacts to CLI-driven agent stop/start mutations promptly instead of waiting for the periodic audit sweep.

- AgentStore gains fs.watch-based (with poll fallback) cross-process notification, modeled on TaskStore's existing mechanism
- Re-emits existing agent:updated/agent:stateChanged events in the engine process when another process (the fn CLI) mutates an agent row
- HeartbeatTriggerScheduler listeners now fire immediately instead of waiting up to 60s for the auditTimerRegistrations sweep; the sweep remains as durable backstop
- in-process-runtime.ts wires up the new notification bus
- Adds unit tests for agent-store cross-process notifications and heartbeat-scheduler reaction behavior
- Updates docs/agents.md and docs/architecture.md
- Adds changeset (patch) for @runfusion/fusion

Files changed:
 .changeset/fn-7723-cross-process-agent-notify.md   |   7 +
 docs/agents.md                                     |   1 +
 docs/architecture.md                               |   1 +
 packages/core/src/__tests__/agent-store.test.ts    | 177 +++++++++++++++++
 packages/core/src/agent-store.ts                   | 210 ++++++++++++++++++++-
 .../src/__tests__/heartbeat-scheduler.test.ts      | 162 ++++++++++++++++
 packages/engine/src/runtimes/in-process-runtime.ts |  30 +++
 7 files changed, 587 insertions(+), 1 deletion(-)

Fusion-Task-Id: FN-7723
Fusion-Task-Lineage: d3a7fa05-b40d-4388-8e98-140f9d8861c9
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-09 19:58:04 -07:00
gsxdsm
a24b0fac1a FN-7721: cap heartbeat worktree-acquisition retries and record exhaustion failures
Bounds durable-agent heartbeat worktree acquisition to a fixed retry count instead of requeuing to todo indefinitely across heartbeat cycles.

- Add MAX_HEARTBEAT_WORKTREE_ACQUISITION_RETRIES (3) in agent-heartbeat.ts, reusing Task.recoveryRetryCount as a cross-heartbeat counter (no schema migration)
- On cap exhaustion, terminally mark the task status:"failed" with an explanatory error, log the entry, and reopen to todo with preserveStatus so the failed status isn't wiped by reopen-to-todo semantics
- Add onTaskAcquisitionExhausted callback wired in in-process-runtime.ts to CentralCore.recordTaskCompletion(taskId, false) so exhausted acquisitions count toward totalTasksFailed
- Add regression tests in agent-heartbeat-worktree.test.ts and in-process-runtime.test.ts covering the retry cap and completion recording
- Add changeset (patch) and a docs/solutions/logic-errors writeup documenting the investigation and other worktree-collision sub-gaps found not to reproduce on HEAD

Files changed:
 .changeset/fn-7721-worktree-heartbeat-retry-cap.md |  7 ++
 docs/solutions/logic-errors/heartbeat-worktree-acquisition-unbounded-requeue.md | 84 ++++++++++++++++++++++
 packages/engine/src/__tests__/agent-heartbeat-worktree.test.ts | 58 +++++++++++++++
 packages/engine/src/__tests__/in-process-runtime.test.ts | 11 +++
 packages/engine/src/agent-heartbeat.ts | 72 ++++++++++++++++++-
 packages/engine/src/runtimes/in-process-runtime.ts | 12 ++++
 6 files changed, 242 insertions(+), 2 deletions(-)

Fusion-Task-Id: FN-7721

Fusion-Task-Lineage: caad671c-f360-4c1c-8aaa-5b48fca5a55b

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-09 19:58:04 -07:00
gsxdsm
171aaa2432 FN-7722: route Grok execution through CLI with NDJSON streaming
Switches the Grok runtime plugin to execute prompts via the Grok CLI, parsing its NDJSON stream output instead of the previous invocation path.

- Add cli-stream.ts to spawn and stream the Grok CLI process
- Add stream-parser.ts to parse NDJSON CLI output into runtime events
- Rework runtime-adapter.ts to route execution through CLI streaming
- Extend types.ts with CLI stream/NDJSON event types
- Add docs/grok-cli-contract.md documenting the CLI streaming contract
- Add/update tests for stream-parser and runtime-adapter
- Update plugin README with CLI streaming details
- Add changeset for the Grok CLI streaming change

Files changed:
 .changeset/fn-7722-grok-cli-streaming.md           |   7 +
 docs/grok-cli-contract.md                          | 200 +++++++++++++++++++++
 plugins/fusion-plugin-grok-runtime/README.md       |  28 +++
 .../src/__tests__/runtime-adapter.test.ts          | 135 ++++++++++++--
 .../src/__tests__/stream-parser.test.ts            |  79 ++++++++
 .../fusion-plugin-grok-runtime/src/cli-stream.ts   |  52 ++++++
 .../src/runtime-adapter.ts                         | 182 ++++++++++++++++---
 .../src/stream-parser.ts                           |  54 ++++++
 plugins/fusion-plugin-grok-runtime/src/types.ts    | 120 +++++++++++++
 9 files changed, 816 insertions(+), 41 deletions(-)

Fusion-Task-Id: FN-7722

Fusion-Task-Lineage: c5f33e9d-0032-432b-88b5-4ad8d786d67e

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-09 19:58:04 -07:00
gsxdsm
cda9532c3b FN-7718: fix zombie heartbeat timers surviving agent stop/start
Ensures stopping and restarting an agent durably clears its heartbeat timer instead of relying on the later FN-7645 watchdog repair.

- HeartbeatTriggerScheduler.auditTimerRegistrations now unregisters lingering timers for non-eligible (stopped/paused/disabled) agents
- syncTimerForAgent force-re-arms a stale present timer on a start transition so no orphaned timer entry lingers
- Added 308 lines of new heartbeat-scheduler regression tests covering the stop/start zombie-timer scenarios
- Added changeset (patch) documenting the fix
- Updated docs/agents.md and docs/architecture.md to describe the new invariant

Files changed:
 .changeset/fn-7718-zombie-timer-invalidate.md      |   7 +
 docs/agents.md                                     |   2 +
 docs/architecture.md                               |   1 +
 .../src/__tests__/heartbeat-scheduler.test.ts      | 308 +++++++++++++++++++++
 packages/engine/src/agent-heartbeat.ts             |  49 +++-
 5 files changed, 364 insertions(+), 3 deletions(-)

Fusion-Task-Id: FN-7718

Fusion-Task-Lineage: fc834ccd-495e-4294-805d-325b4cb536a2

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-09 19:58:04 -07:00
gsxdsm
a4931a4731 FN-7719: derive implicit planning fallback model when no fallback configured
Triage planning-model retries no longer dead-end on "no fallback configured" when a provider primary-model call fails (e.g. a 404 wrapped in a 429 for nvidia/moonshotai/kimi-k2.6).

- Add resolveImplicitPlanningFallbackModel() to agent-session-helpers.ts: derives a fallback from the resolved project/global default (execution) model when neither planningFallback*/global fallback* is set, guarding against self-swap and skipping in test mode.
- Wire the implicit fallback into TriageProcessor.specifyTask() in triage.ts so a retryable primary planner-model failure swaps once via the derived fallback instead of failing triage outright.
- Add unit test coverage in agent-session-helpers.test.ts and triage.test.ts for the new implicit-fallback resolution and its triage integration.
- Document the new implicit-fallback behavior in docs/settings-reference.md.
- Add a patch changeset for @runfusion/fusion describing the fix.

Files changed:
 .changeset/fn-7719-triage-planning-implicit-fallback.md           |   7 +
 docs/settings-reference.md                                       |   2 +
 packages/engine/src/__tests__/agent-session-helpers.test.ts       |  75 +++++++
 packages/engine/src/__tests__/triage.test.ts                      | 237 +++++++++++++++++++++
 packages/engine/src/agent-session-helpers.ts                      |  41 ++++
 packages/engine/src/triage.ts                                     |  31 ++-
 6 files changed, 389 insertions(+), 4 deletions(-)

Fusion-Task-Id: FN-7719

Fusion-Task-Lineage: 69e797e1-5bac-47f3-8dce-505b9d64d83c

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-09 19:58:04 -07:00
gsxdsm
71e9f484bb FN-7716: stop requiring a Fusion-visible API key for Grok CLI provider
Grok CLI provider readiness now mirrors the Cursor CLI provider: it is derived from the `grok` binary being available rather than requiring a Fusion-visible GROK_API_KEY or ~/.grok/user-settings.json, since the CLI manages its own auth.

- probeGrokBinary now derives `authenticated` from binary availability (readiness) instead of API-key/user-settings presence; key detection surfaces as a non-blocking `apiKeyDetected` hint
- /auth/status treats the grok-cli provider as authenticated when enabled + binary available
- GrokCliProviderCard drops the blocking "Set GROK_API_KEY" state
- Direct xAI streaming path is unchanged and still uses $GROK_API_KEY when present (FN-7711/FN-7714)
- Added changeset for @runfusion/fusion (patch)

Files changed:
$(cat /tmp/diffstat_fn7716.txt)

Fusion-Task-Id: FN-7716

Fusion-Task-Lineage: ac0efc79-2510-465e-9cd2-4938c08989c9

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-09 19:58:03 -07:00
gsxdsm
c8fcbec94f FN-7717: release active-session locks when a task is archived
Archiving a task from triage/planning/todo (not just in-progress) previously left leaked active-session-registry entries, so a successor task could hit ActiveSessionPathHeldByForeignTaskError and get blocked from Plan Review.

- Add an explicit `to === "archived"` branch in the task-move handler that awaits abort of in-flight task work and sweeps any leftover activeSessionRegistry paths for the task, checked before the narrower `from === "in-progress"` branch so direct in-progress→archived transitions are covered too.
- Deliberately exclude `to === "done"` / `to === "in-review"` from this sweep since those columns legitimately hold ai-merge / workspace-repo-land merge leases that must survive the transition.
- Add regression test coverage for archive releasing active sessions across originating columns.
- Add changeset and architecture doc note.

Files changed:
 .../fn-7717-archive-active-session-release.md      |   7 +
 docs/architecture.md                               |   1 +
 ...xecutor-archive-releases-active-session.test.ts | 167 +++++++++++++++++++++
 packages/engine/src/executor.ts                    |  35 +++++
 4 files changed, 210 insertions(+)

Fusion-Task-Id: FN-7717

Fusion-Task-Lineage: 7cff6821-7bb3-4b75-b502-a26467ca7f51

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-09 19:58:03 -07:00
gsxdsm
b2613b7132 FN-7714: honor ~/.grok/user-settings.json apiKey when GROK_API_KEY is unset
Fall back to the Grok CLI's user-settings file for the API key so pi's $GROK_API_KEY provider reference resolves even when the env var isn't exported.

- Add hydrateGrokApiKeyFromUserSettings() in grok-provider.ts, called from registerBuiltInGrokProvider(), which hydrates process.env.GROK_API_KEY from ~/.grok/user-settings.json { apiKey } only when the env var is unset/empty
- Env var always wins; a missing (ENOENT), malformed, or empty-apiKey settings file is fail-soft (no throw, no env mutation), mirroring the grok-runtime probe's fallback behavior
- Add regression tests covering env-precedence, fallback hydration, and fail-soft error paths (grok-provider-user-settings.test.ts)
- Document the fallback in docs/settings-reference.md
- Add a patch changeset for @runfusion/fusion

Files changed:
 .changeset/fn-7714-grok-user-settings-apikey.md    |   7 +
 docs/settings-reference.md                         |   2 +-
 .../__tests__/grok-provider-user-settings.test.ts  | 156 +++++++++++++++++++++
 packages/core/src/grok-provider.ts                 |  47 +++++++
 4 files changed, 211 insertions(+), 1 deletion(-)

Fusion-Task-Id: FN-7714

Fusion-Task-Lineage: 5450b480-3a32-4331-9494-867b84605464

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-09 19:58:03 -07:00
gsxdsm
335dfc3bec FN-7715: clarify GrokRuntimeAdapter no-op stub with intent documentation
Documents that GrokRuntimeAdapter.promptWithFallback is an intentional no-op rather than unfinished work, and updates its regression test to assert that contract explicitly.

- Add FNXC:GrokCli comment on promptWithFallback explaining Grok streaming already flows through the pi/xAI OpenAI-compatible path from FN-7711, that the grok CLI has no documented non-interactive prompt/stream subcommand, and that this stub is only reached via an unused runtimeConfig.runtimeHint === "grok" path
- Remove the stale TODO(FN-7705) comment
- Rename/expand the promptWithFallback test to assert the intentional no-op contract (resolves without throwing, returns undefined)

Files changed:
 .../src/__tests__/runtime-adapter.test.ts              | 11 ++++++++++-
 .../fusion-plugin-grok-runtime/src/runtime-adapter.ts  | 18 ++++++++++++++++--
 2 files changed, 26 insertions(+), 3 deletions(-)

Fusion-Task-Id: FN-7715

Fusion-Task-Lineage: 118639d3-5530-45d5-bc66-de9b1f18fbc4

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-09 19:58:03 -07:00
gsxdsm
7dc271027f FN-7711: add built-in Grok CLI provider to fix pi model registry lookup
Registers a built-in grok-cli provider so Grok CLI model executions no longer hard-fail with "not found in the pi model registry".

- Add packages/core/src/grok-provider.ts: built-in grok-cli provider config (xAI OpenAI-compatible endpoint https://api.x.ai/v1, api openai-completions, apiKey $GROK_API_KEY), mirroring the existing Z.ai provider
- Register the provider in packages/engine/src/pi.ts (registerExtensionProviders) and packages/engine/src/provider-registration.ts (seedDashboardProviders)
- Wire the provider into CLI entrypoints: packages/cli/src/commands/daemon.ts, dashboard.ts, serve.ts
- Export grok-provider from packages/core/src/index.ts and packages/core/src/index.gate.ts
- Add unit tests: packages/core/src/__tests__/grok-provider.test.ts, and extend packages/engine/src/__tests__/pi-create-fn-agent.test.ts and provider-registration.test.ts
- Document the new provider in docs/settings-reference.md
- Add changeset .changeset/fn-7711-grok-cli-model-registry.md (patch, category: fix)

Note: Grok CLI binary remains discovery/probe only; GrokRuntimeAdapter streaming is a stub (tracked follow-up).

Files changed:
 .changeset/fn-7711-grok-cli-model-registry.md      |   7 +
 docs/settings-reference.md                         |   2 +
 packages/cli/src/commands/daemon.ts                |   4 +
 packages/cli/src/commands/dashboard.ts             |   4 +
 packages/cli/src/commands/serve.ts                 |   4 +
 packages/core/src/__tests__/grok-provider.test.ts  | 130 ++++++++++++
 packages/core/src/grok-provider.ts                 | 224 +++++++++++++++++++++
 packages/core/src/index.gate.ts                    |   7 +
 packages/core/src/index.ts                         |   7 +
 .../src/__tests__/pi-create-fn-agent.test.ts       |  78 ++++++-
 .../src/__tests__/provider-registration.test.ts    |   4 +-
 packages/engine/src/pi.ts                          |   4 +
 packages/engine/src/provider-registration.ts       |   4 +
 13 files changed, 476 insertions(+), 3 deletions(-)

Fusion-Task-Id: FN-7711

Fusion-Task-Lineage: ae90b54f-206e-46fd-8365-b0a4488ceb84

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-09 19:58:03 -07:00
gsxdsm
6cff782308 FN-7710: refresh model caches so Grok/Cursor CLI models appear without reopening Settings
Adds a shared single-flight cache refresh so newly enabled Grok/Cursor CLI providers show their models in pickers immediately, instead of requiring a Settings reopen.

- useModelsCache now exposes a shared refreshModelsCache() that clears the SWR MODELS cache key and notifies subscribers
- AuthenticationSection calls refreshModelsCache() after toggling cursor-cli/grok-cli/claude-cli/llama-cpp providers
- Server-side cursor/grok model-cache lookups use a short negative-TTL so transient cold-start empty results self-heal instead of sticking
- Adds regression tests covering the cache refresh flow, hook behavior, and cursor/grok cache TTL self-healing
- Adds changeset (patch) documenting the fix

Files changed:
 .../fn-7710-cli-provider-model-cache-refresh.md    |   7 +
 ...thenticationSection.modelsCacheRefresh.test.tsx | 137 ++++++++++++++++++
 .../settings/sections/AuthenticationSection.tsx    |  32 +++--
 .../app/hooks/__tests__/useModelsCache.test.ts     | 159 ++++++++++++++++++++-
 packages/dashboard/app/hooks/useModelsCache.ts     |  72 +++++++++-
 .../src/__tests__/cursor-model-cache.test.ts       |  34 +++++
 .../src/__tests__/grok-model-cache.test.ts         |  33 +++++
 packages/dashboard/src/cursor-model-cache.ts       |  23 ++-
 packages/dashboard/src/grok-model-cache.ts         |  23 ++-
 9 files changed, 500 insertions(+), 20 deletions(-)

Fusion-Task-Id: FN-7710

Fusion-Task-Lineage: ebac46ba-5b3e-41f2-acc4-26f9139c0f71

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-09 19:58:03 -07:00
gsxdsm
2580524421 FN-7712: fix Grok CLI model list parsing for real grok models output
Fixes the Grok CLI model picker showing raw prompt/preamble text instead of real model names by rewriting parseModelLines to match the actual verified `grok models` output shape.

- Rewrote parseModelLines in process-manager.ts to strip the login/"Default model:"/"Available models:" preamble
- Strip `*`/`-` bullet markers and the `(default)` annotation from each model line
- Preserve existing legacy `id - Label`, columnar, and JSON parsing paths
- Added regression tests covering the real grok models output shape
- Added changeset (patch) documenting the fix

Files changed:
 .changeset/fn-7712-grok-model-parse.md             |  7 ++++
 .../src/__tests__/process-manager.test.ts          | 39 ++++++++++++++++++++++
 .../src/process-manager.ts                         | 34 ++++++++++++-------
 3 files changed, 68 insertions(+), 12 deletions(-)

Fusion-Task-Id: FN-7712

Fusion-Task-Lineage: 93e34513-07b9-41b3-8b8b-ecdb763b4208

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-09 19:58:03 -07:00
ddonaldson130
8dce51fdd9 fix(dashboard): project-scope Command Center analytics (FUX-037)
Apply FUX-037 projectId scoping to Command Center and Reliability view.
2026-07-09 08:17:52 -07:00
gsxdsm
f10c39fa0b feat: add fn_task_file_scope_add tool so agents can widen their File Scope
Agents that must edit files beyond a task's declared ## File Scope had no
way to keep the scope in sync, so those edits were stranded at merge (the
squash merge is scoped to ## File Scope, and cross-task overlap blocking +
the merge file-scope invariant both read it).

New executor tool fn_task_file_scope_add validates repo-relative
paths/globs with isValidFileScopeEntry, de-dupes against existing scope,
appends them to the ## File Scope section of PROMPT.md, and persists via
store.updateTask({ prompt }) (same validation + task.json/PROMPT.md sync as
fn_task_prompt_write). Registered in the main coding-agent tool list; the
base executor prompt now instructs the agent to call it when editing beyond
the declared scope. Merge-time peer-claim refusal is unchanged and remains
the cross-task backstop.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 23:40:52 -07:00
gsxdsm
7f2e34f5b3 test(FN-7690): reconcile anthropic-compatible apiType assertions + de-slow retry test
FN-7690 changed resolveApiType() to return the registered pi-ai key
"anthropic-messages" for anthropic-compatible providers (the bare
"anthropic" key is never registered and throws at stream time), but left
behind a stale JSDoc and a stale test expectation:

- custom-provider-registry.ts: update the FN-7689 buildCustomProviderModels
  comment that still described the anthropic/anthropic-messages drift as
  unresolved.
- provider-registration.test.ts: assert config.api === "anthropic-messages"
  (was still asserting the pre-fix "anthropic").

Also de-slow a retry-exhaustion test: the describe uses fake timers with
shouldAdvanceTime, so awaiting a 3-retry backoff (1s+5s+15s) burned ~21s of
real wall time. Drive the backoff with advanceTimersByTimeAsync instead
(Standing Rule: prefer fake timers over real time waits).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 23:40:52 -07:00
gsxdsm
66069029a5 FN-7709: unref background integrity-check spawn and scheduling timer
Prevents short-lived CLI processes from being held open by background SQLite integrity checks.

- unref the sqlite3 child process (and its stdio) spawned by integrityCheckSqliteFileAsync via the shared unrefQmdChildProcess helper, immediately after spawn
- unref the 60s scheduling timer in scheduleBackgroundIntegrityCheck so a short-lived caller isn't pinned waiting for a background check it never asked to block on
- add regression test coverage (db-integrity-check-unref.test.ts) plus a CLI fixture (db-integrity-check-fixture.mjs) that exercises the fix in a real short-lived process
- add changeset documenting the fix and the audit of other spawn sites across @fusion/core/@fusion/engine/@fusion/dashboard/cli confirming they are safe

Files changed:
 .changeset/fn-7709-db-integrity-check-unref.md     |   7 ++
 .../src/__tests__/db-integrity-check-unref.test.ts | 135 +++++++++++++++++++++
 .../fixtures/db-integrity-check-fixture.mjs        |  28 +++++
 packages/core/src/db.ts                            |  26 ++++
 4 files changed, 196 insertions(+)

Fusion-Task-Id: FN-7709
Fusion-Task-Lineage: 6594aca4-0268-4bba-9a7f-af96d695f1e9
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-08 23:39:35 -07:00
gsxdsm
409de31e57 fix: stop false Anthropic OAuth expiry notifications when token is valid
The OAuth expiry monitor and validity logger iterated the un-aliased
getOAuthProviders() id `anthropic` and evaluated get("anthropic"), which
can resolve to a stale legacy/supplemental row (e.g. ~/.pi/agent/auth.json)
even when the fresh, actually-used token lives under `anthropic-subscription`.
That fired a false "Anthropic OAuth expired" notification while the real
subscription token had refreshed successfully.

Both surfaces now resolve the freshest of the two aliased ids via a shared
resolveEffectiveOAuthCredential helper (mirroring the refresh scheduler's
getRefreshCandidateIds alias handling), so a live subscription token
suppresses the false alert. Notification throttle/cadence unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 23:39:35 -07:00
gsxdsm
dcfbee9ae6 FN-7707: reuse hardened unref'd executor in searchWithQmd
Fixes searchWithQmd's inline promisify(execFile) copy that could hold a caller open by reusing the already-hardened, synchronously-unref'd executor established for the background refresh path.

- searchWithQmd now calls getDefaultExecFileAsync() instead of building its own promisify(execFile) executor inline
- Removes the second un-unref'd execFile executor that could keep a short-lived caller (e.g. one-shot CLI memory search) open up to the awaited timeout
- Adds regression test fixture and test coverage (qmd-search-fixture.mjs, qmd-search-unref.test.ts) asserting the shared executor is used
- Adds changeset (patch) for @runfusion/fusion

Files changed:
 .changeset/fn-7707-qmd-search-unref.md                       |   7 +
 packages/core/src/__tests__/fixtures/qmd-search-fixture.mjs  |  30 ++++
 packages/core/src/__tests__/qmd-search-unref.test.ts         | 166 +++++++++++++++++++++
 packages/core/src/memory-backend.ts                          |  16 +-
 4 files changed, 216 insertions(+), 3 deletions(-)

Fusion-Task-Id: FN-7707
Fusion-Task-Lineage: 3f9f94a7-5613-4b9a-a3ba-8e9bcdd6b687
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-08 23:39:35 -07:00
gsxdsm
4fb2bf5c55 FN-7706: unref qmd child process so background refresh doesn't block exit
Replaces promisify(execFile) with a hand-rolled spawn()-based qmd executor that unrefs the child process and its stdio, so a fire-and-forget scheduleQmd* memory-index refresh never keeps a short-lived caller process (e.g. CLI) alive; long-lived callers like the dashboard server still see refresh resolve/reject normally.

- memory-backend.ts: replace promisify(execFile) qmd exec path with spawn()-based executor that unrefs child + stdio
- Add qmd-refresh-unref.test.ts covering unref behavior with a qmd-refresh-fixture.mjs test fixture
- Add changeset fn-7706-qmd-unref.md (patch, fix category)

Files changed:
 .changeset/fn-7706-qmd-unref.md                    |   7 ++
 .../src/__tests__/fixtures/qmd-refresh-fixture.mjs |  28 +++++
 .../core/src/__tests__/qmd-refresh-unref.test.ts   | 136 +++++++++++++++++++++
 packages/core/src/memory-backend.ts                | 123 ++++++++++++++++++-
 4 files changed, 291 insertions(+), 3 deletions(-)

Fusion-Task-Id: FN-7706

Fusion-Task-Lineage: 713c23c2-d7da-42c4-b066-31883ba78321

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-08 23:39:34 -07:00
gsxdsm
081dae0e0f FN-7705: Add Grok CLI runtime support as a bundled plugin
Adds a new bundled Grok CLI runtime plugin, wiring it end-to-end into settings, auth routes, model discovery, and the dashboard authentication UI.

- New `fusion-plugin-grok-runtime` package with CLI spawn, probe, provider, process-manager, and runtime-adapter modules plus tests
- Bundled-plugin install list (CLI + core) updated to auto-install the grok-cli plugin
- New `useGrokCli`/`grokCliBinaryPath` settings in `settings-schema.ts` and `types.ts`
- Dashboard: `GrokCliProviderCard` component/styles, `ProviderIcon` grok entry, `AuthenticationSection` wiring
- New `grok-model-cache.ts` for caching `grok models` discovery results, registered model/auth routes for `/auth/grok-cli` and `/providers/grok-cli/status`, merged into `/api/models`
- `runtime-provider-probes.ts` extended with Grok CLI probe/model-discovery delegation
- Docs updated (`PLUGIN_AUTHORING.md`, `settings-reference.md`) and changeset added (minor, feature)
- Workspace config (`pnpm-workspace.yaml`, `pnpm-lock.yaml`) updated to register the new plugin package

Files changed:
 .changeset/fn-7705-grok-cli-runtime.md             |   7 +
 docs/PLUGIN_AUTHORING.md                           |   2 +-
 docs/settings-reference.md                         |   4 +
 packages/cli/src/plugins/bundled-plugin-install.ts |   8 +
 .../cli/src/plugins/staged-bundled-plugin-ids.ts   |   1 +
 packages/cli/vitest.config.ts                      |  12 +
 .../core/src/__tests__/grok-cli-settings.test.ts   |  34 +++
 packages/core/src/index.ts                         |   1 +
 .../core/src/plugins/bundled-plugin-install.ts     |  10 +
 packages/core/src/settings-schema.ts               |   6 +
 packages/core/src/types.ts                         |   9 +
 packages/dashboard/app/api/legacy.ts               |  40 ++++
 .../app/components/GrokCliProviderCard.css         |  65 ++++++
 .../app/components/GrokCliProviderCard.tsx         | 204 ++++++++++++++++
 packages/dashboard/app/components/ProviderIcon.tsx |   5 +
 .../__tests__/GrokCliProviderCard.test.tsx         | 105 +++++++++
 .../app/components/__tests__/ProviderIcon.test.tsx |   8 +
 .../settings/sections/AuthenticationSection.tsx    |   8 +-
 packages/dashboard/package.json                    |   1 +
 .../src/__tests__/grok-model-cache.test.ts         | 152 ++++++++++++
 .../register-model-routes-grok-cli.test.ts         | 214 +++++++++++++++++
 .../dashboard/src/__tests__/routes-auth.test.ts    | 258 ++++++++++++++++++++-
 packages/dashboard/src/grok-model-cache.ts         | 166 +++++++++++++
 packages/dashboard/src/routes.ts                   |   1 +
 .../dashboard/src/routes/register-auth-routes.ts   | 134 ++++++++++-
 .../dashboard/src/routes/register-model-routes.ts  |  51 ++++
 packages/dashboard/src/runtime-provider-probes.ts  |  43 ++++
 packages/dashboard/vitest.config.ts                |  12 +
 packages/desktop/scripts/workspace-tools.ts        |   3 +-
 plugins/fusion-plugin-grok-runtime/CHANGELOG.md    |   7 +
 plugins/fusion-plugin-grok-runtime/README.md       |  54 +++++
 plugins/fusion-plugin-grok-runtime/manifest.json   |   6 +
 plugins/fusion-plugin-grok-runtime/package.json    |  40 ++++
 .../src/__tests__/cli-spawn.test.ts                | 103 ++++++++
 .../src/__tests__/index.test.ts                    |  12 +
 .../src/__tests__/probe.test.ts                    | 135 +++++++++++
 .../src/__tests__/process-manager.test.ts          |  96 ++++++++
 .../src/__tests__/provider.test.ts                 |  57 +++++
 .../src/__tests__/runtime-adapter.test.ts          |  21 ++
 .../fusion-plugin-grok-runtime/src/cli-spawn.ts    |  50 ++++
 plugins/fusion-plugin-grok-runtime/src/index.ts    |  74 ++++++
 plugins/fusion-plugin-grok-runtime/src/probe.ts    | 107 +++++++++
 .../src/process-manager.ts                         |  86 +++++++
 plugins/fusion-plugin-grok-runtime/src/provider.ts |  25 ++
 .../src/runtime-adapter.ts                         |  25 ++
 plugins/fusion-plugin-grok-runtime/src/types.ts    |  12 +
 plugins/fusion-plugin-grok-runtime/tsconfig.json   |  10 +
 .../fusion-plugin-grok-runtime/vitest.config.ts    |  22 ++
 pnpm-lock.yaml                                     |  25 ++
 pnpm-workspace.yaml                                |   1 +
 50 files changed, 2525 insertions(+), 7 deletions(-)

Fusion-Task-Id: FN-7705

Fusion-Task-Lineage: b8194ea8-c773-4199-a52a-b0e4e7347192

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-08 23:39:34 -07:00