Commit Graph

9050 Commits

Author SHA1 Message Date
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
gsxdsm
022bee5842 feat(acp): U11/KTD10 — publish bundled bridge path on plugin load
The acp-runtime plugin's onLoad now publishes the identity-pinned bundled
claude-code-cli-acp path to FUSION_CLAUDE_ACP_BRIDGE (when unset), so the
pi-claude-cli kill-switch resolves the bridge WITHOUT a manual env var — no
engine->plugin static coupling. Publishes the path only; the ACP transport stays
OFF until an operator sets FUSION_CLAUDE_ACP=1 (rollout gate). Explicit env
override wins; resolver is pinned to the plugin's node_modules/.bin shim.

204/204 plugin tests green (3 new KTD10 tests); typecheck clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 11:34:36 -07:00
gsxdsm
239bec74c4 docs(acp): record U11 tool-flow verification PASS — enablement gate cleared
Live run: forwarded MCP tools and native Bash both refuse to execute when we
return cancelled to session/request_permission (no TOCTOU). streamViaAcp's
deny-by-default + break-early is verified safe. Env allow-list (incl. XDG/USER)
validated as required for the bridged claude to authenticate.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 11:21:43 -07:00
gsxdsm
71a6c5a05f test(acp): verify kill-switch dispatch routing (U11/R9/R14)
streamSimple routes to streamViaAcp ONLY when FUSION_CLAUDE_ACP=1 AND a bridge
path is provided; otherwise stays on the -p streamViaCli path. Covers the three
cases (off / flag-without-path / flag+path) and asserts the bridge path + env
are forwarded. 333/333 pi-claude-cli tests green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 10:55:27 -07:00
gsxdsm
0d6b3f6660 fix(acp): apply review findings to streamViaAcp (U11)
Three-reviewer pass (correctness/security/reliability) on the highest-risk file.

P0:
- Break-early now gates on isPiKnownClaudeTool: Claude's internal ToolSearch
  (used to load deferred MCP tools) no longer aborts the turn before the real
  fn_* call. Surface+break works from both tool_call updates and
  request_permission. New test replays the U9 [ToolSearch, fn_task_list] sequence.
- Downgrade a tool_use turn that surfaced zero pi tool calls -> stop (mirrors
  provider.ts), so pi never dispatches non-existent tools.
- register the bridge child in the process registry (no orphan on teardown).
- inactivity timeout (30 min, re-armed per chunk) + per-RPC timeouts on
  newSession (a hung bridge now ends the stream and dies).

P1:
- capture bridge stderr + child 'close' handler -> surface exit code/stderr
  (no more silent, undebuggable failures).
- sanitize untrusted agent output: strip ANSI/control chars, per-chunk +
  per-turn caps, bound tool ids/names (no terminal-escape injection / DoS).
- validate bridge path (absolute + exists) before spawn.
- preserve image content blocks in the prompt (flatten-to-text dropped vision).

P2:
- enforce the bridge env allow-list INSIDE the driver (HOME/PATH/terminal only),
  not trusting the caller-supplied object.

Documented residual (kill-switch stays OFF until verified): the bridge's
tool-execution ordering and native-tool (Bash/Read/Write) execution-prevention
need a live behavioral test before any lane enables this path.

pi-claude-cli: 330/330 tests green; typecheck clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 06:17:11 -07:00
gsxdsm
85c180508c feat(acp): U11 — drive pi-claude-cli provider via the ACP bridge (kill-switch OFF)
Adds streamViaAcp: a drop-in alternative to streamViaCli that drives Claude
through the claude-code-cli-acp bridge over ACP instead of `claude -p`. Returns
the same AssistantMessageEventStream, so streamSimple dispatches to either
transport behind a kill-switch (FUSION_CLAUDE_ACP=1 + an injected bridge path),
OFF by default — the live `-p` path is byte-for-byte untouched until soak.

- Full-history prompt every turn (buildPrompt) — the ACP path has no --resume (R13).
- Forwards schema-only MCP servers so Claude emits correct tool calls; breaks
  early on the first tool_call (cancel turn, surface to pi) so the bridge never
  executes Fusion's tools — mirrors the `-p` break-early pattern.
- Translation reuses the tested createEventBridge by synthesizing Claude stream
  events from ACP session/updates, sharing pi sequencing + tool-name mapping.
- Bridge env forwards only HOME/PATH so `claude` authenticates from the login
  session (R17); never inherited process.env or API keys.

Verified: 3/3 translation unit tests; real-bridge session/update shapes confirmed
(agent_message_chunk text + tool_call); 326/326 existing pi-claude-cli tests green;
typecheck clean.

Remaining for Route A: engine injection of the bridge path (KTD10), U12 picker/
auth/status, U13 workflow verification.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 06:08:27 -07:00
gsxdsm
03d12b6289 docs(acp): record U11 implementation design (ready to execute)
Reverse-engineered the streamViaCli contract and locked the U11 build plan:
AssistantMessageEventStream shape to match, the kill-switch branch point in
streamSimple, the KTD10 injection seam (pi-claude-cli adds @agentclientprotocol/sdk;
bridge path injected like mcpConfigPath), MCP-server construction reusing
ensureMcpConfig, full-history prompting (R13), ACP->pi event translation
paralleling event-bridge.ts, and live-bridge verification via the U9 harness.

No transport change yet — the live `claude -p` path is untouched.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 05:56:47 -07:00
gsxdsm
079844e1c1 feat(acp): forward MCP servers on session/new (U10) + record U9 GO / R17
Route A unblock + the first Route A code increment.

- U9 verdict recorded (plan OQ1 + docs/acp-contract.md): in an authenticated
  interactive session the pinned claude-code-cli-acp 0.1.1 bridge forwards
  session/new mcpServers to Claude, Claude invokes the forwarded Fusion tool,
  and the call traverses the ACP permission gate (session/request_permission).
  Both security-critical answers resolve positively — overturns the headless
  NOT-GO chain (FN-6466/6467/6473/6476), whose only blocker was running
  detached from the login keychain session.
- R17 (daemon auth) recorded and closed for the supported setup: creds are
  macOS Keychain-only; the user's login-session fn daemon has keychain access
  (the existing claude -p provider authenticates there), so the bridge does too.
- U10: thread an optional mcpServers list through the ACP runtime contract.
  newAcpSession now forwards it (was hardcoded []); AgentRuntimeOptions (engine
  + plugin-local copy) gains the field; defaults to [] to preserve Route B's
  read-only ask posture. Tool calls still route through the U5 permission floor.

Plugin typechecks clean; provider-session tests 12/12 (incl. 2 new forwarding
tests). U11-U13 (provider transport swap, picker/auth, workflow verify) remain.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 05:56:47 -07:00
gsxdsm
bc6dfd386e FN-6478: surface paused workflow graph failures
Surface stranded paused workflow exits as actionable executor failures.

- Treat paused or aborted graph exits as benign only while the live task remains in-progress.
- Preserve terminal/review lifecycle state while recording operator-actionable failure evidence for advanced columns.
- Cover user-paused, pause-aborted, existing-failure, in-progress, in-review, todo, and done column recovery paths.
- Document the workflow lifecycle invariant and add a patch changeset.

Files changed:
 .changeset/fn-6478-paused-workflow-executions.md   |   5 +
 docs/architecture.md                               |   1 +
 .../engine/src/__tests__/executor-recovery.test.ts | 283 +++++++++++++++++++++
 packages/engine/src/executor.ts                    |  30 ++-
 4 files changed, 315 insertions(+), 4 deletions(-)

Fusion-Task-Id: FN-6478

Fusion-Task-Lineage: 219d8612-6604-4dbc-9a3a-a1c7837419c1
2026-06-15 02:30:41 -07:00
gsxdsm
de8f871b4d FN-6479: index upstream ACP MCP forwarding doc
Index the upstream ACP MCP forwarding sponsorship doc so the docs README and CLI index test keep it discoverable.

- Add the upstream ACP MCP passthrough and permission forwarding sponsorship doc link under Audit Reports.
- Add the upstream doc to the required docs README index coverage.
- Guard that CLI Printing Press docs remain indexed in Audit Reports only, not duplicated under Plugins.

Files changed:
 docs/README.md                                      |  5 +++++
 .../cli/src/__tests__/docs-readme-index.test.ts     | 21 +++++++++++++++++++++
 2 files changed, 26 insertions(+)

Fusion-Task-Id: FN-6479

Fusion-Task-Lineage: f23afeba-a989-4552-8857-fe2984df6081
2026-06-15 02:30:41 -07:00
gsxdsm
56d4fd24b3 FN-6476: record ACP auth rerun blockage
Document the authenticated ACP bridge rerun attempt and preserve the Route A blocked verdict.

- Update the ACP contract with FN-6476 readiness proof results showing the pinned bridge still reports an unauthenticated Claude session.
- Keep OQ1 answers unresolved because no forwarded Fusion tool invocation or permission-gate traversal was observed.
- Add FN-6476 status notes to the Claude ACP runtime plan so U9 remains NOT GO without a claude -p fallback.

Files changed:
 docs/acp-contract.md                                      | 11 ++++++++++-
 docs/plans/2026-06-14-001-feat-claude-acp-runtime-plan.md |  3 +++
 2 files changed, 13 insertions(+), 1 deletion(-)

Fusion-Task-Id: FN-6476

Fusion-Task-Lineage: f37dcc62-9758-47af-bb50-169e902211a5
2026-06-15 02:30:41 -07:00
gsxdsm
fcca1366ef FN-6475: document ACP MCP forwarding sponsorship
Record the upstream sponsorship package for ACP MCP passthrough and permission gating while keeping Route A blocked.\n\n- Add a ready-to-file upstream issue for claude-code-cli-acp MCP passthrough and permission-forwarding support.\n- Link the filed upstream issue from the ACP contract and runtime plan.\n- Preserve the OQ1/U9 NOT GO status until authenticated reruns prove forwarded tool invocation and gating.\n\nFiles changed:\n docs/acp-contract.md                               |   5 +\n .../2026-06-14-001-feat-claude-acp-runtime-plan.md |   3 +\n ...laude-code-cli-acp-mcp-permission-forwarding.md | 121 +++++++++++++++++++++\n 3 files changed, 129 insertions(+)

Fusion-Task-Id: FN-6475

Fusion-Task-Lineage: 3cbd14e3-9388-4cf4-b256-3678459eb926
2026-06-15 02:30:41 -07:00
gsxdsm
1d474a1dff FN-6473: document Route A ACP escalation blockage
Record the authenticated Route A ACP escalation rerun and keep U9 blocked.

- Update the ACP contract OQ1 status to FN-6473 with the observed unauthenticated bridge result.
- Capture the explicit request-permission instrumentation outcome: zero forwarded tool calls and zero permission callbacks.
- Extend the Claude ACP runtime plan with the escalation status and upstream bridge/ACP permission-forwarding requirement.

Files changed:
 docs/acp-contract.md                                      | 13 +++++++++++--
 docs/plans/2026-06-14-001-feat-claude-acp-runtime-plan.md |  3 +++
 2 files changed, 14 insertions(+), 2 deletions(-)

Fusion-Task-Id: FN-6473

Fusion-Task-Lineage: 2e6ec23b-a9cd-4fd0-b24e-72ee8bb145ac
2026-06-15 02:30:41 -07:00
gsxdsm
d8fe994ca7 FN-6472: make release dry-runs non-interactive by default
Make dry-run release previews skip stdin prompts unless explicitly requested.

- Add a release prompt gate that suppresses version prompts for default dry-runs and honors --interactive as an opt-in.
- Update release CLI usage text and argument parsing for dry-run interactivity.
- Cover dry-run, --yes, real-release, and release.mjs ordering behavior with script tests.

Files changed:
 scripts/__tests__/release-prompt-gate.test.mjs | 72 ++++++++++++++++++++++++++
 scripts/lib/release-prompt-gate.mjs            | 13 +++++
 scripts/release.mjs                            | 16 ++++--
 3 files changed, 97 insertions(+), 4 deletions(-)

Fusion-Task-Id: FN-6472

Fusion-Task-Lineage: 07bfd944-f4a0-454a-883f-dadf1aa0b7d4
2026-06-15 02:30:41 -07:00
gsxdsm
830bc7a67c FN-6467: record ACP bridge rerun blocker
Record the FN-6467 U9 rerun outcome so Route A remains gated on authenticated ACP bridge evidence.

- Document the second direct bridge attempt against claude 2.1.177 and claude-code-cli-acp 0.1.1.
- Preserve the accepted 62-tool custom-tools MCP payload details and lockfile integrity evidence.
- Mark forwarded tool invocation and ACP permission-gate traversal as unresolved because the bridge still reports Not logged in.

Files changed:
 docs/acp-contract.md                                      | 15 ++++++++++-----
 docs/plans/2026-06-14-001-feat-claude-acp-runtime-plan.md |  3 +++
 2 files changed, 13 insertions(+), 5 deletions(-)

Fusion-Task-Id: FN-6467
Fusion-Task-Lineage: fa2c1e16-7822-421b-80cf-e4ab247641a5
2026-06-15 02:30:41 -07:00
gsxdsm
1b1d6f4359 FN-6466: record blocked ACP bridge spike result
Record the real Route A U9 bridge attempt and keep OQ1 at NOT GO.

- Document that claude-code-cli-acp accepted a non-empty Fusion MCP server declaration.
- Capture the unauthenticated claude blocker before forwarded tool invocation or permission telemetry.
- Keep FN-6460 blocked until an authenticated rerun proves tool forwarding and ACP permission traversal.

Files changed:
 docs/acp-contract.md                                      | 13 +++++++++++--
 docs/plans/2026-06-14-001-feat-claude-acp-runtime-plan.md |  3 +++
 2 files changed, 14 insertions(+), 2 deletions(-)

Fusion-Task-Id: FN-6466

Fusion-Task-Lineage: 0bce3b9f-fbab-4562-9a7b-9d5551335fa4
2026-06-15 02:30:41 -07:00
gsxdsm
41d4704138 FN-6465: document ACP Route A recovery blockers
Record the unrecovered Route A U9 verdict and the design-only U14 confirmation so follow-up work preserves the ACP permission-gate blocker.\n\n- Add an ACP contract open-question entry that marks Route A as NOT GO until real MCP forwarding and ACP permission-gate traversal are proven.\n- Capture the FN-6465 recovery outcome in the Claude ACP runtime plan, including the missing FN-6459 evidence and required rerun criteria.\n- Confirm the internal Route A design mechanisms while keeping implementation blocked on U9.\n\nFiles changed:\n docs/acp-contract.md                               | 24 ++++++++++++++++++++++\n .../2026-06-14-001-feat-claude-acp-runtime-plan.md |  9 ++++++++\n 2 files changed, 33 insertions(+)

Fusion-Task-Id: FN-6465

Fusion-Task-Lineage: d4762440-cbb9-4206-b4b2-be578eba30dd
2026-06-15 02:30:41 -07:00
gsxdsm
863ebfaa96 FN-6464: add CLI session relaunch route
Enable exhausted CLI sessions to request a fresh task-backed relaunch from the dashboard.

- Add an authenticated project-scoped relaunch endpoint for task-bound CLI sessions.\n- Wire relaunch intent through the dashboard server to clear resume linkage and re-enqueue the owning task.\n- Enable the session banner Relaunch fresh action and cover API, UI, transport, and runtime wiring behavior.\n- Document the CLI session action contract and add a published package changeset.\n\nFiles changed:\n .changeset/fn-6464-cli-relaunch-route.md           |  5 ++
 docs/agents.md                                     |  4 +
 packages/cli/src/commands/dashboard.ts             |  2 +
 packages/dashboard/app/App.tsx                     | 20 +++--
 .../app/__tests__/app-cli-action-wiring.test.tsx   | 31 +++++++-
 packages/dashboard/app/api/legacy.ts               |  7 ++
 .../__tests__/SessionNotificationBanner.test.tsx   | 52 ++++++++++---
 .../src/__tests__/cli-agent-runtime-wiring.test.ts | 49 +++++++++++-
 .../src/__tests__/cli-session-transport.test.ts    | 36 +++++++++
 .../src/__tests__/cli-sessions-routes.test.ts      | 50 +++++++++++-
 packages/dashboard/src/cli-session-transport.ts    | 38 +++++++++
 packages/dashboard/src/index.ts                    |  3 +-
 packages/dashboard/src/routes/cli-sessions.ts      | 26 ++++++-
 packages/dashboard/src/server.ts                   | 89 ++++++++++++++++++++++
 14 files changed, 390 insertions(+), 22 deletions(-)

Fusion-Task-Id: FN-6464

Fusion-Task-Lineage: f1ce171b-84a7-4893-9288-e1c8f01c3305
2026-06-15 02:30:41 -07:00