@khalilgharbaoui/opencode-claude-code-plugin 0.36.4 → 0.36.5
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 +4 -3
- package/dist/index.js +97 -27
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/skills/claude-code-plugin/SKILL.md +2 -0
package/README.md
CHANGED
|
@@ -59,6 +59,7 @@ Nothing in the picker? [Troubleshooting](./docs/troubleshooting/symptoms.md) is
|
|
|
59
59
|
| **Subagents: your account, their model** | `forceModel`, `reasoningEffort` and `cacheTtl` in an agent file, inheriting the caller's account. `task_batch` runs several subagents at once. [Subagents](./docs/configuration/subagents.md) |
|
|
60
60
|
| **18 models, reasoning variants, fast mode** | Haiku 4.5 through Opus 5.5, Fable and Mythos, each with a `(N×)` list-price suffix, `low` to `max` effort variants, and a fallback chain for a model this account cannot run today. [Models](./docs/models.md) |
|
|
61
61
|
| **`/btw` and `/claude-code-doctor`** | Side questions on the live process, and a health report whose `bundle` form is redacted by allowlist so it is safe to paste into a public issue. [`/btw`](./docs/guides/btw.md) · [Doctor](./docs/guides/doctor.md) |
|
|
62
|
+
| **Ships its own setup skill** | Ask Claude to configure it. The bundled `claude-code-plugin` skill knows every option, env var, model id and troubleshooting rule, is staged into Claude Code on every spawn, and tests keep it in step with the code. [Skills](./docs/configuration/skills.md) |
|
|
62
63
|
| **Read-only preset, plan mode** | `"permissionPreset": "read-only"` holds at the CLI, the proxy and the permission layer at once. [Permissions](./docs/configuration/permissions.md) |
|
|
63
64
|
|
|
64
65
|
## How this compares
|
|
@@ -102,12 +103,12 @@ This README used to hold all of the above. Release notes and bookmarks point at
|
|
|
102
103
|
|
|
103
104
|
## Credits
|
|
104
105
|
|
|
105
|
-
This plugin absorbs work from its forks directly, cherry-picked with the original authorship preserved or reimplemented with the author named in the commit. The people behind the features you are using, and what each built, are on the [Credits](./docs/credits.md) page; `git log --author` on this repo shows the preserved authorship.
|
|
106
|
+
Made and maintained by [Khalil Gharbaoui (@khalilgharbaoui)](https://github.com/khalilgharbaoui). This plugin absorbs work from its forks directly, cherry-picked with the original authorship preserved or reimplemented with the author named in the commit. The people behind the features you are using, and what each built, are on the [Credits](./docs/credits.md) page; `git log --author` on this repo shows the preserved authorship.
|
|
106
107
|
|
|
107
|
-
Free and MIT-licensed. If the plugin saves you time, you can buy its maintainer a coffee:
|
|
108
|
+
Free and MIT-licensed. If the plugin saves you time, you can buy [its maintainer](https://github.com/khalilgharbaoui) a coffee:
|
|
108
109
|
|
|
109
110
|
<a href="https://www.buymeacoffee.com/khalilgharbaoui"><img src="site/public/buy-me-a-coffee.png" alt="Buy me a coffee" width="214" height="60"></a>
|
|
110
111
|
|
|
111
112
|
## License
|
|
112
113
|
|
|
113
|
-
MIT. See [LICENSE](./LICENSE). The first version was written by Émilien ([@unixfox](https://github.com/unixfox)); everything since by Khalil Gharbaoui and the people in [Credits](./docs/credits.md).
|
|
114
|
+
MIT. See [LICENSE](./LICENSE). The first version was written by Émilien ([@unixfox](https://github.com/unixfox)); everything since by [Khalil Gharbaoui](https://github.com/khalilgharbaoui) and the people in [Credits](./docs/credits.md).
|
package/dist/index.js
CHANGED
|
@@ -808,6 +808,13 @@ function formatSilentTurnNote(hadReasoning) {
|
|
|
808
808
|
const what = hadReasoning ? "Claude Code finished the turn after thinking but never wrote an answer" : "Claude Code finished the turn without writing anything or calling a tool";
|
|
809
809
|
return `
|
|
810
810
|
${SILENT_TURN_MARKER} ${what}, so there is no reply above. Nothing failed and nothing is pending: send the message again, or rephrase it.
|
|
811
|
+
`;
|
|
812
|
+
}
|
|
813
|
+
var UNATTENDED_REPLAY_MARKER = "\u258C **between turns:**";
|
|
814
|
+
function formatUnattendedReplayNote(dropped) {
|
|
815
|
+
const lost = dropped > 0 ? ` ${dropped} earlier line${dropped === 1 ? "" : "s"} were dropped.` : "";
|
|
816
|
+
return `${UNATTENDED_REPLAY_MARKER} The Claude Code CLI wrote this after the previous turn had already finished, so it is not an answer to the message above.${lost}
|
|
817
|
+
|
|
811
818
|
`;
|
|
812
819
|
}
|
|
813
820
|
var UNRECOGNIZED_MODEL_STDERR_MARKER = "[claude-code:unrecognized_model]";
|
|
@@ -7286,7 +7293,8 @@ var PLUGIN_NOTE_MARKERS = [
|
|
|
7286
7293
|
SILENT_TURN_MARKER,
|
|
7287
7294
|
FAILOVER_MARKER,
|
|
7288
7295
|
ACCOUNT_BLOCK_MARKER,
|
|
7289
|
-
MODEL_FALLBACK_MARKER
|
|
7296
|
+
MODEL_FALLBACK_MARKER,
|
|
7297
|
+
UNATTENDED_REPLAY_MARKER
|
|
7290
7298
|
];
|
|
7291
7299
|
function isPluginNote(part) {
|
|
7292
7300
|
if (!part || part.type !== "text" || typeof part.text !== "string") return false;
|
|
@@ -9688,6 +9696,8 @@ function createTurnState(init) {
|
|
|
9688
9696
|
toolCallMap: /* @__PURE__ */ new Map(),
|
|
9689
9697
|
skipResultForIds: /* @__PURE__ */ new Set(),
|
|
9690
9698
|
toolCallsById: /* @__PURE__ */ new Map(),
|
|
9699
|
+
toolCallEmittedIds: /* @__PURE__ */ new Set(),
|
|
9700
|
+
toolCallAnsweredIds: /* @__PURE__ */ new Set(),
|
|
9691
9701
|
resultMeta: {},
|
|
9692
9702
|
lastCallUsage: void 0,
|
|
9693
9703
|
resultFailure: void 0,
|
|
@@ -9704,6 +9714,23 @@ function createTurnState(init) {
|
|
|
9704
9714
|
};
|
|
9705
9715
|
return state;
|
|
9706
9716
|
}
|
|
9717
|
+
function cliToolCallInputJson(state, id) {
|
|
9718
|
+
for (const entry of state.toolCallMap.values()) {
|
|
9719
|
+
if (entry.id === id) return entry.inputJson || "{}";
|
|
9720
|
+
}
|
|
9721
|
+
return "{}";
|
|
9722
|
+
}
|
|
9723
|
+
function emitCliToolCall(state, id, name, inputJson, executed) {
|
|
9724
|
+
if (state.toolCallEmittedIds.has(id)) return;
|
|
9725
|
+
state.toolCallEmittedIds.add(id);
|
|
9726
|
+
state.controller.enqueue({
|
|
9727
|
+
type: "tool-call",
|
|
9728
|
+
toolCallId: id,
|
|
9729
|
+
toolName: name,
|
|
9730
|
+
input: inputJson,
|
|
9731
|
+
providerExecuted: executed
|
|
9732
|
+
});
|
|
9733
|
+
}
|
|
9707
9734
|
|
|
9708
9735
|
// src/turn-abort.ts
|
|
9709
9736
|
function watchTurnAbort(signal) {
|
|
@@ -10113,9 +10140,46 @@ function deliverPendingCompletions(state, force = false) {
|
|
|
10113
10140
|
armStartWatchdog(state);
|
|
10114
10141
|
return true;
|
|
10115
10142
|
}
|
|
10143
|
+
var CLI_RESULT_DEFERRED_OUTPUT = "Claude Code ran this tool itself and kept its output in its own context. This step ended on a tool call opencode has to run, so the output was not available to show here.";
|
|
10144
|
+
function closeDeferredCliToolResults(state) {
|
|
10145
|
+
const answer = (id, name, stage) => {
|
|
10146
|
+
emitCliToolCall(state, id, name, cliToolCallInputJson(state, id), true);
|
|
10147
|
+
state.controller.enqueue({
|
|
10148
|
+
type: "tool-result",
|
|
10149
|
+
toolCallId: id,
|
|
10150
|
+
toolName: name,
|
|
10151
|
+
result: {
|
|
10152
|
+
output: CLI_RESULT_DEFERRED_OUTPUT,
|
|
10153
|
+
title: name,
|
|
10154
|
+
metadata: {}
|
|
10155
|
+
},
|
|
10156
|
+
providerExecuted: true
|
|
10157
|
+
});
|
|
10158
|
+
state.toolCallsById.delete(id);
|
|
10159
|
+
state.toolCallAnsweredIds.add(id);
|
|
10160
|
+
log.info("closing a CLI-executed tool call whose result this step cannot wait for", {
|
|
10161
|
+
sessionKey: state.sessionKey,
|
|
10162
|
+
toolUseId: id,
|
|
10163
|
+
name,
|
|
10164
|
+
stage
|
|
10165
|
+
});
|
|
10166
|
+
};
|
|
10167
|
+
for (const [id, toolCall] of [...state.toolCallsById]) {
|
|
10168
|
+
if (state.skipResultForIds.has(id)) continue;
|
|
10169
|
+
answer(id, toolCall.name, "registered");
|
|
10170
|
+
}
|
|
10171
|
+
for (const entry of state.toolCallMap.values()) {
|
|
10172
|
+
if (!entry.started || !entry.mappedName) continue;
|
|
10173
|
+
if (state.skipResultForIds.has(entry.id)) continue;
|
|
10174
|
+
if (state.toolCallAnsweredIds.has(entry.id)) continue;
|
|
10175
|
+
if (state.toolCallEmittedIds.has(entry.id)) continue;
|
|
10176
|
+
answer(entry.id, entry.mappedName, "open-block");
|
|
10177
|
+
}
|
|
10178
|
+
}
|
|
10116
10179
|
function finishWithToolCalls(state, calls) {
|
|
10117
10180
|
if (state.controllerClosed) return;
|
|
10118
10181
|
if (calls.length === 0) return;
|
|
10182
|
+
closeDeferredCliToolResults(state);
|
|
10119
10183
|
const enqueueToolCall = (toolCallId, toolName, input) => {
|
|
10120
10184
|
state.controller.enqueue({
|
|
10121
10185
|
type: "tool-input-start",
|
|
@@ -10321,6 +10385,26 @@ var KNOWN_DELTA_TYPES = /* @__PURE__ */ new Set([
|
|
|
10321
10385
|
"signature_delta"
|
|
10322
10386
|
]);
|
|
10323
10387
|
var PROXY_RESULT_BOUNDARY_GRACE_MS = 250;
|
|
10388
|
+
function adoptOpenCliToolCall(state, ctx, id) {
|
|
10389
|
+
for (const entry of state.toolCallMap.values()) {
|
|
10390
|
+
if (entry.id !== id || !entry.started || !entry.mappedName) continue;
|
|
10391
|
+
let parsedInput = {};
|
|
10392
|
+
try {
|
|
10393
|
+
parsedInput = JSON.parse(entry.inputJson || "{}");
|
|
10394
|
+
} catch {
|
|
10395
|
+
}
|
|
10396
|
+
const { input: mappedInput, executed } = mapTool(entry.name, parsedInput, {
|
|
10397
|
+
webSearch: ctx.config.webSearch,
|
|
10398
|
+
sessionId: getClaudeSessionId(state.sessionKey),
|
|
10399
|
+
toolUseId: entry.id
|
|
10400
|
+
});
|
|
10401
|
+
const registration = { id: entry.id, name: entry.mappedName, input: parsedInput };
|
|
10402
|
+
state.toolCallsById.set(entry.id, registration);
|
|
10403
|
+
emitCliToolCall(state, entry.id, entry.mappedName, JSON.stringify(mappedInput), executed);
|
|
10404
|
+
return registration;
|
|
10405
|
+
}
|
|
10406
|
+
return void 0;
|
|
10407
|
+
}
|
|
10324
10408
|
function createLineHandler(state, ctx) {
|
|
10325
10409
|
return (line) => {
|
|
10326
10410
|
if (!line.trim()) return;
|
|
@@ -10449,6 +10533,7 @@ function createLineHandler(state, ctx) {
|
|
|
10449
10533
|
);
|
|
10450
10534
|
if (!skip) {
|
|
10451
10535
|
entry.started = true;
|
|
10536
|
+
entry.mappedName = mappedName;
|
|
10452
10537
|
state.controller.enqueue({
|
|
10453
10538
|
type: "tool-input-start",
|
|
10454
10539
|
id: block2.id,
|
|
@@ -10606,20 +10691,14 @@ ${plan}
|
|
|
10606
10691
|
sessionId: getClaudeSessionId(state.sessionKey),
|
|
10607
10692
|
toolUseId: tc.id
|
|
10608
10693
|
});
|
|
10609
|
-
if (!skip) {
|
|
10694
|
+
if (!skip && !state.toolCallAnsweredIds.has(tc.id)) {
|
|
10610
10695
|
state.toolCallsById.set(tc.id, {
|
|
10611
10696
|
id: tc.id,
|
|
10612
10697
|
name: mappedName,
|
|
10613
10698
|
input: parsedInput
|
|
10614
10699
|
});
|
|
10615
10700
|
if (!executed) state.skipResultForIds.add(tc.id);
|
|
10616
|
-
state.
|
|
10617
|
-
type: "tool-call",
|
|
10618
|
-
toolCallId: tc.id,
|
|
10619
|
-
toolName: mappedName,
|
|
10620
|
-
input: JSON.stringify(mappedInput),
|
|
10621
|
-
providerExecuted: executed
|
|
10622
|
-
});
|
|
10701
|
+
emitCliToolCall(state, tc.id, mappedName, JSON.stringify(mappedInput), executed);
|
|
10623
10702
|
}
|
|
10624
10703
|
log.info("tool call complete", {
|
|
10625
10704
|
name: tc.name,
|
|
@@ -10805,13 +10884,7 @@ ${plan}
|
|
|
10805
10884
|
toolName: mappedName,
|
|
10806
10885
|
providerExecuted: executed
|
|
10807
10886
|
});
|
|
10808
|
-
state.
|
|
10809
|
-
type: "tool-call",
|
|
10810
|
-
toolCallId: block2.id,
|
|
10811
|
-
toolName: mappedName,
|
|
10812
|
-
input: JSON.stringify(mappedInput),
|
|
10813
|
-
providerExecuted: executed
|
|
10814
|
-
});
|
|
10887
|
+
emitCliToolCall(state, block2.id, mappedName, JSON.stringify(mappedInput), executed);
|
|
10815
10888
|
}
|
|
10816
10889
|
log.info("tool_use from assistant message", {
|
|
10817
10890
|
name: block2.name,
|
|
@@ -10877,7 +10950,7 @@ ${plan}
|
|
|
10877
10950
|
noteToolActivity(state);
|
|
10878
10951
|
}
|
|
10879
10952
|
}
|
|
10880
|
-
const toolCall = state.toolCallsById.get(block2.tool_use_id);
|
|
10953
|
+
const toolCall = state.toolCallsById.get(block2.tool_use_id) ?? adoptOpenCliToolCall(state, ctx, block2.tool_use_id);
|
|
10881
10954
|
if (toolCall) {
|
|
10882
10955
|
const isError = block2.is_error === true;
|
|
10883
10956
|
state.controller.enqueue({
|
|
@@ -10899,6 +10972,7 @@ ${plan}
|
|
|
10899
10972
|
isError
|
|
10900
10973
|
});
|
|
10901
10974
|
state.toolCallsById.delete(block2.tool_use_id);
|
|
10975
|
+
state.toolCallAnsweredIds.add(block2.tool_use_id);
|
|
10902
10976
|
}
|
|
10903
10977
|
}
|
|
10904
10978
|
}
|
|
@@ -12561,16 +12635,12 @@ var ClaudeCodeLanguageModel = class {
|
|
|
12561
12635
|
});
|
|
12562
12636
|
let partialText = false;
|
|
12563
12637
|
{
|
|
12564
|
-
|
|
12565
|
-
|
|
12566
|
-
|
|
12567
|
-
|
|
12568
|
-
|
|
12569
|
-
|
|
12570
|
-
|
|
12571
|
-
`
|
|
12572
|
-
});
|
|
12573
|
-
}
|
|
12638
|
+
const replayId = state.startTextBlock();
|
|
12639
|
+
controller.enqueue({
|
|
12640
|
+
type: "text-delta",
|
|
12641
|
+
id: replayId,
|
|
12642
|
+
delta: formatUnattendedReplayNote(unattended.dropped)
|
|
12643
|
+
});
|
|
12574
12644
|
for (const line of unattended.lines) {
|
|
12575
12645
|
try {
|
|
12576
12646
|
const outer = JSON.parse(line);
|