diff --git a/src/main/services/team/TeamProvisioningService.ts b/src/main/services/team/TeamProvisioningService.ts index bbd145f7..3d510f15 100644 --- a/src/main/services/team/TeamProvisioningService.ts +++ b/src/main/services/team/TeamProvisioningService.ts @@ -6043,17 +6043,21 @@ export class TeamProvisioningService { // IMPORTANT: request_id is NESTED inside response, NOT top-level // (asymmetry with control_request — confirmed by Python SDK, Elixir SDK and issue #29991) const allowResponse: Record = { behavior: 'allow' }; - // For AskUserQuestion: pass user's answer via updatedInput so the CLI - // can deliver it without re-prompting. Format follows --permission-prompt-tool spec. + // For AskUserQuestion: pass user's answers via updatedInput so the CLI + // can deliver them without re-prompting. Format follows --permission-prompt-tool spec. if (allow && message) { const pending = run.pendingApprovals.get(requestId); if (pending?.toolName === 'AskUserQuestion') { - const questions = (pending.toolInput.questions as { question?: string }[]) ?? []; - const answers: Record = {}; - for (const q of questions) { - if (q.question) answers[q.question] = message; + try { + const answers = JSON.parse(message) as Record; + allowResponse.updatedInput = { ...pending.toolInput, answers }; + } catch { + // If message isn't JSON, use as-is for the first question + const questions = (pending.toolInput.questions as { question?: string }[]) ?? []; + const answers: Record = {}; + if (questions[0]?.question) answers[questions[0].question] = message; + allowResponse.updatedInput = { ...pending.toolInput, answers }; } - allowResponse.updatedInput = { ...pending.toolInput, answers }; } } const response = allow diff --git a/src/renderer/components/team/ToolApprovalSheet.tsx b/src/renderer/components/team/ToolApprovalSheet.tsx index 2b801363..8f66578c 100644 --- a/src/renderer/components/team/ToolApprovalSheet.tsx +++ b/src/renderer/components/team/ToolApprovalSheet.tsx @@ -170,10 +170,26 @@ export const ToolApprovalSheet: React.FC = () => { setDisabled(true); setError(null); - // For AskUserQuestion, build answers from selected options + // For AskUserQuestion, build per-question answers from selected options + // Key format in selectedOptions: "qi:label" — parse question index to map correctly const answersMessage = allow && current.toolName === 'AskUserQuestion' && selectedOptions.size > 0 - ? Array.from(selectedOptions).join(', ') + ? (() => { + const questions = Array.isArray(current.toolInput.questions) + ? (current.toolInput.questions as { question?: string }[]) + : []; + const answersByQuestion: Record = {}; + for (const key of selectedOptions) { + const colonIdx = key.indexOf(':'); + if (colonIdx < 0) continue; + const qi = parseInt(key.slice(0, colonIdx), 10); + const label = key.slice(colonIdx + 1); + const questionText = questions[qi]?.question ?? `Question ${qi + 1}`; + const existing = answersByQuestion[questionText]; + answersByQuestion[questionText] = existing ? `${existing}, ${label}` : label; + } + return JSON.stringify(answersByQuestion); + })() : undefined; // Safety timeout — if IPC hangs (e.g. stdin.write callback never fires), @@ -210,7 +226,12 @@ export const ToolApprovalSheet: React.FC = () => { const handleOptionSelect = useCallback((label: string, multiSelect: boolean) => { setSelectedOptions((prev) => { - const next = multiSelect ? new Set(prev) : new Set(); + // For single-select: clear all options from the SAME question (same prefix) + // Key format: "qi:label" where qi is the question index + const prefix = label.split(':')[0] + ':'; + const next = multiSelect + ? new Set(prev) + : new Set(Array.from(prev).filter((k) => !k.startsWith(prefix))); if (next.has(label)) { next.delete(label); } else { @@ -495,7 +516,7 @@ const ToolInputPreview = ({ {Array.isArray(q.options) && (
{q.options.map((opt, oi) => { - const optKey = opt.label ?? `opt-${oi}`; + const optKey = `${qi}:${opt.label ?? `opt-${oi}`}`; const isSelected = selectedOptions?.has(optKey) ?? false; return (