@khalilgharbaoui/opencode-claude-code-plugin 0.6.2 → 0.7.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 +1 -1
- package/dist/index.d.ts +7 -1
- package/dist/index.js +24 -20
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -319,7 +319,7 @@ Set `permissionMode: "plan"` to forward `--permission-mode plan` to Claude. The
|
|
|
319
319
|
opencode has no native structured ask-question executor to proxy through (unlike `Bash`/`Task`), so the plugin handles `AskUserQuestion` specially:
|
|
320
320
|
|
|
321
321
|
1. **It renders the full question.** The tool's payload — every question, header, option label, and option description — is emitted as readable markdown into the assistant stream so the user actually sees the choices (same approach as `ExitPlanMode`).
|
|
322
|
-
2. **It is never auto-allowed at the CLI gate.** Allowing it would let the headless Claude CLI resolve its own question (no TTY → fabricated/empty answer) and proceed on a guess. `controlRequestBehaviorForTool` hard-denies `AskUserQuestion` and returns a message telling the model to wait for the operator's answer —
|
|
322
|
+
2. **It is never auto-allowed at the CLI gate.** Allowing it would let the headless Claude CLI resolve its own question (no TTY → fabricated/empty answer) and proceed on a guess. `controlRequestBehaviorForTool` hard-denies `AskUserQuestion` and returns a message telling the model to **stop and wait for the operator's answer** — end the turn, call no further tools, and never self-answer. (Before v0.7.0 this message also offered an "if the run is non-interactive, proceed with a reasonable guess" fallback. The model could not reliably tell interactive opencode from a headless run and routinely took it, so questions appeared to be skipped — [issue #8](https://github.com/khalilgharbaoui/opencode-claude-code-plugin/issues/8). For genuinely unattended runs, use the `controlRequestToolBehaviors` override below instead.)
|
|
323
323
|
|
|
324
324
|
This hard-deny sits **below** `controlRequestToolBehaviors` in precedence but **above** the global `controlRequestBehavior`. So:
|
|
325
325
|
|
package/dist/index.d.ts
CHANGED
|
@@ -542,9 +542,15 @@ interface ClaudeCodeProvider {
|
|
|
542
542
|
languageModel(modelId: string): LanguageModelV3;
|
|
543
543
|
}
|
|
544
544
|
declare function createClaudeCode(settings?: ClaudeCodeProviderSettings): ClaudeCodeProvider;
|
|
545
|
+
/**
|
|
546
|
+
* Build models in OpenCode's config schema format (flat properties like
|
|
547
|
+
* `temperature`, `reasoning`, `cost.cache_read`, `modalities`, etc.)
|
|
548
|
+
* so the config-path provider loader parses them correctly.
|
|
549
|
+
*/
|
|
550
|
+
declare function configModelsForProvider(providerModels: OpenCodeProvider["models"], providerID: string, modelSuffix?: string): Record<string, Record<string, unknown>>;
|
|
545
551
|
declare const _default: {
|
|
546
552
|
id: string;
|
|
547
553
|
server: OpenCodePlugin;
|
|
548
554
|
};
|
|
549
555
|
|
|
550
|
-
export { type ClaudeCodeConfig, ClaudeCodeLanguageModel, type ClaudeCodeProvider, type ClaudeCodeProviderSettings, type ClaudeStreamMessage, type OpenCodeHooks, type OpenCodeModel, type OpenCodePlugin, bridgeOpencodeMcp, createClaudeCode, _default as default, defaultModels };
|
|
556
|
+
export { type ClaudeCodeConfig, ClaudeCodeLanguageModel, type ClaudeCodeProvider, type ClaudeCodeProviderSettings, type ClaudeStreamMessage, type OpenCodeHooks, type OpenCodeModel, type OpenCodePlugin, bridgeOpencodeMcp, configModelsForProvider, createClaudeCode, _default as default, defaultModels };
|
package/dist/index.js
CHANGED
|
@@ -2018,6 +2018,11 @@ function isAskUserQuestionTool(name) {
|
|
|
2018
2018
|
const n = name.toLowerCase();
|
|
2019
2019
|
return n === "askuserquestion" || n === "ask_user_question";
|
|
2020
2020
|
}
|
|
2021
|
+
var ASK_USER_QUESTION_DENY_MESSAGE = "Your question and its options have already been presented to the operator verbatim. Stop now: end your turn without calling any more tools and without answering the question yourself. Wait for the operator's reply, which arrives as the next user message. Do not guess, assume, or proceed on their behalf.";
|
|
2022
|
+
function denyMessageForTool(toolName, configuredDenyMessage) {
|
|
2023
|
+
if (isAskUserQuestionTool(toolName)) return ASK_USER_QUESTION_DENY_MESSAGE;
|
|
2024
|
+
return configuredDenyMessage ?? `Denied by opencode-claude-code policy for tool ${toolName}`;
|
|
2025
|
+
}
|
|
2021
2026
|
function formatAskUserQuestion(input) {
|
|
2022
2027
|
const anyInput = input;
|
|
2023
2028
|
const questions = Array.isArray(anyInput?.questions) ? anyInput.questions : [];
|
|
@@ -2460,7 +2465,10 @@ var ClaudeCodeLanguageModel = class {
|
|
|
2460
2465
|
toolName
|
|
2461
2466
|
});
|
|
2462
2467
|
} else {
|
|
2463
|
-
const denyMessage =
|
|
2468
|
+
const denyMessage = denyMessageForTool(
|
|
2469
|
+
toolName,
|
|
2470
|
+
this.config.controlRequestDenyMessage
|
|
2471
|
+
);
|
|
2464
2472
|
this.writeControlResponse(proc, requestId, {
|
|
2465
2473
|
behavior: "deny",
|
|
2466
2474
|
message: denyMessage,
|
|
@@ -4559,22 +4567,6 @@ function cleanProviderOptions(options = {}) {
|
|
|
4559
4567
|
delete result.accounts;
|
|
4560
4568
|
return result;
|
|
4561
4569
|
}
|
|
4562
|
-
function mergeDefaultVariants(models = {}) {
|
|
4563
|
-
const result = { ...models };
|
|
4564
|
-
for (const [id, model] of Object.entries(defaultModels)) {
|
|
4565
|
-
if (!model.variants) continue;
|
|
4566
|
-
const existing = result[id] && typeof result[id] === "object" ? result[id] : {};
|
|
4567
|
-
const variants = existing.variants && typeof existing.variants === "object" ? existing.variants : {};
|
|
4568
|
-
result[id] = {
|
|
4569
|
-
...existing,
|
|
4570
|
-
variants: {
|
|
4571
|
-
...model.variants,
|
|
4572
|
-
...variants
|
|
4573
|
-
}
|
|
4574
|
-
};
|
|
4575
|
-
}
|
|
4576
|
-
return result;
|
|
4577
|
-
}
|
|
4578
4570
|
function defaultModelsForProvider(providerModels, providerID = PROVIDER_ID2, modelSuffix) {
|
|
4579
4571
|
const models = Object.fromEntries(
|
|
4580
4572
|
Object.entries(defaultModels).map(([id, model]) => {
|
|
@@ -4611,6 +4603,7 @@ function configModelsForProvider(providerModels, providerID, modelSuffix) {
|
|
|
4611
4603
|
for (const [id, model] of Object.entries(defaultModels)) {
|
|
4612
4604
|
const modelId = modelSuffix ? `${id}@${modelSuffix}` : id;
|
|
4613
4605
|
const existing = providerModels[id] ?? providerModels[modelId];
|
|
4606
|
+
const existingVariants = existing && typeof existing.variants === "object" ? existing.variants ?? {} : {};
|
|
4614
4607
|
const full = {
|
|
4615
4608
|
...model,
|
|
4616
4609
|
id: modelId,
|
|
@@ -4620,6 +4613,10 @@ function configModelsForProvider(providerModels, providerID, modelSuffix) {
|
|
|
4620
4613
|
id: modelId,
|
|
4621
4614
|
npm: existing?.api?.npm ?? model.api.npm,
|
|
4622
4615
|
url: existing?.api?.url ?? model.api.url
|
|
4616
|
+
},
|
|
4617
|
+
variants: {
|
|
4618
|
+
...model.variants ?? {},
|
|
4619
|
+
...existingVariants
|
|
4623
4620
|
}
|
|
4624
4621
|
};
|
|
4625
4622
|
models[modelId] = toConfigModel(full);
|
|
@@ -4648,8 +4645,10 @@ async function providerConfig(existing, providerID = PROVIDER_ID2, optionDefault
|
|
|
4648
4645
|
options: {
|
|
4649
4646
|
...mergedOptions,
|
|
4650
4647
|
...runtime
|
|
4651
|
-
}
|
|
4652
|
-
models:
|
|
4648
|
+
}
|
|
4649
|
+
// models is intentionally omitted: both callers overwrite it with
|
|
4650
|
+
// configModelsForProvider(), which emits the flat config schema
|
|
4651
|
+
// opencode's config-path loader parses (and merges user variants).
|
|
4653
4652
|
};
|
|
4654
4653
|
}
|
|
4655
4654
|
async function expandAccountProviders(config) {
|
|
@@ -4717,7 +4716,11 @@ var server = async (input) => {
|
|
|
4717
4716
|
const existing = config.provider[PROVIDER_ID2];
|
|
4718
4717
|
config.provider[PROVIDER_ID2] = {
|
|
4719
4718
|
...existing,
|
|
4720
|
-
...await providerConfig(existing)
|
|
4719
|
+
...await providerConfig(existing),
|
|
4720
|
+
models: configModelsForProvider(
|
|
4721
|
+
existing?.models ?? {},
|
|
4722
|
+
PROVIDER_ID2
|
|
4723
|
+
)
|
|
4721
4724
|
};
|
|
4722
4725
|
log.notice("registered claude-code provider", {
|
|
4723
4726
|
id: PROVIDER_ID2,
|
|
@@ -4768,6 +4771,7 @@ var index_default = {
|
|
|
4768
4771
|
export {
|
|
4769
4772
|
ClaudeCodeLanguageModel,
|
|
4770
4773
|
bridgeOpencodeMcp,
|
|
4774
|
+
configModelsForProvider,
|
|
4771
4775
|
createClaudeCode,
|
|
4772
4776
|
index_default as default,
|
|
4773
4777
|
defaultModels
|