@khalilgharbaoui/opencode-claude-code-plugin 0.31.1 → 0.33.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@khalilgharbaoui/opencode-claude-code-plugin",
3
- "version": "0.31.1",
3
+ "version": "0.33.0",
4
4
  "description": "Claude Code CLI provider plugin for opencode",
5
5
  "author": "Khalil Gharbaoui",
6
6
  "type": "module",
@@ -21,7 +21,7 @@
21
21
  "build": "tsup",
22
22
  "dev": "tsup --watch",
23
23
  "typecheck": "tsc --noEmit",
24
- "test": "OPENCODE_CLAUDE_CODE_LOG_FILE=0 tsx --test test-bridge.ts test-broker.ts test-proxy-mcp.ts test-proxy-task.ts test-auto-continue.ts test-has-new-user-content.ts test-get-claude-user-message.ts test-logger.ts test-cli-args.ts test-permission-presets.ts test-session-manager.ts test-compaction-model.ts test-tool-mapping.ts test-cwd-resolution.ts test-todo-ledger.ts test-session-affinity.ts test-config-models.ts test-ask-user-question.ts test-claude-session-wrapper.ts test-spawn-env.ts test-respawn.ts test-startup-diagnostics.ts test-subagent-hint.ts test-exit-plan-mode-question.ts test-compress-tool.ts test-agent-models.ts test-side-question.ts test-btw-command.ts test-effort-sessions.ts test-tool-block-index.ts test-context-usage.ts test-skill-bridge.ts test-turn-stats.ts test-cli-events.ts test-cli-events-stream.ts test-result-fallback.ts test-doctor.ts test-configure-skill.ts test-unattended-replay.ts test-process-lifecycle.ts test-account-failover.ts test-host-tools.ts test-v2-entrypoint.ts test-v2-client.ts test-tmp-dir.ts test-cleanup-stale.ts test-account-wrapper.ts test-runtime-status-sessions.ts test-index-hooks.ts test-silent-turn.ts test-mcp-tool-result-name.ts test-model-fallback.ts test-do-generate.ts"
24
+ "test": "OPENCODE_CLAUDE_CODE_LOG_FILE=0 tsx --test test-bridge.ts test-broker.ts test-proxy-mcp.ts test-proxy-task.ts test-auto-continue.ts test-has-new-user-content.ts test-get-claude-user-message.ts test-logger.ts test-cli-args.ts test-permission-presets.ts test-session-manager.ts test-compaction-model.ts test-tool-mapping.ts test-cwd-resolution.ts test-todo-ledger.ts test-session-affinity.ts test-config-models.ts test-ask-user-question.ts test-claude-session-wrapper.ts test-spawn-env.ts test-respawn.ts test-startup-diagnostics.ts test-subagent-hint.ts test-exit-plan-mode-question.ts test-compress-tool.ts test-agent-models.ts test-side-question.ts test-btw-command.ts test-effort-sessions.ts test-tool-block-index.ts test-context-usage.ts test-skill-bridge.ts test-turn-stats.ts test-cli-events.ts test-cli-events-stream.ts test-result-fallback.ts test-doctor.ts test-configure-skill.ts test-unattended-replay.ts test-process-lifecycle.ts test-account-failover.ts test-host-tools.ts test-v2-entrypoint.ts test-v2-client.ts test-tmp-dir.ts test-cleanup-stale.ts test-account-wrapper.ts test-runtime-status-sessions.ts test-index-hooks.ts test-silent-turn.ts test-mcp-tool-result-name.ts test-model-fallback.ts test-do-generate.ts test-interactive-usage.ts test-background-subagents.ts test-interactive-result.ts"
25
25
  },
26
26
  "dependencies": {
27
27
  "@ai-sdk/provider": "^3.0.8",
@@ -457,11 +457,63 @@ Names below become `mcp__opencode_proxy__<name>`; input config is case-insensiti
457
457
  | `edit` | `"Edit"`, default; replaces CLI Edit. |
458
458
  | `write` | `"Write"`, default; replaces CLI Write. |
459
459
  | `webfetch` | `"WebFetch"`, default; replaces CLI WebFetch. |
460
- | `task` | `"Task"`, default; disables CLI Agent and dispatches opencode subagents under its permissions. No proxy deadline by default; a positive `proxyToolTimeoutMs` entry adds one. |
460
+ | `task` | `"Task"`, default; disables CLI Agent and dispatches opencode subagents under its permissions. No proxy deadline by default; a positive `proxyToolTimeoutMs` entry adds one. Takes `background: true` only on a host that runs background subagents (see below). |
461
461
  | `task_batch` | Included with Task; one MCP call fans out two or more independent task inputs concurrently. Separate task calls were measured serial on CLI 2.1.258. |
462
+ | `task_status` | Included with Task, and only on a host that runs background subagents. Reads a background subagent's state by `task_id` and collects its result. A recovery path for a completion notification that never arrived, not a progress poll; a result is handed over once. Answered in-process (opencode has no such tool) and refuses any session that is not this conversation's subagent. Not nameable in `proxyTools`. |
463
+ | `task_cancel` | Included with Task, same host gate as `task_status`. Aborts a background subagent's child session; a cancelled subagent sends no completion notification. |
462
464
  | `question` | `"Question"`, opt-in; replaces AskUserQuestion only if the live opencode registry has question. Round-trip verified on plugin 0.18.0 / CLI 2.1.258 / opencode 1.18.29, headless and as a real TUI form, with no `permission` block; grant `permission.question` only if a subagent's form is refused. Opt-in because it disables Claude's own AskUserQuestion. |
463
465
  | `compress` | `"Compress"`, opt-in; in-process summary/reset interceptor, no opencode permission prompt and no built-in replacement. Discards prior CLI detail on a later eligible turn, retaining the summary, not the full transcript. Keep off unless explicitly requested. Reset round-trip verified live on CLI 2.1.263 / opencode 1.18.31. Not the same tool as a forwarded opencode `compress` (see `proxyOpencodeTools`): this one resets the Claude session, that one compresses opencode's transcript. Enabling both leaves this one holding the name. |
464
466
 
467
+ ### Background subagents (fire-and-collect)
468
+
469
+ Off unless the **opencode process** has `OPENCODE_EXPERIMENTAL_BACKGROUND_SUBAGENTS=true`
470
+ (or `OPENCODE_EXPERIMENTAL=true`) in its environment on opencode 1.x; unconditional on
471
+ opencode 2.x. It is opencode's feature, not this plugin's: the plugin only surfaces it.
472
+ There is no provider option, and nothing in `opencode.json` can turn it on, because the
473
+ flag is read by opencode itself at startup.
474
+
475
+ ```sh
476
+ OPENCODE_EXPERIMENTAL_BACKGROUND_SUBAGENTS=true opencode
477
+ ```
478
+
479
+ With it set, `task` takes `background: true` and returns at once with
480
+ `<task id="ses_..." state="running">` instead of the subagent's answer. The model keeps
481
+ working and ends its turn; when the child finishes, opencode prompts the same
482
+ conversation with `<task ... state="completed"><task_result>...</task_result></task>` as
483
+ a new message. Delivery is automatic, so polling is wrong and the tool descriptions say
484
+ so. `task_status` and `task_cancel` join the tool list, keyed on the `id` from that
485
+ envelope (the child's opencode session id).
486
+
487
+ opencode 2 uses different envelopes and the plugin's tool descriptions follow the host:
488
+ there a background dispatch answers in prose,
489
+ `The subagent is working in the background (sessionID: ses_...)`, and the completion
490
+ arrives as `<subagent sessionID="..." state="completed" description="...">`. The
491
+ `sessionID` is the `task_id`. Both extra tools work on both majors (on opencode 2 over
492
+ `session.context` and `session.interrupt`, the session routes a plugin is given there);
493
+ verified live on 2.0.16.
494
+
495
+ Without it, opencode rejects a `background: true` call outright
496
+ (`Background subagents require OPENCODE_EXPERIMENTAL_BACKGROUND_SUBAGENTS=true`), losing
497
+ the dispatch, so the plugin strips `background` from the `task` and `task_batch` schemas
498
+ on such a host and registers neither extra tool. Which way it went is in `plugin.log`:
499
+
500
+ ```
501
+ background subagent gate {"supported":false,"registryResolved":true,"hostApi":"v1","note":"`background` stripped ..."}
502
+ ```
503
+
504
+ Troubleshooting: `background` missing from the tool schema, or a refusal naming the env
505
+ var, means the flag is not set on the opencode process (setting it in a shell after
506
+ opencode started does nothing, and a plugin upgrade cannot change it). A `task_status`
507
+ that answers `not a subagent of this conversation` means the id came from a different
508
+ conversation.
509
+
510
+ `/claude-code-doctor` has a **Background subagents** section answering the same question
511
+ without reading the log: whether `background` was offered and the two tools registered,
512
+ the opencode major, what decided it (the live `task` schema, a registry that did not
513
+ answer, or opencode 2 offering it unconditionally), and the background tasks this
514
+ process has collected or cancelled. The gate is read while a turn plans its proxy tools,
515
+ so a fresh process reports `Not read yet this process` until one message has been sent.
516
+
465
517
  A proxied call is held open until an event ends it, and the plugin listens to the
466
518
  `claude` process, the stream and the control protocol for those events rather than
467
519
  inferring failure from elapsed time: opencode's result resolves the call; an abort
@@ -675,6 +727,14 @@ warned about content that did not load. Read it whenever bridged skills are miss
675
727
  `opencode-skills@...` row is the skill bridge itself, which is a plugin bug to report,
676
728
  not something to fix in the user's config.
677
729
 
730
+ A **Background subagents** section is always printed: whether `background` was offered
731
+ to Claude and `task_status` / `task_cancel` registered, the opencode major, what decided
732
+ it, and the background tasks this process collected or cancelled. It reads
733
+ `Not read yet this process` until a turn has planned its proxy tools, which is not the
734
+ same as "no": on a fresh process, send a message and run it again before concluding
735
+ anything. Only a 1.x host that said no is told about
736
+ `OPENCODE_EXPERIMENTAL_BACKGROUND_SUBAGENTS`.
737
+
678
738
  `/claude-code-doctor usage` adds a **Plan usage** section: the CLI's own `/cost` answer
679
739
  (subscription vs API key, 5-hour and 7-day window use, reset times, what is driving
680
740
  them). Measured free on 2.1.280 (`num_turns: 0`, `$0`, no API call), so suggest it for
@@ -749,6 +809,9 @@ Prefer the doctor: it needs no logging change and no restart.
749
809
  | Claude "forgot" the earlier part of a long conversation | Claude Code compacted its own context | Look for the `▌ **context compacted:**` note in the transcript |
750
810
  | Claude forgot the whole conversation at once | Claude Code cleared it (`/clear` sent as a message, or a plan-mode exit that clears context) | Look for the `▌ **claude code reset:**` note. The plugin does not replay history there on purpose; a new opencode session gets a clean slate |
751
811
  | Wanting the per-turn cost in the chat | Not shown by default | Set `turnStats: true` and restart opencode |
812
+ | On the interactive transport, every turn ends with a `▌ **claude code error:**` note naming `end_turn` (or `stop_sequence` / `max_tokens`), and `turnStats` never prints | Plugin older than this fix put the stop reason in the synthesized `result`'s `subtype`, and any non-`success` subtype finishes the turn as an error, which also suppresses the stats footer | Upgrade and relaunch. A turn that reaches a terminal stop reason now synthesizes the shape a headless turn emits (`subtype: "success"`, the stop reason in a top-level `stop_reason`), so it finishes as an ordinary reply. A turn that reaches NO terminal stop reason is still an error on purpose, so truncation stays visible |
813
+ | On the interactive transport with a working directory under `/tmp` (or any symlinked path), the turn hangs until the 30-minute turn timeout and then reports no terminal stop reason | Plugin older than this fix named the transcript directory from `path.resolve`, which does not follow symlinks, so it tailed a file Claude Code never writes. On macOS `/tmp` is a symlink to `/private/tmp` | Upgrade and relaunch. The directory is now named from the cwd's resolved real path, which is what the CLI uses (`/tmp/scratch` is `~/.claude/projects/-private-tmp-scratch`). Check the `jsonlPath` in the `prepared interactive claude session` log line against the directory that actually exists under `<CLAUDE_CONFIG_DIR>/projects/` |
814
+ | On the interactive transport, a turn's output tokens look about double, and `turnStats` shows one call's input where the turn used many | Plugin older than this fix summed the session transcript's usage per RECORD, and the JSONL writes one record per content block with the call's usage repeated on each | Upgrade and relaunch. Counting is now once per API call: a four-tool turn that reported 1,306 output tokens reports its real 653, and the stats line carries the turn's totals as it does headlessly. Headless turns were never affected by this one |
752
815
  | opencode auto-compacts a Claude session far below the model's window, often several times in a row after tool-heavy turns | Plugin older than this fix reported the CLI's turn-summed usage (every API call's cache reads added up) as the context size | Upgrade and relaunch. opencode's per-message tokens are now the last call's context, so its cost figure for a multi-call turn is lower than the real one; the real cost is in `turnStats` and `providerMetadata["claude-code"].costUsd` |
753
816
  | Turn ends with an error naming an exit code or signal and a stderr tail | The `claude` child died mid-turn without emitting its terminal `result` | Read the quoted stderr; that is the CLI's own reason. Older builds reported this as a normal stop, so a truncated answer looked finished |
754
817
  | An answer is cut off with no error, in a window with many open chats | Plugin older than this fix: LRU eviction could kill a process mid-turn | Upgrade. Eviction now takes the oldest idle process and skips the round when all 8 are busy; the 30-minute idle timer spares a busy worker too |