Repository navigation
Release 0.2.1: shared native harness lifecycle and reliability fixes - #39
Merged
Merged
Conversation
…nd prompt modules Slice 0 of the shared-harness refactor: six composition-only modules under plugins/multi-core/src/gateway/, with no provider file touched yet. - harness-session.ts: HarnessSessionStore owns the lock file, the busy flag and the load gate; acquire() and loadOnly() are the only ways to a record and both refuse a busy identity with HarnessBusyError, so a provider cannot re-add queuing. It also holds readJson, atomicJson (explicit platform) and the persisted-state validators. - harness-exchange.ts: HarnessEvent, HarnessExchange and ExchangeRegistry (start/get/all/observe) with an optional retain guard for an uncertain run, plus replayPersisted for a completed identical request. - harness-response.ts: HarnessResponse (text, optional multi-block display rows, held-back terminal events) over one HarnessUsageFields vocabulary. - harness-notices.ts: interrupted, policy and rewind notices, safeText, stderr diagnostics, continuation, historyRewound, harnessHistoryHash, terminalSuffix. - harness-process.ts: runNativeCli with the SIGINT/SIGTERM/SIGKILL cascade, nativeEnvironment, redactStderr and NativeCliError; every event grammar plugs in through parseLine and finish, which stay provider-side. - harness-prompt.ts: prepareNativePrompt and validateNativeMessages, with catalogue stripping and empty-turn dropping off by default. Every platform-dependent path takes an explicit platform option. Six node:test suites cover the new API, including the busy refusal, disk replay, rewind detection, notices, the process cascade with a fake spawn and prompt preparation with catalogues on and off. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0112UmL1KthnW34TDdkcCJww
…se prompts while busy Antigravity now composes the shared harness plumbing instead of carrying its own copy. Moved out of plugins/multi-antigravity/src (-663 lines): - harness.ts: the session store (lock, load gate, busy flag, versioned read, validators, atomic save), the exchange registry and its `cachedExecute` replay, `HarnessResponse`, the interrupted/policy/rewind notices, `safeText`, the stderr diagnostics filter, `continuation`, `historyRewound` and the JSON/hash helpers. - cli.ts: the process lifecycle (spawn, NDJSON framing, output limits, SIGINT/SIGTERM/SIGKILL escalation across the tree, cancellation settling, pipe teardown, stderr redaction) and the environment deny list. - request.ts: the prompt builder, the Messages validator, the history hash and the terminal suffix. Kept provider-side, per the plan's do-not-touch list: the init/step/result grammar, `finish` gating a failed exit on `status === 'SUCCESS'`, the stream-json stdin delivery and its argument-size choice, the usage vocabulary adapter and `usageDelta`, the `denied_actions` diagnostics, the permission maps, and the `nativeSpelling(body.model)` key normalisation in `handle()` that keeps `[1m]` and plain spellings one request identity. Busy behaviour: 502 retryable -> 400 deterministic. `HarnessSessionStore` is now the only path to a session record, `acquire()` refuses a busy agent with `HarnessBusyError`, and that call moved inside `execute()`'s `try` so the refusal is wrapped. `AntigravityProviderError` maps `HarnessBusyError` to 400. A 502 is retryable, so Claude re-sent a prompt whose history stops at the still-running turn and the retry resumed the native conversation with stale history, forwarding a paid turn a second time. New tests pin the refusal at the harness (one native call) and over HTTP (400, not 502). Adopting the store also fixes the missing `platform` on the session write, which previously bypassed the Windows atomic-write path. No shared-module changes were needed. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0112UmL1KthnW34TDdkcCJww
Grok adopts the six plugins/multi-core/src/gateway/harness-*.ts modules
extracted in slice 0, as the reference implementation for the shared-harness
refactor:
- harness-session.ts: HarnessSessionStore replaces Grok's own session map,
lock handling, and Saved/Session validators. GrokBusyError is deleted;
GrokProviderError now maps HarnessBusyError to status 400 directly.
- harness-exchange.ts: ExchangeRegistry replaces the hand-rolled exchange
map/observe logic; replayPersisted replaces serve()/cachedExecute().
- harness-response.ts: HarnessResponse/HarnessUsageFields replace Grok's own
response-builder class, via a 6-line GrokUsage -> HarnessUsageFields
adapter kept in harness.ts.
- harness-notices.ts: writeNotices, interruptedNotice, safeText,
stderrDiagnostics, continuation, and historyRewound replace their
Grok-local copies.
- harness-process.ts: runNativeCli replaces spawnGrok's process-lifecycle
cascade. GrokCliError now extends the shared NativeCliError so
`instanceof GrokCliError` still holds for every failure path; a small
adapter rewraps the rare bare-NativeCliError rejection runNativeCli can
raise before any Grok parser state exists.
- harness-prompt.ts: prepareNativePrompt/validateNativeMessages replace
prepareGrokRequest's own message-flattening and validation; request.ts
is now a thin wrapper supplying Grok's preamble and
stripCatalogues/dropEmptyTurns options. grokHistoryHash now delegates to
harnessHistoryHash({ stripReminders: true }).
Grok-owned pieces stay as the plan requires: NDJSON parsing (parseGrokLine
and friends), `finish` semantics (finishValue), toolset verification
(parseTools/sameTools), TRANSIENT_SPAWN/permanentFailure/spawnSystemCode,
the GrokUsage adapter, and the errors.ts advice tables.
Fixed a busy-lock leak the coordinator flagged after the Antigravity slice
landed: HarnessSessionStore.acquire() marks a session busy before
continuation() can validate the request, so continuation()/historyRewound()
now run inside execute()'s try/finally (extracted into openTurn() to keep
execute() under the complexity limit) instead of a separate session()
helper outside it. A new test pins that a rejected continuation still
releases the record for the next request. The store's persisted `provider`
field stays the lowercase 'grok' discriminator; ExchangeRegistry and
replayPersisted use the capitalized 'Grok' display tag so exchange/replay
messages read exactly as they did before this slice.
No shared-module changes were needed; harness-process.ts, harness-session.ts,
harness-exchange.ts, harness-response.ts, harness-notices.ts, and
harness-prompt.ts are used exactly as slice 0 defined them.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0112UmL1KthnW34TDdkcCJww
…nd notice modules and refuse prompts while busy What moved out of plugins/multi-cursor/src/: - Session state: the record map, lock file, busy flag, load gate, atomic save and persisted-state validation now live in HarnessSessionStore. Cursor keeps its SDK agent lifecycle (create/resume, closeAgent, configureSession, recoverRun/recoverSession, archiveReply, persistDispatch, 32-agent eviction); only the lock/persist/validate layer is shared. The record identity is [cwd, scope] and the SDK-specific fields (agentId, pendingRun) plus their validator stay provider-side. - Exchange plumbing: the exchange map, forwarding emitter, settle/retain rule and observe() are ExchangeRegistry; the disk replay path is replayPersisted. - HarnessResponse is the shared one with multiBlock: true, so mod display rows keep their own content blocks. Cursor's TokenUsage is mapped into HarnessUsageFields in one adapter, and the terminal events are now taken from takeTerminalEvents() and delivered on the same path as before: recorded into the replay, held back until the turn is durably committed. - Notices: continuation, historyRewound, harnessHistoryHash (no reminder stripping, as Cursor hashed history today), terminalSuffix, interruptedNotice and writeNotices. cursorHistoryHash and cursorTerminalSuffix are deleted from request.ts. - Cursor does not adopt harness-process or harness-prompt: the whole SDK agent lifecycle and prepareCursorRequest stay Cursor-side. Exchange retention is expressed through the registry's retain option so the crash/restart ordering the harness test pins is unchanged: a finished turn stays addressable for replay, a failure that may have run stays so its uncertainty is reported instead of repeating native edits, and a failure that provably ran nothing is dropped. Busy behaviour change (user visible): a prompt that arrives while a run owns the agent was answered 502, which is retryable, so Claude resent the same prompt -- whose history stops at the still-running turn -- and the retry resumed the native conversation with stale history, forwarding a paid turn again. Both Cursor gates (taking the turn, and the interrupted-state recovery gate) now raise HarnessBusyError through HarnessSessionStore.acquire()/loadOnly(), and cursorFailure maps it to a deterministic 400 before the CODE_STATUS table. There is no queue and no parameter to add one. Session record version 2 -> 3 for the shared provider/identity header. A version 2 record is ignored rather than refused, so the next turn starts a fresh native agent instead of failing to load. Shared-module additions (additive only, no signature breaks) for the integrator to reconcile with the parallel Grok and Antigravity slices: - HarnessSessionStore: new `transient` constructor option (live-only record keys stripped by save(); Cursor passes agent/run/policy), new forget(identity) so a provider can drop a cached record while keeping or releasing its lock itself, and sessionFile(identity) changed from private to public for the reads that must not take the lock (Cursor's billed-usage query). - ExchangeRegistry: new `size` getter and evictSettled(), which Cursor's 256-exchange cap needs; a running exchange is never dropped. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0112UmL1KthnW34TDdkcCJww
…tus mapping server.ts's errorStatus() already forwards a single failure.status field for all three *ProviderError classes with one 502 default; each provider already makes HarnessBusyError deterministic (400) at its own boundary, so there is no duplicated switch left to unify there. Grok and Antigravity now read the exchange registry's size getter instead of all().length, matching Cursor. Document the shared harness-*.ts modules in ARCHITECTURE.md (state, isolation, platform layer) and AGENTS.md's code map, and note in docs/cursor.md and docs/antigravity.md that a prompt sent while a run is in flight is refused with a deterministic error instead of queued, matching docs/grok.md. Record the refactor, the Antigravity/Cursor busy-refusal status change, the Cursor session record version bump, and the Cursor token estimate fallback change in CHANGELOG.md. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0112UmL1KthnW34TDdkcCJww
… shared harness Cursor's interrupted-state recovery now acquires the session record for its whole duration, so a second request is refused instead of dispatching a run whose pendingRun the finishing recovery would clear. Replay validation is provider-parameterized: Cursor accepts its display-only tool_use rows, Grok and Antigravity stay text-only, so a mod-row turn replays from the record and from its archived response file instead of failing forever. Cursor's 32-agent budget counts records that hold a native SDK agent, and the replay path's use of the record lock is documented rather than removed. HarnessSessionStore takes a display tag, so a busy refusal names Antigravity rather than its on-disk discriminator. continuation() names the provider whose native session could not be continued. Antigravity wraps loadOnly, so a first-load race is answered 400 instead of a retryable 502. Antigravity rewraps a synchronous spawn failure as AntigravityCliError, keeping the operating system's own code. CHANGELOG records the Grok transient-spawn status change and the Cursor replay lock, and counts the behaviour changes correctly. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0112UmL1KthnW34TDdkcCJww
Share scoped session leases and durable completion, preserve Cursor legacy records, and bound SDK capacity across creation and billing queries. Extract conversation normalization and inject provider-owned harness and usage adapters through the existing Mods control plane.
Reduce the OpenAI profile to Claude-hosted compatibility, remove the legacy fleet ban, and distinguish conventions from execution contracts. Document Claude Mods with the maintainer's explicit integration requirement, repair platform-specific skills and stale operational claims, and record refactor behavior and verification limits.
…ember model releases Cursor keeps the pending run when a completion save fails, so a retry recovers instead of re-dispatching. Idle eviction and disk-only replay release record locks without deleting native state, temporary billing handles count toward the SDK budget, legacy `pending` records migrate, and ambiguous v2/v3 ownership reports a documented recovery path. Shared normalization rejects malformed messages again, `loadOnly` is removed, and the opt-in OpenAI instructions probe matches the compatibility note. Codex workers `openai-luna` and `openai-sol` now run `gpt-6-luna` and `gpt-6-sol`, and the no-Claude fallback starts on `gpt-6-luna`. The Cursor picker shows Grok 4.7 instead of Grok 4.6. Zen adds `gpt-6-luna` and `gpt-6-sol` to its catalog. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014HE2qVAwqeZ1AZALmufezm
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Seven unresolved findings remain, including two critical Cursor replay-identity issues and lifecycle, cancellation, rewind, validation, and malformed-tool handling issues.
Get a fresh assessment by requesting another Copilot review.
Review effort: Lite
Findings: 2
Open (4)
What changed in this PR
Release 0.2.1 centralizes native harness lifecycle, replay, prompt normalization, and completion handling for Cursor, Antigravity, and Grok, alongside model, usage, documentation, test, and version updates.
Changes:
- Adds shared native session, exchange, response, prompt, and completion utilities.
- Improves provider recovery, busy-request handling, model defaults, and usage reporting.
- Updates documentation, platform guidance, plugin metadata, and regression coverage.
Review findings:
- Critical (2 votes): Cursor exchange identity still hashes raw request bodies, allowing cache-marker changes to miss replay and rerun native turns.
- Critical (1 vote): Cursor’s normalized history hash is not used at the exchange-key call site, causing the same replay risk.
- Moderate (2 votes): Completion archives have no bounded cleanup policy.
- Moderate (2 votes): Canceled observers can receive cached SSE events before abort handling.
- Moderate (1 vote): Duplicate assistant content can defeat rewind detection.
- Moderate (1 vote): Malformed non-array
stop_sequencesvalues can be silently ignored. - Moderate (1 vote):
nulltool entries can produce generic dereference errors instead of validation errors.
| File | Reviewed changes |
|---|---|
test/unit/native-zen-models.test.ts |
Covers new Zen model catalog entries. |
test/unit/native-tool-discovery.test.ts |
Updates discovery model coverage. |
test/unit/native-openai-approval.test.ts |
Updates OpenAI approval model coverage. |
test/unit/native-mod-routes.test.ts |
Updates native route fixtures. |
test/unit/native-launcher.test.ts |
Updates launcher catalog coverage. |
test/unit/native-harness-response.test.ts |
Tests shared response streaming and durable completion. |
test/unit/native-harness-prompt.test.ts |
Tests shared prompt preparation. |
test/unit/native-harness-process.test.ts |
Tests native process execution and cancellation. |
test/unit/native-harness-notices.test.ts |
Tests notices and replay/history handling. |
test/unit/native-harness-interface.test.ts |
Tests native error status handling. |
test/unit/native-harness-exchange.test.ts |
Tests exchange sharing, replay, and cancellation. |
test/unit/native-grok-harness.test.ts |
Tests Grok lifecycle handling. |
test/unit/native-gateway.test.ts |
Updates gateway model and instruction coverage. |
test/unit/native-cursor-request.test.ts |
Tests Cursor normalization and validation. |
test/unit/native-cursor-models.test.ts |
Updates Cursor picker defaults. |
test/unit/native-cursor-mod-rows.test.ts |
Tests Cursor display-row replay. |
test/unit/native-cursor-harness-http.test.ts |
Tests Cursor busy-request HTTP behavior. |
test/unit/native-approval.test.ts |
Updates provider approval fixtures. |
test/unit/native-antigravity-harness.test.ts |
Tests Antigravity busy and race handling. |
test/unit/native-antigravity-gateway.test.ts |
Tests Antigravity gateway refusals. |
test/unit/native-antigravity-cli.test.ts |
Tests CLI spawn error wrapping. |
test/unit/mod-policy.test.ts |
Tests unsupported Workflow diagnostics. |
test/live/native-translation.ts |
Updates the live translation model. |
test/live/native-reviewer.ts |
Updates the live reviewer model. |
test/live/native-provider-approval.ts |
Updates the live approval model. |
test/live/native-permissions.ts |
Updates live permission defaults. |
test/live/native-openai-instructions.ts |
Tests current instruction behavior. |
test/live/native-openai-cache.ts |
Updates the live cache probe model. |
test/live/native-main-switch.ts |
Updates live model switching. |
test/live/native-approval-worker.ts |
Updates the live worker model. |
README.md |
Clarifies setup, platform, and asset documentation. |
PRIVACY.md |
Documents local usage, receipts, and provider lookups. |
plugins/multi-zen/src/usage-adapter.ts |
Adds Zen usage integration. |
plugins/multi-zen/src/models.ts |
Adds Zen catalog entries. |
plugins/multi-zen/skills/connect/SKILL.md |
Adds shell-specific connection commands. |
plugins/multi-zen/.claude-plugin/plugin.json |
Bumps the Zen plugin version. |
plugins/multi-openai/src/usage.ts |
Updates the Codex client version. |
plugins/multi-openai/src/usage-adapter.ts |
Adds OpenAI usage integration. |
plugins/multi-openai/src/responses.ts |
Uses shared conversation normalization. |
plugins/multi-openai/src/models.ts |
Updates OpenAI default mappings. |
plugins/multi-openai/src/instructions.ts |
Updates compatibility instruction loading. |
plugins/multi-openai/src/instructions.md |
Replaces inherited workflow instructions. |
plugins/multi-openai/skills/login/SKILL.md |
Adds shell-specific login commands. |
plugins/multi-openai/.claude-plugin/plugin.json |
Bumps the OpenAI plugin version. |
plugins/multi-grok/src/usage.ts |
Clarifies native credential handling. |
plugins/multi-grok/src/usage-adapter.ts |
Adds Grok usage integration. |
plugins/multi-grok/src/request.ts |
Uses shared native prompt and history helpers. |
plugins/multi-grok/skills/login/SKILL.md |
Updates login guidance and shell commands. |
plugins/multi-grok/.claude-plugin/plugin.json |
Bumps the Grok plugin version. |
plugins/multi-cursor/src/usage-adapter.ts |
Adds Cursor usage integration. |
plugins/multi-cursor/src/session-record.ts |
Adds Cursor record migration and recovery. |
plugins/multi-cursor/src/request.ts |
Uses shared normalization and validation. |
plugins/multi-cursor/src/models.ts |
Updates Cursor picker defaults. |
plugins/multi-cursor/src/errors.ts |
Maps busy errors to deterministic refusals. |
plugins/multi-cursor/skills/login/SKILL.md |
Adds shell-specific login commands. |
plugins/multi-cursor/.claude-plugin/plugin.json |
Bumps the Cursor plugin version. |
plugins/multi-core/src/launcher.ts |
Wires usage readers and new defaults. |
plugins/multi-core/src/gateway/server.ts |
Uses shared harness contracts and usage adapters. |
plugins/multi-core/src/gateway/provider-usage.ts |
Exposes provider usage interfaces. |
plugins/multi-core/src/gateway/native-harness.ts |
Defines shared native harness boundaries. |
plugins/multi-core/src/gateway/mode-hook.ts |
Improves unsupported worker diagnostics. |
plugins/multi-core/src/gateway/harness-response.ts |
Builds bounded native responses. |
plugins/multi-core/src/gateway/harness-prompt.ts |
Normalizes native prompts. |
plugins/multi-core/src/gateway/harness-notices.ts |
Provides notices and history helpers. |
plugins/multi-core/src/gateway/harness-exchange.ts |
Coordinates in-flight exchanges and replay. |
plugins/multi-core/src/gateway/harness-completion.ts |
Persists responses before terminal events. |
plugins/multi-core/src/gateway/conversation.ts |
Centralizes message and media normalization. |
plugins/multi-core/skills/uninstall/SKILL.md |
Updates shell-specific uninstall guidance. |
plugins/multi-core/skills/status/SKILL.md |
Updates shell-specific status guidance. |
plugins/multi-core/skills/setup/SKILL.md |
Updates shell-specific setup guidance. |
plugins/multi-core/hooks/tests/workers.test.ts |
Updates worker model fixtures. |
plugins/multi-antigravity/src/usage-adapter.ts |
Adds Antigravity usage integration. |
plugins/multi-antigravity/src/request.ts |
Uses shared native prompt helpers. |
plugins/multi-antigravity/skills/connect/SKILL.md |
Adds shell-specific connection commands. |
plugins/multi-antigravity/.claude-plugin/plugin.json |
Bumps the Antigravity plugin version. |
package.json |
Bumps the release version and adds a live test script. |
package-lock.json |
Synchronizes package version metadata. |
docs/zen.md |
Updates Zen setup and model documentation. |
docs/usage.md |
Updates provider and receipt documentation. |
docs/platform-support.md |
Records verification scope and WSL2 status. |
docs/permissions.md |
Documents native admission and Workflow limitations. |
docs/openai.md |
Updates OpenAI models and instruction behavior. |
docs/installation.md |
Updates setup and launcher guidance. |
docs/grok.md |
Documents Grok usage and busy-request handling. |
docs/cursor.md |
Documents Cursor recovery and lifecycle behavior. |
docs/claude-mods.md |
Documents the Claude Mods integration boundary. |
docs/assets/README.md |
Clarifies illustration provenance. |
docs/antigravity.md |
Documents Antigravity busy-request handling. |
CONTRIBUTING.md |
Documents Mods test requirements. |
CLAUDE.md |
Adds Mods contribution guidance. |
CHANGELOG.md |
Adds the 0.2.1 release notes. |
ARCHITECTURE.md |
Describes shared harness architecture. |
AGENTS.md |
Updates architecture and verification guidance. |
.github/ISSUE_TEMPLATE/feature_request.yml |
Adds Grok to feature options. |
.github/ISSUE_TEMPLATE/bug_report.yml |
Adds Grok to bug options. |
.claude-plugin/plugin.json |
Bumps the root plugin version. |
.claude-plugin/marketplace.json |
Bumps marketplace plugin versions. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
387
to
388
| { ...body, stream: undefined }, | ||
| cursorPermissionPolicy(permissions).identity, |
Comment on lines
+2
to
5
| import { normalizeConversation, textContent } from '../../multi-core/src/gateway/conversation.ts'; | ||
| import { isDirectToolAvailable } from '../../multi-core/src/gateway/direct-tools.ts'; | ||
| import type { MessagesRequest } from '../../multi-core/src/gateway/messages.ts'; | ||
| import { estimateTextTokens } from '../../multi-core/src/gateway/tokens.ts'; |
Comment on lines
+73
to
+75
| await atomicJson( | ||
| path.join(args.stateDirectory, `${replay.key}.response.json`), | ||
| { response, events: replay.events }, |
Comment on lines
+105
to
+124
| async observe( | ||
| exchange: HarnessExchange<M>, | ||
| signal: AbortSignal, | ||
| emit?: Emit, | ||
| ): Promise<MessagesResponse> { | ||
| exchange.observers++; | ||
| const aborted = Promise.withResolvers<never>(); | ||
| void aborted.promise.catch(() => {}); | ||
| const cancel = () => aborted.reject(signal.reason); | ||
| signal.addEventListener('abort', cancel, { once: true }); | ||
| try { | ||
| if (emit) { | ||
| exchange.listeners.add(emit); | ||
| for (const event of exchange.events) { | ||
| emit(...event); | ||
| } | ||
| } | ||
| signal.throwIfAborted(); | ||
| return await Promise.race([exchange.result, aborted.promise]); | ||
| } finally { |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


Prepare 0.2.1 with shared native-harness lifecycle handling, preserved Cursor recovery, updated model defaults, and the outstanding quick issue fixes.
Cursor, Antigravity and Grok now share session leases, in-flight exchange handling, durable completion and response helpers. Concurrent conflicting prompts are refused before dispatch, and Cursor migrations retain native identities and pending run IDs. Provider authentication, permissions and native execution remain provider-owned.
The release also updates documentation and plugin versions, requires multi-core ~0.2.1 for each provider, improves unsupported Workflow worker diagnostics (#32), and explicitly records WSL2 as untested (#21). These issue references are partial follow-ups, not closure claims.
Validation: npm run check and npm run test:mod locally; required Linux, macOS and Windows CI must pass before merge. No new paid provider probes or WSL2 verification were performed.