@khalilgharbaoui/opencode-claude-code-plugin 0.6.3 → 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 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 — or, if the run is non-interactive, to proceed with the single most reasonable option and state its assumption rather than stall.
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.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 = isAskUserQuestionTool(toolName) ? "Your question and its options have already been presented to the operator in full. Prefer to stop here and wait for their answer in the next message \u2014 do not silently guess. But if this is an automated or otherwise non-interactive run where no operator will reply, do not stall: proceed with the single most reasonable option and state, in one line, the assumption you made so it can be corrected later." : this.config.controlRequestDenyMessage ?? `Denied by opencode-claude-code policy for tool ${toolName}`;
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,