check_permissions
Analyze permission handling patterns in code to identify issues and get suggestions for proper flow for push, camera, or location features.
Instructions
Analyze permission handling patterns in code for a specific SDK feature. Returns analysis with suggestions for proper permission flow.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| code | Yes | Code to analyze for permission handling | |
| feature | Yes | Feature requiring permission (push, camera, or location) |
Implementation Reference
- src/tools/check-permissions.ts:34-67 (handler)Main handler function that analyzes permission handling in code for a given feature (push/camera/location). Calls analyzePermissionPatterns() and buildAnalysisOutput().
export async function checkPermissions( args: Record<string, unknown> ): Promise<{ content: Array<{ type: "text"; text: string }> }> { const { code, feature } = args as unknown as CheckPermissionsArgs; if (!code || !feature) { return { content: [ { type: "text", text: "Please provide both `code` and `feature` (push, camera, or location) parameters.", }, ], }; } if (!featureApiMap[feature]) { return { content: [ { type: "text", text: `Invalid feature. Permission-required features are: ${Object.keys(featureApiMap).join(", ")}`, }, ], }; } const analysis = analyzePermissionPatterns(code, feature); const output = buildAnalysisOutput(feature, analysis); return { content: [{ type: "text", text: output }], }; } - Analyzes code patterns for permission handling: checks for requestPermission, status checks, denied/undetermined handling, error handling, and user explanations. Returns a PermissionAnalysis report.
function analyzePermissionPatterns( code: string, feature: PermissionFeature ): PermissionAnalysis { const analysis: PermissionAnalysis = { hasPermissionRequest: false, hasStatusCheck: false, hasDeniedHandling: false, hasUndeterminedHandling: false, hasErrorHandling: false, hasUserExplanation: false, issues: [], suggestions: [], }; const { protectedMethods } = featureApiMap[feature]; // Check for permission request if (code.includes("requestPermission")) { analysis.hasPermissionRequest = true; } // Check for status/permission variable handling if ( code.includes("permission") || code.includes("status") || code.includes("'granted'") || code.includes('"granted"') ) { analysis.hasStatusCheck = true; } // Check for denied handling if ( code.includes("'denied'") || code.includes('"denied"') || code.includes("=== 'denied'") || code.includes('=== "denied"') ) { analysis.hasDeniedHandling = true; } // Check for undetermined handling if ( code.includes("'undetermined'") || code.includes('"undetermined"') || code.includes("null") ) { analysis.hasUndeterminedHandling = true; } // Check for error handling if (code.includes("try") && code.includes("catch")) { analysis.hasErrorHandling = true; } // Check for user explanation (common patterns) if ( code.includes("modal") || code.includes("Modal") || code.includes("dialog") || code.includes("Dialog") || code.includes("alert") || code.includes("confirm") || code.includes("explanation") || code.includes("why") || code.includes("permission needed") ) { analysis.hasUserExplanation = true; } // Check for issues for (const method of protectedMethods) { if (code.includes(`.${method}(`) && !code.includes("requestPermission")) { analysis.issues.push( `Protected method \`${method}\` is used without requesting permission first.` ); } } if (!analysis.hasPermissionRequest) { analysis.issues.push( `No \`requestPermission()\` call found for ${feature}.` ); } if (!analysis.hasDeniedHandling) { analysis.issues.push( "No handling for 'denied' permission status. Users who deny permission won't see helpful feedback." ); } // Add suggestions if (!analysis.hasUserExplanation) { analysis.suggestions.push( "Consider explaining to users WHY you need this permission before requesting it. This improves acceptance rates." ); } if (!analysis.hasErrorHandling) { analysis.suggestions.push( "Add try/catch blocks to handle potential errors during permission requests." ); } if (!analysis.hasUndeterminedHandling) { analysis.suggestions.push( "Handle the 'undetermined' state - this is the initial state before the user makes a choice." ); } return analysis; } - Builds a formatted markdown output string from the PermissionAnalysis, including a checklist, issues, suggestions, and a recommended code pattern.
function buildAnalysisOutput( feature: PermissionFeature, analysis: PermissionAnalysis ): string { const sections: string[] = []; sections.push(`## ${feature.charAt(0).toUpperCase() + feature.slice(1)} Permission Analysis\n`); // Checklist sections.push("### Permission Flow Checklist\n"); sections.push( `- [${analysis.hasPermissionRequest ? "x" : " "}] Calls \`requestPermission()\`` ); sections.push( `- [${analysis.hasStatusCheck ? "x" : " "}] Checks permission status` ); sections.push( `- [${analysis.hasDeniedHandling ? "x" : " "}] Handles 'denied' status` ); sections.push( `- [${analysis.hasUndeterminedHandling ? "x" : " "}] Handles initial/undetermined state` ); sections.push( `- [${analysis.hasErrorHandling ? "x" : " "}] Has error handling` ); sections.push( `- [${analysis.hasUserExplanation ? "x" : " "}] Explains why permission is needed` ); sections.push(""); // Issues if (analysis.issues.length > 0) { sections.push("### Issues Found\n"); analysis.issues.forEach((issue) => sections.push(`- ❌ ${issue}`)); sections.push(""); } // Suggestions if (analysis.suggestions.length > 0) { sections.push("### Suggestions\n"); analysis.suggestions.forEach((s) => sections.push(`- 💡 ${s}`)); sections.push(""); } // Best practice example sections.push("### Recommended Pattern\n"); sections.push("```tsx"); sections.push(getRecommendedPattern(feature)); sections.push("```"); return sections.join("\n"); } - Returns a recommended code pattern for the given feature (push, camera, or location) showing proper permission flow.
function getRecommendedPattern(feature: PermissionFeature): string { const patterns: Record<PermissionFeature, string> = { push: `import { useState } from 'react'; import { getAppo, type PermissionStatus } from '@appolabs/appo'; function PushNotificationSetup() { const [status, setStatus] = useState<PermissionStatus | null>(null); const [showExplanation, setShowExplanation] = useState(true); const appo = getAppo(); const handleEnable = async () => { try { const result = await appo.push.requestPermission(); setStatus(result); if (result === 'granted') { const token = await appo.push.getToken(); // Send token to your backend } } catch (error) { console.error('Push permission error:', error); } }; if (status === 'denied') { return <p>Push notifications are disabled. Enable them in Settings.</p>; } if (showExplanation) { return ( <div> <p>We'll send you updates about your orders and exclusive offers.</p> <button onClick={() => { setShowExplanation(false); handleEnable(); }}> Enable Notifications </button> </div> ); } return null; }`, camera: `import { useState } from 'react'; import { getAppo, type PermissionStatus } from '@appolabs/appo'; function CameraCapture() { const [status, setStatus] = useState<PermissionStatus | null>(null); const appo = getAppo(); const handleCapture = async () => { try { // Request permission first if (status !== 'granted') { const result = await appo.camera.requestPermission(); setStatus(result); if (result !== 'granted') return; } // Now safe to capture const photo = await appo.camera.takePicture(); if (photo) { // Handle photo } } catch (error) { console.error('Camera error:', error); } }; if (status === 'denied') { return <p>Camera access denied. Please enable in Settings.</p>; } return <button onClick={handleCapture}>Take Photo</button>; }`, location: `import { useState } from 'react'; import { getAppo, type PermissionStatus } from '@appolabs/appo'; function LocationAccess() { const [status, setStatus] = useState<PermissionStatus | null>(null); const [showRationale, setShowRationale] = useState(true); const appo = getAppo(); const handleGetLocation = async () => { try { if (status !== 'granted') { const result = await appo.location.requestPermission(); setStatus(result); if (result !== 'granted') return; } const position = await appo.location.getCurrentPosition(); if (position) { // Use location } } catch (error) { console.error('Location error:', error); } }; if (status === 'denied') { return <p>Location access denied. Enable in Settings to use this feature.</p>; } if (showRationale) { return ( <div> <p>We need your location to find nearby stores.</p> <button onClick={() => { setShowRationale(false); handleGetLocation(); }}> Share Location </button> </div> ); } return null; }`, }; return patterns[feature]; } - src/tools/check-permissions.ts:1-6 (schema)Type definitions: PermissionFeature union type and CheckPermissionsArgs interface with code and feature fields.
type PermissionFeature = "push" | "camera" | "location"; interface CheckPermissionsArgs { code: string; feature: PermissionFeature; } - src/tools/index.ts:130-149 (registration)Tool registration with name 'check_permissions', description, and inputSchema defining code (string) and feature (enum: push/camera/location) as required params.
{ name: "check_permissions", description: "Analyze permission handling patterns in code for a specific SDK feature. Returns analysis with suggestions for proper permission flow.", inputSchema: { type: "object", properties: { code: { type: "string", description: "Code to analyze for permission handling", }, feature: { type: "string", enum: ["push", "camera", "location"], description: "Feature requiring permission (push, camera, or location)", }, }, required: ["code", "feature"], }, }, - src/tools/index.ts:194-195 (registration)Router case in handleToolCall that dispatches to the checkPermissions handler.
case "check_permissions": return checkPermissions(args); - src/tools/index.ts:6-6 (registration)Import statement bringing checkPermissions from its module.
import { checkPermissions } from "./check-permissions.js";