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
- The assistant launches an AFT Bash task with
background: true.
- The assistant ends its turn while the task runs.
- The task finishes successfully. In the inspected instance, a Desktop build completed with exit code 0 after 56 seconds.
- AFT schedules and fires a completion wakeup.
- Both the normal injection path and fallback fail; retries eventually stop.
- 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.
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.promptAsyncand invokes it without its receiver. The generated OpenCode SDK method accessesthis._client, so the wake request throws before it can reach OpenCode.Environment
Observed sequence
background: true.bash_statuscall 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.promptAsynccontinuation without another user message or status lookup.Logs
Selected fields from
aft-plugin.log, with session identifiers, local paths, and prompt-context metadata omitted:Wake attempts were logged with retry indices 0 through 4 before the hard stop. The eventual in-turn append followed the user-triggered
bash_statuslookup.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:The generated OpenCode SDK implementation,
packages/sdk/js/src/gen/sdk.gen.ts(approximately lines 639–647), uses its receiver: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 toclient.session, or calling it with that receiver explicitly. Retain the existing optional-method availability check where needed.Suggested regression coverage
For runtime confirmation, expect
bash_completion_wake_prompt_async_startfollowed by successful injection and an actual assistant continuation—not merely eventual in-turn acknowledgment.