@raindrop-ai/wizard 0.0.1 → 0.0.2

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 (71) hide show
  1. package/dist/src/docs/claude-agent-sdk.mdx +382 -0
  2. package/dist/src/docs/{typescript.md → typescript.mdx} +8 -4
  3. package/dist/src/docs/vercel-ai-sdk.mdx +769 -0
  4. package/dist/src/lib/agent-interface.d.ts +4 -3
  5. package/dist/src/lib/agent-interface.js +290 -197
  6. package/dist/src/lib/agent-interface.js.map +1 -1
  7. package/dist/src/lib/constants.d.ts +1 -0
  8. package/dist/src/lib/constants.js +1 -0
  9. package/dist/src/lib/constants.js.map +1 -1
  10. package/dist/src/lib/handlers.d.ts +16 -8
  11. package/dist/src/lib/handlers.js +232 -118
  12. package/dist/src/lib/handlers.js.map +1 -1
  13. package/dist/src/lib/integration-testing.d.ts +5 -5
  14. package/dist/src/lib/integration-testing.js +28 -12
  15. package/dist/src/lib/integration-testing.js.map +1 -1
  16. package/dist/src/lib/mcp.d.ts +1 -1
  17. package/dist/src/lib/mcp.js +88 -49
  18. package/dist/src/lib/mcp.js.map +1 -1
  19. package/dist/src/lib/sdk-messages.d.ts +8 -1
  20. package/dist/src/lib/sdk-messages.js +83 -27
  21. package/dist/src/lib/sdk-messages.js.map +1 -1
  22. package/dist/src/lib/wizard.js +16 -20
  23. package/dist/src/lib/wizard.js.map +1 -1
  24. package/dist/src/ui/App.d.ts +5 -4
  25. package/dist/src/ui/App.js +12 -12
  26. package/dist/src/ui/App.js.map +1 -1
  27. package/dist/src/ui/components/ClarifyingQuestionsPrompt.js +4 -2
  28. package/dist/src/ui/components/ClarifyingQuestionsPrompt.js.map +1 -1
  29. package/dist/src/ui/components/ContinuePrompt.d.ts +3 -2
  30. package/dist/src/ui/components/ContinuePrompt.js +4 -4
  31. package/dist/src/ui/components/ContinuePrompt.js.map +1 -1
  32. package/dist/src/ui/components/DiffDisplay.js +16 -6
  33. package/dist/src/ui/components/DiffDisplay.js.map +1 -1
  34. package/dist/src/ui/components/FeedbackSelectPrompt.js +6 -3
  35. package/dist/src/ui/components/FeedbackSelectPrompt.js.map +1 -1
  36. package/dist/src/ui/components/HistoryItemDisplay.d.ts +5 -3
  37. package/dist/src/ui/components/HistoryItemDisplay.js +10 -9
  38. package/dist/src/ui/components/HistoryItemDisplay.js.map +1 -1
  39. package/dist/src/ui/components/Logo.js +19 -34
  40. package/dist/src/ui/components/Logo.js.map +1 -1
  41. package/dist/src/ui/components/OrgInfoBox.d.ts +2 -1
  42. package/dist/src/ui/components/OrgInfoBox.js +2 -4
  43. package/dist/src/ui/components/OrgInfoBox.js.map +1 -1
  44. package/dist/src/ui/components/PersistentTextInput.js +13 -11
  45. package/dist/src/ui/components/PersistentTextInput.js.map +1 -1
  46. package/dist/src/ui/components/PromptContainer.js +4 -8
  47. package/dist/src/ui/components/PromptContainer.js.map +1 -1
  48. package/dist/src/ui/components/ToolApprovalPrompt.js +4 -4
  49. package/dist/src/ui/components/ToolApprovalPrompt.js.map +1 -1
  50. package/dist/src/ui/components/WriteKeyDisplay.d.ts +1 -1
  51. package/dist/src/ui/components/WriteKeyDisplay.js +1 -1
  52. package/dist/src/ui/components/WriteKeyDisplay.js.map +1 -1
  53. package/dist/src/ui/contexts/WizardContext.d.ts +13 -5
  54. package/dist/src/ui/contexts/WizardContext.js +60 -20
  55. package/dist/src/ui/contexts/WizardContext.js.map +1 -1
  56. package/dist/src/ui/render.js +49 -5
  57. package/dist/src/ui/render.js.map +1 -1
  58. package/dist/src/ui/types.d.ts +4 -2
  59. package/dist/src/ui/types.js.map +1 -1
  60. package/dist/src/utils/oauth.js +0 -4
  61. package/dist/src/utils/oauth.js.map +1 -1
  62. package/dist/src/utils/session.d.ts +1 -0
  63. package/dist/src/utils/session.js +40 -1
  64. package/dist/src/utils/session.js.map +1 -1
  65. package/dist/src/utils/ui.d.ts +7 -2
  66. package/dist/src/utils/ui.js +9 -2
  67. package/dist/src/utils/ui.js.map +1 -1
  68. package/package.json +2 -1
  69. package/dist/src/docs/vercel-ai-sdk.md +0 -304
  70. /package/dist/src/docs/{browser.md → browser.mdx} +0 -0
  71. /package/dist/src/docs/{python.md → python.mdx} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"agent-interface.js","sourceRoot":"","sources":["../../../src/lib/agent-interface.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Shared agent interface for wizards\n * Uses Claude Agent SDK directly with streaming input support\n */\n\nimport path from 'path';\nimport { createRequire } from 'module';\nimport ui from '../utils/ui.js';\nimport type { AgentQueryHandle } from '../ui/types.js';\nimport {\n debug,\n logToFile,\n initLogFile,\n LOG_FILE_PATH,\n} from '../utils/debug.js';\nimport {\n createCanUseToolHandler,\n createAgentQueryHandle,\n type PendingToolCall,\n type SessionInfo,\n} from './handlers.js';\nimport { processSDKMessage } from './sdk-messages.js';\nimport { createCompletionMcpServer } from './mcp.js';\nimport type { WizardOptions } from '../utils/types.js';\nimport { query } from '@anthropic-ai/claude-agent-sdk';\n\n// Create a require function for ESM compatibility\nconst require = createRequire(import.meta.url);\n\n/**\n * Get the path to the bundled Claude Code CLI from the SDK package.\n * This ensures we use the SDK's bundled version rather than the user's installed Claude Code.\n */\nfunction getClaudeCodeExecutablePath(): string {\n // require.resolve finds the package's main entry, then we get cli.js from same dir\n const sdkPackagePath = require.resolve('@anthropic-ai/claude-agent-sdk');\n return path.join(path.dirname(sdkPackagePath), 'cli.js');\n}\n\n// Re-export AgentQueryHandle for external use\nexport type { AgentQueryHandle };\n\nexport type AgentConfig = {\n workingDirectory: string;\n};\n\n/**\n * Result from runAgentLoop including session ID and query handle\n */\nexport interface AgentRunResult {\n sessionId?: string;\n handle: AgentQueryHandle;\n}\n\n/**\n * Internal configuration object returned by initializeAgent\n */\nexport type AgentRunConfig = {\n workingDirectory: string;\n model: string;\n};\n\n/**\n * Initialize agent configuration for the Claude agent\n */\nexport function initializeAgent(\n config: AgentConfig,\n options: WizardOptions,\n): AgentRunConfig {\n // Initialize log file for this run\n initLogFile();\n logToFile('Agent initialization starting');\n logToFile('Install directory:', options.installDir);\n\n try {\n process.env.CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS = 'true';\n // Set default subagent model to Sonnet\n process.env.CLAUDE_CODE_SUBAGENT_MODEL = 'claude-sonnet-4-5-20250929';\n\n const agentRunConfig: AgentRunConfig = {\n workingDirectory: config.workingDirectory,\n model: 'opus',\n };\n\n logToFile('Agent config:', {\n workingDirectory: agentRunConfig.workingDirectory,\n });\n\n if (options.debug) {\n debug('Agent config:', {\n workingDirectory: agentRunConfig.workingDirectory,\n });\n }\n\n ui.addItem({\n type: 'step',\n text: `I'll keep verbose logs for this session at: ${LOG_FILE_PATH}`,\n });\n return agentRunConfig;\n } catch (error) {\n ui.addItem({\n type: 'error',\n text: `Failed to initialize agent: ${(error as Error).message}`,\n });\n logToFile('Agent initialization error:', error);\n debug('Agent initialization error:', error);\n throw error;\n }\n}\n\n/**\n * Configuration for runAgentLoop\n */\nexport interface RunAgentConfig {\n spinnerMessage?: string;\n successMessage?: string;\n resume?: string;\n accessToken: string;\n orgId: string;\n}\n\n/**\n * Execute an agent with the provided prompt and options.\n * Supports streaming input for user interruption and follow-up messages.\n * Uses a while loop to handle user interactions instead of recursion.\n *\n * @returns Session ID and query handle for controlling the agent\n */\nexport async function runAgentLoop(\n agentConfig: AgentRunConfig,\n prompt: string,\n options: WizardOptions,\n config?: RunAgentConfig,\n): Promise<AgentRunResult> {\n const {\n spinnerMessage = 'Raindrop wizard is working...',\n successMessage = 'Raindrop integration complete',\n resume,\n accessToken,\n } = config ?? ({} as RunAgentConfig);\n\n // Add header to indicate start of interactive agent phase\n ui.addItem({ type: 'phase', text: '─── Agent ───' });\n\n const cliPath = getClaudeCodeExecutablePath();\n logToFile('Starting agent run');\n logToFile('Claude Code executable:', cliPath);\n\n // Loop-persistent state\n let currentPrompt = prompt;\n let currentSessionId: string | undefined = resume;\n let handle: AgentQueryHandle;\n\n // Cache for approved files (persists across all iterations)\n const approvedFilesCache = new Set<string>();\n\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const spinner = ui.spinner();\n\n logToFile('Prompt:', currentPrompt);\n if (currentSessionId) {\n logToFile('Resuming session:', currentSessionId);\n }\n\n // Timing and session state\n const startTime = Date.now();\n let sessionId: string | undefined = currentSessionId;\n let queryObject: any = null;\n\n // Message and tool call collectors\n const collectedText: string[] = [];\n const pendingToolCalls = new Map<string, PendingToolCall>();\n\n // Shared ref objects for cross-boundary state\n const hasCompletedWorkRef = { value: false };\n const isInterruptingRef = { value: false };\n const waitingForUserInputRef = { value: false };\n const pendingUserMessageRef = { value: null as string | null };\n const exitHintShownRef = { value: false };\n\n // Promise resolver for waiting on user input after interrupt\n let resolveUserMessage: ((message: string) => void) | null = null;\n\n // Query handle for external control (interrupt, etc.)\n handle = createAgentQueryHandle({\n isInterruptingRef,\n waitingForUserInputRef,\n pendingToolCalls,\n getQueryObject: () => queryObject,\n });\n\n // Create MCP server with CompleteIntegration tool\n const completionMcpServer = createCompletionMcpServer(\n hasCompletedWorkRef,\n {\n sessionId: options.sessionId,\n accessToken,\n orgId: config?.orgId ?? '',\n installDir: agentConfig.workingDirectory,\n },\n );\n\n // Define callbacks for persistent input\n const handlePersistentSubmit = (message: string) => {\n // Reset exit hint flag when user submits a message\n exitHintShownRef.value = false;\n\n if (isInterruptingRef.value) {\n // Already interrupted - resolve the waiting promise with this message\n logToFile('User submitted message after interrupt:', message);\n pendingUserMessageRef.value = message;\n if (resolveUserMessage) {\n resolveUserMessage(message);\n resolveUserMessage = null;\n }\n } else {\n // Not yet interrupted - store message and trigger interrupt\n pendingUserMessageRef.value = message;\n logToFile(\n 'User submitted message while agent running - triggering interrupt',\n );\n void handle.interrupt();\n }\n };\n\n const handlePersistentInterrupt = () => {\n logToFile('User requested interrupt (Esc)');\n // Stop spinner immediately - persistent input stays visible\n spinner.stop();\n void handle.interrupt();\n };\n\n const handlePersistentCtrlC = () => {\n logToFile('User pressed Ctrl+C');\n\n // If already interrupted and exit hint was shown, exit immediately\n if (\n (isInterruptingRef.value || waitingForUserInputRef.value) &&\n exitHintShownRef.value\n ) {\n logToFile('Second Ctrl+C - exiting');\n ui.stopPersistentInput();\n ui.exit();\n // Small delay to allow UI to clean up before exit\n setTimeout(() => process.exit(130), 100);\n return;\n }\n\n // If already interrupted but hint not shown yet, show hint and clear input\n if (isInterruptingRef.value || waitingForUserInputRef.value) {\n logToFile('First Ctrl+C while interrupted - showing exit hint');\n exitHintShownRef.value = true;\n\n // Clear the input and update placeholder with hint\n ui.stopPersistentInput();\n ui.startPersistentInput({\n onSubmit: handlePersistentSubmit,\n onInterrupt: handlePersistentInterrupt,\n onCtrlC: handlePersistentCtrlC,\n placeholder: 'Press Ctrl+C again to exit',\n });\n return;\n }\n\n // Not interrupted yet - treat as normal interrupt\n logToFile('First Ctrl+C - triggering interrupt');\n spinner.stop();\n void handle.interrupt();\n };\n\n spinner.start(spinnerMessage);\n ui.startPersistentInput({\n onSubmit: handlePersistentSubmit,\n onInterrupt: handlePersistentInterrupt,\n onCtrlC: handlePersistentCtrlC,\n });\n\n // Session info for notifications\n const sessionInfo: SessionInfo = {\n sessionId: options.sessionId,\n accessToken,\n orgId: config?.orgId ?? '',\n };\n\n queryObject = query({\n prompt: currentPrompt,\n options: {\n model: agentConfig.model,\n cwd: agentConfig.workingDirectory,\n permissionMode: 'default',\n mcpServers: {\n 'raindrop-wizard': completionMcpServer,\n },\n systemPrompt: '{WIZARD_SYSTEM_PROMPT}',\n env: { ...process.env },\n resume: currentSessionId,\n canUseTool: createCanUseToolHandler(sessionInfo, approvedFilesCache),\n stderr: (data: string) => {\n logToFile('CLI stderr:', data);\n if (options.debug) {\n debug('CLI stderr:', data);\n }\n },\n },\n });\n\n // Update agent state\n ui.setAgentState({\n isRunning: true,\n queryHandle: handle,\n });\n\n // Process the query stream\n for await (const message of queryObject) {\n // FIX: Check interrupt flag at start of each iteration\n // This handles the case where interrupt() was called before SDK initialized\n if (isInterruptingRef.value) {\n logToFile(\n 'Breaking out of for-await loop - interrupt flag set before SDK init',\n );\n // Capture session_id from init message if available before breaking\n if (message.session_id && !sessionId) {\n sessionId = message.session_id;\n ui.setAgentState({ sessionId });\n }\n break;\n }\n\n // Capture session_id from any message\n if (message.session_id && !sessionId) {\n sessionId = message.session_id;\n ui.setAgentState({ sessionId });\n }\n\n processSDKMessage(\n message,\n options,\n collectedText,\n pendingToolCalls,\n isInterruptingRef.value,\n );\n }\n\n const durationMs = Date.now() - startTime;\n logToFile(`Agent run completed in ${Math.round(durationMs / 1000)}s`);\n logToFile('Session ID for resuming:', sessionId);\n logToFile('Completion status:', hasCompletedWorkRef.value);\n\n // Check if we need user input to continue (either stream ended without completion or interrupted)\n const needsUserInput =\n !hasCompletedWorkRef.value && !waitingForUserInputRef.value && sessionId;\n const wasInterrupted = waitingForUserInputRef.value && sessionId;\n\n if (needsUserInput || wasInterrupted) {\n if (needsUserInput) {\n logToFile(\n 'Stream ended but agent has not called CompleteIntegration - waiting for user response',\n );\n } else {\n logToFile('Stream ended after interrupt, waiting for user input');\n }\n\n spinner.stop();\n ui.setAgentState({ isRunning: false });\n\n // Get the resume message - either from pending submit or wait for user to submit\n let userMessage: string;\n\n if (pendingUserMessageRef.value) {\n // Message was submitted during execution - use it directly\n userMessage = pendingUserMessageRef.value;\n pendingUserMessageRef.value = null; // Clear for next iteration\n logToFile('Using pending user message:', userMessage);\n } else {\n // No pending message - wait for user to submit via persistent input\n logToFile('Waiting for user to submit message via persistent input...');\n\n // Persistent input is already visible, spinner already stopped - just wait for user\n\n userMessage = await new Promise<string>((resolve) => {\n resolveUserMessage = resolve;\n });\n\n // Check if user cancelled (empty message from Esc)\n if (!userMessage) {\n logToFile('User cancelled input, ending session');\n ui.stopPersistentInput();\n return { sessionId, handle };\n }\n\n logToFile('Received user message from persistent input:', userMessage);\n }\n\n // Show user message in UI\n ui.addItem({\n type: 'user-message',\n text: userMessage,\n });\n\n // Update state for next iteration\n logToFile('Resuming agent with user message:', userMessage);\n currentPrompt = userMessage;\n currentSessionId = sessionId;\n continue;\n }\n\n // Normal completion - clean up and return\n ui.stopPersistentInput();\n ui.setAgentState({ isRunning: false });\n spinner.stop(successMessage);\n return { sessionId, handle };\n }\n}\n"]}
1
+ {"version":3,"file":"agent-interface.js","sourceRoot":"","sources":["../../../src/lib/agent-interface.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Shared agent interface for wizards\n * Uses Claude Agent SDK directly with streaming input support\n */\n\nimport { query, type SDKUserMessage } from '@anthropic-ai/claude-agent-sdk';\nimport { createRequire } from 'module';\nimport path from 'path';\nimport type { AgentQueryHandle } from '../ui/types.js';\nimport {\n debug,\n initLogFile,\n LOG_FILE_PATH,\n logToFile,\n} from '../utils/debug.js';\nimport type { WizardOptions } from '../utils/types.js';\nimport ui from '../utils/ui.js';\nimport {\n createAgentQueryHandle,\n createCanUseToolHandler,\n createPreToolUseHook,\n type PendingToolCall,\n type SessionInfo,\n} from './handlers.js';\nimport { createMcpServer } from './mcp.js';\nimport { processSDKMessage } from './sdk-messages.js';\n\n// Create a require function for ESM compatibility\nconst require = createRequire(import.meta.url);\n\n/**\n * Get the path to the bundled Claude Code CLI from the SDK package.\n * This ensures we use the SDK's bundled version rather than the user's installed Claude Code.\n */\nfunction getClaudeCodeExecutablePath(): string {\n // require.resolve finds the package's main entry, then we get cli.js from same dir\n const sdkPackagePath = require.resolve('@anthropic-ai/claude-agent-sdk');\n return path.join(path.dirname(sdkPackagePath), 'cli.js');\n}\n\n// Re-export AgentQueryHandle for external use\nexport type { AgentQueryHandle };\n\nexport type AgentConfig = {\n workingDirectory: string;\n};\n\n/**\n * Result from runAgentLoop including session ID and query handle\n */\nexport interface AgentRunResult {\n sessionId?: string;\n handle: AgentQueryHandle;\n completed: boolean;\n}\n\n/**\n * Internal configuration object returned by initializeAgent\n */\nexport type AgentRunConfig = {\n workingDirectory: string;\n model: string;\n};\n\ntype QueuedUserMessage = {\n type: 'user';\n message: {\n role: 'user';\n content: string;\n };\n};\n\ntype QueryMessage = {\n type?: string;\n session_id?: string;\n [key: string]: unknown;\n};\n\ntype QueryObject = AsyncIterable<QueryMessage> & {\n interrupt?: () => Promise<void>;\n};\n\n/**\n * Async queue for user messages.\n * Messages are pushed by UI callbacks and consumed by the SDK as an async iterable.\n */\nclass UserMessageQueue implements AsyncIterable<QueuedUserMessage> {\n private messages: QueuedUserMessage[] = [];\n\n private waitingResolver:\n | ((message: QueuedUserMessage | null) => void)\n | null = null;\n\n private closed = false;\n\n push(content: string): void {\n if (this.closed) {\n return;\n }\n\n const message: QueuedUserMessage = {\n type: 'user',\n message: {\n role: 'user',\n content,\n },\n };\n\n if (this.waitingResolver) {\n this.waitingResolver(message);\n this.waitingResolver = null;\n return;\n }\n\n this.messages.push(message);\n }\n\n hasPending(): boolean {\n return this.messages.length > 0;\n }\n\n close(): void {\n this.closed = true;\n if (this.waitingResolver) {\n this.waitingResolver(null);\n this.waitingResolver = null;\n }\n }\n\n async *[Symbol.asyncIterator](): AsyncIterableIterator<QueuedUserMessage> {\n while (!this.closed) {\n if (this.messages.length > 0) {\n const nextMessage = this.messages.shift();\n if (nextMessage) {\n yield nextMessage;\n }\n continue;\n }\n\n const nextMessage = await new Promise<QueuedUserMessage | null>(\n (resolve) => {\n this.waitingResolver = resolve;\n },\n );\n\n if (!nextMessage) {\n return;\n }\n\n yield nextMessage;\n }\n }\n}\n\n/**\n * Initialize agent configuration for the Claude agent\n */\nexport function initializeAgent(\n config: AgentConfig,\n options: WizardOptions,\n): AgentRunConfig {\n // Initialize log file for this run\n initLogFile();\n logToFile('Agent initialization starting');\n logToFile('Install directory:', options.installDir);\n\n try {\n process.env.MAX_THINKING_TOKENS = '10000';\n process.env.CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS = 'true';\n // Set default subagent model to Sonnet\n process.env.CLAUDE_CODE_SUBAGENT_MODEL = 'claude-sonnet-4-5-20250929';\n\n const agentRunConfig: AgentRunConfig = {\n workingDirectory: config.workingDirectory,\n model: 'sonnet',\n };\n\n logToFile('Agent config:', {\n workingDirectory: agentRunConfig.workingDirectory,\n });\n\n if (options.debug) {\n debug('Agent config:', {\n workingDirectory: agentRunConfig.workingDirectory,\n });\n }\n\n ui.addItem({\n type: 'step',\n text: `I'll keep verbose logs for this session at: ${LOG_FILE_PATH}`,\n });\n return agentRunConfig;\n } catch (error) {\n ui.addItem({\n type: 'error',\n text: `Failed to initialize agent: ${(error as Error).message}`,\n });\n logToFile('Agent initialization error:', error);\n debug('Agent initialization error:', error);\n throw error;\n }\n}\n\n/**\n * Configuration for runAgentLoop\n */\nexport interface RunAgentConfig {\n spinnerMessage?: string;\n successMessage?: string;\n accessToken: string;\n orgId: string;\n onCompleteIntegration?: () => Promise<boolean | string>;\n}\n\n/**\n * Execute an agent with the provided prompt and options.\n * Supports streaming input for user interruption and follow-up messages.\n * Uses a single long-lived SDK query fed by an async message queue.\n *\n * @returns Session ID and query handle for controlling the agent\n */\nexport async function runAgentLoop(\n agentConfig: AgentRunConfig,\n prompt: string,\n options: WizardOptions,\n config: RunAgentConfig,\n): Promise<AgentRunResult> {\n const {\n spinnerMessage = 'Raindrop wizard is working...',\n successMessage = 'Raindrop integration complete',\n accessToken,\n orgId,\n onCompleteIntegration,\n } = config;\n\n // Add header to indicate start of interactive agent phase\n ui.addItem({ type: 'phase', text: '─── Agent ───' });\n\n const cliPath = getClaudeCodeExecutablePath();\n logToFile('Starting agent run');\n logToFile('Claude Code executable:', cliPath);\n\n const startTime = Date.now();\n const inputQueue = new UserMessageQueue();\n inputQueue.push(prompt);\n\n const approvedFilesCache = new Set<string>();\n const collectedText: string[] = [];\n const pendingToolCalls = new Map<string, PendingToolCall>();\n\n const hasCompletedWorkRef = { value: false };\n const isInterruptingRef = { value: false };\n const waitingForUserInputRef = { value: false };\n const exitHintShownRef = { value: false };\n\n let sessionId: string | undefined;\n let queryObject: QueryObject | null = null;\n let isSpinnerRunning = false;\n let completed = false;\n let shouldEndSession = false;\n\n const spinner = ui.spinner();\n\n // Track current spinner base message and when it last changed.\n let currentSpinnerMsg = spinnerMessage;\n let lastActivityTime = Date.now();\n\n const updateSpinner = (msg: string) => {\n if (!isSpinnerRunning) return;\n currentSpinnerMsg = msg;\n lastActivityTime = Date.now();\n spinner.message(msg);\n };\n\n // Every second, if the agent has been silent for >= 10s, append a counting thinking indicator.\n // Pure JS interval — Ink only re-renders when the string actually changes.\n const thinkingTimer = setInterval(() => {\n if (!isSpinnerRunning) return;\n const idleS = Math.floor((Date.now() - lastActivityTime) / 1000);\n if (idleS >= 20) {\n const mins = Math.floor(idleS / 60);\n const secs = idleS % 60;\n const timeStr = mins > 0 ? `${mins}m ${secs}s` : `${secs}s`;\n spinner.message(`${currentSpinnerMsg} (thinking · ${timeStr})`);\n }\n }, 1000);\n\n const setAgentRunning = (isRunning: boolean) => {\n if (isRunning) {\n if (!isSpinnerRunning) {\n spinner.start(spinnerMessage);\n isSpinnerRunning = true;\n }\n ui.setAgentState({ isRunning: true });\n return;\n }\n\n if (isSpinnerRunning) {\n spinner.stop();\n isSpinnerRunning = false;\n }\n ui.setAgentState({ isRunning: false });\n };\n\n // Create MCP server with CompleteIntegration tool\n const toolsMcpServer = createMcpServer(hasCompletedWorkRef, {\n sessionId: options.sessionId,\n accessToken,\n orgId,\n installDir: agentConfig.workingDirectory,\n });\n\n // Session info for notifications\n const sessionInfo: SessionInfo = {\n sessionId: options.sessionId,\n accessToken,\n orgId,\n };\n\n const handle = createAgentQueryHandle({\n isInterruptingRef,\n waitingForUserInputRef,\n pendingToolCalls,\n getQueryObject: () => queryObject,\n sendMessage: (message: string) => {\n inputQueue.push(message);\n },\n });\n\n const startPersistentInput = (placeholder?: string) => {\n ui.startPersistentInput({\n onSubmit: handlePersistentSubmit,\n onInterrupt: handlePersistentInterrupt,\n onCtrlC: handlePersistentCtrlC,\n placeholder,\n });\n };\n\n // Define callbacks for persistent input\n const handlePersistentSubmit = (message: string) => {\n const trimmedMessage = message.trim();\n if (!trimmedMessage) {\n return;\n }\n\n exitHintShownRef.value = false;\n\n ui.addItem({\n type: 'user-message',\n text: trimmedMessage,\n });\n\n handle.sendMessage(trimmedMessage);\n\n if (waitingForUserInputRef.value) {\n waitingForUserInputRef.value = false;\n isInterruptingRef.value = false;\n setAgentRunning(true);\n return;\n }\n\n if (!isInterruptingRef.value) {\n logToFile(\n 'User submitted message while agent is running - interrupting current turn',\n );\n void handle.interrupt(true);\n }\n };\n\n const handlePersistentInterrupt = () => {\n logToFile('User requested interrupt (Esc)');\n setAgentRunning(false);\n void handle.interrupt();\n };\n\n const handlePersistentCtrlC = () => {\n logToFile('User pressed Ctrl+C');\n\n // If already interrupted and exit hint was shown, exit immediately\n if (\n (isInterruptingRef.value || waitingForUserInputRef.value) &&\n exitHintShownRef.value\n ) {\n logToFile('Second Ctrl+C - exiting');\n ui.stopPersistentInput();\n ui.exit();\n // Small delay to allow UI to clean up before exit\n setTimeout(() => process.exit(130), 100);\n return;\n }\n\n // If already interrupted but hint not shown yet, show hint and clear input\n if (isInterruptingRef.value || waitingForUserInputRef.value) {\n logToFile('First Ctrl+C while interrupted - showing exit hint');\n exitHintShownRef.value = true;\n ui.stopPersistentInput();\n startPersistentInput('Press Ctrl+C again to exit');\n return;\n }\n\n // Not interrupted yet - treat as normal interrupt\n logToFile('First Ctrl+C - triggering interrupt');\n setAgentRunning(false);\n void handle.interrupt();\n };\n\n startPersistentInput();\n setAgentRunning(true);\n\n queryObject = query({\n prompt: inputQueue as unknown as AsyncIterable<SDKUserMessage>,\n options: {\n model: agentConfig.model,\n cwd: agentConfig.workingDirectory,\n permissionMode: 'default',\n mcpServers: {\n 'raindrop-wizard': toolsMcpServer,\n },\n systemPrompt: '{WIZARD_SYSTEM_PROMPT}',\n env: { ...process.env },\n canUseTool: createCanUseToolHandler(approvedFilesCache),\n hooks: {\n PreToolUse: [{ hooks: [createPreToolUseHook(sessionInfo)] }],\n },\n stderr: (data: string) => {\n logToFile('CLI stderr:', data);\n if (options.debug) {\n debug('CLI stderr:', data);\n }\n },\n },\n }) as QueryObject;\n\n // Update agent state\n ui.setAgentState({\n isRunning: true,\n queryHandle: handle,\n });\n\n try {\n for await (const message of queryObject) {\n // Capture session_id from any message\n if (message.session_id && !sessionId) {\n sessionId = message.session_id;\n ui.setAgentState({ sessionId });\n }\n\n // If we were waiting for user input but got a new message,\n // the queued message has started processing.\n if (\n waitingForUserInputRef.value &&\n !isInterruptingRef.value &&\n message.type !== 'result'\n ) {\n waitingForUserInputRef.value = false;\n isInterruptingRef.value = false;\n setAgentRunning(true);\n }\n\n processSDKMessage(\n message,\n options,\n collectedText,\n pendingToolCalls,\n isInterruptingRef.value,\n { updateSpinner, baseSpinnerMessage: spinnerMessage },\n );\n\n if (message.type !== 'result') {\n continue;\n }\n\n if (hasCompletedWorkRef.value) {\n setAgentRunning(false);\n ui.stopPersistentInput();\n\n const completionDecision = onCompleteIntegration\n ? await onCompleteIntegration()\n : true;\n\n if (typeof completionDecision === 'string') {\n const feedbackPrompt = completionDecision.trim();\n if (!feedbackPrompt) {\n logToFile('Received empty feedback prompt - ending session');\n completed = false;\n shouldEndSession = true;\n inputQueue.close();\n break;\n }\n\n logToFile('Received testing feedback - queueing feedback prompt');\n hasCompletedWorkRef.value = false;\n waitingForUserInputRef.value = false;\n isInterruptingRef.value = false;\n handle.sendMessage(feedbackPrompt);\n startPersistentInput();\n setAgentRunning(true);\n continue;\n }\n\n completed = completionDecision;\n shouldEndSession = true;\n inputQueue.close();\n break;\n }\n\n // Turn ended without completion. If there are no queued messages,\n // we are waiting for the user to submit the next one.\n isInterruptingRef.value = false;\n\n if (!inputQueue.hasPending()) {\n waitingForUserInputRef.value = true;\n setAgentRunning(false);\n } else {\n waitingForUserInputRef.value = false;\n setAgentRunning(true);\n }\n }\n } finally {\n inputQueue.close();\n clearInterval(thinkingTimer);\n }\n\n const durationMs = Date.now() - startTime;\n logToFile(`Agent session completed in ${Math.round(durationMs / 1000)}s`);\n logToFile('Session ID:', sessionId);\n logToFile('Completion status:', hasCompletedWorkRef.value);\n\n if (!shouldEndSession && hasCompletedWorkRef.value) {\n // Fallback: if stream ended after completion, mark as completed.\n completed = true;\n }\n\n ui.stopPersistentInput();\n ui.setAgentState({ isRunning: false });\n\n if (completed) {\n spinner.stop(successMessage);\n } else if (isSpinnerRunning) {\n spinner.stop();\n }\n\n return { sessionId, handle, completed };\n}\n"]}
@@ -14,6 +14,7 @@ export declare const EVENTS_LIST_ENDPOINT = "https://api.dawnai.com/api/cli/even
14
14
  export declare const ANTHROPIC_BASE_URL = "https://api.dawnai.com/api/cli";
15
15
  export declare const SESSION_START_ENDPOINT = "https://api.dawnai.com/api/cli/session/init";
16
16
  export declare const SESSION_UPDATE_ENDPOINT = "https://api.dawnai.com/api/cli/session/update";
17
+ export declare const SESSION_COMPLETE_ENDPOINT = "https://api.dawnai.com/api/cli/session/complete";
17
18
  /**
18
19
  * Spinner message shown during wizard execution
19
20
  */
@@ -31,6 +31,7 @@ export const EVENTS_LIST_ENDPOINT = `${API_BASE_URL}/api/cli/events/list`;
31
31
  export const ANTHROPIC_BASE_URL = `${API_BASE_URL}/api/cli`;
32
32
  export const SESSION_START_ENDPOINT = `${API_BASE_URL}/api/cli/session/init`;
33
33
  export const SESSION_UPDATE_ENDPOINT = `${API_BASE_URL}/api/cli/session/update`;
34
+ export const SESSION_COMPLETE_ENDPOINT = `${API_BASE_URL}/api/cli/session/complete`;
34
35
  /**
35
36
  * Spinner message shown during wizard execution
36
37
  */
@@ -1 +1 @@
1
- {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../src/lib/constants.ts"],"names":[],"mappings":"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","sourcesContent":["export enum Integration {\n python = 'python',\n typescript = 'typescript',\n vercelAiSdk = 'vercel-ai-sdk',\n}\n\nexport function getIntegrationDescription(type: string): string {\n switch (type) {\n case Integration.python:\n return 'a Python SDK';\n case Integration.typescript:\n return 'a TypeScript SDK';\n case Integration.vercelAiSdk:\n return 'the Vercel AI SDK';\n default:\n throw new Error(`Unknown integration ${type}`);\n }\n}\n\nexport const IS_DEV = ['test', 'development'].includes(\n process.env.NODE_ENV ?? '',\n);\n\nexport const ISSUES_URL = 'https://github.com/raindrop/wizard/issues';\n\nexport const CALLBACK_PORT = 8259;\nconst RAINDROP_APP_URL = 'https://app.raindrop.ai';\nconst RAINDROP_API_URL = 'https://api.dawnai.com';\nexport const API_BASE_URL = RAINDROP_API_URL;\nexport const APP_URL = RAINDROP_APP_URL;\n// For local dev:\n// export const API_BASE_URL = 'http://localhost:3000';\n// export const APP_URL = 'http://localhost:5173';\nexport const WRITE_KEY_ENDPOINT = `${API_BASE_URL}/api/cli/users/key`;\nexport const EVENTS_LIST_ENDPOINT = `${API_BASE_URL}/api/cli/events/list`;\nexport const ANTHROPIC_BASE_URL = `${API_BASE_URL}/api/cli`;\nexport const SESSION_START_ENDPOINT = `${API_BASE_URL}/api/cli/session/init`;\nexport const SESSION_UPDATE_ENDPOINT = `${API_BASE_URL}/api/cli/session/update`;\n\n/**\n * Spinner message shown during wizard execution\n */\nexport const SPINNER_MESSAGE = 'Raindrop wizard is working...';\n\n/**\n * Safe bash command patterns that can be auto-approved without user confirmation.\n * Uses simple prefix matching with optional * wildcard at the end.\n *\n * NOTE: Package manager install/build/run commands are NOT auto-approved and require user confirmation.\n */\nexport const SAFE_BASH_PATTERNS: string[] = [\n // === Package Managers - Read-only commands ===\n 'npm ls*',\n 'npm outdated*',\n 'npm audit*',\n\n 'pip list*',\n 'pip show*',\n 'pip freeze*',\n\n 'poetry show*',\n\n 'uv pip list*',\n\n 'cargo check*',\n 'cargo clippy*',\n 'cargo fmt*',\n\n 'go fmt*',\n\n // === Type Checking / Linting / Formatting ===\n 'tsc*',\n 'eslint *',\n 'prettier *',\n 'biome *',\n 'mypy *',\n 'python -m mypy*',\n 'ruff *',\n 'black *',\n 'flake8 *',\n 'pylint *',\n 'pyright*',\n 'rubocop*',\n 'rustfmt*',\n 'gofmt*',\n 'swiftlint*',\n 'ktlint*',\n\n // === Build Tools ===\n 'make',\n 'make build*',\n 'make test*',\n 'make lint*',\n 'make check*',\n 'cmake *',\n 'gradle build*',\n 'gradle test*',\n './gradlew build*',\n './gradlew test*',\n 'mvn compile*',\n 'mvn test*',\n 'mvn package*',\n\n // === Testing ===\n 'jest*',\n 'vitest*',\n 'mocha*',\n 'pytest*',\n 'python -m pytest*',\n 'npx playwright test*',\n 'npx cypress run*',\n 'npx jest*',\n 'npx vitest*',\n\n // === Git (read-only operations) ===\n 'git status*',\n 'git diff*',\n 'git log*',\n 'git show*',\n 'git branch*',\n 'git fetch*',\n 'git remote -v*',\n 'git ls-files*',\n 'git rev-parse*',\n\n // === File/Directory Info (read-only) ===\n 'ls *',\n 'ls',\n 'cat *',\n 'head *',\n 'tail *',\n 'less *',\n 'find *',\n 'grep *',\n 'rg *',\n 'ag *',\n 'tree*',\n 'pwd',\n 'wc *',\n 'file *',\n 'stat *',\n 'du *',\n 'df *',\n\n // === Environment/System Info ===\n 'which *',\n 'whereis *',\n 'type *',\n 'command -v *',\n 'node --version*',\n 'node -v*',\n 'npm --version*',\n 'npm -v*',\n 'python --version*',\n 'python -V*',\n 'python3 --version*',\n '*--version',\n '*-v',\n '*-V',\n 'env',\n 'printenv*',\n 'echo *',\n 'uname*',\n 'hostname',\n 'whoami',\n 'date',\n 'uptime',\n\n // === Docker (read-only / safe) ===\n 'docker ps*',\n 'docker images*',\n 'docker logs*',\n 'docker inspect*',\n 'docker-compose ps*',\n 'docker-compose logs*',\n 'docker build*',\n 'docker compose build*',\n 'docker compose up*',\n\n // === Directory Navigation ===\n 'cd *',\n 'pushd *',\n 'popd',\n];\n"]}
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../src/lib/constants.ts"],"names":[],"mappings":"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","sourcesContent":["export enum Integration {\n python = 'python',\n typescript = 'typescript',\n vercelAiSdk = 'vercel-ai-sdk',\n}\n\nexport function getIntegrationDescription(type: string): string {\n switch (type) {\n case Integration.python:\n return 'a Python SDK';\n case Integration.typescript:\n return 'a TypeScript SDK';\n case Integration.vercelAiSdk:\n return 'the Vercel AI SDK';\n default:\n throw new Error(`Unknown integration ${type}`);\n }\n}\n\nexport const IS_DEV = ['test', 'development'].includes(\n process.env.NODE_ENV ?? '',\n);\n\nexport const ISSUES_URL = 'https://github.com/raindrop/wizard/issues';\n\nexport const CALLBACK_PORT = 8259;\nconst RAINDROP_APP_URL = 'https://app.raindrop.ai';\nconst RAINDROP_API_URL = 'https://api.dawnai.com';\nexport const API_BASE_URL = RAINDROP_API_URL;\nexport const APP_URL = RAINDROP_APP_URL;\n// For local dev:\n// export const API_BASE_URL = 'http://localhost:3000';\n// export const APP_URL = 'http://localhost:5173';\nexport const WRITE_KEY_ENDPOINT = `${API_BASE_URL}/api/cli/users/key`;\nexport const EVENTS_LIST_ENDPOINT = `${API_BASE_URL}/api/cli/events/list`;\nexport const ANTHROPIC_BASE_URL = `${API_BASE_URL}/api/cli`;\nexport const SESSION_START_ENDPOINT = `${API_BASE_URL}/api/cli/session/init`;\nexport const SESSION_UPDATE_ENDPOINT = `${API_BASE_URL}/api/cli/session/update`;\nexport const SESSION_COMPLETE_ENDPOINT = `${API_BASE_URL}/api/cli/session/complete`;\n\n/**\n * Spinner message shown during wizard execution\n */\nexport const SPINNER_MESSAGE = 'Raindrop wizard is working...';\n\n/**\n * Safe bash command patterns that can be auto-approved without user confirmation.\n * Uses simple prefix matching with optional * wildcard at the end.\n *\n * NOTE: Package manager install/build/run commands are NOT auto-approved and require user confirmation.\n */\nexport const SAFE_BASH_PATTERNS: string[] = [\n // === Package Managers - Read-only commands ===\n 'npm ls*',\n 'npm outdated*',\n 'npm audit*',\n\n 'pip list*',\n 'pip show*',\n 'pip freeze*',\n\n 'poetry show*',\n\n 'uv pip list*',\n\n 'cargo check*',\n 'cargo clippy*',\n 'cargo fmt*',\n\n 'go fmt*',\n\n // === Type Checking / Linting / Formatting ===\n 'tsc*',\n 'eslint *',\n 'prettier *',\n 'biome *',\n 'mypy *',\n 'python -m mypy*',\n 'ruff *',\n 'black *',\n 'flake8 *',\n 'pylint *',\n 'pyright*',\n 'rubocop*',\n 'rustfmt*',\n 'gofmt*',\n 'swiftlint*',\n 'ktlint*',\n\n // === Build Tools ===\n 'make',\n 'make build*',\n 'make test*',\n 'make lint*',\n 'make check*',\n 'cmake *',\n 'gradle build*',\n 'gradle test*',\n './gradlew build*',\n './gradlew test*',\n 'mvn compile*',\n 'mvn test*',\n 'mvn package*',\n\n // === Testing ===\n 'jest*',\n 'vitest*',\n 'mocha*',\n 'pytest*',\n 'python -m pytest*',\n 'npx playwright test*',\n 'npx cypress run*',\n 'npx jest*',\n 'npx vitest*',\n\n // === Git (read-only operations) ===\n 'git status*',\n 'git diff*',\n 'git log*',\n 'git show*',\n 'git branch*',\n 'git fetch*',\n 'git remote -v*',\n 'git ls-files*',\n 'git rev-parse*',\n\n // === File/Directory Info (read-only) ===\n 'ls *',\n 'ls',\n 'cat *',\n 'head *',\n 'tail *',\n 'less *',\n 'find *',\n 'grep *',\n 'rg *',\n 'ag *',\n 'tree*',\n 'pwd',\n 'wc *',\n 'file *',\n 'stat *',\n 'du *',\n 'df *',\n\n // === Environment/System Info ===\n 'which *',\n 'whereis *',\n 'type *',\n 'command -v *',\n 'node --version*',\n 'node -v*',\n 'npm --version*',\n 'npm -v*',\n 'python --version*',\n 'python -V*',\n 'python3 --version*',\n '*--version',\n '*-v',\n '*-V',\n 'env',\n 'printenv*',\n 'echo *',\n 'uname*',\n 'hostname',\n 'whoami',\n 'date',\n 'uptime',\n\n // === Docker (read-only / safe) ===\n 'docker ps*',\n 'docker images*',\n 'docker logs*',\n 'docker inspect*',\n 'docker-compose ps*',\n 'docker-compose logs*',\n 'docker build*',\n 'docker compose build*',\n 'docker compose up*',\n\n // === Directory Navigation ===\n 'cd *',\n 'pushd *',\n 'popd',\n];\n"]}
@@ -2,7 +2,8 @@
2
2
  * Tool approval handlers for the Claude agent
3
3
  * Handles UI integration for tool approvals and clarifying questions
4
4
  */
5
- import type { ToolApprovalResult, AgentQueryHandle } from '../ui/types.js';
5
+ import type { HookInput, HookJSONOutput } from '@anthropic-ai/claude-agent-sdk';
6
+ import type { AgentQueryHandle, ToolApprovalResult } from '../ui/types.js';
6
7
  /**
7
8
  * Clear all session-wide file approvals.
8
9
  * Useful when starting a new session or resetting permissions.
@@ -28,6 +29,8 @@ export interface PendingToolCall {
28
29
  toolName: string;
29
30
  input: Record<string, unknown>;
30
31
  description?: string;
32
+ /** ID of the 'executing' history item, used to update it on completion/interrupt */
33
+ historyItemId?: number;
31
34
  }
32
35
  /**
33
36
  * Dependencies required for creating an AgentQueryHandle
@@ -43,6 +46,7 @@ export interface AgentQueryHandleDeps {
43
46
  getQueryObject: () => {
44
47
  interrupt?: () => Promise<void>;
45
48
  } | null;
49
+ sendMessage: (message: string) => void;
46
50
  }
47
51
  /**
48
52
  * Create an AgentQueryHandle for external control of the agent.
@@ -58,11 +62,15 @@ export interface SessionInfo {
58
62
  orgId: string;
59
63
  }
60
64
  /**
61
- * Create a canUseTool handler that integrates with the UI for approvals.
62
- * - Handles AskUserQuestion by showing clarifying questions UI
63
- * - Handles ExitPlanMode by showing plan approval UI
64
- * - Handles WebSearch by restricting to allowed domains
65
- * - Shows approval UI for other tools
66
- * - Supports caching file approvals for "allow all edits to this file"
65
+ * PreToolUse hook that handles all silent auto-approve/deny decisions.
66
+ * Fires for every tool call before canUseTool, so this is the right place
67
+ * for decisions that don't require user interaction.
68
+ * Returns { continue: true } for tools that need canUseTool (UI interaction).
67
69
  */
68
- export declare function createCanUseToolHandler(sessionInfo?: SessionInfo, approvedFilesCache?: Set<string>): (toolName: string, input: unknown) => Promise<ToolApprovalResult>;
70
+ export declare function createPreToolUseHook(sessionInfo?: SessionInfo): (input: HookInput) => Promise<HookJSONOutput>;
71
+ /**
72
+ * Create a canUseTool handler for tools that require user interaction.
73
+ * Auto-approve/deny logic lives in createPreToolUseHook instead.
74
+ * This handler is only reached for tools that PreToolUse passes through.
75
+ */
76
+ export declare function createCanUseToolHandler(approvedFilesCache?: Set<string>): (toolName: string, input: unknown) => Promise<ToolApprovalResult>;
@@ -2,11 +2,11 @@
2
2
  * Tool approval handlers for the Claude agent
3
3
  * Handles UI integration for tool approvals and clarifying questions
4
4
  */
5
- import ui from '../utils/ui.js';
6
- import { logToFile } from '../utils/debug.js';
7
5
  import { createTwoFilesPatch } from 'diff';
8
- import { SAFE_BASH_PATTERNS } from './constants.js';
6
+ import { logToFile } from '../utils/debug.js';
9
7
  import { sendSessionUpdate } from '../utils/session.js';
8
+ import ui from '../utils/ui.js';
9
+ import { SAFE_BASH_PATTERNS } from './constants.js';
10
10
  // ============================================================================
11
11
  // Session-wide Approval Tracking
12
12
  // ============================================================================
@@ -84,9 +84,9 @@ function isCommandApprovedForSession(command) {
84
84
  * Handles interrupts by marking pending tool calls (keeps persistent input running).
85
85
  */
86
86
  export function createAgentQueryHandle(deps) {
87
- const { isInterruptingRef, waitingForUserInputRef, pendingToolCalls, getQueryObject, } = deps;
87
+ const { isInterruptingRef, waitingForUserInputRef, pendingToolCalls, getQueryObject, sendMessage, } = deps;
88
88
  return {
89
- interrupt: async () => {
89
+ interrupt: async (fromUserMessage) => {
90
90
  logToFile('Soft interrupt requested (Esc)');
91
91
  // If already interrupted, don't add another "Interrupted" item
92
92
  if (isInterruptingRef.value || waitingForUserInputRef.value) {
@@ -98,21 +98,31 @@ export function createAgentQueryHandle(deps) {
98
98
  // Mark all pending tool calls as interrupted and show them in history
99
99
  if (pendingToolCalls.size > 0) {
100
100
  for (const [toolUseId, pendingCall] of pendingToolCalls) {
101
- ui.addItem({
102
- type: 'tool-call',
103
- text: pendingCall.toolName,
104
- toolCall: {
105
- toolName: pendingCall.toolName,
106
- status: 'interrupted',
107
- input: pendingCall.input,
108
- description: pendingCall.description,
109
- },
110
- });
101
+ const interruptedToolCall = {
102
+ toolName: pendingCall.toolName,
103
+ status: 'interrupted',
104
+ input: pendingCall.input,
105
+ description: pendingCall.description,
106
+ };
107
+ if (pendingCall.historyItemId !== undefined) {
108
+ ui.updateItem(pendingCall.historyItemId, {
109
+ type: 'tool-call',
110
+ text: pendingCall.toolName,
111
+ toolCall: interruptedToolCall,
112
+ });
113
+ }
114
+ else {
115
+ ui.addItem({
116
+ type: 'tool-call',
117
+ text: pendingCall.toolName,
118
+ toolCall: interruptedToolCall,
119
+ });
120
+ }
111
121
  pendingToolCalls.delete(toolUseId);
112
122
  }
113
123
  }
114
- else {
115
- // Only show generic "Interrupted" if no pending tool calls to display
124
+ else if (!fromUserMessage) {
125
+ // No pending tool calls and not interrupted by a user message - show generic indicator
116
126
  ui.addItem({
117
127
  type: 'error',
118
128
  text: 'Interrupted',
@@ -131,9 +141,13 @@ export function createAgentQueryHandle(deps) {
131
141
  logToFile('No queryObject.interrupt available');
132
142
  }
133
143
  },
134
- sendMessage: () => {
135
- // No-op: use interrupt + resume pattern instead of streaming messages
136
- logToFile('sendMessage called but not supported - use interrupt and resume');
144
+ sendMessage: (message) => {
145
+ const trimmedMessage = message.trim();
146
+ if (!trimmedMessage) {
147
+ return;
148
+ }
149
+ logToFile('Queueing user message for active session');
150
+ sendMessage(trimmedMessage);
137
151
  },
138
152
  };
139
153
  }
@@ -205,7 +219,9 @@ async function handleToolApproval(toolName, input, approvedFilesCache) {
205
219
  const result = await ui.toolApproval(props);
206
220
  logToFile('Tool approval result:', result);
207
221
  // If user chose "allow all edits to this file", add to both caches
208
- if (result.behavior === 'allow' && 'allowAllForFile' in result && result.allowAllForFile) {
222
+ if (result.behavior === 'allow' &&
223
+ 'allowAllForFile' in result &&
224
+ result.allowAllForFile) {
209
225
  approvedFilesForSession.add(result.allowAllForFile);
210
226
  logToFile('Added file to approved list:', result.allowAllForFile);
211
227
  }
@@ -276,53 +292,204 @@ async function handleClarifyingQuestions(input) {
276
292
  async function handlePlanApproval(input, sessionInfo) {
277
293
  logToFile('Handling ExitPlanMode:', input);
278
294
  const planContent = typeof input.plan === 'string' ? input.plan : '';
279
- // Stop spinner while waiting for user approval
280
- const spinner = ui.spinner();
281
- spinner.stop();
282
- try {
283
- const result = await ui.planApproval({ planContent });
284
- logToFile('Plan approval result:', result);
285
- // Restart spinner after user responds
286
- spinner.start();
287
- if (result.approved) {
288
- // Send session update with approved plan
289
- if (sessionInfo) {
290
- sendSessionUpdate(sessionInfo.sessionId, planContent, sessionInfo.accessToken, sessionInfo.orgId);
291
- }
292
- // User approved the plan - allow the tool
293
- return {
294
- behavior: 'allow',
295
- updatedInput: input,
296
- };
297
- }
298
- else {
299
- // User rejected with feedback - deny the tool
300
- return {
301
- behavior: 'deny',
302
- message: result.feedback || 'User rejected plan',
303
- };
304
- }
305
- }
306
- catch (error) {
307
- logToFile('Error in plan approval:', error);
308
- return {
309
- behavior: 'deny',
310
- message: 'Failed to get user response',
311
- };
295
+ // Send session update with plan content
296
+ if (sessionInfo) {
297
+ sendSessionUpdate(sessionInfo.sessionId, planContent, sessionInfo.accessToken, sessionInfo.orgId);
312
298
  }
299
+ return {
300
+ behavior: 'allow',
301
+ updatedInput: input,
302
+ };
313
303
  }
314
304
  /**
315
305
  * Tools that are automatically approved without user confirmation
316
306
  */
317
307
  const AUTO_APPROVED_TOOLS = new Set([
318
308
  'mcp__raindrop-wizard__CompleteIntegration',
319
- 'mcp__raindrop-wizard__LoadPythonDocumentation',
320
- 'mcp__raindrop-wizard__LoadTypeScriptDocumentation',
321
- 'mcp__raindrop-wizard__LoadVercelAiSdkDocumentation',
322
- 'mcp__raindrop-wizard__LoadBrowserDocumentation',
309
+ 'mcp__raindrop-wizard__LoadDocumentation',
323
310
  'mcp__raindrop-wizard__InitializeSession',
324
311
  'EnterPlanMode',
325
312
  ]);
313
+ /**
314
+ * Patterns indicating a file path or glob likely targets secret/credential files.
315
+ * Used to auto-deny Read/Glob/Grep operations on sensitive files.
316
+ */
317
+ const SECRET_PATH_PATTERNS = [
318
+ /\.env(\.|$)/, // .env, .env.local, .env.production, etc.
319
+ /\bsecrets?\b/i, // secrets.json, secret.yaml, etc.
320
+ /\bcredentials?\b/i, // credentials.json, credential.yaml
321
+ /private[._-]?key/i, // private_key.pem, privatekey.pem
322
+ /\.pem$/i, // PEM certificates/keys
323
+ /\.key$/i, // Key files (e.g. myapp.key, certificate.key)
324
+ /\.p12$/i, // PKCS12 keystores
325
+ /\.pfx$/i, // PFX keystores
326
+ /\bid_rsa\b/, // SSH private keys
327
+ /\bid_ed25519\b/, // SSH private keys
328
+ /\bid_ecdsa\b/, // SSH private keys
329
+ /\.netrc$/, // .netrc files
330
+ /serviceaccount.*\.json$/i, // GCP service account keys
331
+ ];
332
+ const SECRET_PATH_ALLOWLIST = [
333
+ /\.env\.example$/, // .env.example is safe to read
334
+ ];
335
+ /**
336
+ * Returns true if a file path or glob pattern likely targets a secrets file.
337
+ */
338
+ function isSecretPath(value) {
339
+ if (SECRET_PATH_ALLOWLIST.some((re) => re.test(value)))
340
+ return false;
341
+ return SECRET_PATH_PATTERNS.some((re) => re.test(value));
342
+ }
343
+ /**
344
+ * Check if a Read/Glob/Grep input targets a secrets file and should be denied.
345
+ * For Grep, only the file-targeting fields (path, glob) are checked — not the
346
+ * search pattern itself.
347
+ */
348
+ function targetsSecretFile(toolName, input) {
349
+ if (toolName === 'Read' || toolName === 'Edit' || toolName === 'Write') {
350
+ const filePath = typeof input.file_path === 'string'
351
+ ? input.file_path
352
+ : typeof input.path === 'string'
353
+ ? input.path
354
+ : '';
355
+ return isSecretPath(filePath);
356
+ }
357
+ if (toolName === 'NotebookEdit') {
358
+ const notebookPath = typeof input.notebook_path === 'string' ? input.notebook_path : '';
359
+ return isSecretPath(notebookPath);
360
+ }
361
+ if (toolName === 'Glob') {
362
+ const pattern = typeof input.pattern === 'string' ? input.pattern : '';
363
+ const path = typeof input.path === 'string' ? input.path : '';
364
+ return isSecretPath(pattern) || isSecretPath(path);
365
+ }
366
+ if (toolName === 'Grep') {
367
+ const path = typeof input.path === 'string' ? input.path : '';
368
+ const glob = typeof input.glob === 'string' ? input.glob : '';
369
+ return isSecretPath(path) || isSecretPath(glob);
370
+ }
371
+ return false;
372
+ }
373
+ /**
374
+ * Returns true if a bash command string references a secret/credential file.
375
+ * Splits on shell delimiters and checks each token against SECRET_PATH_PATTERNS.
376
+ */
377
+ function bashCommandTargetsSecretFile(command) {
378
+ const tokens = command.split(/[\s|;&<>]+/);
379
+ for (const token of tokens) {
380
+ // Strip surrounding quotes
381
+ const cleaned = token.replace(/^['"]|['"]$/g, '');
382
+ if (cleaned && !cleaned.startsWith('-') && isSecretPath(cleaned)) {
383
+ return true;
384
+ }
385
+ }
386
+ return false;
387
+ }
388
+ /**
389
+ * PreToolUse hook that handles all silent auto-approve/deny decisions.
390
+ * Fires for every tool call before canUseTool, so this is the right place
391
+ * for decisions that don't require user interaction.
392
+ * Returns { continue: true } for tools that need canUseTool (UI interaction).
393
+ */
394
+ export function createPreToolUseHook(sessionInfo) {
395
+ return async (input) => {
396
+ if (input.hook_event_name !== 'PreToolUse')
397
+ return { continue: true };
398
+ const { tool_name, tool_input } = input;
399
+ const inp = (tool_input ?? {});
400
+ // Block secret file access for all relevant tools
401
+ if (targetsSecretFile(tool_name, inp) ||
402
+ (tool_name === 'Bash' &&
403
+ typeof inp.command === 'string' &&
404
+ bashCommandTargetsSecretFile(inp.command))) {
405
+ logToFile(`PreToolUse: blocking ${tool_name} - secret file pattern detected`, inp);
406
+ return {
407
+ hookSpecificOutput: {
408
+ hookEventName: 'PreToolUse',
409
+ permissionDecision: 'deny',
410
+ permissionDecisionReason: 'Reading or writing secret or credential files is not allowed.',
411
+ },
412
+ };
413
+ }
414
+ // Auto-approve internal MCP tools and EnterPlanMode
415
+ if (AUTO_APPROVED_TOOLS.has(tool_name)) {
416
+ return {
417
+ hookSpecificOutput: {
418
+ hookEventName: 'PreToolUse',
419
+ permissionDecision: 'allow',
420
+ },
421
+ };
422
+ }
423
+ // Auto-approve read-only file tools
424
+ if (tool_name === 'Read' || tool_name === 'Glob' || tool_name === 'Grep') {
425
+ return {
426
+ hookSpecificOutput: {
427
+ hookEventName: 'PreToolUse',
428
+ permissionDecision: 'allow',
429
+ },
430
+ };
431
+ }
432
+ // Auto-approve safe or session-approved bash commands
433
+ if (tool_name === 'Bash' && typeof inp.command === 'string') {
434
+ if (isSafeBashCommand(inp.command) ||
435
+ isCommandApprovedForSession(inp.command)) {
436
+ logToFile('PreToolUse: auto-approving bash command:', inp.command);
437
+ return {
438
+ hookSpecificOutput: {
439
+ hookEventName: 'PreToolUse',
440
+ permissionDecision: 'allow',
441
+ },
442
+ };
443
+ }
444
+ }
445
+ // Auto-approve WebSearch with domain restriction applied via updatedInput
446
+ if (tool_name === 'WebSearch') {
447
+ return {
448
+ hookSpecificOutput: {
449
+ hookEventName: 'PreToolUse',
450
+ permissionDecision: 'allow',
451
+ updatedInput: {
452
+ ...inp,
453
+ allowed_domains: ['raindrop.ai/docs', 'ai-sdk.dev/docs/'],
454
+ },
455
+ },
456
+ };
457
+ }
458
+ // Auto-approve ExitPlanMode and fire session update
459
+ if (tool_name === 'ExitPlanMode') {
460
+ const planContent = typeof inp.plan === 'string' ? inp.plan : '';
461
+ if (sessionInfo) {
462
+ sendSessionUpdate(sessionInfo.sessionId, planContent, sessionInfo.accessToken, sessionInfo.orgId);
463
+ }
464
+ return {
465
+ hookSpecificOutput: {
466
+ hookEventName: 'PreToolUse',
467
+ permissionDecision: 'allow',
468
+ permissionDecisionReason: 'System automatically approved.',
469
+ },
470
+ };
471
+ }
472
+ // Auto-approve edits to files that were already approved this session
473
+ if (tool_name === 'Edit' || tool_name === 'Write') {
474
+ const fileName = typeof inp.file_path === 'string'
475
+ ? inp.file_path
476
+ : typeof inp.path === 'string'
477
+ ? inp.path
478
+ : undefined;
479
+ if (fileName && approvedFilesForSession.has(fileName)) {
480
+ logToFile('PreToolUse: auto-approving edit to session-approved file:', fileName);
481
+ return {
482
+ hookSpecificOutput: {
483
+ hookEventName: 'PreToolUse',
484
+ permissionDecision: 'allow',
485
+ },
486
+ };
487
+ }
488
+ }
489
+ // Anything else needs user interaction — let canUseTool handle it
490
+ return {};
491
+ };
492
+ }
326
493
  /**
327
494
  * Check if a bash command matches a safe pattern and can be auto-approved.
328
495
  */
@@ -344,76 +511,23 @@ function isSafeBashCommand(command) {
344
511
  });
345
512
  }
346
513
  /**
347
- * Create a canUseTool handler that integrates with the UI for approvals.
348
- * - Handles AskUserQuestion by showing clarifying questions UI
349
- * - Handles ExitPlanMode by showing plan approval UI
350
- * - Handles WebSearch by restricting to allowed domains
351
- * - Shows approval UI for other tools
352
- * - Supports caching file approvals for "allow all edits to this file"
514
+ * Create a canUseTool handler for tools that require user interaction.
515
+ * Auto-approve/deny logic lives in createPreToolUseHook instead.
516
+ * This handler is only reached for tools that PreToolUse passes through.
353
517
  */
354
- export function createCanUseToolHandler(sessionInfo, approvedFilesCache) {
518
+ export function createCanUseToolHandler(approvedFilesCache) {
355
519
  return async (toolName, input) => {
356
520
  const inputRecord = input;
357
521
  logToFile('canUseTool called:', { toolName, input: inputRecord });
358
- if (AUTO_APPROVED_TOOLS.has(toolName)) {
359
- return {
360
- behavior: 'allow',
361
- updatedInput: inputRecord,
362
- };
363
- }
364
- // Auto-approve safe bash commands
365
- if (toolName === 'Bash' && typeof inputRecord.command === 'string') {
366
- // Check if command matches safe patterns
367
- if (isSafeBashCommand(inputRecord.command)) {
368
- logToFile('Auto-approving safe bash command:', inputRecord.command);
369
- return {
370
- behavior: 'allow',
371
- updatedInput: inputRecord,
372
- };
373
- }
374
- // Check if command pattern has been approved for the session
375
- if (isCommandApprovedForSession(inputRecord.command)) {
376
- logToFile('Auto-approving bash command based on session approval:', inputRecord.command);
377
- return {
378
- behavior: 'allow',
379
- updatedInput: inputRecord,
380
- };
381
- }
382
- }
383
- // Handle WebSearch by adding allowed domains restriction
384
- if (toolName === 'WebSearch') {
385
- return {
386
- behavior: 'allow',
387
- updatedInput: {
388
- ...inputRecord,
389
- allowed_domains: ['raindrop.ai/docs', 'ai-sdk.dev/docs/'],
390
- },
391
- };
392
- }
393
522
  // Handle AskUserQuestion specially
394
523
  if (toolName === 'AskUserQuestion') {
395
524
  return handleClarifyingQuestions(inputRecord);
396
525
  }
397
- // Handle ExitPlanMode specially
526
+ // ExitPlanMode is auto-approved (session update already fired in PreToolUse hook)
398
527
  if (toolName === 'ExitPlanMode') {
399
- return handlePlanApproval(inputRecord, sessionInfo);
400
- }
401
- // Check if file has been granted blanket approval for this session
402
- if (toolName === 'Edit' || toolName === 'Write') {
403
- const fileName = typeof inputRecord.file_path === 'string'
404
- ? inputRecord.file_path
405
- : typeof inputRecord.path === 'string'
406
- ? inputRecord.path
407
- : undefined;
408
- if (fileName && approvedFilesForSession.has(fileName)) {
409
- logToFile('Auto-approving edit to previously approved file:', fileName);
410
- return {
411
- behavior: 'allow',
412
- updatedInput: inputRecord,
413
- };
414
- }
528
+ return { behavior: 'allow', updatedInput: inputRecord };
415
529
  }
416
- // Show approval UI for other tools
530
+ // Show approval UI for all other tools
417
531
  return handleToolApproval(toolName, inputRecord, approvedFilesCache);
418
532
  };
419
533
  }