@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.
- package/dist/src/docs/claude-agent-sdk.mdx +382 -0
- package/dist/src/docs/{typescript.md → typescript.mdx} +8 -4
- package/dist/src/docs/vercel-ai-sdk.mdx +769 -0
- package/dist/src/lib/agent-interface.d.ts +4 -3
- package/dist/src/lib/agent-interface.js +290 -197
- package/dist/src/lib/agent-interface.js.map +1 -1
- package/dist/src/lib/constants.d.ts +1 -0
- package/dist/src/lib/constants.js +1 -0
- package/dist/src/lib/constants.js.map +1 -1
- package/dist/src/lib/handlers.d.ts +16 -8
- package/dist/src/lib/handlers.js +232 -118
- package/dist/src/lib/handlers.js.map +1 -1
- package/dist/src/lib/integration-testing.d.ts +5 -5
- package/dist/src/lib/integration-testing.js +28 -12
- package/dist/src/lib/integration-testing.js.map +1 -1
- package/dist/src/lib/mcp.d.ts +1 -1
- package/dist/src/lib/mcp.js +88 -49
- package/dist/src/lib/mcp.js.map +1 -1
- package/dist/src/lib/sdk-messages.d.ts +8 -1
- package/dist/src/lib/sdk-messages.js +83 -27
- package/dist/src/lib/sdk-messages.js.map +1 -1
- package/dist/src/lib/wizard.js +16 -20
- package/dist/src/lib/wizard.js.map +1 -1
- package/dist/src/ui/App.d.ts +5 -4
- package/dist/src/ui/App.js +12 -12
- package/dist/src/ui/App.js.map +1 -1
- package/dist/src/ui/components/ClarifyingQuestionsPrompt.js +4 -2
- package/dist/src/ui/components/ClarifyingQuestionsPrompt.js.map +1 -1
- package/dist/src/ui/components/ContinuePrompt.d.ts +3 -2
- package/dist/src/ui/components/ContinuePrompt.js +4 -4
- package/dist/src/ui/components/ContinuePrompt.js.map +1 -1
- package/dist/src/ui/components/DiffDisplay.js +16 -6
- package/dist/src/ui/components/DiffDisplay.js.map +1 -1
- package/dist/src/ui/components/FeedbackSelectPrompt.js +6 -3
- package/dist/src/ui/components/FeedbackSelectPrompt.js.map +1 -1
- package/dist/src/ui/components/HistoryItemDisplay.d.ts +5 -3
- package/dist/src/ui/components/HistoryItemDisplay.js +10 -9
- package/dist/src/ui/components/HistoryItemDisplay.js.map +1 -1
- package/dist/src/ui/components/Logo.js +19 -34
- package/dist/src/ui/components/Logo.js.map +1 -1
- package/dist/src/ui/components/OrgInfoBox.d.ts +2 -1
- package/dist/src/ui/components/OrgInfoBox.js +2 -4
- package/dist/src/ui/components/OrgInfoBox.js.map +1 -1
- package/dist/src/ui/components/PersistentTextInput.js +13 -11
- package/dist/src/ui/components/PersistentTextInput.js.map +1 -1
- package/dist/src/ui/components/PromptContainer.js +4 -8
- package/dist/src/ui/components/PromptContainer.js.map +1 -1
- package/dist/src/ui/components/ToolApprovalPrompt.js +4 -4
- package/dist/src/ui/components/ToolApprovalPrompt.js.map +1 -1
- package/dist/src/ui/components/WriteKeyDisplay.d.ts +1 -1
- package/dist/src/ui/components/WriteKeyDisplay.js +1 -1
- package/dist/src/ui/components/WriteKeyDisplay.js.map +1 -1
- package/dist/src/ui/contexts/WizardContext.d.ts +13 -5
- package/dist/src/ui/contexts/WizardContext.js +60 -20
- package/dist/src/ui/contexts/WizardContext.js.map +1 -1
- package/dist/src/ui/render.js +49 -5
- package/dist/src/ui/render.js.map +1 -1
- package/dist/src/ui/types.d.ts +4 -2
- package/dist/src/ui/types.js.map +1 -1
- package/dist/src/utils/oauth.js +0 -4
- package/dist/src/utils/oauth.js.map +1 -1
- package/dist/src/utils/session.d.ts +1 -0
- package/dist/src/utils/session.js +40 -1
- package/dist/src/utils/session.js.map +1 -1
- package/dist/src/utils/ui.d.ts +7 -2
- package/dist/src/utils/ui.js +9 -2
- package/dist/src/utils/ui.js.map +1 -1
- package/package.json +2 -1
- package/dist/src/docs/vercel-ai-sdk.md +0 -304
- /package/dist/src/docs/{browser.md → browser.mdx} +0 -0
- /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":"AAAA,MAAM,CAAN,IAAY,WAIX;AAJD,WAAY,WAAW;IACrB,gCAAiB,CAAA;IACjB,wCAAyB,CAAA;IACzB,4CAA6B,CAAA;AAC/B,CAAC,EAJW,WAAW,KAAX,WAAW,QAItB;AAED,MAAM,UAAU,yBAAyB,CAAC,IAAY;IACpD,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,WAAW,CAAC,MAAM;YACrB,OAAO,cAAc,CAAC;QACxB,KAAK,WAAW,CAAC,UAAU;YACzB,OAAO,kBAAkB,CAAC;QAC5B,KAAK,WAAW,CAAC,WAAW;YAC1B,OAAO,mBAAmB,CAAC;QAC7B;YACE,MAAM,IAAI,KAAK,CAAC,uBAAuB,IAAI,EAAE,CAAC,CAAC;IACnD,CAAC;AACH,CAAC;AAED,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC,QAAQ,CACpD,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,EAAE,CAC3B,CAAC;AAEF,MAAM,CAAC,MAAM,UAAU,GAAG,2CAA2C,CAAC;AAEtE,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,CAAC;AAClC,MAAM,gBAAgB,GAAG,yBAAyB,CAAC;AACnD,MAAM,gBAAgB,GAAG,wBAAwB,CAAC;AAClD,MAAM,CAAC,MAAM,YAAY,GAAG,gBAAgB,CAAC;AAC7C,MAAM,CAAC,MAAM,OAAO,GAAG,gBAAgB,CAAC;AACxC,iBAAiB;AACjB,uDAAuD;AACvD,kDAAkD;AAClD,MAAM,CAAC,MAAM,kBAAkB,GAAG,GAAG,YAAY,oBAAoB,CAAC;AACtE,MAAM,CAAC,MAAM,oBAAoB,GAAG,GAAG,YAAY,sBAAsB,CAAC;AAC1E,MAAM,CAAC,MAAM,kBAAkB,GAAG,GAAG,YAAY,UAAU,CAAC;AAC5D,MAAM,CAAC,MAAM,sBAAsB,GAAG,GAAG,YAAY,uBAAuB,CAAC;AAC7E,MAAM,CAAC,MAAM,uBAAuB,GAAG,GAAG,YAAY,yBAAyB,CAAC;
|
|
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 {
|
|
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
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
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
|
|
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>;
|
package/dist/src/lib/handlers.js
CHANGED
|
@@ -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 {
|
|
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
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
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
|
-
//
|
|
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
|
-
|
|
136
|
-
|
|
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' &&
|
|
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
|
-
//
|
|
280
|
-
|
|
281
|
-
|
|
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-
|
|
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
|
|
348
|
-
* -
|
|
349
|
-
*
|
|
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(
|
|
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
|
-
//
|
|
526
|
+
// ExitPlanMode is auto-approved (session update already fired in PreToolUse hook)
|
|
398
527
|
if (toolName === 'ExitPlanMode') {
|
|
399
|
-
return
|
|
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
|
}
|