@raindrop-ai/wizard 0.0.11 → 0.0.13

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.
Files changed (34) hide show
  1. package/dist/src/docs/opencode.mdx +75 -0
  2. package/dist/src/docs/python.mdx +6 -0
  3. package/dist/src/docs/typescript.mdx +125 -28
  4. package/dist/src/lib/__tests__/sdk-messages.test.d.ts +4 -0
  5. package/dist/src/lib/__tests__/sdk-messages.test.js +296 -0
  6. package/dist/src/lib/__tests__/sdk-messages.test.js.map +1 -0
  7. package/dist/src/lib/agent-interface.js +40 -14
  8. package/dist/src/lib/agent-interface.js.map +1 -1
  9. package/dist/src/lib/agent-prompts.js +4 -1
  10. package/dist/src/lib/agent-prompts.js.map +1 -1
  11. package/dist/src/lib/constants.d.ts +7 -0
  12. package/dist/src/lib/constants.js +15 -0
  13. package/dist/src/lib/constants.js.map +1 -1
  14. package/dist/src/lib/handlers.js +21 -18
  15. package/dist/src/lib/handlers.js.map +1 -1
  16. package/dist/src/lib/mcp.js +13 -11
  17. package/dist/src/lib/mcp.js.map +1 -1
  18. package/dist/src/lib/sdk-messages.d.ts +41 -2
  19. package/dist/src/lib/sdk-messages.js +89 -41
  20. package/dist/src/lib/sdk-messages.js.map +1 -1
  21. package/dist/src/lib/wizard.js +1 -1
  22. package/dist/src/lib/wizard.js.map +1 -1
  23. package/dist/src/ui/components/ToolCallDisplay.js +30 -0
  24. package/dist/src/ui/components/ToolCallDisplay.js.map +1 -1
  25. package/dist/src/ui/contexts/WizardContext.d.ts +0 -11
  26. package/dist/src/ui/contexts/WizardContext.js +2 -19
  27. package/dist/src/ui/contexts/WizardContext.js.map +1 -1
  28. package/dist/src/utils/__mocks__/ui.d.ts +10 -0
  29. package/dist/src/utils/__mocks__/ui.js +7 -0
  30. package/dist/src/utils/__mocks__/ui.js.map +1 -0
  31. package/dist/src/utils/session.d.ts +22 -0
  32. package/dist/src/utils/session.js +67 -1
  33. package/dist/src/utils/session.js.map +1 -1
  34. package/package.json +16 -1
@@ -1 +1 @@
1
- {"version":3,"file":"handlers.js","sourceRoot":"","sources":["../../../src/lib/handlers.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Tool approval handlers for the Claude agent\n * Handles UI integration for tool approvals and clarifying questions\n */\n\nimport type { HookInput, HookJSONOutput } from '@anthropic-ai/claude-agent-sdk';\nimport { createTwoFilesPatch } from 'diff';\nimport type { AgentQueryHandle, ToolApprovalResult } from '../ui/types.js';\nimport { logToFile } from '../utils/debug.js';\nimport { sendSessionUpdate } from '../utils/session.js';\nimport ui from '../utils/ui.js';\nimport { SAFE_BASH_PATTERNS } from './constants.js';\n\n// ============================================================================\n// Session-wide Approval Tracking\n// ============================================================================\n\n/**\n * Set of file paths that have been granted blanket approval for the session.\n * When a file is in this set, Edit/Write operations on it are auto-approved.\n */\nconst approvedFilesForSession = new Set<string>();\n\n/**\n * Set of command patterns that have been granted blanket approval for the session.\n * When a command matches a pattern in this set, Bash operations are auto-approved.\n * Patterns use simple prefix matching (e.g., \"npm install\" matches \"npm install axios\").\n */\nconst approvedCommandPatternsForSession = new Set<string>();\n\n/**\n * Clear all session-wide file approvals.\n * Useful when starting a new session or resetting permissions.\n */\nexport function clearApprovedFiles(): void {\n approvedFilesForSession.clear();\n logToFile('Cleared all approved files for session');\n}\n\n/**\n * Clear all session-wide command pattern approvals.\n * Useful when starting a new session or resetting permissions.\n */\nexport function clearApprovedCommandPatterns(): void {\n approvedCommandPatternsForSession.clear();\n logToFile('Cleared all approved command patterns for session');\n}\n\n/**\n * Get the list of currently approved files (for debugging/display purposes)\n */\nexport function getApprovedFiles(): string[] {\n return Array.from(approvedFilesForSession);\n}\n\n/**\n * Get the list of currently approved command patterns (for debugging/display purposes)\n */\nexport function getApprovedCommandPatterns(): string[] {\n return Array.from(approvedCommandPatternsForSession);\n}\n\n/**\n * Extract the command pattern from a bash command for session approval.\n * Returns the base command with the first argument(s) to match similar commands.\n * Examples:\n * \"npm install axios\" -> \"npm install\"\n * \"npm run build\" -> \"npm run\"\n * \"pip install requests\" -> \"pip install\"\n * \"yarn add lodash\" -> \"yarn add\"\n */\nfunction extractCommandPattern(command: string): string {\n const trimmed = command.trim();\n const parts = trimmed.split(/\\s+/);\n\n // For package managers with subcommands, include the subcommand\n if (parts.length >= 2) {\n const [cmd, subcmd] = parts;\n // Common package managers\n if (\n ['npm', 'yarn', 'bun', 'pip', 'pip3', 'poetry', 'cargo', 'go'].includes(\n cmd,\n )\n ) {\n return `${cmd} ${subcmd}`;\n }\n }\n\n // For other commands, just return the first part\n return parts[0] || trimmed;\n}\n\n/**\n * Check if a bash command matches any approved command pattern for the session.\n */\nfunction isCommandApprovedForSession(command: string): boolean {\n const pattern = extractCommandPattern(command);\n return approvedCommandPatternsForSession.has(pattern);\n}\n\n// ============================================================================\n// Pending Tool Call Types\n// ============================================================================\n\n/**\n * Pending tool call info stored while waiting for result\n */\nexport interface PendingToolCall {\n toolName: string;\n input: Record<string, unknown>;\n description?: string;\n /** ID of the 'executing' history item, used to update it on completion/interrupt */\n historyItemId?: number;\n}\n\n// ============================================================================\n// Agent Query Handle Factory\n// ============================================================================\n\n/**\n * Dependencies required for creating an AgentQueryHandle\n */\nexport interface AgentQueryHandleDeps {\n isInterruptingRef: { value: boolean };\n waitingForUserInputRef: { value: boolean };\n pendingToolCalls: Map<string, PendingToolCall>;\n getQueryObject: () => { interrupt?: () => Promise<void> } | null;\n sendMessage: (message: string) => void;\n}\n\n/**\n * Create an AgentQueryHandle for external control of the agent.\n * Handles interrupts by marking pending tool calls (keeps persistent input running).\n */\nexport function createAgentQueryHandle(\n deps: AgentQueryHandleDeps,\n): AgentQueryHandle {\n const {\n isInterruptingRef,\n waitingForUserInputRef,\n pendingToolCalls,\n getQueryObject,\n sendMessage,\n } = deps;\n\n return {\n interrupt: async (fromUserMessage?: boolean) => {\n logToFile('Soft interrupt requested (Esc)');\n\n // If already interrupted, don't add another \"Interrupted\" item\n if (isInterruptingRef.value || waitingForUserInputRef.value) {\n logToFile('Already interrupted - ignoring duplicate interrupt request');\n return;\n }\n\n isInterruptingRef.value = true;\n waitingForUserInputRef.value = true;\n\n // Mark all pending tool calls as interrupted and show them in history\n if (pendingToolCalls.size > 0) {\n for (const [toolUseId, pendingCall] of pendingToolCalls) {\n const interruptedToolCall = {\n toolName: pendingCall.toolName,\n status: 'interrupted' as const,\n input: pendingCall.input,\n description: pendingCall.description,\n };\n if (pendingCall.historyItemId !== undefined) {\n ui.updateItem(pendingCall.historyItemId, {\n type: 'tool-call',\n text: pendingCall.toolName,\n toolCall: interruptedToolCall,\n });\n } else {\n ui.addItem({\n type: 'tool-call',\n text: pendingCall.toolName,\n toolCall: interruptedToolCall,\n });\n }\n pendingToolCalls.delete(toolUseId);\n }\n } else if (!fromUserMessage) {\n // No pending tool calls and not interrupted by a user message - show generic indicator\n ui.addItem({\n type: 'error',\n text: 'Interrupted',\n });\n }\n\n // Note: Don't stop persistent input here - keep it visible for user to type their message\n // The spinner will be stopped separately, and the input remains for user to submit\n\n // Call SDK interrupt\n const queryObject = getQueryObject();\n if (queryObject?.interrupt) {\n logToFile('Calling queryObject.interrupt()');\n await queryObject.interrupt();\n logToFile('queryObject.interrupt() completed');\n } else {\n logToFile('No queryObject.interrupt available');\n }\n },\n sendMessage: (message: string) => {\n const trimmedMessage = message.trim();\n if (!trimmedMessage) {\n return;\n }\n logToFile('Queueing user message for active session');\n sendMessage(trimmedMessage);\n },\n };\n}\n\n// ============================================================================\n// Enhanced canUseTool Handler with UI Integration\n// ============================================================================\n\n/**\n * Generate a unified diff for Edit tool inputs (old_string -> new_string)\n */\nfunction generateEditDiff(\n filePath: string,\n oldString: string,\n newString: string,\n): string {\n // createTwoFilesPatch generates a unified diff\n return createTwoFilesPatch(\n filePath,\n filePath,\n oldString,\n newString,\n '', // old header\n '', // new header\n { context: 3 }, // context lines\n );\n}\n\n/**\n * Handle tool approval request by showing approval UI\n */\nasync function handleToolApproval(\n toolName: string,\n input: Record<string, unknown>,\n approvedFilesCache?: Set<string>,\n): Promise<ToolApprovalResult> {\n logToFile('Showing tool approval UI:', { toolName, input });\n\n // Extract file path\n const fileName =\n typeof input.file_path === 'string'\n ? input.file_path\n : typeof input.path === 'string'\n ? input.path\n : undefined;\n\n // Check if this file has been approved for all edits\n if (\n approvedFilesCache &&\n fileName &&\n (toolName === 'Edit' || toolName === 'Write') &&\n approvedFilesCache.has(fileName)\n ) {\n logToFile('Auto-approving edit to previously approved file:', fileName);\n return {\n behavior: 'allow',\n updatedInput: input,\n };\n }\n\n // Stop spinner while waiting for user approval\n const spinner = ui.spinner();\n spinner.stop();\n\n // Generate diff content for file modification tools\n let diffContent: string | undefined;\n if (\n toolName === 'Edit' &&\n typeof input.old_string === 'string' &&\n typeof input.new_string === 'string' &&\n fileName\n ) {\n // Edit: show old -> new diff\n diffContent = generateEditDiff(\n fileName,\n input.old_string,\n input.new_string,\n );\n } else if (\n toolName === 'Write' &&\n typeof input.content === 'string' &&\n fileName\n ) {\n // Write: show content as all additions (empty -> content)\n diffContent = generateEditDiff(fileName, '', input.content);\n } else if (typeof input.file_diff === 'string') {\n // Use pre-generated diff if available\n diffContent = input.file_diff;\n }\n\n // Build props for the approval prompt\n const props = {\n toolName,\n input,\n description:\n typeof input.description === 'string' ? input.description : undefined,\n diffContent,\n fileName,\n };\n\n try {\n const result = await ui.toolApproval(props);\n logToFile('Tool approval result:', result);\n\n // If user chose \"allow all edits to this file\", add to both caches\n if (\n result.behavior === 'allow' &&\n 'allowAllForFile' in result &&\n result.allowAllForFile\n ) {\n approvedFilesForSession.add(result.allowAllForFile);\n logToFile('Added file to approved list:', result.allowAllForFile);\n }\n if (\n result.behavior === 'allow' &&\n result.allowAllEdits &&\n fileName &&\n approvedFilesCache\n ) {\n logToFile('Adding file to approved files cache:', fileName);\n approvedFilesCache.add(fileName);\n }\n\n // If user selected \"allow all for this command pattern\", add to approved set\n if (\n result.behavior === 'allow' &&\n 'allowAllForCommandPattern' in result &&\n result.allowAllForCommandPattern\n ) {\n approvedCommandPatternsForSession.add(result.allowAllForCommandPattern);\n logToFile(\n 'Added command pattern to approved list:',\n result.allowAllForCommandPattern,\n );\n }\n\n // Restart spinner after user responds\n spinner.start();\n\n return result;\n } catch (error) {\n logToFile('Error in tool approval:', error);\n return {\n behavior: 'deny',\n message: 'Failed to get user approval',\n };\n }\n}\n\n/**\n * Handle the AskUserQuestion tool by showing clarifying questions UI.\n * Input already contains { questions: [...] } in the correct format.\n * Returns { questions, answers } as expected by the SDK.\n */\nasync function handleClarifyingQuestions(\n input: Record<string, unknown>,\n): Promise<ToolApprovalResult> {\n logToFile('Handling AskUserQuestion:', input);\n\n // Stop spinner while waiting for user input\n const spinner = ui.spinner();\n spinner.stop();\n\n try {\n // Input is already in ClarifyingQuestionsProps format\n const result = await ui.clarifyingQuestions(input as any);\n logToFile('Clarifying questions result:', result);\n\n // Restart spinner after user responds\n spinner.start();\n\n // Return questions + answers as expected by SDK\n return {\n behavior: 'allow',\n updatedInput: {\n questions: result.questions,\n answers: result.answers,\n },\n };\n } catch (error) {\n logToFile('Error in clarifying questions:', error);\n return {\n behavior: 'deny',\n message: 'Failed to get user answers',\n };\n }\n}\n\n/**\n * Session info for notifications\n */\nexport interface SessionInfo {\n sessionId: string;\n accessToken: string;\n orgId: string;\n}\n\n/**\n * Handle the ExitPlanMode tool by showing plan approval UI.\n * Input contains { plan: \"...\" } with the plan in markdown format.\n * If user approves, returns allow. If user rejects, returns deny with feedback.\n */\nasync function handlePlanApproval(\n input: Record<string, unknown>,\n sessionInfo?: SessionInfo,\n): Promise<ToolApprovalResult> {\n logToFile('Handling ExitPlanMode:', input);\n\n const planContent = typeof input.plan === 'string' ? input.plan : '';\n\n // Send session update with plan content\n if (sessionInfo) {\n sendSessionUpdate(\n sessionInfo.sessionId,\n planContent,\n sessionInfo.accessToken,\n sessionInfo.orgId,\n );\n }\n\n return {\n behavior: 'allow',\n updatedInput: input,\n };\n}\n\n/** Prefix for MCP tools (e.g. mcp__server__tool or mcp____server____tool). All are auto-approved and not shown in approval UI. */\nconst MCP_TOOL_PREFIX = 'mcp__';\n\n/**\n * Tools that are automatically approved without user confirmation.\n * MCP tools (name starts with mcp__) are approved via wildcard in PreToolUse.\n */\nconst AUTO_APPROVED_TOOLS = new Set(['EnterPlanMode']);\n\n/**\n * Patterns indicating a file path or glob likely targets secret/credential files.\n * Used to auto-deny Read/Glob/Grep operations on sensitive files.\n */\nconst SECRET_PATH_PATTERNS: RegExp[] = [\n /\\.env(\\.|$)/, // .env, .env.local, .env.production, etc.\n /\\bsecrets?\\b/i, // secrets.json, secret.yaml, etc.\n /\\bcredentials?\\b/i, // credentials.json, credential.yaml\n /private[._-]?key/i, // private_key.pem, privatekey.pem\n /\\.pem$/i, // PEM certificates/keys\n /\\.key$/i, // Key files (e.g. myapp.key, certificate.key)\n /\\.p12$/i, // PKCS12 keystores\n /\\.pfx$/i, // PFX keystores\n /\\bid_rsa\\b/, // SSH private keys\n /\\bid_ed25519\\b/, // SSH private keys\n /\\bid_ecdsa\\b/, // SSH private keys\n /\\.netrc$/, // .netrc files\n /serviceaccount.*\\.json$/i, // GCP service account keys\n];\n\nconst SECRET_PATH_ALLOWLIST: RegExp[] = [\n /\\.env\\.example$/, // .env.example is safe to read\n];\n\n/**\n * Returns true if a file path or glob pattern likely targets a secrets file.\n */\nfunction isSecretPath(value: string): boolean {\n if (SECRET_PATH_ALLOWLIST.some((re) => re.test(value))) return false;\n return SECRET_PATH_PATTERNS.some((re) => re.test(value));\n}\n\n/**\n * Check if a Read/Glob/Grep input targets a secrets file and should be denied.\n * For Grep, only the file-targeting fields (path, glob) are checked — not the\n * search pattern itself.\n */\nfunction targetsSecretFile(\n toolName: string,\n input: Record<string, unknown>,\n): boolean {\n if (toolName === 'Read' || toolName === 'Edit' || toolName === 'Write') {\n const filePath =\n typeof input.file_path === 'string'\n ? input.file_path\n : typeof input.path === 'string'\n ? input.path\n : '';\n return isSecretPath(filePath);\n }\n if (toolName === 'NotebookEdit') {\n const notebookPath =\n typeof input.notebook_path === 'string' ? input.notebook_path : '';\n return isSecretPath(notebookPath);\n }\n if (toolName === 'Glob') {\n const pattern = typeof input.pattern === 'string' ? input.pattern : '';\n const path = typeof input.path === 'string' ? input.path : '';\n return isSecretPath(pattern) || isSecretPath(path);\n }\n if (toolName === 'Grep') {\n const path = typeof input.path === 'string' ? input.path : '';\n const glob = typeof input.glob === 'string' ? input.glob : '';\n return isSecretPath(path) || isSecretPath(glob);\n }\n return false;\n}\n\n/**\n * Returns true if a bash command string references a secret/credential file.\n * Splits on shell delimiters and checks each token against SECRET_PATH_PATTERNS.\n */\nfunction bashCommandTargetsSecretFile(command: string): boolean {\n const tokens = command.split(/[\\s|;&<>]+/);\n for (const token of tokens) {\n // Strip surrounding quotes\n const cleaned = token.replace(/^['\"]|['\"]$/g, '');\n if (cleaned && !cleaned.startsWith('-') && isSecretPath(cleaned)) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * PreToolUse hook that handles all silent auto-approve/deny decisions.\n * Fires for every tool call before canUseTool, so this is the right place\n * for decisions that don't require user interaction.\n * Returns { continue: true } for tools that need canUseTool (UI interaction).\n */\nexport function createPreToolUseHook(sessionInfo?: SessionInfo) {\n return async (input: HookInput): Promise<HookJSONOutput> => {\n if (input.hook_event_name !== 'PreToolUse') return { continue: true };\n const { tool_name, tool_input } = input;\n const inp = (tool_input ?? {}) as Record<string, unknown>;\n\n // Block secret file access for all relevant tools\n if (\n targetsSecretFile(tool_name, inp) ||\n (tool_name === 'Bash' &&\n typeof inp.command === 'string' &&\n bashCommandTargetsSecretFile(inp.command))\n ) {\n logToFile(\n `PreToolUse: blocking ${tool_name} - secret file pattern detected`,\n inp,\n );\n return {\n hookSpecificOutput: {\n hookEventName: 'PreToolUse',\n permissionDecision: 'deny',\n permissionDecisionReason:\n 'Reading or writing secret or credential files is not allowed.',\n },\n };\n }\n\n // Auto-approve all MCP tools (mcp__*) and EnterPlanMode — no approval UI\n if (\n tool_name.startsWith(MCP_TOOL_PREFIX) ||\n AUTO_APPROVED_TOOLS.has(tool_name)\n ) {\n return {\n hookSpecificOutput: {\n hookEventName: 'PreToolUse',\n permissionDecision: 'allow',\n },\n };\n }\n\n // Auto-approve read-only file tools\n if (tool_name === 'Read' || tool_name === 'Glob' || tool_name === 'Grep') {\n return {\n hookSpecificOutput: {\n hookEventName: 'PreToolUse',\n permissionDecision: 'allow',\n },\n };\n }\n\n // Auto-approve safe or session-approved bash commands\n if (tool_name === 'Bash' && typeof inp.command === 'string') {\n if (\n isSafeBashCommand(inp.command) ||\n isCommandApprovedForSession(inp.command)\n ) {\n logToFile('PreToolUse: auto-approving bash command:', inp.command);\n return {\n hookSpecificOutput: {\n hookEventName: 'PreToolUse',\n permissionDecision: 'allow',\n },\n };\n }\n }\n\n // Auto-approve WebSearch with domain restriction applied via updatedInput\n if (tool_name === 'WebSearch') {\n return {\n hookSpecificOutput: {\n hookEventName: 'PreToolUse',\n permissionDecision: 'allow',\n updatedInput: {\n ...inp,\n allowed_domains: ['raindrop.ai/docs', 'ai-sdk.dev/docs/'],\n },\n },\n };\n }\n\n // Auto-approve ExitPlanMode and fire session update\n if (tool_name === 'ExitPlanMode') {\n const planContent = typeof inp.plan === 'string' ? inp.plan : '';\n if (sessionInfo) {\n sendSessionUpdate(\n sessionInfo.sessionId,\n planContent,\n sessionInfo.accessToken,\n sessionInfo.orgId,\n );\n }\n return {\n hookSpecificOutput: {\n hookEventName: 'PreToolUse',\n permissionDecision: 'allow',\n permissionDecisionReason: 'System automatically approved.',\n },\n };\n }\n\n // Auto-approve edits to files that were already approved this session\n if (tool_name === 'Edit' || tool_name === 'Write') {\n const fileName =\n typeof inp.file_path === 'string'\n ? inp.file_path\n : typeof inp.path === 'string'\n ? inp.path\n : undefined;\n if (fileName && approvedFilesForSession.has(fileName)) {\n logToFile(\n 'PreToolUse: auto-approving edit to session-approved file:',\n fileName,\n );\n return {\n hookSpecificOutput: {\n hookEventName: 'PreToolUse',\n permissionDecision: 'allow',\n },\n };\n }\n }\n\n // Anything else needs user interaction — let canUseTool handle it\n return {};\n };\n}\n\n/**\n * Check if a bash command matches a safe pattern and can be auto-approved.\n */\nfunction isSafeBashCommand(command: string): boolean {\n const trimmed = command.trim();\n return SAFE_BASH_PATTERNS.some((pattern) => {\n if (pattern.startsWith('*')) {\n // Suffix match (e.g., '*--version')\n return trimmed.endsWith(pattern.slice(1));\n } else if (pattern.endsWith('*')) {\n // Prefix match (e.g., 'npm install*')\n return trimmed.startsWith(pattern.slice(0, -1));\n } else {\n // Exact match\n return trimmed === pattern;\n }\n });\n}\n\n/**\n * Create a canUseTool handler for tools that require user interaction.\n * Auto-approve/deny logic lives in createPreToolUseHook instead.\n * This handler is only reached for tools that PreToolUse passes through.\n */\nexport function createCanUseToolHandler(approvedFilesCache?: Set<string>) {\n return async (\n toolName: string,\n input: unknown,\n ): Promise<ToolApprovalResult> => {\n const inputRecord = input as Record<string, unknown>;\n logToFile('canUseTool called:', { toolName, input: inputRecord });\n\n // Handle AskUserQuestion specially\n if (toolName === 'AskUserQuestion') {\n return handleClarifyingQuestions(inputRecord);\n }\n\n // ExitPlanMode is auto-approved (session update already fired in PreToolUse hook)\n if (toolName === 'ExitPlanMode') {\n return { behavior: 'allow', updatedInput: inputRecord };\n }\n\n // Show approval UI for all other tools\n return handleToolApproval(toolName, inputRecord, approvedFilesCache);\n };\n}\n"]}
1
+ {"version":3,"file":"handlers.js","sourceRoot":"","sources":["../../../src/lib/handlers.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Tool approval handlers for the Claude agent\n * Handles UI integration for tool approvals and clarifying questions\n */\n\nimport type { HookInput, HookJSONOutput } from '@anthropic-ai/claude-agent-sdk';\nimport { createTwoFilesPatch } from 'diff';\nimport type { AgentQueryHandle, ToolApprovalResult } from '../ui/types.js';\nimport { logToFile } from '../utils/debug.js';\nimport { sendSessionUpdate } from '../utils/session.js';\nimport ui from '../utils/ui.js';\nimport { MCP_TOOL_PREFIX, SAFE_BASH_PATTERNS } from './constants.js';\n\n// ============================================================================\n// Session-wide Approval Tracking\n// ============================================================================\n\n/**\n * Set of file paths that have been granted blanket approval for the session.\n * When a file is in this set, Edit/Write operations on it are auto-approved.\n */\nconst approvedFilesForSession = new Set<string>();\n\n/**\n * Set of command patterns that have been granted blanket approval for the session.\n * When a command matches a pattern in this set, Bash operations are auto-approved.\n * Patterns use simple prefix matching (e.g., \"npm install\" matches \"npm install axios\").\n */\nconst approvedCommandPatternsForSession = new Set<string>();\n\n/**\n * Clear all session-wide file approvals.\n * Useful when starting a new session or resetting permissions.\n */\nexport function clearApprovedFiles(): void {\n approvedFilesForSession.clear();\n logToFile('Cleared all approved files for session');\n}\n\n/**\n * Clear all session-wide command pattern approvals.\n * Useful when starting a new session or resetting permissions.\n */\nexport function clearApprovedCommandPatterns(): void {\n approvedCommandPatternsForSession.clear();\n logToFile('Cleared all approved command patterns for session');\n}\n\n/**\n * Get the list of currently approved files (for debugging/display purposes)\n */\nexport function getApprovedFiles(): string[] {\n return Array.from(approvedFilesForSession);\n}\n\n/**\n * Get the list of currently approved command patterns (for debugging/display purposes)\n */\nexport function getApprovedCommandPatterns(): string[] {\n return Array.from(approvedCommandPatternsForSession);\n}\n\n/**\n * Extract the command pattern from a bash command for session approval.\n * Returns the base command with the first argument(s) to match similar commands.\n * Examples:\n * \"npm install axios\" -> \"npm install\"\n * \"npm run build\" -> \"npm run\"\n * \"pip install requests\" -> \"pip install\"\n * \"yarn add lodash\" -> \"yarn add\"\n */\nfunction extractCommandPattern(command: string): string {\n const trimmed = command.trim();\n const parts = trimmed.split(/\\s+/);\n\n // For package managers with subcommands, include the subcommand\n if (parts.length >= 2) {\n const [cmd, subcmd] = parts;\n // Common package managers\n if (\n ['npm', 'yarn', 'bun', 'pip', 'pip3', 'poetry', 'cargo', 'go'].includes(\n cmd,\n )\n ) {\n return `${cmd} ${subcmd}`;\n }\n }\n\n // For other commands, just return the first part\n return parts[0] || trimmed;\n}\n\n/**\n * Check if a bash command matches any approved command pattern for the session.\n */\nfunction isCommandApprovedForSession(command: string): boolean {\n const pattern = extractCommandPattern(command);\n return approvedCommandPatternsForSession.has(pattern);\n}\n\n// ============================================================================\n// Pending Tool Call Types\n// ============================================================================\n\n/**\n * Pending tool call info stored while waiting for result\n */\nexport interface PendingToolCall {\n toolName: string;\n input: Record<string, unknown>;\n description?: string;\n /** ID of the 'executing' history item, used to update it on completion/interrupt */\n historyItemId?: number;\n}\n\n// ============================================================================\n// Agent Query Handle Factory\n// ============================================================================\n\n/**\n * Dependencies required for creating an AgentQueryHandle\n */\nexport interface AgentQueryHandleDeps {\n isInterruptingRef: { value: boolean };\n waitingForUserInputRef: { value: boolean };\n pendingToolCalls: Map<string, PendingToolCall>;\n getQueryObject: () => { interrupt?: () => Promise<void> } | null;\n sendMessage: (message: string) => void;\n}\n\n/**\n * Create an AgentQueryHandle for external control of the agent.\n * Handles interrupts by marking pending tool calls (keeps persistent input running).\n */\nexport function createAgentQueryHandle(\n deps: AgentQueryHandleDeps,\n): AgentQueryHandle {\n const {\n isInterruptingRef,\n waitingForUserInputRef,\n pendingToolCalls,\n getQueryObject,\n sendMessage,\n } = deps;\n\n return {\n interrupt: async (fromUserMessage?: boolean) => {\n logToFile('Soft interrupt requested (Esc)');\n\n // If already interrupted, don't add another \"Interrupted\" item\n if (isInterruptingRef.value || waitingForUserInputRef.value) {\n logToFile('Already interrupted - ignoring duplicate interrupt request');\n return;\n }\n\n isInterruptingRef.value = true;\n waitingForUserInputRef.value = true;\n\n // Mark all pending tool calls as interrupted and show them in history\n if (pendingToolCalls.size > 0) {\n for (const [toolUseId, pendingCall] of pendingToolCalls) {\n const interruptedToolCall = {\n toolName: pendingCall.toolName,\n status: 'interrupted' as const,\n input: pendingCall.input,\n description: pendingCall.description,\n };\n if (pendingCall.historyItemId !== undefined) {\n ui.updateItem(pendingCall.historyItemId, {\n type: 'tool-call',\n text: pendingCall.toolName,\n toolCall: interruptedToolCall,\n });\n } else {\n ui.addItem({\n type: 'tool-call',\n text: pendingCall.toolName,\n toolCall: interruptedToolCall,\n });\n }\n pendingToolCalls.delete(toolUseId);\n }\n } else if (!fromUserMessage) {\n // No pending tool calls and not interrupted by a user message - show generic indicator\n ui.addItem({\n type: 'error',\n text: 'Interrupted',\n });\n }\n\n // Note: Don't stop persistent input here - keep it visible for user to type their message\n // The spinner will be stopped separately, and the input remains for user to submit\n\n // Call SDK interrupt\n const queryObject = getQueryObject();\n if (queryObject?.interrupt) {\n logToFile('Calling queryObject.interrupt()');\n await queryObject.interrupt();\n logToFile('queryObject.interrupt() completed');\n } else {\n logToFile('No queryObject.interrupt available');\n }\n },\n sendMessage: (message: string) => {\n const trimmedMessage = message.trim();\n if (!trimmedMessage) {\n return;\n }\n logToFile('Queueing user message for active session');\n sendMessage(trimmedMessage);\n },\n };\n}\n\n// ============================================================================\n// Enhanced canUseTool Handler with UI Integration\n// ============================================================================\n\n/**\n * Generate a unified diff for Edit tool inputs (old_string -> new_string)\n */\nfunction generateEditDiff(\n filePath: string,\n oldString: string,\n newString: string,\n): string {\n // createTwoFilesPatch generates a unified diff\n return createTwoFilesPatch(\n filePath,\n filePath,\n oldString,\n newString,\n '', // old header\n '', // new header\n { context: 3 }, // context lines\n );\n}\n\n/**\n * Handle tool approval request by showing approval UI\n */\nasync function handleToolApproval(\n toolName: string,\n input: Record<string, unknown>,\n approvedFilesCache?: Set<string>,\n): Promise<ToolApprovalResult> {\n logToFile('Showing tool approval UI:', { toolName, input });\n\n // Extract file path\n const fileName =\n typeof input.file_path === 'string'\n ? input.file_path\n : typeof input.path === 'string'\n ? input.path\n : undefined;\n\n // Check if this file has been approved for all edits\n if (\n approvedFilesCache &&\n fileName &&\n (toolName === 'Edit' || toolName === 'Write') &&\n approvedFilesCache.has(fileName)\n ) {\n logToFile('Auto-approving edit to previously approved file:', fileName);\n return {\n behavior: 'allow',\n updatedInput: input,\n };\n }\n\n // Stop spinner while waiting for user approval\n const spinner = ui.spinner();\n spinner.stop();\n\n // Generate diff content for file modification tools\n let diffContent: string | undefined;\n if (\n toolName === 'Edit' &&\n typeof input.old_string === 'string' &&\n typeof input.new_string === 'string' &&\n fileName\n ) {\n // Edit: show old -> new diff\n diffContent = generateEditDiff(\n fileName,\n input.old_string,\n input.new_string,\n );\n } else if (\n toolName === 'Write' &&\n typeof input.content === 'string' &&\n fileName\n ) {\n // Write: show content as all additions (empty -> content)\n diffContent = generateEditDiff(fileName, '', input.content);\n } else if (typeof input.file_diff === 'string') {\n // Use pre-generated diff if available\n diffContent = input.file_diff;\n }\n\n // Build props for the approval prompt\n const props = {\n toolName,\n input,\n description:\n typeof input.description === 'string' ? input.description : undefined,\n diffContent,\n fileName,\n };\n\n try {\n const result = await ui.toolApproval(props);\n logToFile('Tool approval result:', result);\n\n // If user chose \"allow all edits to this file\", add to both caches\n if (\n result.behavior === 'allow' &&\n 'allowAllForFile' in result &&\n result.allowAllForFile\n ) {\n approvedFilesForSession.add(result.allowAllForFile);\n logToFile('Added file to approved list:', result.allowAllForFile);\n }\n if (\n result.behavior === 'allow' &&\n result.allowAllEdits &&\n fileName &&\n approvedFilesCache\n ) {\n logToFile('Adding file to approved files cache:', fileName);\n approvedFilesCache.add(fileName);\n }\n\n // If user selected \"allow all for this command pattern\", add to approved set\n if (\n result.behavior === 'allow' &&\n 'allowAllForCommandPattern' in result &&\n result.allowAllForCommandPattern\n ) {\n approvedCommandPatternsForSession.add(result.allowAllForCommandPattern);\n logToFile(\n 'Added command pattern to approved list:',\n result.allowAllForCommandPattern,\n );\n }\n\n // Restart spinner after user responds\n spinner.start();\n\n return result;\n } catch (error) {\n logToFile('Error in tool approval:', error);\n return {\n behavior: 'deny',\n message: 'Failed to get user approval',\n };\n }\n}\n\n/**\n * Handle the AskUserQuestion tool by showing clarifying questions UI.\n * Input already contains { questions: [...] } in the correct format.\n * Returns { questions, answers } as expected by the SDK.\n */\nasync function handleClarifyingQuestions(\n input: Record<string, unknown>,\n): Promise<ToolApprovalResult> {\n logToFile('Handling AskUserQuestion:', input);\n\n // Stop spinner while waiting for user input\n const spinner = ui.spinner();\n spinner.stop();\n\n try {\n // Input is already in ClarifyingQuestionsProps format\n const result = await ui.clarifyingQuestions(input as any);\n logToFile('Clarifying questions result:', result);\n\n // Restart spinner after user responds\n spinner.start();\n\n // Return questions + answers as expected by SDK\n return {\n behavior: 'allow',\n updatedInput: {\n questions: result.questions,\n answers: result.answers,\n },\n };\n } catch (error) {\n logToFile('Error in clarifying questions:', error);\n return {\n behavior: 'deny',\n message: 'Failed to get user answers',\n };\n }\n}\n\n/**\n * Session info for notifications\n */\nexport interface SessionInfo {\n sessionId: string;\n accessToken: string;\n orgId: string;\n}\n\n/**\n * Handle the ExitPlanMode tool by showing plan approval UI.\n * Input contains { plan: \"...\" } with the plan in markdown format.\n * If user approves, returns allow. If user rejects, returns deny with feedback.\n */\nasync function handlePlanApproval(\n input: Record<string, unknown>,\n sessionInfo?: SessionInfo,\n): Promise<ToolApprovalResult> {\n logToFile('Handling ExitPlanMode:', input);\n\n const planContent = typeof input.plan === 'string' ? input.plan : '';\n\n // Send session update with plan content\n if (sessionInfo) {\n sendSessionUpdate(\n sessionInfo.sessionId,\n planContent,\n sessionInfo.accessToken,\n sessionInfo.orgId,\n );\n }\n\n return {\n behavior: 'allow',\n updatedInput: input,\n };\n}\n\n/**\n * Tools that are automatically approved without user confirmation.\n * MCP tools (name starts with mcp__) are approved via wildcard in PreToolUse.\n */\nconst AUTO_APPROVED_TOOLS = new Set([\n 'EnterPlanMode',\n 'WebFetch',\n]);\n\n/**\n * Patterns indicating a file path or glob likely targets secret/credential files.\n * Used to auto-deny Read/Glob/Grep operations on sensitive files.\n */\nconst SECRET_PATH_PATTERNS: RegExp[] = [\n /\\.env(\\.|$)/, // .env, .env.local, .env.production, etc.\n /\\bsecrets?\\b/i, // secrets.json, secret.yaml, etc.\n /\\bcredentials?\\b/i, // credentials.json, credential.yaml\n /private[._-]?key/i, // private_key.pem, privatekey.pem\n /\\.pem$/i, // PEM certificates/keys\n /\\.key$/i, // Key files (e.g. myapp.key, certificate.key)\n /\\.p12$/i, // PKCS12 keystores\n /\\.pfx$/i, // PFX keystores\n /\\bid_rsa\\b/, // SSH private keys\n /\\bid_ed25519\\b/, // SSH private keys\n /\\bid_ecdsa\\b/, // SSH private keys\n /\\.netrc$/, // .netrc files\n /serviceaccount.*\\.json$/i, // GCP service account keys\n];\n\nconst SECRET_PATH_ALLOWLIST: RegExp[] = [\n /\\.env\\.example$/, // .env.example is safe to read\n];\n\n/**\n * Returns true if a file path or glob pattern likely targets a secrets file.\n */\nfunction isSecretPath(value: string): boolean {\n if (SECRET_PATH_ALLOWLIST.some((re) => re.test(value))) return false;\n return SECRET_PATH_PATTERNS.some((re) => re.test(value));\n}\n\n/**\n * Check if a Read/Glob/Grep input targets a secrets file and should be denied.\n * For Grep, only the file-targeting fields (path, glob) are checked — not the\n * search pattern itself.\n */\nfunction targetsSecretFile(\n toolName: string,\n input: Record<string, unknown>,\n): boolean {\n if (toolName === 'Read' || toolName === 'Edit' || toolName === 'Write') {\n const filePath =\n typeof input.file_path === 'string'\n ? input.file_path\n : typeof input.path === 'string'\n ? input.path\n : '';\n return isSecretPath(filePath);\n }\n if (toolName === 'NotebookEdit') {\n const notebookPath =\n typeof input.notebook_path === 'string' ? input.notebook_path : '';\n return isSecretPath(notebookPath);\n }\n if (toolName === 'Glob') {\n const pattern = typeof input.pattern === 'string' ? input.pattern : '';\n const path = typeof input.path === 'string' ? input.path : '';\n return isSecretPath(pattern) || isSecretPath(path);\n }\n if (toolName === 'Grep') {\n const path = typeof input.path === 'string' ? input.path : '';\n const glob = typeof input.glob === 'string' ? input.glob : '';\n return isSecretPath(path) || isSecretPath(glob);\n }\n return false;\n}\n\n/**\n * Returns true if a bash command string references a secret/credential file.\n * Splits on shell delimiters and checks each token against SECRET_PATH_PATTERNS.\n */\nfunction bashCommandTargetsSecretFile(command: string): boolean {\n const tokens = command.split(/[\\s|;&<>]+/);\n for (const token of tokens) {\n // Strip surrounding quotes\n const cleaned = token.replace(/^['\"]|['\"]$/g, '');\n if (cleaned && !cleaned.startsWith('-') && isSecretPath(cleaned)) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * PreToolUse hook that handles all silent auto-approve/deny decisions.\n * Fires for every tool call before canUseTool, so this is the right place\n * for decisions that don't require user interaction.\n * Returns { continue: true } for tools that need canUseTool (UI interaction).\n */\nexport function createPreToolUseHook(sessionInfo?: SessionInfo) {\n return async (input: HookInput): Promise<HookJSONOutput> => {\n if (input.hook_event_name !== 'PreToolUse') return { continue: true };\n const { tool_name, tool_input } = input;\n const inp = (tool_input ?? {}) as Record<string, unknown>;\n\n // Block secret file access for all relevant tools\n if (\n targetsSecretFile(tool_name, inp) ||\n (tool_name === 'Bash' &&\n typeof inp.command === 'string' &&\n bashCommandTargetsSecretFile(inp.command))\n ) {\n logToFile(\n `PreToolUse: blocking ${tool_name} - secret file pattern detected`,\n inp,\n );\n return {\n hookSpecificOutput: {\n hookEventName: 'PreToolUse',\n permissionDecision: 'deny',\n permissionDecisionReason:\n 'Reading or writing secret or credential files is not allowed.',\n },\n };\n }\n\n // Auto-approve WebSearch with domain restriction applied via updatedInput.\n // Keep this before the generic AUTO_APPROVED_TOOLS branch so WebSearch\n // still receives input hardening.\n if (tool_name === 'WebSearch') {\n return {\n hookSpecificOutput: {\n hookEventName: 'PreToolUse',\n permissionDecision: 'allow',\n updatedInput: {\n ...inp,\n allowed_domains: ['raindrop.ai/docs', 'ai-sdk.dev/docs/'],\n },\n },\n };\n }\n\n // Auto-approve all MCP tools (mcp__*) and core auto-approved tools — no approval UI\n if (\n tool_name.startsWith(MCP_TOOL_PREFIX) ||\n AUTO_APPROVED_TOOLS.has(tool_name)\n ) {\n return {\n hookSpecificOutput: {\n hookEventName: 'PreToolUse',\n permissionDecision: 'allow',\n },\n };\n }\n\n // Auto-approve read-only file tools\n if (tool_name === 'Read' || tool_name === 'Glob' || tool_name === 'Grep') {\n return {\n hookSpecificOutput: {\n hookEventName: 'PreToolUse',\n permissionDecision: 'allow',\n },\n };\n }\n\n // Auto-approve safe or session-approved bash commands\n if (tool_name === 'Bash' && typeof inp.command === 'string') {\n if (\n isSafeBashCommand(inp.command) ||\n isCommandApprovedForSession(inp.command)\n ) {\n logToFile('PreToolUse: auto-approving bash command:', inp.command);\n return {\n hookSpecificOutput: {\n hookEventName: 'PreToolUse',\n permissionDecision: 'allow',\n },\n };\n }\n }\n\n // Auto-approve ExitPlanMode and fire session update\n if (tool_name === 'ExitPlanMode') {\n const planContent = typeof inp.plan === 'string' ? inp.plan : '';\n if (sessionInfo) {\n sendSessionUpdate(\n sessionInfo.sessionId,\n planContent,\n sessionInfo.accessToken,\n sessionInfo.orgId,\n );\n }\n return {\n hookSpecificOutput: {\n hookEventName: 'PreToolUse',\n permissionDecision: 'allow',\n permissionDecisionReason: 'System automatically approved.',\n },\n };\n }\n\n // Auto-approve edits to files that were already approved this session\n if (tool_name === 'Edit' || tool_name === 'Write') {\n const fileName =\n typeof inp.file_path === 'string'\n ? inp.file_path\n : typeof inp.path === 'string'\n ? inp.path\n : undefined;\n if (fileName && approvedFilesForSession.has(fileName)) {\n logToFile(\n 'PreToolUse: auto-approving edit to session-approved file:',\n fileName,\n );\n return {\n hookSpecificOutput: {\n hookEventName: 'PreToolUse',\n permissionDecision: 'allow',\n },\n };\n }\n }\n\n // Anything else needs user interaction — let canUseTool handle it\n return {};\n };\n}\n\n/**\n * Check if a bash command matches a safe pattern and can be auto-approved.\n */\nfunction isSafeBashCommand(command: string): boolean {\n const trimmed = command.trim();\n return SAFE_BASH_PATTERNS.some((pattern) => {\n if (pattern.startsWith('*')) {\n // Suffix match (e.g., '*--version')\n return trimmed.endsWith(pattern.slice(1));\n } else if (pattern.endsWith('*')) {\n // Prefix match (e.g., 'npm install*')\n return trimmed.startsWith(pattern.slice(0, -1));\n } else {\n // Exact match\n return trimmed === pattern;\n }\n });\n}\n\n/**\n * Create a canUseTool handler for tools that require user interaction.\n * Auto-approve/deny logic lives in createPreToolUseHook instead.\n * This handler is only reached for tools that PreToolUse passes through.\n */\nexport function createCanUseToolHandler(approvedFilesCache?: Set<string>) {\n return async (\n toolName: string,\n input: unknown,\n ): Promise<ToolApprovalResult> => {\n const inputRecord = input as Record<string, unknown>;\n logToFile('canUseTool called:', { toolName, input: inputRecord });\n\n // Handle AskUserQuestion specially\n if (toolName === 'AskUserQuestion') {\n return handleClarifyingQuestions(inputRecord);\n }\n\n // ExitPlanMode is auto-approved (session update already fired in PreToolUse hook)\n if (toolName === 'ExitPlanMode') {\n return { behavior: 'allow', updatedInput: inputRecord };\n }\n\n // Show approval UI for all other tools\n return handleToolApproval(toolName, inputRecord, approvedFilesCache);\n };\n}\n"]}
@@ -17,22 +17,24 @@ const DOCS_FILE_BY_INTEGRATION_TYPE = {
17
17
  'vercel-ai-sdk': 'vercel-ai-sdk.mdx',
18
18
  browser: 'browser.mdx',
19
19
  'claude-agent-sdk': 'claude-agent-sdk.mdx',
20
- 'opencode-sdk': 'opencode-sdk.mdx',
20
+ 'opencode-plugin': 'opencode.mdx',
21
21
  };
22
22
  const INTEGRATION_TYPE_ALIASES = {
23
23
  'typescript sdk': 'typescript',
24
- 'typescript_sdk': 'typescript',
24
+ typescript_sdk: 'typescript',
25
25
  'browser sdk': 'browser',
26
- 'browser_sdk': 'browser',
26
+ browser_sdk: 'browser',
27
27
  'edge runtime': 'browser',
28
28
  'edge-runtime': 'browser',
29
29
  'vercel ai sdk': 'vercel-ai-sdk',
30
- 'vercel_ai_sdk': 'vercel-ai-sdk',
30
+ vercel_ai_sdk: 'vercel-ai-sdk',
31
31
  'claude agent sdk': 'claude-agent-sdk',
32
- 'claude_agent_sdk': 'claude-agent-sdk',
33
- 'opencode sdk': 'opencode-sdk',
34
- 'opencode ai sdk': 'opencode-sdk',
35
- 'opencode_ai_sdk': 'opencode-sdk',
32
+ claude_agent_sdk: 'claude-agent-sdk',
33
+ 'opencode sdk': 'opencode-plugin',
34
+ 'opencode ai sdk': 'opencode-plugin',
35
+ opencode_ai_sdk: 'opencode-plugin',
36
+ opencode_plugin: 'opencode-plugin',
37
+ 'opencode-sdk': 'opencode-plugin',
36
38
  };
37
39
  const SUPPORTED_INTEGRATION_TYPES = Object.keys(DOCS_FILE_BY_INTEGRATION_TYPE);
38
40
  function normalizeIntegrationType(integrationType) {
@@ -64,7 +66,7 @@ export function createMcpServer(hasCompletedWorkRef, sessionContext) {
64
66
  integrationType: z
65
67
  .string()
66
68
  .optional()
67
- .describe('The integration type to load docs for: python, typescript, vercel-ai-sdk, browser, claude-agent-sdk, or opencode-sdk'),
69
+ .describe('The integration type to load docs for: python, typescript, vercel-ai-sdk, browser, claude-agent-sdk, or opencode-plugin'),
68
70
  interactionType: z
69
71
  .string()
70
72
  .optional()
@@ -104,7 +106,7 @@ export function createMcpServer(hasCompletedWorkRef, sessionContext) {
104
106
  integrationType: z
105
107
  .string()
106
108
  .optional()
107
- .describe('The detected integration type: python, typescript, vercel-ai-sdk, browser, claude-agent-sdk, or opencode-sdk'),
109
+ .describe('The detected integration type: python, typescript, vercel-ai-sdk, browser, claude-agent-sdk, or opencode-plugin'),
108
110
  interactionType: z
109
111
  .string()
110
112
  .optional()
@@ -125,7 +127,7 @@ export function createMcpServer(hasCompletedWorkRef, sessionContext) {
125
127
  normalizedIntegrationType === 'vercel-ai-sdk' ||
126
128
  normalizedIntegrationType === 'browser' ||
127
129
  normalizedIntegrationType === 'claude-agent-sdk' ||
128
- normalizedIntegrationType === 'opencode-sdk') {
130
+ normalizedIntegrationType === 'opencode-plugin') {
129
131
  details = await collectTypeScriptSetupDetails(sessionContext.installDir);
130
132
  }
131
133
  else {
@@ -1 +1 @@
1
- {"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../../src/lib/mcp.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * MCP server utilities for the Claude agent\n */\n\nimport { createSdkMcpServer, tool } from '@anthropic-ai/claude-agent-sdk';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { fileURLToPath } from 'url';\nimport { z } from 'zod';\nimport { logToFile } from '../utils/debug.js';\nimport { sendSessionInit } from '../utils/session.js';\nimport {\n collectPythonSetupDetails,\n collectTypeScriptSetupDetails,\n type SetupDetail,\n} from './config.js';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\nconst DOCS_FILE_BY_INTEGRATION_TYPE = {\n python: 'python.mdx',\n typescript: 'typescript.mdx',\n 'vercel-ai-sdk': 'vercel-ai-sdk.mdx',\n browser: 'browser.mdx',\n 'claude-agent-sdk': 'claude-agent-sdk.mdx',\n 'opencode-sdk': 'opencode-sdk.mdx',\n} as const;\n\ntype SupportedIntegrationType = keyof typeof DOCS_FILE_BY_INTEGRATION_TYPE;\n\nconst INTEGRATION_TYPE_ALIASES: Record<string, SupportedIntegrationType> = {\n 'typescript sdk': 'typescript',\n 'typescript_sdk': 'typescript',\n 'browser sdk': 'browser',\n 'browser_sdk': 'browser',\n 'edge runtime': 'browser',\n 'edge-runtime': 'browser',\n 'vercel ai sdk': 'vercel-ai-sdk',\n 'vercel_ai_sdk': 'vercel-ai-sdk',\n 'claude agent sdk': 'claude-agent-sdk',\n 'claude_agent_sdk': 'claude-agent-sdk',\n 'opencode sdk': 'opencode-sdk',\n 'opencode ai sdk': 'opencode-sdk',\n 'opencode_ai_sdk': 'opencode-sdk',\n};\n\nconst SUPPORTED_INTEGRATION_TYPES = Object.keys(\n DOCS_FILE_BY_INTEGRATION_TYPE,\n) as SupportedIntegrationType[];\n\nfunction normalizeIntegrationType(\n integrationType: string,\n): SupportedIntegrationType | null {\n const normalized = integrationType.trim().toLowerCase();\n if (normalized in DOCS_FILE_BY_INTEGRATION_TYPE) {\n return normalized as SupportedIntegrationType;\n }\n return INTEGRATION_TYPE_ALIASES[normalized] ?? null;\n}\n\n/**\n * Create an in-process MCP server with the CompleteIntegration tool\n */\nexport function createMcpServer(\n hasCompletedWorkRef: {\n value: boolean;\n },\n sessionContext: {\n sessionId: string;\n accessToken: string;\n orgId: string;\n installDir: string;\n },\n): any {\n const completionTool = tool(\n 'CompleteIntegration',\n 'Signals that the Raindrop integration is complete. Call this tool ONLY after you have confirmed that: 1) the Raindrop package is successfully installed, 2) Raindrop is integrated into user-facing AI features, and 3) Verified the project builds/runs without errors.',\n {}, // No input parameters\n (_args: Record<string, never>, _extra: unknown): any => {\n logToFile(\n 'Agent called CompleteIntegration tool - integration is complete',\n );\n\n // Set the completion flag\n hasCompletedWorkRef.value = true;\n\n return {\n content: [\n {\n type: 'text',\n text: 'Integration completion acknowledged. Transitioning to testing phase...',\n },\n ],\n };\n },\n );\n\n const loadDocumentationTool = tool(\n 'LoadDocumentation',\n 'Load Raindrop documentation for a specific integration type',\n {\n integrationType: z\n .string()\n .optional()\n .describe(\n 'The integration type to load docs for: python, typescript, vercel-ai-sdk, browser, claude-agent-sdk, or opencode-sdk',\n ),\n interactionType: z\n .string()\n .optional()\n .describe('Alias for integrationType for backward compatibility'),\n },\n async (\n args: { integrationType?: string; interactionType?: string },\n _extra: unknown,\n ): Promise<any> => {\n const requestedIntegrationType =\n args.integrationType || args.interactionType;\n if (!requestedIntegrationType) {\n return {\n content: [\n {\n type: 'text',\n text: `Missing integration type. Supported values: ${SUPPORTED_INTEGRATION_TYPES.join(\n ', ',\n )}`,\n },\n ],\n };\n }\n\n const normalizedIntegrationType = normalizeIntegrationType(\n requestedIntegrationType,\n );\n if (!normalizedIntegrationType) {\n return {\n content: [\n {\n type: 'text',\n text: `Unsupported integration type: ${requestedIntegrationType}. Supported values: ${SUPPORTED_INTEGRATION_TYPES.join(\n ', ',\n )}`,\n },\n ],\n };\n }\n\n const docsPath = path.resolve(\n __dirname,\n '../../src/docs',\n DOCS_FILE_BY_INTEGRATION_TYPE[normalizedIntegrationType],\n );\n logToFile(`Loading ${normalizedIntegrationType} docs from: ${docsPath}`);\n const docs = await fs.promises.readFile(docsPath, 'utf-8');\n const processedDocs = docs.replace(\n /__WIZARD_SESSION_UUID__/g,\n sessionContext.sessionId,\n );\n return {\n content: [{ type: 'text', text: processedDocs }],\n };\n },\n );\n\n const initializeSessionTool = tool(\n 'InitializeSession',\n 'Initialize session context for the integration. Call this immediately after confirming the integration type with the user and BEFORE loading documentation.',\n {\n integrationType: z\n .string()\n .optional()\n .describe(\n 'The detected integration type: python, typescript, vercel-ai-sdk, browser, claude-agent-sdk, or opencode-sdk',\n ),\n interactionType: z\n .string()\n .optional()\n .describe('Alias for integrationType for backward compatibility'),\n },\n async (\n args: { integrationType?: string; interactionType?: string },\n _extra: unknown,\n ): Promise<any> => {\n const requestedIntegrationType =\n args.integrationType || args.interactionType;\n logToFile(\n `InitializeSession called with integrationType: ${requestedIntegrationType}`,\n );\n\n try {\n // Collect setup details based on integration type\n let details: SetupDetail[] = [];\n const normalizedIntegrationType = requestedIntegrationType\n ? normalizeIntegrationType(requestedIntegrationType)\n : null;\n\n if (normalizedIntegrationType === 'python') {\n details = await collectPythonSetupDetails(sessionContext.installDir);\n } else if (\n normalizedIntegrationType === 'typescript' ||\n normalizedIntegrationType === 'vercel-ai-sdk' ||\n normalizedIntegrationType === 'browser' ||\n normalizedIntegrationType === 'claude-agent-sdk' ||\n normalizedIntegrationType === 'opencode-sdk'\n ) {\n details = await collectTypeScriptSetupDetails(\n sessionContext.installDir,\n );\n } else {\n logToFile(\n `Unknown or missing integration type: ${requestedIntegrationType}, defaulting to TypeScript setup details`,\n );\n details = await collectTypeScriptSetupDetails(\n sessionContext.installDir,\n );\n }\n\n // Format setup details into the expected string format\n const compiledSetup = details\n .map((d) => `=== ${d.filename} ===\\n${d.content}`)\n .join('\\n\\n');\n\n logToFile(\n `Collected ${details.length} setup details, total length: ${compiledSetup.length}`,\n );\n\n // Send session init with the setup details\n sendSessionInit(\n sessionContext.sessionId,\n compiledSetup,\n sessionContext.accessToken,\n sessionContext.orgId,\n );\n\n logToFile('InitializeSession completed successfully');\n\n return {\n content: [\n {\n type: 'text',\n text: 'Session initialized successfully. You may now proceed to load documentation.',\n },\n ],\n };\n } catch (error) {\n // Log error but still return success to allow wizard to continue\n logToFile('Error in InitializeSession:', error);\n\n // Still send session init with minimal details\n sendSessionInit(\n sessionContext.sessionId,\n '',\n sessionContext.accessToken,\n sessionContext.orgId,\n );\n\n return {\n content: [\n {\n type: 'text',\n text: 'Session initialized with partial details. You may proceed to load documentation.',\n },\n ],\n };\n }\n },\n );\n\n return createSdkMcpServer({\n name: 'raindrop-wizard',\n version: '1.0.0',\n tools: [completionTool, loadDocumentationTool, initializeSessionTool],\n });\n}\n"]}
1
+ {"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../../src/lib/mcp.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * MCP server utilities for the Claude agent\n */\n\nimport { createSdkMcpServer, tool } from '@anthropic-ai/claude-agent-sdk';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { fileURLToPath } from 'url';\nimport { z } from 'zod';\nimport { logToFile } from '../utils/debug.js';\nimport { sendSessionInit } from '../utils/session.js';\nimport {\n collectPythonSetupDetails,\n collectTypeScriptSetupDetails,\n type SetupDetail,\n} from './config.js';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\nconst DOCS_FILE_BY_INTEGRATION_TYPE = {\n python: 'python.mdx',\n typescript: 'typescript.mdx',\n 'vercel-ai-sdk': 'vercel-ai-sdk.mdx',\n browser: 'browser.mdx',\n 'claude-agent-sdk': 'claude-agent-sdk.mdx',\n 'opencode-plugin': 'opencode.mdx',\n} as const;\n\ntype SupportedIntegrationType = keyof typeof DOCS_FILE_BY_INTEGRATION_TYPE;\n\nconst INTEGRATION_TYPE_ALIASES: Record<string, SupportedIntegrationType> = {\n 'typescript sdk': 'typescript',\n typescript_sdk: 'typescript',\n 'browser sdk': 'browser',\n browser_sdk: 'browser',\n 'edge runtime': 'browser',\n 'edge-runtime': 'browser',\n 'vercel ai sdk': 'vercel-ai-sdk',\n vercel_ai_sdk: 'vercel-ai-sdk',\n 'claude agent sdk': 'claude-agent-sdk',\n claude_agent_sdk: 'claude-agent-sdk',\n 'opencode sdk': 'opencode-plugin',\n 'opencode ai sdk': 'opencode-plugin',\n opencode_ai_sdk: 'opencode-plugin',\n opencode_plugin: 'opencode-plugin',\n 'opencode-sdk': 'opencode-plugin',\n};\n\nconst SUPPORTED_INTEGRATION_TYPES = Object.keys(\n DOCS_FILE_BY_INTEGRATION_TYPE,\n) as SupportedIntegrationType[];\n\nfunction normalizeIntegrationType(\n integrationType: string,\n): SupportedIntegrationType | null {\n const normalized = integrationType.trim().toLowerCase();\n if (normalized in DOCS_FILE_BY_INTEGRATION_TYPE) {\n return normalized as SupportedIntegrationType;\n }\n return INTEGRATION_TYPE_ALIASES[normalized] ?? null;\n}\n\n/**\n * Create an in-process MCP server with the CompleteIntegration tool\n */\nexport function createMcpServer(\n hasCompletedWorkRef: {\n value: boolean;\n },\n sessionContext: {\n sessionId: string;\n accessToken: string;\n orgId: string;\n installDir: string;\n },\n): any {\n const completionTool = tool(\n 'CompleteIntegration',\n 'Signals that the Raindrop integration is complete. Call this tool ONLY after you have confirmed that: 1) the Raindrop package is successfully installed, 2) Raindrop is integrated into user-facing AI features, and 3) Verified the project builds/runs without errors.',\n {}, // No input parameters\n (_args: Record<string, never>, _extra: unknown): any => {\n logToFile(\n 'Agent called CompleteIntegration tool - integration is complete',\n );\n\n // Set the completion flag\n hasCompletedWorkRef.value = true;\n\n return {\n content: [\n {\n type: 'text',\n text: 'Integration completion acknowledged. Transitioning to testing phase...',\n },\n ],\n };\n },\n );\n\n const loadDocumentationTool = tool(\n 'LoadDocumentation',\n 'Load Raindrop documentation for a specific integration type',\n {\n integrationType: z\n .string()\n .optional()\n .describe(\n 'The integration type to load docs for: python, typescript, vercel-ai-sdk, browser, claude-agent-sdk, or opencode-plugin',\n ),\n interactionType: z\n .string()\n .optional()\n .describe('Alias for integrationType for backward compatibility'),\n },\n async (\n args: { integrationType?: string; interactionType?: string },\n _extra: unknown,\n ): Promise<any> => {\n const requestedIntegrationType =\n args.integrationType || args.interactionType;\n if (!requestedIntegrationType) {\n return {\n content: [\n {\n type: 'text',\n text: `Missing integration type. Supported values: ${SUPPORTED_INTEGRATION_TYPES.join(\n ', ',\n )}`,\n },\n ],\n };\n }\n\n const normalizedIntegrationType = normalizeIntegrationType(\n requestedIntegrationType,\n );\n if (!normalizedIntegrationType) {\n return {\n content: [\n {\n type: 'text',\n text: `Unsupported integration type: ${requestedIntegrationType}. Supported values: ${SUPPORTED_INTEGRATION_TYPES.join(\n ', ',\n )}`,\n },\n ],\n };\n }\n\n const docsPath = path.resolve(\n __dirname,\n '../../src/docs',\n DOCS_FILE_BY_INTEGRATION_TYPE[normalizedIntegrationType],\n );\n logToFile(`Loading ${normalizedIntegrationType} docs from: ${docsPath}`);\n const docs = await fs.promises.readFile(docsPath, 'utf-8');\n const processedDocs = docs.replace(\n /__WIZARD_SESSION_UUID__/g,\n sessionContext.sessionId,\n );\n return {\n content: [{ type: 'text', text: processedDocs }],\n };\n },\n );\n\n const initializeSessionTool = tool(\n 'InitializeSession',\n 'Initialize session context for the integration. Call this immediately after confirming the integration type with the user and BEFORE loading documentation.',\n {\n integrationType: z\n .string()\n .optional()\n .describe(\n 'The detected integration type: python, typescript, vercel-ai-sdk, browser, claude-agent-sdk, or opencode-plugin',\n ),\n interactionType: z\n .string()\n .optional()\n .describe('Alias for integrationType for backward compatibility'),\n },\n async (\n args: { integrationType?: string; interactionType?: string },\n _extra: unknown,\n ): Promise<any> => {\n const requestedIntegrationType =\n args.integrationType || args.interactionType;\n logToFile(\n `InitializeSession called with integrationType: ${requestedIntegrationType}`,\n );\n\n try {\n // Collect setup details based on integration type\n let details: SetupDetail[] = [];\n const normalizedIntegrationType = requestedIntegrationType\n ? normalizeIntegrationType(requestedIntegrationType)\n : null;\n\n if (normalizedIntegrationType === 'python') {\n details = await collectPythonSetupDetails(sessionContext.installDir);\n } else if (\n normalizedIntegrationType === 'typescript' ||\n normalizedIntegrationType === 'vercel-ai-sdk' ||\n normalizedIntegrationType === 'browser' ||\n normalizedIntegrationType === 'claude-agent-sdk' ||\n normalizedIntegrationType === 'opencode-plugin'\n ) {\n details = await collectTypeScriptSetupDetails(\n sessionContext.installDir,\n );\n } else {\n logToFile(\n `Unknown or missing integration type: ${requestedIntegrationType}, defaulting to TypeScript setup details`,\n );\n details = await collectTypeScriptSetupDetails(\n sessionContext.installDir,\n );\n }\n\n // Format setup details into the expected string format\n const compiledSetup = details\n .map((d) => `=== ${d.filename} ===\\n${d.content}`)\n .join('\\n\\n');\n\n logToFile(\n `Collected ${details.length} setup details, total length: ${compiledSetup.length}`,\n );\n\n // Send session init with the setup details\n sendSessionInit(\n sessionContext.sessionId,\n compiledSetup,\n sessionContext.accessToken,\n sessionContext.orgId,\n );\n\n logToFile('InitializeSession completed successfully');\n\n return {\n content: [\n {\n type: 'text',\n text: 'Session initialized successfully. You may now proceed to load documentation.',\n },\n ],\n };\n } catch (error) {\n // Log error but still return success to allow wizard to continue\n logToFile('Error in InitializeSession:', error);\n\n // Still send session init with minimal details\n sendSessionInit(\n sessionContext.sessionId,\n '',\n sessionContext.accessToken,\n sessionContext.orgId,\n );\n\n return {\n content: [\n {\n type: 'text',\n text: 'Session initialized with partial details. You may proceed to load documentation.',\n },\n ],\n };\n }\n },\n );\n\n return createSdkMcpServer({\n name: 'raindrop-wizard',\n version: '1.0.0',\n tools: [completionTool, loadDocumentationTool, initializeSessionTool],\n });\n}\n"]}
@@ -5,20 +5,59 @@
5
5
  import type { WizardOptions } from '../utils/types.js';
6
6
  import type { PendingToolCall } from './handlers.js';
7
7
  type SDKMessage = any;
8
+ /**
9
+ * Return canned error display text from error string (extracts optional status code).
10
+ */
11
+ export declare function getCannedErrorDisplayText(errorText: string): string;
8
12
  /**
9
13
  * Extract result summary from tool result content
10
14
  */
11
15
  export declare function extractResultSummary(toolName: string, resultContent: unknown, input?: Record<string, unknown>): string | undefined;
12
16
  /**
13
- * Context passed into processSDKMessage for spinner updates.
17
+ * Context passed into processSDKMessage for spinner updates and optional error reporting.
14
18
  */
15
19
  export interface SDKMessageContext {
16
20
  updateSpinner: (msg: string) => void;
17
21
  baseSpinnerMessage: string;
22
+ /** When set, errors (message.error) are reported to Slack with the agent run log path. */
23
+ onError?: {
24
+ wizardSessionId: string;
25
+ accessToken: string;
26
+ orgId: string;
27
+ /** Resolved absolute project path (e.g. /Users/.../project). */
28
+ workingDirectory: string;
29
+ };
30
+ /**
31
+ * Whether the most recently processed assistant message had any visible (text) content.
32
+ * Set by the caller from the return value of the previous processSDKMessage call.
33
+ * When false on a success result, we report to session/error and can queue a follow-up prompt.
34
+ */
35
+ lastAssistantHadVisibleContent?: boolean;
36
+ /**
37
+ * When set, used to queue a follow-up user message so the agent continues (e.g. after
38
+ * last assistant had only thinking content). The prompt async iterable will yield this
39
+ * and the agent will run another turn.
40
+ */
41
+ queueFollowUpPrompt?: (prompt: string) => void;
42
+ /**
43
+ * When true, the agent has already called CompleteIntegration and is transitioning to
44
+ * testing. Skip queuing [Wizard] Continue. since the testing phase will handle next steps.
45
+ */
46
+ hasCompletedWork?: boolean;
47
+ }
48
+ /**
49
+ * Return value from processSDKMessage when the message was an assistant message.
50
+ * Caller should pass lastAssistantHadVisibleContent back in context on the next call.
51
+ */
52
+ export interface ProcessSDKMessageResult {
53
+ lastAssistantHadVisibleContent?: boolean;
18
54
  }
19
55
  /**
20
56
  * Process SDK messages and provide user feedback.
21
57
  * Handles assistant text, tool use, tool results, and system messages.
58
+ * Returns lastAssistantHadVisibleContent when message type is 'assistant' so the caller
59
+ * can pass it back in context for the next call (used to show a fallback on success result
60
+ * when the last assistant had only thinking content).
22
61
  */
23
- export declare function processSDKMessage(message: SDKMessage, options: WizardOptions, collectedText: string[], pendingToolCalls: Map<string, PendingToolCall>, isInterrupting: boolean, context?: SDKMessageContext): void;
62
+ export declare function processSDKMessage(message: SDKMessage, options: WizardOptions, pendingToolCalls: Map<string, PendingToolCall>, isInterrupting: boolean, context?: SDKMessageContext): ProcessSDKMessageResult | void;
24
63
  export {};
@@ -4,20 +4,9 @@
4
4
  */
5
5
  import { createTwoFilesPatch } from 'diff';
6
6
  import { debug, logToFile } from '../utils/debug.js';
7
+ import { reportSessionError } from '../utils/session.js';
7
8
  import ui from '../utils/ui.js';
8
- /** Internal SDK tools that should not be stored/displayed in the UI */
9
- const INTERNAL_TOOL_NAMES = new Set([
10
- 'Task',
11
- 'AskUserQuestion',
12
- 'TodoWrite',
13
- 'EnterPlanMode',
14
- 'ExitPlanMode',
15
- ]);
16
- /** Prefix for MCP tools; all are internal (not shown in UI). Matches mcp__server__tool and mcp____... */
17
- const MCP_TOOL_PREFIX = 'mcp__';
18
- function isInternalTool(toolName) {
19
- return (INTERNAL_TOOL_NAMES.has(toolName) || toolName.startsWith(MCP_TOOL_PREFIX));
20
- }
9
+ import { ERROR_DISPLAY_MESSAGE, INTERNAL_TOOL_NAMES, MCP_TOOL_PREFIX, } from './constants.js';
21
10
  /**
22
11
  * Generate a unified diff for Edit tool inputs (old_string -> new_string)
23
12
  */
@@ -56,15 +45,28 @@ function extractWriteSummary(input) {
56
45
  const fileName = typeof input.path === 'string' ? input.path.split('/').pop() : 'file';
57
46
  return `Wrote ${lines} line${lines === 1 ? '' : 's'} to ${fileName}`;
58
47
  }
59
- /**
60
- * Generate diff content and file name for Edit/Write tools
61
- */
62
- function extractEditWriteInfo(toolName, input) {
63
- const fileName = typeof input.file_path === 'string'
48
+ function getToolFileName(input) {
49
+ return typeof input.file_path === 'string'
64
50
  ? input.file_path
65
51
  : typeof input.path === 'string'
66
52
  ? input.path
67
53
  : undefined;
54
+ }
55
+ function shouldHideToolCall(toolName, input) {
56
+ if (INTERNAL_TOOL_NAMES.has(toolName) || toolName.startsWith(MCP_TOOL_PREFIX)) {
57
+ return true;
58
+ }
59
+ if (toolName === 'Edit' || toolName === 'Write') {
60
+ const fileName = getToolFileName(input);
61
+ return Boolean(fileName && fileName.includes('plans/'));
62
+ }
63
+ return false;
64
+ }
65
+ /**
66
+ * Generate diff content and file name for Edit/Write tools
67
+ */
68
+ function extractEditWriteInfo(toolName, input) {
69
+ const fileName = getToolFileName(input);
68
70
  if (toolName === 'Edit' && fileName) {
69
71
  const oldString = typeof input.old_string === 'string' ? input.old_string : '';
70
72
  const newString = typeof input.new_string === 'string' ? input.new_string : '';
@@ -78,6 +80,15 @@ function extractEditWriteInfo(toolName, input) {
78
80
  }
79
81
  return {};
80
82
  }
83
+ /**
84
+ * Return canned error display text from error string (extracts optional status code).
85
+ */
86
+ export function getCannedErrorDisplayText(errorText) {
87
+ const codeMatch = errorText.match(/^Error:\s*(\d+)/i) ||
88
+ errorText.match(/^API Error:\s*(\d+)/i);
89
+ const code = codeMatch?.[1];
90
+ return ERROR_DISPLAY_MESSAGE(code);
91
+ }
81
92
  /**
82
93
  * Extract result summary from tool result content
83
94
  */
@@ -160,8 +171,11 @@ function getToolSpinnerMessage(toolName, input) {
160
171
  /**
161
172
  * Process SDK messages and provide user feedback.
162
173
  * Handles assistant text, tool use, tool results, and system messages.
174
+ * Returns lastAssistantHadVisibleContent when message type is 'assistant' so the caller
175
+ * can pass it back in context for the next call (used to show a fallback on success result
176
+ * when the last assistant had only thinking content).
163
177
  */
164
- export function processSDKMessage(message, options, collectedText, pendingToolCalls, isInterrupting, context) {
178
+ export function processSDKMessage(message, options, pendingToolCalls, isInterrupting, context) {
165
179
  logToFile(`SDK Message: ${message.type}`, JSON.stringify(message, null, 2));
166
180
  if (options.debug) {
167
181
  debug(`SDK Message type: ${message.type}`);
@@ -170,28 +184,38 @@ export function processSDKMessage(message, options, collectedText, pendingToolCa
170
184
  case 'assistant': {
171
185
  // Extract text content from assistant messages
172
186
  const content = message.message?.content;
187
+ let hadVisibleContent = false;
173
188
  if (Array.isArray(content)) {
174
189
  for (const block of content) {
175
190
  if (block.type === 'text' && typeof block.text === 'string') {
176
- collectedText.push(block.text);
177
- // Add agent message to history for visibility
191
+ hadVisibleContent = true;
192
+ // If message.error and text looks like an error, report to Slack; use canned text in UI only for "unknown".
193
+ const isError = message.error != null && /(API )?Error/i.test(block.text);
194
+ const displayText = isError && message.error === 'unknown'
195
+ ? getCannedErrorDisplayText(block.text)
196
+ : block.text;
197
+ if (isError && context?.onError && message.session_id) {
198
+ reportSessionError(block.text, message.session_id, context.onError);
199
+ }
178
200
  ui.addItem({
179
201
  type: 'agent-message',
180
- text: block.text,
202
+ text: displayText,
181
203
  });
182
204
  // Reset spinner after assistant responds — "Analysing" after "Perfect!" looks wrong
183
205
  if (context?.updateSpinner) {
184
206
  context.updateSpinner(context.baseSpinnerMessage);
185
207
  }
186
208
  }
187
- // Handle tool_use blocks - store pending, don't add to history yet
209
+ }
210
+ // Handle tool_use blocks - store pending, don't add to history yet
211
+ for (const block of content) {
188
212
  if (block.type === 'tool_use') {
189
213
  const toolName = block.name || 'Unknown tool';
190
- const toolInput = block.input || {};
214
+ const toolInput = (block.input || {});
191
215
  const toolUseId = block.id;
192
216
  logToFile(`Tool use requested: ${toolName} (id: ${toolUseId})`, toolInput);
193
- // Skip storing/displaying internal SDK tools (including all mcp__* tools)
194
- if (isInternalTool(toolName)) {
217
+ // Skip storing/displaying internal tools and plan-file edits
218
+ if (shouldHideToolCall(toolName, toolInput)) {
195
219
  continue;
196
220
  }
197
221
  // Show tool as executing immediately (pretooluse)
@@ -219,7 +243,7 @@ export function processSDKMessage(message, options, collectedText, pendingToolCa
219
243
  }
220
244
  }
221
245
  }
222
- break;
246
+ return { lastAssistantHadVisibleContent: hadVisibleContent };
223
247
  }
224
248
  case 'user': {
225
249
  // Tool results come as 'user' messages with tool_result content
@@ -238,12 +262,12 @@ export function processSDKMessage(message, options, collectedText, pendingToolCa
238
262
  const pendingCall = pendingToolCalls.get(toolUseId);
239
263
  if (pendingCall) {
240
264
  pendingToolCalls.delete(toolUseId);
241
- // Extract diff content and file name for Edit/Write tools
242
- const { diffContent, fileName } = extractEditWriteInfo(pendingCall.toolName, pendingCall.input);
243
- // Skip displaying tool calls for plan files
244
- if (fileName && fileName.includes('plans/')) {
265
+ // Skip displaying Edit/Write tool calls for plan files
266
+ if (shouldHideToolCall(pendingCall.toolName, pendingCall.input)) {
245
267
  continue;
246
268
  }
269
+ // Extract diff content and file name for Edit/Write tools
270
+ const { diffContent, fileName } = extractEditWriteInfo(pendingCall.toolName, pendingCall.input);
247
271
  // Extract result summary based on tool type
248
272
  const resultSummary = extractResultSummary(pendingCall.toolName, resultContent, pendingCall.input);
249
273
  // Update the existing 'executing' history item with the final result (posttooluse)
@@ -291,29 +315,53 @@ export function processSDKMessage(message, options, collectedText, pendingToolCa
291
315
  case 'result': {
292
316
  if (message.subtype === 'success') {
293
317
  logToFile('Agent completed successfully');
294
- if (typeof message.result === 'string') {
295
- collectedText.push(message.result);
296
- // Note: We intentionally don't display the result message here.
297
- // The SDK's result.result field contains the same text as the last
298
- // assistant message, which we already render above. Displaying both
299
- // would cause duplicate output in the UI.
318
+ // When the last assistant message had only thinking content, report to session/error
319
+ const lastHadVisible = context?.lastAssistantHadVisibleContent !== false;
320
+ if (!lastHadVisible &&
321
+ !isInterrupting &&
322
+ !context?.hasCompletedWork &&
323
+ context?.onError &&
324
+ message.session_id) {
325
+ ui.addItem({
326
+ type: 'agent-message',
327
+ text: "I'm still thinking. Thank you for your patience.",
328
+ });
329
+ reportSessionError('Last assistant message did not have a text response.', message.session_id, context.onError);
330
+ context.queueFollowUpPrompt?.('[Wizard] Continue.');
300
331
  }
301
332
  }
302
333
  else {
303
- // Error result - suppress if it's an interrupt-related error
334
+ // Error result - collect non-interrupt errors, report once to session/error, show first in UI when not interrupting
304
335
  logToFile('Agent error result:', message.subtype);
305
- if (message.errors && !isInterrupting) {
336
+ if (message.errors) {
337
+ const reportableErrors = [];
338
+ let isFirstError = true;
306
339
  for (const err of message.errors) {
307
- // Check if error is interrupt-related
308
340
  const errStr = String(err);
309
341
  const isInterruptError = errStr.includes('aborted') ||
310
342
  errStr.includes('interrupted') ||
311
343
  errStr.includes('403');
312
344
  if (!isInterruptError) {
313
- ui.addItem({ type: 'error', text: `Error: ${err}` });
345
+ reportableErrors.push(errStr);
346
+ if (!isInterrupting && isFirstError) {
347
+ ui.addItem({
348
+ type: 'error',
349
+ text: getCannedErrorDisplayText(errStr),
350
+ });
351
+ isFirstError = false;
352
+ }
314
353
  }
315
354
  logToFile('ERROR:', err);
316
355
  }
356
+ if (reportableErrors.length > 0 &&
357
+ context?.onError &&
358
+ message.session_id) {
359
+ // Send raw error text; session/error route adds "Customer got the following error:" and code block
360
+ const combinedMessage = reportableErrors.length === 1
361
+ ? reportableErrors[0]
362
+ : reportableErrors.join('\n\n');
363
+ reportSessionError(combinedMessage, message.session_id, context.onError);
364
+ }
317
365
  }
318
366
  }
319
367
  break;