Skip to content

v0.6.3

Choose a tag to compare

@hueyexe hueyexe released this 26 Mar 04:31
· 82 commits to main since this release

Fix: Lead hangs indefinitely during team_spawn

This release fixes a persistent bug where the team lead would hang with a loading spinner after spawning teammates. The teammates were actually working (permission popups appeared, code was being written in worktrees), but the lead's tool call never returned.

Three root causes were identified across v0.6.1–v0.6.3. The first two patches (v0.6.1, v0.6.2) treated symptoms; this release fixes the actual bugs.

Root cause 1: await on fire-and-forget promptAsync

promptAsync is HTTP 204 on the server — it accepts the message and returns immediately with no body. But the plugin code awaited it. Through a proxy or slow transport, the await blocked the tool call indefinitely. The lead's team_spawn never returned, so the model never generated its "team is started" response.

  • All promptAsync calls in team_spawn, team_message, and team_broadcast are now fire-and-forget (no await)
  • Messages are persisted in the DB before the promptAsync call
  • Async .catch() handles rollback on failure
  • If a spawn fails, the lead receives a system message: Teammate "X" failed to start and was removed

Root cause 2: v1→v2 SDK transport extraction

The plugin framework provides a v1 SDK client. We extract its HeyAPI transport and pass it to the v2 SDK constructor. The v1 SDK stores the transport as ._client (underscore), while the v2 SDK stores it as .client (no underscore). An earlier patch accidentally changed the extraction to read .client from the v1 class, which returned undefined. The v2 constructor fell back to a default HTTP transport that couldn't reach the server — every session.create() failed with "Unable to connect".

  • Restored correct ._client property extraction from v1 plugin client
  • Added V2Transport type alias to avoid as any cast
  • Documented the v1/v2 property name difference in AGENTS.md as a settled decision

Root cause 3: Teammate messages interrupting the lead's active stream (v0.6.2)

When teammates finished fast and sent messages back via promptAsync while the lead was busy, the proxy would cancel the lead's active stream. This was fixed in v0.6.2 with a busy-session guard and idle-flush backstop, and remains in place.

Also in this release

  • Biome linter added with noExplicitAny: error — the as any cast that caused root cause 2 is now a lint error
  • All non-null assertions (!) replaced with nullish coalescing (?? "unknown")
  • Dead code removed from notify.ts
  • allSessionIds() public method replaces private property access on MemberRegistry
  • Async rollback in team_spawn wrapped in try/catch to prevent unhandled rejections
  • DB rollback uses session_id instead of name to prevent race with re-spawned teammates

Why it took three patches

v0.6.1 reduced payload sizes and added sequential spawn guidance — treating the proxy truncation symptom, not the blocking await cause. v0.6.2 correctly identified the message-interruption race but missed that the lead was hanging during the spawn itself, before any messages arrived. v0.6.3 identified both the await blocking and the transport extraction bug through a thorough SDK source audit, and added Biome enforcement to prevent as any casts from hiding type mismatches in the future.

Full Changelog: v0.6.2...v0.6.3