Grok advertises promptCapabilities.image=false and ignores ACP image
ContentBlocks (live probe: NO_IMAGE). Path-based vision works when the
agent is given an absolute file path. Include path hints in chat prompts
from .fusion/chat-attachments and carry path on ChatImageContent for
file:// uris.
AcpRuntimeAdapter.promptWithFallback ignored options, so dashboard chat
images never became ACP ContentBlock image entries. Extract images from
prompt options and pass them through buildPromptBlocks for both acp-runtime
and the Grok vendored client.
Grok emits `_x.ai/session_notification` / `_x.ai/session/update` for
hook_execution status. The ACP SDK routes those to Client.extNotification;
without it, every successful post_tool_use hook logged -32601 Method not
found. Implement no-op extMethod/extNotification on default and bridging
handlers in acp-runtime and the Grok vendored copy.
Replace one-shot grok -p JSON with native grok agent stdio (ACP) for realtime
streaming, tool visibility, and multi-turn sessions. Vendor the ACP client
into fusion-plugin-grok-runtime, forward Fusion fn_* tools and operator MCP,
stage Fusion skills via --plugin-dir, authenticate per xAI headless docs, and
align project chat manager store resolution so Grok chat sessions can send.
Raises Grok and Droid CLI cold-start timeout defaults from 60s to 120s and lets operators override them via environment variables.
- Grok runtime adapter: new GROK_CLI_FIRST_OUTPUT_TIMEOUT_MS env override for the first-output cold-start guard; default raised 60000ms → 120000ms; invalid/non-positive values fall back to the default
- Droid provider: new PI_DROID_CLI_FIRST_LINE_TIMEOUT_MS env override for the first-line cold-start guard; default raised 60000ms → 120000ms; invalid/non-positive values fall back to the default
- 30-minute inactivity safety net left unchanged on both adapters
- Added/updated unit tests covering the new env-driven timeout resolution and fallback behavior for both plugins
- Documented the new settings in docs/settings-reference.md and both plugin READMEs
- Added a minor changeset for @runfusion/fusion
Files changed:
.changeset/fn-7838-cli-timeout-configurable.md | 7 ++
docs/settings-reference.md | 13 ++-
plugins/fusion-plugin-droid-runtime/README.md | 8 ++
.../src/__tests__/provider.test.ts | 97 +++++++++++++++++++++-
.../fusion-plugin-droid-runtime/src/provider.ts | 26 ++++--
plugins/fusion-plugin-grok-runtime/README.md | 8 ++
.../src/__tests__/runtime-adapter.test.ts | 52 +++++++++++-
.../src/runtime-adapter.ts | 23 ++++-
8 files changed, 222 insertions(+), 12 deletions(-)
Fusion-Task-Id: FN-7838
Fusion-Task-Lineage: 7aad4470-b28f-42bd-be01-8363a1dd05e5
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
- scope session collections to the active project\n- clean up runtime stage registration in discovery tests\n- model brainstorms and plans as repeatable artifact collections\n- compact the singleton Strategy presentation
The running dashboard loads the compiled plugin dist, which was stale and
invoked `grok --prompt <text> --format json --directory <cwd>` — flags grok
0.2.93 rejects ("unexpected argument '--prompt'"), yielding a non-zero exit,
no JSON, and an empty "No message" bubble. The source already switched to the
valid `grok -p <text> --output-format json [-m <model>] [--cwd <dir>]`
contract (FN-7790/FN-7796); this rebuilds dist to match.
Also reconcile the FN-7779 test suite: a genuinely empty response is a parsed
`{text:"",stopReason:"EndTurn"}` object, not zero stdout bytes, so the
"stays silent" test now models that shape instead of contradicting the
FN-7796 zero-stdout wrong-binary diagnostic. All 64 plugin tests pass.
Fusion-Task-Id: FN-7779
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Narrative: the streaming-json headless contract intermittently emitted only thought events then stopReason:Cancelled with zero text, leaving Chat replies silently empty; the adapter now spawns grok with --output-format json, buffers stdout, and parses the single JSON response on process close, with streaming-json parsing kept only as a diagnostic fallback.
- Change grok CLI invocation from --output-format streaming-json to --output-format json (cli-stream.ts)
- Add GrokCliJsonResponse type ({text, stopReason, sessionId, requestId, thought}) and parseJsonOutput() to stream-parser.ts, keeping legacy NDJSON line parsing for fallback/diagnostics
- Rework runtime-adapter.ts to buffer full stdout, parse it via parsePromptOutput (JSON object first, NDJSON fallback), and surface a formatTerminalNoTextDiagnostic when a non-EndTurn stopReason yields no assistant text
- Rename first-line/inactivity timeout bookkeeping from line-based to output/chunk-based (FIRST_OUTPUT_TIMEOUT_MS, firstOutputReceived, firstStdoutChunk) since stdout is no longer consumed via readline
- Update cli-stream/runtime-adapter/stream-parser tests to cover the JSON response path and the Cancelled/no-text diagnostic
- Update docs/grok-cli-contract.md and plugin README to document the json output-format contract and diagnostics
- Add changeset fn-7796-grok-cli-reliable-headless.md (patch, fix)
Files changed:
.changeset/fn-7796-grok-cli-reliable-headless.md | 7 +
docs/grok-cli-contract.md | 108 ++++++++-----
plugins/fusion-plugin-grok-runtime/README.md | 16 +-
.../src/__tests__/cli-stream.test.ts | 4 +-
.../src/__tests__/runtime-adapter.test.ts | 73 ++++++++-
.../src/__tests__/stream-parser.test.ts | 80 +++++----
.../fusion-plugin-grok-runtime/src/cli-stream.ts | 14 +-
.../src/runtime-adapter.ts | 180 ++++++++++++---------
.../src/stream-parser.ts | 65 ++++++--
plugins/fusion-plugin-grok-runtime/src/types.ts | 13 +-
10 files changed, 373 insertions(+), 187 deletions(-)
Fusion-Task-Id: FN-7796
Fusion-Task-Lineage: c920fcf0-98f8-42ec-867a-7f76c0aca1b7
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Align the Grok CLI runtime plugin adapter with the real xAI grok CLI stream contract so tool responses are no longer silently dropped, and update tests/docs to match.
- Rework stream-parser.ts to parse the actual grok CLI event/message shape instead of the previously assumed schema
- Trim runtime-adapter.ts and types.ts down to the fields the real CLI contract emits, removing speculative/unsupported fields
- Update cli-stream.ts to match the corrected event handling
- Rewrite runtime-adapter, stream-parser, and cli-stream test suites to exercise the real CLI contract end-to-end
- Update docs/grok-cli-contract.md and plugin README to document the verified contract
- Add changeset for the grok-runtime plugin fix
Files changed:
.changeset/fn-7790-grok-cli-real-contract.md | 7 +
docs/grok-cli-contract.md | 432 +++++++--------------
plugins/fusion-plugin-grok-runtime/README.md | 149 ++-----
.../src/__tests__/cli-stream.test.ts | 22 +-
.../src/__tests__/runtime-adapter.test.ts | 250 ++++--------
.../src/__tests__/stream-parser.test.ts | 108 ++----
.../fusion-plugin-grok-runtime/src/cli-stream.ts | 22 +-
.../src/runtime-adapter.ts | 109 ++----
.../src/stream-parser.ts | 27 +-
plugins/fusion-plugin-grok-runtime/src/types.ts | 104 +----
10 files changed, 338 insertions(+), 892 deletions(-)
Fusion-Task-Id: FN-7790
Fusion-Task-Lineage: 377e86c4-c005-46a5-9eb4-69e858c38b79
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Fixes the residual "Grok CLI still returns no message immediately" case where a headless run exits code 0 but never emits any parsed NDJSON event, previously treated as a silent success.
- Detect a code-0 close with zero parsed NDJSON events and surface a diagnostic explaining the likely cause (wrong/unsupported grok binary falling into interactive mode and hitting EOF on stdin).
- Track and emit assistant text/diagnostics via a new appendMessage/emitDiagnosticText path so onText and session.state.errorMessage stay in sync, including on spawn failure and inactivity/first-line timeouts.
- Add first-line/inactivity timeout diagnostics with concrete elapsed-time messaging instead of silent kills.
- Add regression coverage in runtime-adapter.test.ts and grok-runtime-routing.test.ts for the zero-NDJSON exit path.
- Document the contract update in docs/grok-cli-contract.md.
- Add a patch changeset for @runfusion/fusion.
Files changed:
$(cat /tmp/diffstat_fn7788.txt)
Fusion-Task-Id: FN-7788
Fusion-Task-Lineage: dbb238a9-9601-47fc-8a88-40817d749337
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Root-causes the Grok CLI empty-response bug: readline close no longer finalizes the session before the subprocess close event can attach exit code/stderr diagnostics, so failures were silently swallowed as empty assistant messages.
- Wait for subprocess close/error (not readline close) to finalize the Grok CLI session, so non-zero exits can attach stderr before callers inspect the result
- Add GrokSession.state.errorMessage to carry concrete diagnostics (spawn failure, process error, non-zero exit + stderr, or NDJSON error event) through the resolve-never-reject runtime contract
- Track whether any text was received so error diagnostics are only recorded when the run actually produced nothing
- Add a changeset documenting the fix for @runfusion/fusion
- Extend runtime-adapter tests to cover spawn failure, process error, non-zero exit with/without stderr, and NDJSON error-event diagnostics
Files changed:
.changeset/fn-7782-grok-cli-no-response.md | 7 ++
.../src/__tests__/runtime-adapter.test.ts | 98 ++++++++++++++++++++--
.../src/runtime-adapter.ts | 75 +++++++++++++----
plugins/fusion-plugin-grok-runtime/src/types.ts | 1 +
4 files changed, 161 insertions(+), 20 deletions(-)
Fusion-Task-Id: FN-7782
Fusion-Task-Lineage: c2907a70-0556-488f-bda3-132657b64071
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
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>
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>
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>
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>
Desktop "Local" mode crashed with ERR_MODULE_NOT_FOUND because electron-builder's
pnpm collector drops `deduped` subtrees, so engine's transitive closure
(@modelcontextprotocol/sdk, pi-ai provider SDKs, etc.) was never packed. Stage the
complete flat prod closure with `pnpm deploy --legacy --config.node-linker=hoisted`
and package it via `electron-builder --projectDir deploy`, bypassing the lossy
collector entirely.
Also make the dashboard-imported example plugins loadable under plain Node (the
Electron main runtime): cursor/droid/roadmap now expose compiled `dist` on the
`import` condition (keeping `source`→src for the bun CLI) and are built during the
desktop build. Add `source` conditions to paperclip/agent-browser/even-cards/
even-realities-glasses/whatsapp-chat so the bun `--conditions=source` Windows CLI
compile resolves them from source.
Validated on macOS: @fusion/core|engine|dashboard import cleanly from the staged
deploy; packing yields a complete 705-package asar; bun-windows-x64 cross-compiles
with all plugin dist removed.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The CLI bun `--compile --conditions=source` build could not resolve
@fusion-plugin-examples/hermes-runtime and openclaw-runtime (statically imported
by dashboard routes.ts): those plugins lacked a `source` export condition and
fell through to `import`->dist/index.js, absent on the Windows runner. Add
`"source": "./src/index.ts"` (matching core/dashboard/engine/plugin-sdk) so bun
bundles their TS source directly, independent of dist.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>