Skip to content

fix(v2): avoid blocking TUI setup on RPC and prevent inotify watcher loop - #669

Open
thehaven wants to merge 1 commit into
Tarquinen:masterfrom
thehaven:fix/v2-tui-stall-and-watcher-loop
Open

thehaven wants to merge 1 commit into
Tarquinen:masterfrom
thehaven:fix/v2-tui-stall-and-watcher-loop

Conversation

@thehaven

@thehaven thehaven commented Nov 2, 2026

Copy link
Copy Markdown

Summary

This PR addresses two issues affecting OpenCode v2 (opencode v2):

  1. Eliminate 5000ms TUI setup watchdog stall (role=cli)
    In lib/v2/tui.tsx, setup(ctx) previously called await client.status({}, options()) directly during plugin initialization.
    In OpenCode v2, plugins initialize concurrently while the server defers handling incoming RPC requests until plugin activation completes (awaitActivation). Making an RPC call during setup() creates a circular wait that causes OpenCode's client watchdog timeout to fire after 5000ms:

    level=WARN message="plugin operation stalled" component=plugin stage=setup elapsedMs=5001 plugin=opencode-dcp role=cli
    

    By moving the client.status check into open() (prior to requesting the snapshot), setup(ctx) returns immediately and plugin registration completes in <1ms without stalling CLI startup.

  2. Prevent inotify directory watcher loop during prompt defaults initialization
    In lib/prompts/store.ts, ensureDefaultFiles() previously executed directory creation on every startup without guarding on directory existence. When OpenCode watches configuration directories (such as ~/.config/opencode), touching directories on startup can trigger recursive inotify events and plugin reconciliation cycles. Checking existsSync(this.paths.defaultsDir) ensures prompt directory creation is idempotent and avoids redundant inotify events.

Testing & Verification

  • npm test: all 119 DCP tests + 8 request logger tests pass.
  • npm run typecheck: clean (0 errors).
  • npm run check:package: package tarball builds and verification passes.
  • Verified in OpenCode v2: plugin setup watchdog stalls are eliminated and the /dcp dialog opens and operates as expected.

…loop

- Defer client.status() check in lib/v2/tui.tsx from setup() to open().
  In OpenCode v2, plugins initialize concurrently while the server defers handling
  RPC requests until activation completes (awaitActivation). Invoking RPC during
  setup() causes a circular startup wait that triggers watchdog stalls.
- Make default prompt file initialization idempotent in lib/prompts/store.ts by
  checking directory existence before writing defaults, preventing recursive inotify
  events when watching configuration paths.
@ricardosantisinc

Copy link
Copy Markdown

Confirming this on DCP 3.2.0 + OpenCode 2.2.5 (Linux). Exact symptom:

WARN plugin operation stalled  component=plugin stage=setup elapsedMs=5000 plugin=opencode-dcp role=cli
INFO loading plugin            id=@tarquinen/opencode-dcp@latest entrypoint=.../dist/index.js role=server
INFO Sent HTTP response        http.method=POST http.url=/api/rpc/dcp/status http.status=503
WARN plugin operation failed   stage=setup durationMs=8182 error="UnexpectedStatus: 503" plugin=opencode-dcp role=cli

The 503 is collateral, not the cause: in the same ~10 ms window the server also returned 503 for GET /api/plugin, GET /api/info and GET /api/experimental/migration/v1 — i.e. the service was shutting down/restarting after the setup stall. Once the new service is up, the DCP server RPC answers normally (POST /api/rpc/dcp/status -> {"output":{"enabled":true}}), but OpenCode does not retry a failed TUI setup, so the plugin stays failed for the entire UI session.

Applying the lib/v2/tui.tsx change from this PR to the installed 3.2.0 package removes the blocking: setup() returns immediately and bun build compiles the module cleanly. Looking forward to a release with this fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants