@khalilgharbaoui/opencode-claude-code-plugin 0.26.2 → 0.27.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/README.md +31 -4
- package/dist/index.d.ts +50 -9
- package/dist/index.js +398 -106
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/skills/claude-code-plugin/SKILL.md +36 -11
package/README.md
CHANGED
|
@@ -250,6 +250,7 @@ What a pick does, in full:
|
|
|
250
250
|
- **The conversation is replayed, not resumed.** Claude transcripts live under each account's own `CLAUDE_CONFIG_DIR`, so `--resume` cannot cross accounts. The plugin starts a fresh Claude session on the target and replays the thread from opencode's history, then tells it to carry on. That costs input tokens on the new account, and anything the CLI held but opencode did not is gone.
|
|
251
251
|
- **Per-profile MCP servers do not come along.** A server configured only in the limited account's Claude profile is simply absent on the target.
|
|
252
252
|
- **`stop`, dismissing the form, or any answer that is not one of the offered accounts** ends the turn exactly the way the rate-limit error ends it today.
|
|
253
|
+
- **An account that cannot serve at all gets the same form.** When Claude Code reports that an account's login expired (`authentication_failed`), or that it is on hold, unverified or has a billing problem, the plugin writes a note naming the account and what to do, and offers the switch if another account is configured. For an expired login the note gives the exact command, for example `CLAUDE_CONFIG_DIR=~/.claude-work claude auth login`. The switch lasts until opencode restarts, so restart after logging in again to move back. With a single account you get the note alone.
|
|
253
254
|
|
|
254
255
|
Only two things open the form: a `rate_limit_event` the CLI marked `rejected`, and the two known account-limit error texts (`Third-party apps now draw from your extra usage…`, `You've hit your individual spend limit`). A generic 4xx, a timeout or a bad flag never does, deliberately: a transient failure must not quietly move where your usage is billed.
|
|
255
256
|
|
|
@@ -365,7 +366,8 @@ model: claude-code-work/claude-opus-5@work
|
|
|
365
366
|
| `compactionModel` | string | `"claude-haiku-4-5"` | Model used when opencode invokes `/compact`. Override per-process via the `CLAUDE_CODE_COMPACTION_MODEL` env var (env wins over config). See [Compaction](#compaction). |
|
|
366
367
|
| `ignoreAnthropicApiKey` | boolean | `false` | Strip `ANTHROPIC_API_KEY` / `ANTHROPIC_AUTH_TOKEN` from every spawned `claude` process so it authenticates with your logged-in subscription instead of pay-as-you-go API billing. The plugin warns once at startup whenever an API key is detected, regardless of this setting. See [Billing](#billing). |
|
|
367
368
|
| `idleProcessTimeoutMs` | number | – | Kill a retained headless Claude worker after this many idle milliseconds following a completed turn. The timer starts when a turn finishes, a new turn cancels it, a worker that is mid-turn when it fires is left alone and re-timed, and the session id is preserved for `--resume`. Values above Node's maximum timer delay (`2147483647`) are ignored. Omit or set `0` to retain workers until LRU eviction (16 processes). Interactive transport is excluded. Contributed by [@bernardofortes](https://github.com/bernardofortes). |
|
|
368
|
-
| `bridgeOpencodeSkills` | boolean | `false` | Expose your opencode skills to Claude's native `Skill` tool. Off by default because every bridged skill is also in the system prompt opencode forwards, so a large set is paid for twice per turn; the bundled configuration skill is staged either way. See [Skill bridge](#skill-bridge). Written by [@broskees](https://github.com/broskees). |
|
|
369
|
+
| `bridgeOpencodeSkills` | boolean | `false` | Expose your opencode skills to Claude's native `Skill` tool, from every root opencode itself reads. Off by default because every bridged skill is also in the system prompt opencode forwards, so a large set is paid for twice per turn; the bundled configuration skill is staged either way. See [Skill bridge](#skill-bridge). Written by [@broskees](https://github.com/broskees). |
|
|
370
|
+
| `bridgeSkipNativeSkills` | boolean | `true` | Leave a skill unbridged when the Claude session already loads it from `$CLAUDE_CONFIG_DIR/skills`, the project's `.claude/skills`, or an installed plugin, so one skill does not reach the model twice. Matched by resolved path, by identical `SKILL.md`, or by name. `false` bridges everything and reinstates the duplicates. See [Skills Claude already has](#skills-claude-already-has). |
|
|
369
371
|
| `logging` | object | all defaults | The plugin's own logger, four independent fields: `file` (boolean, default `false`), `dir` (string, default `~/.local/share/opencode-claude-code/`), `mode` (`"silent"` \| `"debug"`, default `"silent"`) and `level` (`"debug"` \| `"info"` \| `"notice"` \| `"warn"` \| `"error"`, default `"info"`). Goes under `provider.claude-code.options` like every other row here. See [Logging](#logging). |
|
|
370
372
|
| `turnStats` | boolean | `false` | Append a one-line cost / duration / cache footer to each finished turn. See [Per-turn stats](#per-turn-stats). |
|
|
371
373
|
| `interactive` | boolean | `false` | **Experimental.** Drive the interactive `claude` TUI (subscription billing) instead of headless `--print`. Requires opencode running under Bun with PTY support; silently falls back to headless otherwise. The tool proxy, `permissionMode` and `/btw` are all unavailable on it, so read [What it does not support](#what-it-does-not-support) before enabling. Env: `CLAUDE_CODE_INTERACTIVE_TRANSPORT=1`. |
|
|
@@ -777,6 +779,7 @@ Four Claude Code stream events used to reach nothing but a debug log:
|
|
|
777
779
|
|
|
778
780
|
- **A rate-limit rejection.** When the CLI reports `status: "rejected"` (or a rejected extra-usage state), the turn now carries a `▌ **rate limit:**` line naming the window, the reason extra usage is unavailable, when it resets, and the four things that can be done about it. Warned once per identity per process. See [Billing](#billing-change-june-15-2026-agent-sdk-credit).
|
|
779
781
|
- **A context compaction Claude Code did on its own.** A `▌ **context compacted:**` note says so, with the before and after token counts, so an answer that suddenly forgets the start of the conversation has a visible cause.
|
|
782
|
+
- **A conversation Claude Code cleared.** Sending `/clear` as a message, or a plan-mode exit that clears context, makes Claude Code start a fresh conversation while opencode still shows the old messages. A `▌ **claude code reset:**` note says so. The plugin deliberately does not replay the earlier messages, since that would undo the clear. Start a new opencode session if you want the two to match.
|
|
780
783
|
- **A `result` whose subtype is not `success`** (`error_max_turns`, `error_during_execution`, …). The subtype is named in the transcript and the turn finishes as an error instead of an ordinary reply.
|
|
781
784
|
- **A CLI-executed tool that failed.** Its result is forwarded with the AI SDK's error flag, so opencode renders the row as failed rather than as a success whose output happens to be an error message.
|
|
782
785
|
|
|
@@ -798,7 +801,7 @@ No separate skill installation or copying is needed. It ships with each package
|
|
|
798
801
|
|
|
799
802
|
## Skill bridge
|
|
800
803
|
|
|
801
|
-
opencode and Claude Code use the same on-disk skill format, a `<name>/SKILL.md` whose frontmatter carries `name` and `description`, but they read from
|
|
804
|
+
opencode and Claude Code use the same on-disk skill format, a `<name>/SKILL.md` whose frontmatter carries `name` and `description`, but they read from overlapping, not identical, directories. opencode looks in `.opencode/skills/`, `~/.config/opencode/skills/`, `~/.agents/skills/` and more; the Claude CLI looks in `~/.claude/skills/`, the project's `.claude/skills/` and its own plugins. Where they differ, opencode advertises a skill in the system prompt it forwards, the model calls `Skill("browser-automation")`, and Claude answers `Unknown skill`. Where they overlap, the same skill reaches one session twice.
|
|
802
805
|
|
|
803
806
|
By default the plugin discovers your opencode skills, stages a throwaway Claude Code plugin directory that links them, and passes it as `claude --plugin-dir`. They register natively, prefixed with the plugin name:
|
|
804
807
|
|
|
@@ -809,9 +812,33 @@ opencode-skills:rtk
|
|
|
809
812
|
|
|
810
813
|
Claude can invoke them with the Skill tool or as `/opencode-skills:<name>`. `--plugin-dir` is scoped to the spawned session, so nothing is written into your `~/.claude`.
|
|
811
814
|
|
|
812
|
-
Discovery
|
|
815
|
+
Discovery covers every root opencode itself reads, first match wins:
|
|
813
816
|
|
|
814
|
-
|
|
817
|
+
1. Walking up from the working directory: `.opencode/skills/`, `.claude/skills/`, `.agents/skills/` at each level.
|
|
818
|
+
2. `~/.opencode/skills/`.
|
|
819
|
+
3. `$OPENCODE_CONFIG_DIR/skills/` and `.../skill/`.
|
|
820
|
+
4. `~/.config/opencode/skills/` and `.../skill/` (or `$XDG_CONFIG_HOME`).
|
|
821
|
+
5. `~/.claude/skills/` and `~/.agents/skills/`.
|
|
822
|
+
|
|
823
|
+
A project skill shadows a global one of the same name, and an opencode-managed copy shadows an external one. Step 5 is opencode's own "external" scan and honours its `OPENCODE_DISABLE_EXTERNAL_SKILLS` and `OPENCODE_DISABLE_CLAUDE_CODE_SKILLS` variables. A skill is known by the `name:` its `SKILL.md` frontmatter declares, falling back to the directory name, which is what opencode advertises. If the skill set is unchanged the staged directory is reused between spawns.
|
|
824
|
+
|
|
825
|
+
### Skills Claude already has
|
|
826
|
+
|
|
827
|
+
Those roots overlap Claude Code's own, which reads `$CLAUDE_CONFIG_DIR/skills/` (`~/.claude/skills/` by default), the project's `.claude/skills/`, and the `skills/` folder of every installed plugin. Without care one skill reaches a single session twice, costing prompt tokens on every turn and leaving it ambiguous which copy answers.
|
|
828
|
+
|
|
829
|
+
So `bridgeSkipNativeSkills` (**on by default**) leaves a skill unbridged when Claude already loads it. A skill counts as already loaded when:
|
|
830
|
+
|
|
831
|
+
- it is literally the same directory, symlinks resolved;
|
|
832
|
+
- its `SKILL.md` is byte-identical to a native one, wherever that one lives (this is the case for a skill installed as a Claude plugin *and* symlinked into `~/.agents/skills`);
|
|
833
|
+
- a **different** skill of the same name is registered under user or project scope. Plugin skills are namespaced `<plugin>:<name>` and so never take a bridged name, only duplicate its content.
|
|
834
|
+
|
|
835
|
+
Only that last case changes which copy answers `Skill("<name>")`, so it is logged at WARN naming both paths; the others are logged at INFO. Set `bridgeSkipNativeSkills: false` to bridge everything regardless and get the duplicates back.
|
|
836
|
+
|
|
837
|
+
One limitation worth knowing: the plugin scan reads `installed_plugins.json` and does not check whether that plugin is actually enabled, so a skill from a disabled plugin can be treated as native. If a skill disappears, grep `plugin.log` for `skills claude code already loads`: one line names both paths and the reason.
|
|
838
|
+
|
|
839
|
+
### Enabling it
|
|
840
|
+
|
|
841
|
+
The bridge itself is **off by default**: every bridged skill's name and description is also in the system prompt opencode already forwards, so a large skill set is paid for twice on every turn. Set `bridgeOpencodeSkills: true` when the model tries `Skill("<name>")` for a skill opencode advertises and gets `Unknown skill`; the bundled configuration skill is staged either way. When on, the bridge applies to the headless, interactive and direct `doGenerate` spawns alike, never to compaction, and it is skipped on a Claude CLI without `--plugin-dir` (the plugin probes `claude --help` and logs a notice).
|
|
815
842
|
|
|
816
843
|
This bridge was written by [@broskees](https://github.com/broskees) (Joseph Roberts) on his fork and absorbed here with credit; see [Credits](#credits).
|
|
817
844
|
|
package/dist/index.d.ts
CHANGED
|
@@ -407,6 +407,8 @@ interface ClaudeCodeConfig {
|
|
|
407
407
|
idleProcessTimeoutMs?: number;
|
|
408
408
|
/** Stage opencode skills as a `--plugin-dir` so Claude's Skill tool can run them. */
|
|
409
409
|
bridgeOpencodeSkills?: boolean;
|
|
410
|
+
/** Leave out the skills the Claude session already loads natively. Default true. */
|
|
411
|
+
bridgeSkipNativeSkills?: boolean;
|
|
410
412
|
/** Append a one-line cost / duration / cache footer to each finished turn. */
|
|
411
413
|
turnStats?: boolean;
|
|
412
414
|
logging?: LoggingConfig;
|
|
@@ -662,17 +664,41 @@ interface ClaudeCodeProviderSettings {
|
|
|
662
664
|
*/
|
|
663
665
|
idleProcessTimeoutMs?: number;
|
|
664
666
|
/**
|
|
665
|
-
* Expose your opencode skills
|
|
666
|
-
*
|
|
667
|
-
*
|
|
668
|
-
*
|
|
669
|
-
*
|
|
670
|
-
*
|
|
671
|
-
*
|
|
672
|
-
*
|
|
673
|
-
*
|
|
667
|
+
* Expose your opencode skills to Claude Code's native Skill tool by staging
|
|
668
|
+
* them as a session-scoped `--plugin-dir`, so a `Skill("<name>")` call for a
|
|
669
|
+
* skill opencode advertises does not fail with `Unknown skill`. Covers every
|
|
670
|
+
* root opencode itself reads: project `.opencode/`, `.claude/` and `.agents/`
|
|
671
|
+
* walking up from the workspace, the opencode config dirs, and the global
|
|
672
|
+
* `~/.claude/skills` and `~/.agents/skills` (those last two behind the same
|
|
673
|
+
* `OPENCODE_DISABLE_EXTERNAL_SKILLS` / `OPENCODE_DISABLE_CLAUDE_CODE_SKILLS`
|
|
674
|
+
* switches opencode honours).
|
|
675
|
+
*
|
|
676
|
+
* Off by default: every bridged skill is also listed in the system prompt
|
|
677
|
+
* opencode forwards, so a large skill set costs prompt tokens twice per turn.
|
|
678
|
+
* When on it applies to the headless, interactive and direct `doGenerate`
|
|
679
|
+
* spawns alike; compaction never loads it, and the bundled configuration
|
|
680
|
+
* skill is staged either way. No-op on CLIs without `--plugin-dir`.
|
|
674
681
|
*/
|
|
675
682
|
bridgeOpencodeSkills?: boolean;
|
|
683
|
+
/**
|
|
684
|
+
* Leave a skill unbridged when the Claude Code session already loads it:
|
|
685
|
+
* from `<CLAUDE_CONFIG_DIR>/skills` (`~/.claude/skills` by default), from the
|
|
686
|
+
* project's own `.claude/skills`, or from an installed plugin's `skills/`.
|
|
687
|
+
* On by default, because those roots overlap opencode's and the duplicate
|
|
688
|
+
* costs prompt tokens on every turn for nothing.
|
|
689
|
+
*
|
|
690
|
+
* A skill is treated as already loaded when it is literally the same
|
|
691
|
+
* directory (symlinks resolved), when its SKILL.md is byte-identical to a
|
|
692
|
+
* native one, or when a *different* skill of the same name is registered
|
|
693
|
+
* under user or project scope. That last case is the only one that changes
|
|
694
|
+
* behaviour, because `Skill("<name>")` then answers from Claude's copy
|
|
695
|
+
* rather than opencode's, so it is logged at WARN naming both paths. Plugin
|
|
696
|
+
* skills are namespaced `<plugin>:<name>` and so only ever match by content.
|
|
697
|
+
*
|
|
698
|
+
* Set `false` to bridge everything regardless, which restores the pre-0.25
|
|
699
|
+
* behaviour of advertising a shared skill twice.
|
|
700
|
+
*/
|
|
701
|
+
bridgeSkipNativeSkills?: boolean;
|
|
676
702
|
/**
|
|
677
703
|
* Append one compact line to the end of every finished (non-compaction,
|
|
678
704
|
* non-error) turn with what that turn cost: dollars, wall duration, how many
|
|
@@ -804,6 +830,14 @@ interface ClaudeStreamMessage {
|
|
|
804
830
|
agent_id?: string;
|
|
805
831
|
description?: string;
|
|
806
832
|
};
|
|
833
|
+
/**
|
|
834
|
+
* On an `assistant` message the CLI synthesised to report a failure: the
|
|
835
|
+
* kind of failure (`authentication_failed`, `billing_error`, ...). Read by
|
|
836
|
+
* `accountBlockKind`; schema confirmed on Claude Code 2.1.280.
|
|
837
|
+
*/
|
|
838
|
+
error?: string;
|
|
839
|
+
/** On a `conversation_reset`: the conversation Claude Code started. */
|
|
840
|
+
new_conversation_id?: string;
|
|
807
841
|
message?: {
|
|
808
842
|
role?: string;
|
|
809
843
|
model?: string;
|
|
@@ -987,6 +1021,13 @@ declare class ClaudeCodeLanguageModel implements LanguageModelV3 {
|
|
|
987
1021
|
* spawn block resolves anything: `userMsg` is built well ahead of it.
|
|
988
1022
|
*/
|
|
989
1023
|
private stripContextRemindersEnabled;
|
|
1024
|
+
/**
|
|
1025
|
+
* Arguments the skill bridge needs beyond `cwd` / `cliPath`: which
|
|
1026
|
+
* `CLAUDE_CONFIG_DIR` this spawn reads its native skills from, and whether
|
|
1027
|
+
* to drop the ones it already loads. A failover moves the spawn to another
|
|
1028
|
+
* account, and therefore to that account's config dir.
|
|
1029
|
+
*/
|
|
1030
|
+
private skillBridgeSpawn;
|
|
990
1031
|
/** Share one lazy registry request within a turn without making it stale. */
|
|
991
1032
|
private createLiveToolInfoLoader;
|
|
992
1033
|
/**
|