Commit Graph

9067 Commits

Author SHA1 Message Date
gsxdsm
669b106548 FN-6514: restore QuickEntryBox test isolation
Rescues the QuickEntryBox suite by restoring jsdom globals instead of keeping it quarantined.

- Snapshot and restore QuickEntryBox viewport, visibility, matchMedia, and object URL descriptors after each test.
- Add a guard test that proves mutated jsdom globals return to their original descriptors.
- Remove the QuickEntryBox quarantine entries while documenting the rescue pattern.

Files changed:
 docs/testing.md                                    |  2 +
 .../components/__tests__/QuickEntryBox.test.tsx    | 50 ++++++++++++++++++++++
 packages/dashboard/vitest.config.ts                |  7 ++-
 scripts/lib/test-quarantine.json                   |  5 ---
 4 files changed, 55 insertions(+), 9 deletions(-)

Fusion-Task-Id: FN-6514

Fusion-Task-Lineage: 12f20ad8-19ee-4168-91a9-33193b1ab5f7
2026-06-16 22:13:46 -07:00
gsxdsm
1c3a4df255 FN-6509: show resumable subtask progress
Subtask breakdowns now show live progress immediately and remain resumable after closing.

- Add startup and reconnecting progress states with empty-thinking feedback.
- Preserve generating and editing subtask sessions for background resume instead of canceling on close.
- Cover mobile, desktop, running, awaiting-input, and completed resume flows in modal tests.
- Document resumable subtask generation behavior and add localized strings.

Files changed:
 docs/task-management.md                            |   2 +
 .../app/components/SubtaskBreakdownModal.tsx       |  80 ++++++++---
 .../__tests__/SubtaskBreakdownModal.test.tsx       | 156 ++++++++++++++++++---
 packages/i18n/locales/en/app.json                  |   5 +
 packages/i18n/src/resources.d.ts                   |   5 +
 5 files changed, 209 insertions(+), 39 deletions(-)

Fusion-Task-Id: FN-6509

Fusion-Task-Lineage: 3bc143fa-a00f-42b6-afd4-ba4fb65b4b63
2026-06-16 21:37:32 -07:00
gsxdsm
602fefff19 FN-6498: smooth mobile quick chat viewport tracking
Keep the mobile Quick Chat sheet aligned with visualViewport changes without redundant layout writes.

- Dedupe repeated mobile visualViewport samples before updating sheet CSS variables.
- Reset viewport tracking state and CSS variables on close/unmount to prevent stale reopen sizing.
- Add regression coverage for mobile tracking, reopen behavior, desktop bypass, and missing visualViewport fallback.
- Document the viewport-smoothing pitfall alongside the keyboard board-shift solution.

Files changed:
 .../quick-chat-mobile-keyboard-board-shift.md      |   4 +
 packages/dashboard/app/components/QuickChatFAB.tsx |  25 +++-
 .../app/components/__tests__/QuickChatFAB.test.tsx | 141 +++++++++++++++++++++
 3 files changed, 167 insertions(+), 3 deletions(-)

Fusion-Task-Id: FN-6498

Fusion-Task-Lineage: 23c17843-778a-4337-aeed-c80793615738
2026-06-16 21:25:39 -07:00
gsxdsm
cc022867be FN-6505: inline chat attachment contents for agents
Chat agents now receive readable attachment content when responding to user prompts.

- Add shared attachment loading and formatting for session and room chat surfaces.
- Inline supported text attachments and forward image attachments through prompt options.
- Cover session and room attachment handling with regression tests and document the behavior.

Files changed:
 .changeset/fuzzy-chat-attachments.md               |   5 +
 docs/dashboard-guide.md                            |   2 +
 .../src/__tests__/chat-attachment-content.test.ts  | 139 ++++++++++++++++++
 .../dashboard/src/__tests__/chat-manager.test.ts   | 123 ++++++++++++++++
 packages/dashboard/src/chat-attachment-content.ts  | 163 +++++++++++++++++++++
 packages/dashboard/src/chat.ts                     |  43 +++++-
 6 files changed, 470 insertions(+), 5 deletions(-)

Fusion-Task-Id: FN-6505

Fusion-Task-Lineage: 9bc7a65c-2516-42a4-8d3c-2bc53ea1c895
2026-06-16 21:09:20 -07:00
gsxdsm
a89804ec5f FN-6508: expose fallback workflow model lanes
Expose declared fallback model lanes in project Settings while preserving workflow-scoped persistence.

- Load the default workflow definition before rendering Project Models lane controls.\n- Show fallback model dropdowns only when the workflow declares matching provider/model settings.\n- Persist and reset fallback lane edits through the Settings modal primary Save action.\n- Update settings documentation for default-workflow and global fallback model placement.

Files changed:\n docs/settings-reference.md                         |  40 +++---\n .../components/__tests__/SettingsModal.test.tsx    | 135 ++++++++++++++++++++-\n .../settings/sections/ProjectModelsSection.tsx     |  52 +++++++-\n 3 files changed, 204 insertions(+), 23 deletions(-)

Fusion-Task-Id: FN-6508

Fusion-Task-Lineage: 18dba2f9-658a-4b82-850f-3bbeb70341d3
2026-06-16 20:59:30 -07:00
gsxdsm
e353079829 FN-6506: add Compound Engineering debug sessions
Add a bundled CE debug stage and skill so operators can launch root-cause investigation sessions from Compound Engineering.

- Register the debug stage with stage metadata, default enabled settings, and dashboard coverage.
- Bundle the ce-debug skill and expose its trigger patterns with reachability and wiring tests.
- Document the new debug flow and add registry coverage for the stage catalog.

Files changed:
 .../fusion-plugin-compound-engineering/README.md   |   7 +-
 .../manifest.json                                  |   4 +-
 .../src/__tests__/manifest.test.ts                 |   1 +
 .../src/__tests__/skill-reachability.test.ts       |  31 +++--
 .../src/__tests__/skill-wiring.test.ts             |  65 ++++++----
 .../src/__tests__/stage-registry.test.ts           |  30 +++++
 .../src/dashboard/__tests__/StageLauncher.test.tsx |   7 +-
 .../src/session/stage-registry.ts                  |  13 ++
 .../src/skills.ts                                  |  13 ++
 .../src/skills/ce-debug/SKILL.md                   | 144 +++++++++++++++++++++
 10 files changed, 273 insertions(+), 42 deletions(-)

Fusion-Task-Id: FN-6506
Fusion-Task-Lineage: d65a238e-83a2-4664-9e97-01244c9df087
2026-06-16 20:28:02 -07:00
gsxdsm
a4537167ab FN-6501: render chat question response controls
Render structured assistant question prompts directly in chat surfaces.

- Add parser and formatter support for question tool calls.
- Add reusable question response UI for select, multi-select, text, and confirm prompts.
- Wire regular chat and quick chat to show live and answered question states.
- Cover parsing and chat response behavior with dashboard tests and localized labels.

Files changed:
 .changeset/fn-6501-chat-question-response.md       |   5 +
 docs/dashboard-guide.md                            |   2 +
 .../app/components/ChatQuestionResponse.css        | 194 ++++++++++++++++
 .../app/components/ChatQuestionResponse.tsx        | 247 +++++++++++++++++++++
 packages/dashboard/app/components/ChatView.tsx     |  85 ++++++-
 packages/dashboard/app/components/QuickChatFAB.tsx |  84 ++++++-
 .../__tests__/ChatQuestionResponse.test.tsx        |  52 +++++
 .../app/components/__tests__/ChatView.test.tsx     |  51 +++++
 .../app/components/__tests__/QuickChatFAB.test.tsx |  64 ++++++
 .../utils/__tests__/parseQuestionToolCall.test.ts  |  82 +++++++
 .../dashboard/app/utils/parseQuestionToolCall.ts   | 240 ++++++++++++++++++++
 packages/i18n/locales/en/app.json                  |  10 +
 12 files changed, 1105 insertions(+), 11 deletions(-)

Fusion-Task-Id: FN-6501
Fusion-Task-Lineage: 1fd4a3aa-b2d7-4157-a196-852fdeda680d
2026-06-16 20:13:13 -07:00
gsxdsm
2ec4eb3518 FN-6507: enlarge task chat send icon
Keep the Task Detail chat send glyph proportional to its touch target on desktop and mobile.

- Set the task chat send button icon sizing token to the larger spacing value.
- Preserve the existing desktop and mobile touch-target dimensions.
- Add CSS regression coverage for the send glyph and mobile sizing rules.

Files changed:
 packages/dashboard/app/components/TaskChatTab.css       |  6 ++++++
 .../app/components/__tests__/TaskChatTab.test.tsx       | 17 +++++++++++++++++
 2 files changed, 23 insertions(+)

Fusion-Task-Id: FN-6507

Fusion-Task-Lineage: 619aef93-d225-443c-9cf2-41a59d794148
2026-06-16 20:00:55 -07:00
gsxdsm
98cb80d88d FN-6500: fix tablet task detail modal sizing
Keeps tablet task detail modals wide enough and within the viewport.\n\n- Reconcile the tablet overlay offset with modal max-height so actions remain visible.\n- Widen the tablet task detail modal to use more horizontal viewport space.\n- Add CSS-focused coverage for tablet sizing plus unchanged desktop and mobile guards.\n- Add a patch changeset for the published Fusion package.\n\nFiles changed:\n .changeset/fn-6500-tablet-task-detail-modal.md     |  5 ++\n .../task-detail-modal-tablet-width.test.ts         | 14 +++--\n .../dashboard/app/components/TaskDetailModal.css   | 15 +++--\n ...etailModal.responsive-and-dependencies.test.tsx | 64 ++++++++++++++++++++++\n .../__tests__/core-modals-mobile.test.tsx          |  5 +-\n 5 files changed, 94 insertions(+), 9 deletions(-)

Fusion-Task-Id: FN-6500

Fusion-Task-Lineage: 016a2839-29f9-48de-b644-a5fcd27b35e3
2026-06-16 19:49:45 -07:00
gsxdsm
21c4d3e5ca FN-6495: load chat session skills
Enable dashboard chat sessions to request the same agent and plugin skills used by execution lanes.

- Pass enabled plugin-contributed skills through the dashboard chat plugin runner contract.
- Add skill selection for bound-agent chat, model-only QuickChat, and room responder sessions.
- Cover regular chat, QuickChat, no-metadata fallback, legacy runner, and room responder skill requests.
- Document dashboard chat skill behavior and add a minor changeset for the published CLI package.

Files changed:
 .changeset/fn-6495-chat-skill-selection.md         |   5 +
 docs/agents.md                                     |   1 +
 .../dashboard/src/__tests__/chat-manager.test.ts   | 125 +++++++++++++++++++++
 .../dashboard/src/__tests__/chat.rooms.test.ts     |  45 ++++++++
 packages/dashboard/src/chat.ts                     |  35 ++++++
 packages/dashboard/src/server.ts                   |   5 +
 packages/engine/src/index.ts                       |   6 +
 7 files changed, 222 insertions(+)

Fusion-Task-Id: FN-6495

Fusion-Task-Lineage: 0b8998e2-848c-4c79-b93a-16c0b3c3d8a3
2026-06-16 19:40:56 -07:00
gsxdsm
bb25eb927d Revert "fix(chat): align message writer store resolution with reader"
This reverts commit 802fecb245.
2026-06-16 19:36:32 -07:00
gsxdsm
0db81349bb FN-6492: clamp task list text output
Bound fn_task_list responses now stay as plain text across board-tool surfaces.\n\n- Add a shared task-list text clamp with an explicit truncation marker.\n- Route CLI, dashboard planning-board, and engine triage task-list output through the shared formatter.\n- Cover bounded and column-filtered output with core and CLI regression tests.\n- Record the patch changeset and quarantine the observed engine CLI executor flake.\n\nFiles changed:\n .changeset/fn-6492-task-list-text-bound.md         |  5 ++\n packages/cli/src/__tests__/extension.test.ts       | 79 +++++++++++++++++++++-\n packages/cli/src/extension.ts                      |  7 +-\n .../core/src/__tests__/task-list-format.test.ts    | 75 ++++++++++++++++++++\n packages/core/src/index.ts                         |  1 +\n packages/core/src/task-list-format.ts              | 45 ++++++++++++\n packages/dashboard/src/planning-board-tools.ts     |  8 ++-\n packages/engine/src/triage.ts                      |  7 +-\n packages/engine/vitest.config.ts                   |  5 ++\n scripts/lib/test-quarantine.json                   |  5 ++\n 10 files changed, 232 insertions(+), 5 deletions(-)

Fusion-Task-Id: FN-6492

Fusion-Task-Lineage: 8b347efb-bc17-4bbe-937c-4f07c63df318
2026-06-16 19:31:33 -07:00
gsxdsm
198fb17277 FN-6496: preserve chat history during streaming attach
Keep existing chat thread messages visible while reconnecting to streamed assistant responses.

- Hydrate or reload prior session messages before attaching an in-flight stream in full chat.
- Add QuickChat session-specific message loading so resumed streams do not hide earlier turns.
- Cover full chat and QuickChat streaming attach behavior with regression tests.
- Add the required patch changeset and quarantine unrelated flaky dashboard tests observed during verification.

Files changed:
 .changeset/fn-6496-chat-stream-prior-thread.md     |   5 +
 .../dashboard/app/hooks/__tests__/useChat.test.ts  | 286 ++++++++++++++++++++-
 .../app/hooks/__tests__/useQuickChat.test.ts       | 147 ++++++++++-
 packages/dashboard/app/hooks/useChat.ts            |  17 +-
 packages/dashboard/app/hooks/useQuickChat.ts       |  62 ++---
 packages/dashboard/vitest.config.ts                |  13 +-
 scripts/lib/test-quarantine.json                   |  13 +-
 7 files changed, 502 insertions(+), 41 deletions(-)

Fusion-Task-Id: FN-6496

Fusion-Task-Lineage: eb371b39-9810-48b7-a395-30066c9bc3be
2026-06-16 19:25:32 -07:00
gsxdsm
a15b4caace FN-6494: keep tablet chat sidebar visible
Keep tablet chat navigation available while software keyboards reduce the viewport.

- Stop auto-hiding the tablet chat sidebar when the keyboard opens.
- Bound the sidebar to its minimum width during tablet keyboard-open layout without overwriting the saved width.
- Cover visible and user-collapsed tablet sidebar behavior in mobile render tests.
- Add a patch changeset for the published Fusion package.

Files changed:
 .changeset/fn-6494-tablet-chat-sidebar.md          |  5 ++
 packages/dashboard/app/components/ChatView.tsx     | 34 +++--------
 .../__tests__/ChatView.mobile-render.test.tsx      | 70 ++++++++++++++++++++--
 3 files changed, 79 insertions(+), 30 deletions(-)

Fusion-Task-Id: FN-6494

Fusion-Task-Lineage: 618cccc3-5102-4e9c-ac0e-6c7a44742940
2026-06-16 18:43:48 -07:00
gsxdsm
7852c34a9f FN-6493: update lazy view inventory guard
Keep the lazy-loaded dashboard inventory aligned with AppModals imports.\n\n- Document SettingsModal and WorkflowNodeEditor alongside other lazy-loaded dashboard views.\n- Update the dashboard guide inventory count and modal lazy-load note.\n- Extend the docs guard test to scan AppModals lazy imports and assert the 22-view inventory.\n\nFiles changed:\n AGENTS.md                                          |  6 ++--\n docs/dashboard-guide.md                            |  5 ++-\n .../app/__tests__/lazy-loaded-views-docs.test.ts   | 40 +++++++++++++++++++---\n 3 files changed, 43 insertions(+), 8 deletions(-)

Fusion-Task-Id: FN-6493

Fusion-Task-Lineage: d2b4de05-fb3c-4965-921e-4f8551e3e96a
2026-06-16 18:22:28 -07:00
gsxdsm
802fecb245 fix(chat): align message writer store resolution with reader
The POST /chat/sessions/:id/messages writer (and cancel + isGenerating
enrichment) resolved its per-project ChatManager/ChatStore via
getOrCreateProjectStore, while the GET reader resolves via the engine-aware
resolveProjectChatContext. When those resolved to different store instances,
a sent message persisted to one store but the reload read from another, so
regular chat (ChatView) messages vanished after leaving and returning.
Quick Chat masked it by keeping its thread warm in memory (no server reload).

resolveScopedChatManager now resolves through resolveProjectChatContext so
writer and reader always share one store. Updated multi-project routing tests
to the corrected invariant and added an engine-aware regression test.
2026-06-16 18:09:55 -07:00
gsxdsm
319236421d fix(mobile): force native webview safe-area padding on Android
Relying on env(safe-area-inset-*) in remotely-served dashboard CSS was
unreliable (depends on device Chromium version reporting insets + the
service-worker-cacheable CSS being current). Configure
@capacitor-community/safe-area with detectViewportFitCoverChanges:false +
initialViewportFitCover:false so it pads the whole webview natively on every
Android device, guaranteeing the app never renders under the status/nav bars
regardless of CSS or webview version.
2026-06-16 18:09:46 -07:00
gsxdsm
91c99dd93e fix(mobile): resolve Android status-bar overlap via safe-area plugin
Android WebView returns 0 for env(safe-area-inset-top) by default, so the
CSS-only header inset had no effect on edge-to-edge devices (API 35+).

- Add @capacitor-community/safe-area@^7.0.0 (Capacitor 7 compatible); it
  patches the webview so env(safe-area-inset-*) report real values. Enabled
  natively (no JS init), so it works in remote/live mode too.
- capacitor.config.ts: declare SafeArea plugin (initialViewportFitCover).
- mobile-run-android.sh: idempotently enable EdgeToEdge in MainActivity after
  cap add (android/ is generated/gitignored), required by the plugin.
2026-06-16 18:03:41 -07:00
gsxdsm
3158e9c6c7 FN-6491: reserve s for agent start in TUI
Keep the Agents view focused when starting the selected agent from the dashboard TUI.

- Treat `s` as the selected-agent start command inside the Agents interactive view.
- Preserve `m` as the universal Main/status shortcut and keep the `s` alias outside Agents.
- Add regression coverage for Agents, non-Agents, status, and empty Agents shortcut behavior.
- Add a patch changeset for the published CLI package.

Files changed:
 .changeset/fn-6491-tui-agents-start-key.md         |   5 +
 .../commands/dashboard-tui/__tests__/app.test.tsx  | 102 ++++++++++++++++++++-
 packages/cli/src/commands/dashboard-tui/app.tsx    |   9 +-
 3 files changed, 112 insertions(+), 4 deletions(-)

Fusion-Task-Id: FN-6491
Fusion-Task-Lineage: 82a9acab-6e4a-400c-80ee-54d051245b57
2026-06-16 17:56:09 -07:00
gsxdsm
5a5c955113 feat(mobile): add android run script and fix status-bar overlap
- Add scripts/mobile-run-android.sh + pnpm mobile:run:android (auto-detects
  Android SDK + JDK 21, writes local.properties, reconnects network ADB
  before deploy, supports remote backend via FUSION_SERVER_URL).
- Header.css: reserve env(safe-area-inset-top) so top app chrome no longer
  draws under the OS status bar on edge-to-edge native shells (Capacitor
  Android API 35+, iOS notch, PWA standalone). No-op on web/desktop.
- .gitignore: ignore generated packages/mobile/{ios,android} (stale paths
  pointed at packages/dashboard/).
2026-06-16 17:52:51 -07:00
gsxdsm
b85d02add0 Merge pull request #1682 from Runfusion/feature/acp-route-a-followups
feat(acp): Route A follow-ups — token usage, opt-in headless auth, status tests + bridge-auth learning
2026-06-17 06:12:06 +08:00
gsxdsm
963362cd43 FN-6490: add mission-goal linking controls
Add bidirectional mission-goal linking in the dashboard with route support and tests.

- Add Goals view controls to list, link, unlink, and navigate linked missions.
- Add Mission detail controls to link active goals and unlink existing goal chips while refreshing summaries.
- Expose goal-to-mission lookup through the goals API and cover route and UI behavior.
- Update mission and dashboard docs for cross-linking flows.

Files changed:
 docs/dashboard-guide.md                            |   4 +-
 docs/missions.md                                   |   8 +-
 packages/dashboard/app/App.tsx                     |   2 +-
 packages/dashboard/app/components/GoalsView.css    |  90 +++++++++-
 packages/dashboard/app/components/GoalsView.tsx    | 191 ++++++++++++++++++++-
 .../dashboard/app/components/MissionManager.css    |  38 +++-
 .../dashboard/app/components/MissionManager.tsx    | 125 +++++++++++++-
 .../app/components/__tests__/GoalsView.test.tsx    | 149 ++++++++++++++--
 .../__tests__/MissionManager.goal-links.test.tsx   | 140 +++++++++++++++
 .../dashboard/src/__tests__/goals-routes.test.ts   |  70 +++++++-
 packages/dashboard/src/goals-routes.ts             |  37 +++-
 11 files changed, 821 insertions(+), 33 deletions(-)

Fusion-Task-Id: FN-6490

Fusion-Task-Lineage: aa51e053-04c5-4124-90a0-bc421c8f979f
2026-06-16 15:08:24 -07:00
gsxdsm
222b5cedf3 FN-6489: replace dashboard rgba tokens with color-mix
Replace raw dashboard RGB alpha colors with color-mix token expressions and guard the global CSS surface.

- Converted global theme shadow, state, mission, event, and theme-data alpha colors from raw rgba() to color-mix() expressions.
- Added CSS fixture loading for theme-data.css and a regression test banning raw rgb/rgba outside var() fallbacks across global app CSS.
- Documented the stricter dashboard styling rule for global and theme token CSS.

Files changed:
 docs/dashboard-guide.md                            |   2 +-
 .../__tests__/global-theme-css-no-raw-rgba.test.ts |  68 +++
 packages/dashboard/app/public/theme-data.css       | 573 +++++++++++----------
 packages/dashboard/app/styles.css                  |  49 +-
 packages/dashboard/app/test/cssFixture.ts          |   7 +
 5 files changed, 389 insertions(+), 310 deletions(-)

Fusion-Task-Id: FN-6489

Fusion-Task-Lineage: 7c466971-d15c-4382-a24b-1b32eea71974
2026-06-16 15:08:24 -07:00
gsxdsm
d08ec053a6 FN-6488: centralize dashboard beforeExit cleanup
Centralize dashboard cleanup registration to prevent repeated module imports from accumulating beforeExit listeners.

- Add a Symbol.for-backed dashboard process lifecycle registry with one shared beforeExit listener.
- Register existing cleanup intervals through the shared lifecycle helper across dashboard modules.
- Cover repeated module evaluation and multi-cleanup dispatch with Vitest regression tests.

Files changed:
 .../src/__tests__/process-lifecycle.test.ts        | 76 ++++++++++++++++++++++
 packages/dashboard/src/agent-generation.ts         |  3 +-
 packages/dashboard/src/ai-refine.ts                |  3 +-
 .../dashboard/src/milestone-slice-interview.ts     |  3 +-
 packages/dashboard/src/mission-interview.ts        |  3 +-
 packages/dashboard/src/planning.ts                 |  3 +-
 packages/dashboard/src/process-lifecycle.ts        | 63 ++++++++++++++++++
 packages/dashboard/src/server.ts                   |  3 +-
 packages/dashboard/src/subtask-breakdown.ts        |  3 +-
 9 files changed, 153 insertions(+), 7 deletions(-)

Fusion-Task-Id: FN-6488
Fusion-Task-Lineage: 3ec47f17-ae38-4ee3-a3fa-3132d23a2b12
2026-06-16 15:08:24 -07:00
gsxdsm
a38752c6bb FN-6486: rescue quarantined flaky tests
Rescue the same-day core and CLI flaky quarantines by fixing their fixture seams instead of appeasing timeouts.

- Make the core concurrent-write lock helper release synchronously inside its child process so package load cannot delay the transient lock release.
- Close real CLI TaskStore fixtures before removing temp roots and switch mock cleanup to non-hoisted unmocking.
- Remove both test files from package quarantine excludes and clear the quarantine ledger while documenting the rescue pattern.

Files changed:
 docs/testing.md                                         |  2 ++
 packages/cli/src/__tests__/extension-task-tools.test.ts | 17 +++++++++++++----
 packages/cli/vitest.config.ts                           |  4 +++-
 .../core/src/__tests__/store-concurrent-writes.test.ts  |  8 +++++++-
 packages/core/vitest.config.ts                          |  4 +++-
 scripts/lib/test-quarantine.json                        | 13 +------------
 6 files changed, 29 insertions(+), 19 deletions(-)

Fusion-Task-Id: FN-6486

Fusion-Task-Lineage: c90358c4-0549-4c68-8d17-2e2a336433b5
2026-06-16 15:08:24 -07:00
gsxdsm
84830595f2 FN-6485: remove synchronous CLI probes
Remove blocking execSync validation paths from CLI process managers while preserving async probe coverage.

- Drop synchronous Claude and Droid CLI presence/auth validators from process managers.
- Keep async spawn-based validation as the sole probing path for session startup.
- Replace sync validator tests with execSync guard coverage for both CLI integrations.

Files changed:
 .../droid-cli/src/__tests__/execsync-guard.test.ts | 17 ++++++++
 .../src/__tests__/process-manager.test.ts          | 46 +---------------------
 .../src/__tests__/execsync-guard.test.ts           | 14 +++++++
 .../src/__tests__/process-manager.test.ts          | 46 +---------------------
 .../pi-claude-cli/src/__tests__/provider.test.ts   |  1 -
 packages/pi-claude-cli/src/process-manager.ts      | 44 +++------------------
 .../src/process-manager.ts                         | 43 +++-----------------
 7 files changed, 45 insertions(+), 166 deletions(-)

Fusion-Task-Id: FN-6485

Fusion-Task-Lineage: e3f0f656-3445-4672-b597-a811924137e9
2026-06-16 15:08:24 -07:00
gsxdsm
589c8e8045 FN-6483: quarantine flaky CLI extension task tests
Quarantine the load-sensitive CLI extension task tools suite instead of widening Vitest timeouts.

- Add the extension task tools test file to the CLI Vitest quarantine exclude list.\n- Record the FN-6483 quarantine evidence in the deletion-ratchet ledger while preserving the existing core quarantine entry.\n\nFiles changed:\n packages/cli/vitest.config.ts    | 5 +++++\n scripts/lib/test-quarantine.json | 5 +++++\n 2 files changed, 10 insertions(+)

Fusion-Task-Id: FN-6483

Fusion-Task-Lineage: 4a3be3b4-b2b4-4e05-afd0-564aa0d28c68
2026-06-16 15:08:24 -07:00
gsxdsm
0093678ee6 FN-6481: require release triage authorization
Block release-class tasks from automatic triage dispatch unless they come from a user-authored source with explicit authorization.

- Add release intent classification and authorization-marker enforcement before final triage transitions.
- Record activity/log details when release tasks are parked awaiting manual approval.
- Surface the new release-authorization activity in dashboard activity views.
- Cover release gating behavior with engine tests and document the architecture pattern.
- Add a changeset for the published CLI package.

Files changed:
 .changeset/fn-6481-release-triage-authorization.md |   5 +
 .../release-triage-requires-user-authorization.md  |  33 +++++
 packages/core/src/types.ts                         |   2 +
 packages/core/vitest.config.ts                     |   4 +
 packages/dashboard/app/components/ActivityFeed.tsx |   5 +
 .../dashboard/app/components/ActivityLogModal.tsx  |   6 +
 .../__tests__/triage-release-authorization.test.ts | 158 +++++++++++++++++++++
 .../engine/src/triage-release-authorization.ts     | 100 +++++++++++++
 packages/engine/src/triage.ts                      |  51 +++++++
 scripts/lib/test-quarantine.json                   |   8 +-
 10 files changed, 371 insertions(+), 1 deletion(-)

Fusion-Task-Id: FN-6481
Fusion-Task-Lineage: 0bddb77a-87e5-4fa5-b31a-e773bdae7a29
2026-06-16 15:08:24 -07:00
gsxdsm
cb91d3fc06 FN-6482: preserve awaiting graph failure states
Preserve resumable workflow graph waits instead of parking them as execute failures.

- Classify awaiting user input and CLI approval node values before terminal graph failure handling.\n- Read foreach container context values for step-execute instances.\n- Cover awaiting graph exits and genuine step-execute-unwired failures in executor recovery tests.\n\nFiles changed:\n .../engine/src/__tests__/executor-recovery.test.ts | 87 ++++++++++++++++++++++\n packages/engine/src/executor.ts                    | 34 +++++++++\n 2 files changed, 121 insertions(+)

Fusion-Task-Id: FN-6482

Fusion-Task-Lineage: 2443d4cd-1307-470a-b456-2f3b44b9cc83
2026-06-16 15:08:24 -07:00
gsxdsm
601a85b7c9 FN-6474: clarify plugin tarball install docs
Clarifies packaged external plugin proof-point docs so tarballs are extracted before installation.

- Document that fn plugin install accepts built plugin directories or installed package names, not raw .tgz archives.
- Update external plugin proof-point and authoring guidance to extract pnpm pack output and install ./package.
- Add a static regression test guarding the runbook and authoring guide against raw tarball install instructions.

Files changed:
 docs/cli-reference.md                              |  1 +
 docs/plugins/external-authoring.md                 |  2 +-
 docs/plugins/external-proof-point-runbook.md       | 10 +++++-
 .../external-proof-point-runbook-install.test.ts   | 40 ++++++++++++++++++++++
 4 files changed, 51 insertions(+), 2 deletions(-)

Fusion-Task-Id: FN-6474

Fusion-Task-Lineage: 744d43ff-ed98-43a1-9cb9-e25f96225ab7
2026-06-16 15:08:24 -07:00
gsxdsm
81188f1996 FN-6480: require operator authorization for releases
Require an out-of-repository operator signal before the release script can mutate version, publish, push, or tag.

- Add a reusable release authorization gate that allows dry-runs and blocks real releases without FUSION_RELEASE_AUTHORIZED.
- Invoke the gate in scripts/release.mjs before the first release mutation while preserving dry-run behavior.
- Cover blocked, authorized, dry-run, whitespace, TTY, and call-order behavior with script tests.

Files changed:
 .../__tests__/release-authorization-gate.test.mjs  | 70 ++++++++++++++++++++++
 scripts/lib/release-authorization-gate.mjs         | 30 ++++++++++
 scripts/release.mjs                                | 26 +++++++-
 3 files changed, 123 insertions(+), 3 deletions(-)

Fusion-Task-Id: FN-6480

Fusion-Task-Lineage: 5347552c-e395-4852-b389-6bbdba0e044e
2026-06-16 15:08:24 -07:00
gsxdsm
65c49585d1 fix(review): address PR #1682 re-review (reuse concurrency + auth hardening)
- P1 (Greptile): a tool-use break-early turn released the warm connection
  (inUse=false) while conn.prompt() was still pending, letting the next turn
  launch a concurrent prompt on the same ACP session (protocol corruption).
  keepWarm now requires !sawToolCall, so a tool-use turn tears the connection
  down like the non-reuse path; only a clean stop turn (prompt fully resolved
  before finish) keeps it warm. + test.
- buildBridgeEnv: treat a whitespace-only auth var as absent (v.trim()), so a
  blank higher-preference token can't shadow a real lower-preference one and we
  never forward a useless blank token. + test.
- Auth-forwarding tests: clear ambient auth vars in beforeEach so a runner-env
  token can't shadow the case under test (CodeRabbit).
- Doc: clarify the allow-list never carries API keys by default; the single
  FUSION_CLAUDE_ACP_FORWARD_AUTH opt-in (default OFF) is the only exception.

348/348 pass, tsc clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 14:52:58 -07:00
gsxdsm
b0bb39aa39 feat(acp): opt-in warm connection reuse across turns (OQ2)
Keep a warm bridge connection + ACP session across turns of one
conversation (gated by FUSION_CLAUDE_ACP_REUSE=1, default OFF), so
multi-turn lanes skip the cold bridge/claude spawn and session/new
round-trip and send only the latest-turn delta (buildResumePrompt).
A stable router indirection serves each turn's handlers.

Addresses the adversarial review of the reuse path:
- P0: a warm-child death routes failure to the CURRENT owner turn via
  router.fail, so a reuse turn fails fast instead of hanging until the
  30-min inactivity timeout.
- P1: eviction is cache-identity-aware (evictCachedAcpConn only deletes
  the map key when it still points at the entry), so a concurrent cold
  turn / stale close handler / idle timer can't evict or kill a newer
  live entry's child.
- P1: an empty resume delta cold-starts instead of issuing an empty
  prompt that could hang.
- P2: a per-turn token drops cross-turn stray updates on the shared
  warm connection.
- The idle reaper is unref'd so it never pins the process.

Default OFF → the cold path is functionally unchanged (reviewer-verified).
Adds multi-turn tests: reuse skips spawn+session/new, flag-off spawns
fresh, fail-fast on warm-child death, empty-resume cold fallback.
346/346 pass, tsc clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 14:38:19 -07:00
gsxdsm
031a5470bb fix(review): address PR #1682 security review (usage validation + cache tokens)
- P2: event-bridge handleMessageDelta now consumes cache_read/cache_creation
  tokens (parity with handleMessageStart) — the OQ3 usage path carried them but
  they were silently dropped, understating cost for cached turns.
- P2: validate the untrusted bridge usage payload — coerce each field to a
  finite, non-negative number before forwarding, so a malformed value
  (string/NaN/negative) can't corrupt totalTokens/cost.
- Tests: usage now asserts cache tokens + totalTokens; new cases for malformed
  usage, tool-use turns reporting zero usage, the ANTHROPIC_AUTH_TOKEN middle
  precedence, and that the auth token is read from process.env (never a
  caller-supplied value — no token substitution).
- Doc: state the auth-forwarding exposure trade-off in the code comment.

acp-driver 13/13; event-bridge tests green; typecheck clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 14:19:17 -07:00
gsxdsm
799e590e3e Merge pull request #1580 from Runfusion/feature/workflow-owned-merge-s07-completion-handoff-merge-work
refactor(workflow): S07 completion handoff creates merge work
2026-06-16 04:30:22 +08:00
gsxdsm
4e2a887422 fix(acp): import afterEach in acp-driver test (typecheck)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 13:28:43 -07:00
gsxdsm
1b5b8708a6 Merge pull request #1579 from Runfusion/feature/workflow-owned-merge-s06-git-merge-capabilities
refactor(workflow): S06 git and merge capability extraction
2026-06-16 04:28:26 +08:00
gsxdsm
d217125a90 feat(acp): wire ACP token usage (OQ3) + opt-in headless auth (R17)
- Item 2 (OQ3): capture PromptResponse.usage from conn.prompt and feed it into
  the bridge before finish(), so ACP-path turns report token usage/cost instead
  of always zero. Zero-when-absent is safe; tool-use (break-early) turns
  inherently report zero (the prompt result never resolves).
- Item 3 (R17): opt-in headless credential delivery. When
  FUSION_CLAUDE_ACP_FORWARD_AUTH=1, buildBridgeEnv forwards a SINGLE Claude auth
  token (CLAUDE_CODE_OAUTH_TOKEN > ANTHROPIC_AUTH_TOKEN > ANTHROPIC_API_KEY) from
  the operator's launch env so a detached daemon (no login Keychain) can
  authenticate. Default OFF — the secure no-secrets posture is unchanged.

acp-driver tests 9/9 (usage + the three auth-opt-in cases); typecheck clean.
Remaining: item 1 (connection reuse / resume latency).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 13:26:15 -07:00
gsxdsm
b83210b471 test(acp): cover the claude-cli status acp block + auth-failure signal (U12)
GET /providers/claude-cli/status: asserts acp.{enabled,bridgeAvailable,active,
authFailed,authReason} reflect the FUSION_CLAUDE_ACP env + the bridge auth-failure
signal file, and that acp is inactive/clean when no bridge path is published.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 13:19:10 -07:00
gsxdsm
ffef0aad6a docs(solutions): ACP bridge 'Not logged in' — thin spawn env + keychain session isolation
Compound learning: the claude-code-cli-acp bridge returned 'Not logged in'
despite a working claude -p, due to (1) a too-thin spawn env (needs XDG_*/USER/
SHELL beyond HOME/PATH) and (2) macOS login-Keychain session isolation for
detached/headless processes. Six headless tasks misdiagnosed it as an upstream
gap. Cross-linked from the ACP runtime integration pattern doc.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 13:15:38 -07:00
gsxdsm
f816598107 Merge pull request #1681 from Runfusion/feature/acp-route-a-enable
feat(acp): enable Claude CLI via ACP bridge by default (experimental switch) + status
2026-06-16 03:51:49 +08:00
gsxdsm
dc8510447f fix(review): address PR #1681 round-2 comments
- CodeRabbit: spinner class `spin` -> `animate-spin` (matches the card's other
  Loader2 usages).
- CodeRabbit (major): tighten auth-failure detection so it only fires when the
  WHOLE turn is the short "Not logged in" message (<=80 chars), not when a long
  legitimate answer merely mentions the phrase — avoids false positives.
- CodeRabbit (major): expand the auth-signal test to assert the full invariant —
  set on a not-logged-in turn, clear (unlink) on a real response, and NOT flag a
  long answer that mentions the phrase.

pi-claude-cli acp-driver 5/5; typecheck clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 12:43:08 -07:00
gsxdsm
5696d4497f fix(review): address PR #1681 feedback (acp.active accuracy + FNXC comments)
- Greptile P2: `acp.active` now reflects the ACTUAL dispatch determinant
  (FUSION_CLAUDE_ACP, which includes the operator force-override), not the
  experimental flag alone — so the status isn't misleading when forced on/off.
- CodeRabbit/Greptile P2: add FNXC:ClaudeAcp comments to the new code blocks
  per the AGENTS.md greppable-comment convention.

Already fixed in the prior commit (daa37d08c): the P1 "sticky env" / latch
(applyClaudeAcpEnable now recomputes each call + FUSION_CLAUDE_ACP_FORCE
override) and the enable->disable-on-same-env regression test.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 12:34:44 -07:00
gsxdsm
daa37d08c5 feat(acp): surface bridge auth failure in the UI with fallback / fix-auth (R17)
When the bridged `claude` can't authenticate (detached daemon / no keychain),
the turn returns "Not logged in" instead of a real answer. Rather than silently
relay that, detect it and let the user choose.

- Driver: detect a "Not logged in"-only turn and write a cross-process signal
  (fusion-acp-bridge-auth.json); a real response clears it (acp-driver test).
- Dashboard status: GET /providers/claude-cli/status reports
  acp.authFailed + authReason from the signal.
- UI: the Claude CLI provider card shows an auth-failure banner with
  "Use claude -p" (sets experimentalFeatures.claudeCliAcp=false) and
  "I fixed auth — re-test", plus a fix hint (run `claude` to log in).
- Enable resolution now recomputes each call with an operator force-override
  (FUSION_CLAUDE_ACP_FORCE), so the "Use -p" fallback takes effect on the next
  turn — no restart. claude-acp-enable tests updated.

pi-claude-cli + engine tests green; dashboard typecheck clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 12:32:00 -07:00
gsxdsm
9314d1c329 Merge pull request #1669 from Runfusion/fix/test-timeout-failures
fix(test-infra): bound test invocations with a fail-fast watchdog + CI timeouts
2026-06-16 03:23:17 +08:00
gsxdsm
2e0bcd75c4 feat(acp): U12 — surface ACP transport state in claude-cli status
GET /providers/claude-cli/status now returns an `acp` block:
{ enabled (experimental flag), bridgeAvailable (KTD10 published path), active
(enabled && acpEnabled && bridgeAvailable) } so operators can see whether Claude
CLI is routing through the ACP bridge vs `claude -p` — important for the
default-on rollout. Additive; typechecks clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 12:16:30 -07:00
gsxdsm
45184aef7e feat(acp): enable Route A via experimental flag (claudeCliAcp), default ON
Replace the manual FUSION_CLAUDE_ACP env enable with an experimental feature
switch. `experimentalFeatures.claudeCliAcp` is ON by default (off only when
explicitly set false); the engine translates it into the FUSION_CLAUDE_ACP
dispatch the pi-claude-cli provider reads, at registerExtensionProviders time.

- Still fail-closed: with no bridge path published (acp-runtime plugin absent),
  the provider falls back to `claude -p`.
- Explicit FUSION_CLAUDE_ACP env always wins (operator / test override).
- New testable helper claude-acp-enable.ts (6/6 tests); flag documented in the
  core experimentalFeatures doc.

So with the acp-runtime plugin installed, Claude CLI now routes through the ACP
bridge by default; set experimentalFeatures.claudeCliAcp=false to force `-p`.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 12:14:20 -07:00
gsxdsm
2bffad1784 Merge remote-tracking branch 'origin/main' into fix/test-timeout-failures
# Conflicts:
#	scripts/test-changed.mjs
2026-06-15 12:13:40 -07:00
gsxdsm
e409f2d437 Merge pull request #1680 from Runfusion/feature/acp-route-a
feat: migrate Claude off `claude -p` to ACP runtime + bridge (Route B + U10; Route A in progress)
2026-06-16 03:08:00 +08:00
gsxdsm
642780220e chore(acp): apply subagent-review follow-ups (changeset, KTD10 tests, docs)
Two-reviewer pass (security + architecture) on KTD10 + the full Route A
increment: no code defects, no P0, merge-ready as a dormant increment. Applying
the P1 follow-ups:

- Add the feature changeset (@runfusion/fusion minor) — the one convention gap.
- KTD10 tests: fail-closed (bridge not resolved -> env stays unset -> -p) and
  idempotency (second onLoad keeps the first published path).
- Document the two intentional, parallel MCP-forwarding paths (U10 engine-adapter
  vs U11 provider-driver) so nobody double-forwards, and the known
  ACP-path-token-usage=0 residual so U12 doesn't treat it as a bug.

Reviewers confirmed: dormancy invariant holds end-to-end (nothing sets
FUSION_CLAUDE_ACP=1; both flag+path required; -p is the default); OAuth pi path
untouched. 206/206 plugin tests, 333/333 pi-claude-cli tests, typecheck clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 11:40:06 -07:00