Skip to content

Bash completion cannot wake idle OpenCode session: unbound promptAsync throws on this._client #297

Description

@null-axiom

Summary

AFT successfully executes background Bash tasks and receives their completion, but fails to resume the idle OpenCode session. The completion reminder only appears after I send another message and the assistant invokes a tool such as bash_status.

The installed plugin extracts client.session.promptAsync and invokes it without its receiver. The generated OpenCode SDK method accesses this._client, so the wake request throws before it can reach OpenCode.

Environment

  • AFT OpenCode plugin: 0.55.1
  • OpenCode Desktop: 1.18.29

Observed sequence

  1. The assistant launches an AFT Bash task with background: true.
  2. The assistant ends its turn while the task runs.
  3. The task finishes successfully. In the inspected instance, a Desktop build completed with exit code 0 after 56 seconds.
  4. AFT schedules and fires a completion wakeup.
  5. Both the normal injection path and fallback fail; retries eventually stop.
  6. No assistant continuation appears until I send another message. A subsequent bash_status call retrieves the successful result and the queued reminder is appended in-turn.

Expected behavior

Once the parent session is idle, a completed background task should trigger the intended session.promptAsync continuation without another user message or status lookup.

Logs

Selected fields from aft-plugin.log, with session identifiers, local paths, and prompt-context metadata omitted:

2026-09-06T06:25:21.031Z
event=bash_completion_wake_scheduled delay_ms=200 pending_completions=1 retry_attempt=0

2026-09-06T06:25:21.236Z
event=bash_completion_wake_fire retry_attempt=0

2026-09-06T06:25:21.276Z
event=bash_completion_wake_prompt_async_start injection_mode=mirrored-context

2026-09-06T06:25:21.276Z
event=bash_completion_wake_prompt_async_error injection_mode=mirrored-context
cause="Cannot read properties of undefined (reading '_client')"

2026-09-06T06:25:21.276Z
event=bash_completion_wake_prompt_async_start injection_mode=model-free-fallback

2026-09-06T06:25:24.560Z
event=bash_completion_inject_hard_stopped
cause="Cannot read properties of undefined (reading '_client')"

2026-09-06T06:27:07.893Z
event=bash_completion_in_turn_append

2026-09-06T06:27:07.902Z
event=bash_completion_ack_ok

Wake attempts were logged with retry indices 0 through 4 before the hard stop. The eventual in-turn append followed the user-triggered bash_status lookup.

These logs rule out missing completion ingestion or an idle deferral that never reached the wake stage for this occurrence.

Source diagnosis

In the installed plugin bundle, dist/index.js, triggerWakeIfPending() (approximately lines 32046–32090) extracts and later calls the method:

const promptAsync = client.session?.promptAsync;
// ...
await promptAsync({ /* request options */ });

The generated OpenCode SDK implementation, packages/sdk/js/src/gen/sdk.gen.ts (approximately lines 639–647), uses its receiver:

public promptAsync(options) {
  return (options.client ?? this._client).post(/* ... */)
}

The detached call loses this. The fallback uses the same detached method, so changing prompt/model context or retrying cannot fix this exception.

Suggested fix

Preserve the SDK method receiver in both the normal and fallback paths, for example by invoking client.session.promptAsync(...) directly, binding the extracted method to client.session, or calling it with that receiver explicitly. Retain the existing optional-method availability check where needed.

Suggested regression coverage

  • Exercise the real wake path with a receiver-dependent SDK method, rather than an arrow-function stub that works when detached.
  • Verify that both mirrored-context and model-free fallback calls preserve the receiver.
  • Verify that a completed task wakes an idle session without a user prompt or status lookup.
  • Cover both completion-before-idle and idle-before-completion ordering.

For runtime confirmation, expect bash_completion_wake_prompt_async_start followed by successful injection and an actual assistant continuation—not merely eventual in-turn acknowledgment.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions