{/* Delete Confirmation Modal */}
      {deleteConfirm && (

                <svg className="w-5 h-5 text-error" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                  <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
                </svg>

Delete Permission

              Are you sure you want to delete this permission?

                  {deleteConfirm.permission_type}

                  {deleteConfirm.permission_value}

              <button
                onClick={() => setDeleteConfirm(null)}
                className="px-4 py-2 text-sm border border-border rounded hover:bg-surface-elevated transition-colors"
              >
                Cancel
              </button>
              <button
                onClick={handleDeletePermission}
                className="px-4 py-2 text-sm bg-error text-white rounded hover:bg-error/80 transition-colors"
              >
                Delete
              </button>

      )}

  )

{/* Delete Confirmation Modal */}
      {deleteConfirm && (

                <svg className="w-5 h-5 text-error" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                  <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
                </svg>

Delete Permission

              Are you sure you want to delete this permission?

                  {deleteConfirm.permission_type}

                  {deleteConfirm.permission_value}

              <button
                onClick={() => setDeleteConfirm(null)}
                className="px-4 py-2 text-sm border border-border rounded hover:bg-surface-elevated transition-colors"
              >
                Cancel
              </button>
              <button
                onClick={handleDeletePermission}
                className="px-4 py-2 text-sm bg-error text-white rounded hover:bg-error/80 transition-colors"
              >
                Delete
              </button>

      )}

      {/* Import Modal */}
      {showImportModal && (

                <svg className="w-5 h-5 text-accent" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                  <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12" />
                </svg>

Import Permissions

              Import permissions from a JSON configuration file.

            {/* File Input */}

              Select File
              <input
                type="file"
                accept=".json"
                onChange={handleFileSelect}
                className="w-full px-3 py-2 bg-surface-elevated border border-border rounded text-sm file:mr-4 file:py-1 file:px-3 file:rounded file:border-0 file:text-sm file:bg-accent file:text-white hover:file:bg-accent/80 file:cursor-pointer"
              />

            {/* Or paste JSON */}

              Or Paste JSON
              <textarea
                value={importText}
                onChange={(e) => setImportText(e.target.value)}
                placeholder='[{"permission_type": "Read", "permission_value": "/src/**", "granted": true}]'
                className="w-full h-32 px-3 py-2 bg-surface-elevated border border-border rounded text-sm font-mono focus:outline-none focus:ring-2 focus:ring-accent resize-none"
              />

            {/* Replace existing checkbox */}

                <input
                  type="checkbox"
                  checked={replaceExisting}
                  onChange={(e) => setReplaceExisting(e.target.checked)}
                  className="w-4 h-4 rounded border-border text-accent focus:ring-accent"
                />
                Replace existing permissions (deletes all current permissions first)

            {/* Error display */}
            {error && (

                <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                  <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
                </svg>
                {error}

            )}

              <button
                onClick={() => {
                  setShowImportModal(false)
                  setImportText('')
                  setReplaceExisting(false)
                  setError(null)
                }}
                className="px-4 py-2 text-sm border border-border rounded hover:bg-surface-elevated transition-colors"
              >
                Cancel
              </button>
              <button
                onClick={handleImport}
                disabled={importing || !importText.trim()}
                className="px-4 py-2 text-sm bg-accent text-white rounded hover:bg-accent/80 transition-colors disabled:opacity-50"
              >
                {importing ? 'Importing...' : 'Import'}
              </button>

      )}

  )


The file C:\Users\MikeSwanson\claude-projects\Autocode-remix\Autocode-fork\frontend\src\components\PermissionEditor.tsx has been updated. Here's the result of running `cat -n` on a snippet of the edited file:
   495→

   496→        )}
   497→

   498→
   499→      {/* Delete Confirmation Modal */}
   500→      {deleteConfirm && (
   501→

   502→

   503→

   504→

   505→                <svg className="w-5 h-5 text-error" fill="none" stroke="currentColor" viewBox="0 0 24 24">
   506→                  <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
   507→                </svg>
   508→

   509→
Delete Permission

   510→

   511→

   512→              Are you sure you want to delete this permission?
   513→

   514→

   515→

   516→
   517→                  {deleteConfirm.permission_type}
   518→
   519→
   520→                  {deleteConfirm.permission_value}
   521→
   522→

   523→

   524→

   525→              <button
   526→                onClick={() => setDeleteConfirm(null)}
   527→                className="px-4 py-2 text-sm border border-border rounded hover:bg-surface-elevated transition-colors"
   528→              >
   529→                Cancel
   530→              </button>
   531→              <button
   532→                onClick={handleDeletePermission}
   533→                className="px-4 py-2 text-sm bg-error text-white rounded hover:bg-error/80 transition-colors"
   534→              >
   535→                Delete
   536→              </button>
   537→

   538→

   539→

   540→      )}
   541→
   542→      {/* Import Modal */}
   543→      {showImportModal && (
   544→

   545→

   546→

   547→

   548→                <svg className="w-5 h-5 text-accent" fill="none" stroke="currentColor" viewBox="0 0 24 24">
   549→                  <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12" />
   550→                </svg>
   551→

   552→
Import Permissions

   553→

   554→

   555→              Import permissions from a JSON configuration file.
   556→

   557→
   558→            {/* File Input */}
   559→

   560→              Select File
   561→              <input
   562→                type="file"
   563→                accept=".json"
   564→                onChange={handleFileSelect}
   565→                className="w-full px-3 py-2 bg-surface-elevated border border-border rounded text-sm file:mr-4 file:py-1 file:px-3 file:rounded file:border-0 file:text-sm file:bg-accent file:text-white hover:file:bg-accent/80 file:cursor-pointer"
   566→              />
   567→

   568→
   569→            {/* Or paste JSON */}
   570→

   571→              Or Paste JSON
   572→              <textarea
   573→                value={importText}
   574→                onChange={(e) => setImportText(e.target.value)}
   575→                placeholder='[{"permission_type": "Read", "permission_value": "/src/**", "granted": true}]'
   576→                className="w-full h-32 px-3 py-2 bg-surface-elevated border border-border rounded text-sm font-mono focus:outline-none focus:ring-2 focus:ring-accent resize-none"
   577→              />
   578→

   579→
   580→            {/* Replace existing checkbox */}
   581→

   582→
   583→                <input
   584→                  type="checkbox"
   585→                  checked={replaceExisting}
   586→                  onChange={(e) => setReplaceExisting(e.target.checked)}
   587→                  className="w-4 h-4 rounded border-border text-accent focus:ring-accent"
   588→                />
   589→                Replace existing permissions (deletes all current permissions first)
   590→
   591→

   592→
   593→            {/* Error display */}
   594→            {error && (
   595→

   596→                <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
   597→                  <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
   598→                </svg>
   599→                {error}
   600→

   601→            )}
   602→
   603→

   604→              <button
   605→                onClick={() => {
   606→                  setShowImportModal(false)
   607→                  setImportText('')
   608→                  setReplaceExisting(false)
   609→                  setError(null)
   610→                }}
   611→                className="px-4 py-2 text-sm border border-border rounded hover:bg-surface-elevated transition-colors"
   612→              >
   613→                Cancel
   614→              </button>
   615→              <button
   616→                onClick={handleImport}
   617→                disabled={importing || !importText.trim()}
   618→                className="px-4 py-2 text-sm bg-accent text-white rounded hover:bg-accent/80 transition-colors disabled:opacity-50"
   619→              >
   620→                {importing ? 'Importing...' : 'Import'}
   621→              </button>
   622→

   623→

   624→

   625→      )}
   626→

   627→  )
   628→}
   629→
   630→export default PermissionEditor
   631→

{/* Delete Confirmation Modal */}
      {deleteConfirm && (

                <svg className="w-5 h-5 text-error" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                  <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
                </svg>

Delete Permission

              Are you sure you want to delete this permission?

                  {deleteConfirm.permission_type}

                  {deleteConfirm.permission_value}

              <button
                onClick={() => setDeleteConfirm(null)}
                className="px-4 py-2 text-sm border border-border rounded hover:bg-surface-elevated transition-colors"
              >
                Cancel
              </button>
              <button
                onClick={handleDeletePermission}
                className="px-4 py-2 text-sm bg-error text-white rounded hover:bg-error/80 transition-colors"
              >
                Delete
              </button>

      )}

      {/* Import Modal */}
      {showImportModal && (

                <svg className="w-5 h-5 text-accent" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                  <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12" />
                </svg>

Import Permissions

              Import permissions from a JSON configuration file.

            {/* File Input */}

              Select File
              <input
                type="file"
                accept=".json"
                onChange={handleFileSelect}
                className="w-full px-3 py-2 bg-surface-elevated border border-border rounded text-sm file:mr-4 file:py-1 file:px-3 file:rounded file:border-0 file:text-sm file:bg-accent file:text-white hover:file:bg-accent/80 file:cursor-pointer"
              />

            {/* Or paste JSON */}

              Or Paste JSON
              <textarea
                value={importText}
                onChange={(e) => setImportText(e.target.value)}
                placeholder='[{"permission_type": "Read", "permission_value": "/src/**", "granted": true}]'
                className="w-full h-32 px-3 py-2 bg-surface-elevated border border-border rounded text-sm font-mono focus:outline-none focus:ring-2 focus:ring-accent resize-none"
              />

            {/* Replace existing checkbox */}

                <input
                  type="checkbox"
                  checked={replaceExisting}
                  onChange={(e) => setReplaceExisting(e.target.checked)}
                  className="w-4 h-4 rounded border-border text-accent focus:ring-accent"
                />
                Replace existing permissions (deletes all current permissions first)

            {/* Error display */}
            {error && (

                <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                  <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
                </svg>
                {error}

            )}

              <button
                onClick={() => {
                  setShowImportModal(false)
                  setImportText('')
                  setReplaceExisting(false)
                  setError(null)
                }}
                className="px-4 py-2 text-sm border border-border rounded hover:bg-surface-elevated transition-colors"
              >
                Cancel
              </button>
              <button
                onClick={handleImport}
                disabled={importing || !importText.trim()}
                className="px-4 py-2 text-sm bg-accent text-white rounded hover:bg-accent/80 transition-colors disabled:opacity-50"
              >
                {importing ? 'Importing...' : 'Import'}
              </button>

      )}

  )

import { useState, useEffect } from 'react'

interface Permission {
  id: number
  project_id: number
  permission_type: string
  permission_value: string
  granted: boolean
  created_at: string
}

interface PermissionEditorProps {
  projectName: string
  onBack: () => void
}

export function PermissionEditor({ projectName, onBack }: PermissionEditorProps) {
  const [permissions, setPermissions] = useState<Permission[]>([])
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState<string | null>(null)
  const [showAddForm, setShowAddForm] = useState(false)
  const [newPermission, setNewPermission] = useState({
    permission_type: '',
    permission_value: '',
    granted: true,
  })
  const [saving, setSaving] = useState(false)
  const [deleteConfirm, setDeleteConfirm] = useState<Permission | null>(null)
  const [applyingPreset, setApplyingPreset] = useState(false)
  const [importing, setImporting] = useState(false)
  const [showImportModal, setShowImportModal] = useState(false)
  const [importText, setImportText] = useState('')
  const [replaceExisting, setReplaceExisting] = useState(false)

  // Permission presets
  const presets = {
    minimal: [
      { permission_type: 'Read', permission_value: '/src/**', granted: true },
    ],
    standard: [
      { permission_type: 'Read', permission_value: '/src/**', granted: true },
      { permission_type: 'Write', permission_value: '/src/**', granted: true },
      { permission_type: 'Bash', permission_value: 'npm install', granted: true },
      { permission_type: 'Bash', permission_value: 'npm run *', granted: true },
    ],
    full: [
      { permission_type: 'Read', permission_value: '/**', granted: true },
      { permission_type: 'Write', permission_value: '/**', granted: true },
      { permission_type: 'Bash', permission_value: '*', granted: true },
      { permission_type: 'WebFetch', permission_value: '*', granted: true },
      { permission_type: 'Edit', permission_value: '/**', granted: true },
    ],
  }

  useEffect(() => {
    fetchPermissions()
  }, [projectName])

  const fetchPermissions = async () => {
    try {
      setLoading(true)
      const res = await fetch(`/api/projects/${projectName}/permissions`)
      if (!res.ok) throw new Error('Failed to fetch permissions')
      const data = await res.json()
      setPermissions(data.permissions)
      setError(null)
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Unknown error')
    } finally {
      setLoading(false)
    }
  }

  const handleToggleGranted = async (permission: Permission) => {
    try {
      setError(null)
      const res = await fetch(`/api/projects/${projectName}/permissions/${permission.id}`, {
        method: 'PUT',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ granted: !permission.granted }),
      })

      if (!res.ok) {
        const data = await res.json()
        throw new Error(data.detail || 'Failed to update permission')
      }

      fetchPermissions()
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Unknown error')
    }
  }

  const handleDeletePermission = async () => {
    if (!deleteConfirm) return

    try {
      setError(null)
      const res = await fetch(`/api/projects/${projectName}/permissions/${deleteConfirm.id}`, {
        method: 'DELETE',
      })

      if (!res.ok) {
        const data = await res.json()
        throw new Error(data.detail || 'Failed to delete permission')
      }

      setDeleteConfirm(null)
      fetchPermissions()
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Unknown error')
    }
  }

  const applyPreset = async (presetName: 'minimal' | 'standard' | 'full') => {
    try {
      setApplyingPreset(true)
      setError(null)

      // Delete all existing permissions
      for (const permission of permissions) {
        await fetch(`/api/projects/${projectName}/permissions/${permission.id}`, {
          method: 'DELETE',
        })
      }

      // Add new permissions from preset
      const presetPermissions = presets[presetName]
      for (const perm of presetPermissions) {
        await fetch(`/api/projects/${projectName}/permissions`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify(perm),
        })
      }

      fetchPermissions()
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Unknown error')
    } finally {
      setApplyingPreset(false)
    }
  }

  const handleAddPermission = async () => {
    if (!newPermission.permission_type || !newPermission.permission_value) {
      setError('Permission type and value are required')
      return
    }

    try {
      setSaving(true)
      setError(null)

      const res = await fetch(`/api/projects/${projectName}/permissions`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(newPermission),
      })

      if (!res.ok) {
        const data = await res.json()
        throw new Error(data.detail || 'Failed to create permission')
      }

      setNewPermission({ permission_type: '', permission_value: '', granted: true })
      setShowAddForm(false)
      fetchPermissions()
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Unknown error')
    } finally {
      setSaving(false)
    }
  }

  const handleExport = async () => {
    try {
      const res = await fetch(`/api/projects/${projectName}/permissions/export`)
      if (!res.ok) throw new Error('Failed to export permissions')
      const data = await res.json()

      // Create downloadable JSON file
      const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' })
      const url = URL.createObjectURL(blob)
      const a = document.createElement('a')
      a.href = url
      a.download = `${projectName}-permissions.json`
      document.body.appendChild(a)
      a.click()
      document.body.removeChild(a)
      URL.revokeObjectURL(url)
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Unknown error')
    }
  }

  const handleImport = async () => {
    try {
      setImporting(true)
      setError(null)

      // Parse the JSON
      let importData
      try {
        importData = JSON.parse(importText)
      } catch {
        throw new Error('Invalid JSON format')
      }

      // Handle both formats: direct array or object with permissions array
      let permissionsArray = Array.isArray(importData)
        ? importData
        : importData.permissions

      if (!Array.isArray(permissionsArray)) {
        throw new Error('Invalid format: expected an array of permissions or an object with "permissions" array')
      }

      const res = await fetch(`/api/projects/${projectName}/permissions/import`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          permissions: permissionsArray,
          replace_existing: replaceExisting,
        }),
      })

      if (!res.ok) {
        const data = await res.json()
        throw new Error(data.detail || 'Failed to import permissions')
      }

      const result = await res.json()
      setShowImportModal(false)
      setImportText('')
      setReplaceExisting(false)
      fetchPermissions()
      // Show success message
      alert(result.message)
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Unknown error')
    } finally {
      setImporting(false)
    }
  }

  const handleFileSelect = (event: React.ChangeEvent<HTMLInputElement>) => {
    const file = event.target.files?.[0]
    if (!file) return

    const reader = new FileReader()
    reader.onload = (e) => {
      const text = e.target?.result as string
      setImportText(text)
    }
    reader.readAsText(file)
  }

  if (loading) {
    return (

          Loading permissions...

    )
  }

  return (

      {/* Header */}

          <button
            onClick={onBack}
            className="flex items-center gap-2 text-text-secondary hover:text-text-primary transition-colors"
          >
            <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
              <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 19l-7-7 7-7" />
            </svg>
            Back
          </button>

Permission Editor

            {permissions.length} permissions

          {/* Import/Export Buttons */}

            <button
              onClick={() => setShowImportModal(true)}
              className="flex items-center gap-1 px-2 py-1 text-xs border border-border rounded hover:bg-surface-elevated transition-colors"
              title="Import permissions from file"
            >
              <svg className="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12" />
              </svg>
              Import
            </button>
            <button
              onClick={handleExport}
              className="flex items-center gap-1 px-2 py-1 text-xs border border-border rounded hover:bg-surface-elevated transition-colors"
              title="Export permissions to file"
            >
              <svg className="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4" />
              </svg>
              Export
            </button>

          {/* Preset Buttons */}

            Presets:
            <button
              onClick={() => applyPreset('minimal')}
              disabled={applyingPreset}
              className="px-2 py-1 text-xs border border-border rounded hover:bg-surface-elevated transition-colors disabled:opacity-50"
            >
              Minimal
            </button>
            <button
              onClick={() => applyPreset('standard')}
              disabled={applyingPreset}
              className="px-2 py-1 text-xs border border-border rounded hover:bg-surface-elevated transition-colors disabled:opacity-50"
            >
              Standard
            </button>
            <button
              onClick={() => applyPreset('full')}
              disabled={applyingPreset}
              className="px-2 py-1 text-xs border border-border rounded hover:bg-surface-elevated transition-colors disabled:opacity-50"
            >
              Full Access
            </button>

          <button
            onClick={() => setShowAddForm(!showAddForm)}
            className="flex items-center gap-2 px-3 py-1.5 bg-accent text-white text-sm rounded hover:bg-accent/80 transition-colors"
          >
            <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
              <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 4v16m8-8H4" />
            </svg>
            Add Permission
          </button>

      {/* Error */}
      {error && (

          <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
            <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
          </svg>
          {error}

      )}

      {/* Add Permission Form */}
      {showAddForm && (

Add New Permission

              Permission Type
              <input
                type="text"
                value={newPermission.permission_type}
                onChange={(e) => setNewPermission({ ...newPermission, permission_type: e.target.value })}
                placeholder="e.g., Bash, Read, Write"
                className="w-full px-3 py-2 bg-surface border border-border rounded text-sm focus:outline-none focus:ring-2 focus:ring-accent"
              />

              Permission Value
              <input
                type="text"
                value={newPermission.permission_value}
                onChange={(e) => setNewPermission({ ...newPermission, permission_value: e.target.value })}
                placeholder="e.g., npm install, /path/to/file"
                className="w-full px-3 py-2 bg-surface border border-border rounded text-sm focus:outline-none focus:ring-2 focus:ring-accent"
              />

              Granted

                  <input
                    type="checkbox"
                    checked={newPermission.granted}
                    onChange={(e) => setNewPermission({ ...newPermission, granted: e.target.checked })}
                    className="w-4 h-4 rounded border-border text-accent focus:ring-accent"
                  />
                  Granted by default

            <button
              onClick={() => setShowAddForm(false)}
              className="px-3 py-1.5 text-sm border border-border rounded hover:bg-surface-elevated transition-colors"
            >
              Cancel
            </button>
            <button
              onClick={handleAddPermission}
              disabled={saving}
              className="px-3 py-1.5 text-sm bg-accent text-white rounded hover:bg-accent/80 transition-colors disabled:opacity-50"
            >
              {saving ? 'Adding...' : 'Add Permission'}
            </button>

      )}

      {/* Permissions List */}

        {permissions.length === 0 ? (

            <svg className="w-12 h-12 mx-auto text-text-secondary/50" fill="none" stroke="currentColor" viewBox="0 0 24 24">
              <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z" />
            </svg>

No permissions configured

Add permissions to control what operations are allowed

        ) : (

            {/* Header Row */}

Type

Value

Status

Actions

            {/* Permission Rows */}
            {permissions.map((permission) => (

                    {permission.permission_type}

                    {permission.permission_value}

                  <button
                    onClick={() => handleToggleGranted(permission)}
                    className={`flex items-center gap-1.5 px-2 py-1 rounded text-xs font-medium transition-colors ${
                      permission.granted
                        ? 'bg-success/20 text-success hover:bg-success/30'
                        : 'bg-error/20 text-error hover:bg-error/30'
                    }`}
                  >
                    {permission.granted ? (
                      <>
                        <svg className="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                          <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
                        </svg>
                        Granted
                      </>
                    ) : (
                      <>
                        <svg className="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                          <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
                        </svg>
                        Denied
                      </>
                    )}
                  </button>

                    {new Date(permission.created_at).toLocaleDateString()}

                  <button
                    onClick={() => setDeleteConfirm(permission)}
                    className="p-1 text-text-secondary hover:text-error hover:bg-error/10 rounded transition-colors"
                    title="Delete permission"
                  >
                    <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                      <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
                    </svg>
                  </button>

            ))}

        )}

      {/* Delete Confirmation Modal */}
      {deleteConfirm && (

                <svg className="w-5 h-5 text-error" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                  <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
                </svg>

Delete Permission

              Are you sure you want to delete this permission?

                  {deleteConfirm.permission_type}

                  {deleteConfirm.permission_value}

              <button
                onClick={() => setDeleteConfirm(null)}
                className="px-4 py-2 text-sm border border-border rounded hover:bg-surface-elevated transition-colors"
              >
                Cancel
              </button>
              <button
                onClick={handleDeletePermission}
                className="px-4 py-2 text-sm bg-error text-white rounded hover:bg-error/80 transition-colors"
              >
                Delete
              </button>

      )}

  )
}

export default PermissionEditor

+        <div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50">

+          <div className="bg-surface rounded-lg border border-border shadow-xl w-full max-w-lg mx-4 p-6">

+            <div className="flex items-center gap-3 mb-4">

+              <div className="w-10 h-10 rounded-full bg-accent/20 flex items-center justify-center">

+                <svg className="w-5 h-5 text-accent" fill="none" stroke="currentColor" viewBox="0 0 24 24">

+                  <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12" />

+            <p className="text-text-secondary mb-4">

+              Import permissions from a JSON configuration file.

+              <label className="block text-sm font-medium mb-2">Select File</label>

+                onChange={handleFileSelect}

+                className="w-full px-3 py-2 bg-surface-elevated border border-border rounded text-sm file:mr-4 file:py-1 file:px-3 file:rounded file:border-0 file:text-sm file:bg-accent file:text-white hover:file:bg-accent/80 file:cursor-pointer"

+              <label className="block text-sm font-medium mb-2">Or Paste JSON</label>

+                onChange={(e) => setImportText(e.target.value)}

+                placeholder='[{"permission_type": "Read", "permission_value": "/src/**", "granted": true}]'

+                className="w-full h-32 px-3 py-2 bg-surface-elevated border border-border rounded text-sm font-mono focus:outline-none focus:ring-2 focus:ring-accent resize-none"

+            {/* Replace existing checkbox */}

+              <label className="flex items-center gap-2 cursor-pointer">

+                  checked={replaceExisting}

+                  onChange={(e) => setReplaceExisting(e.target.checked)}

+                  className="w-4 h-4 rounded border-border text-accent focus:ring-accent"

+                Replace existing permissions (deletes all current permissions first)

+              <div className="mb-4 flex items-center gap-2 text-error bg-error/10 px-4 py-2 rounded">

+                <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">

+                  <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />

+            <div className="flex justify-end gap-3">

+                  setShowImportModal(false)

+                  setReplaceExisting(false)

+                className="px-4 py-2 text-sm border border-border rounded hover:bg-surface-elevated transition-colors"

+                disabled={importing || !importText.trim()}

+                className="px-4 py-2 text-sm bg-accent text-white rounded hover:bg-accent/80 transition-colors disabled:opacity-50"

+                {importing ? 'Importing...' : 'Import'}


Now let me start a new server on port 8097 to pick up the backend changes and test the feature:


Write

#!/bin/bash
# Start server on port 8097
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
BACKEND_DIR="$SCRIPT_DIR/backend"
VENV_DIR="$BACKEND_DIR/venv"

# Determine the Python executable in venv
if [ -f "$VENV_DIR/Scripts/python.exe" ]; then
    VENV_PYTHON="$VENV_DIR/Scripts/python.exe"
elif [ -f "$VENV_DIR/bin/python" ]; then
    VENV_PYTHON="$VENV_DIR/bin/python"
else
    echo "ERROR: Could not find Python in virtual environment"
    exit 1
fi

cd "$BACKEND_DIR"
"$VENV_PYTHON" -m uvicorn app.main:app --host 127.0.0.1 --port 8097


File created successfully at: C:\Users\MikeSwanson\claude-projects\Autocode-remix\Autocode-fork\start_server_8097.sh

#!/bin/bash
# Start server on port 8097
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
BACKEND_DIR="$SCRIPT_DIR/backend"
VENV_DIR="$BACKEND_DIR/venv"

# Determine the Python executable in venv
if [ -f "$VENV_DIR/Scripts/python.exe" ]; then
    VENV_PYTHON="$VENV_DIR/Scripts/python.exe"
elif [ -f "$VENV_DIR/bin/python" ]; then
    VENV_PYTHON="$VENV_DIR/bin/python"
else
    echo "ERROR: Could not find Python in virtual environment"
    exit 1
fi

cd "$BACKEND_DIR"
"$VENV_PYTHON" -m uvicorn app.main:app --host 127.0.0.1 --port 8097


Bash

Start backend server on port 8097


Command running in background with ID: bba787a. Output is being written to: C:\Users\MIKESW~1\AppData\Local\Temp\claude\C--Users-MikeSwanson-claude-projects-Autocode-remix-Autocode-fork\tasks\bba787a.output


sleep 2 && curl -s http://127.0.0.1:8097/api/projects/detail-test 2>&1

Test new server on port 8097


Server is running. Now let me test the import/export API endpoints:


curl -s http://127.0.0.1:8097/api/projects/dup-source-test/permissions/export 2>&1

Test export permissions endpoint


Input should be a valid integer, unable to parse string as an integer

Input: export

Input: export


There's a route conflict - the `/export` is being matched by the `/{permission_id}` route. I need to move the export endpoint before the permission_id route. Let me fix this:


   120→
   121→# ============================================================================
   122→# Permission Endpoints
   123→# ============================================================================
   124→
   125→@router.get("/{name}/permissions", response_model=PermissionListResponse)
   126→async def list_permissions(name: str, db: AsyncSession = Depends(get_db)):
   127→    """List all permissions for a project."""
   128→    # Verify project exists
   129→    result = await db.execute(select(Project).where(Project.name == name))
   130→    project = result.scalar_one_or_none()
   131→
   132→    if not project:
   133→        raise HTTPException(
   134→            status_code=status.HTTP_404_NOT_FOUND,
   135→            detail=f"Project '{name}' not found"
   136→        )
   137→
   138→    # Get permissions
   139→    result = await db.execute(
   140→        select(Permission)
   141→        .where(Permission.project_id == project.id)
   142→        .order_by(Permission.created_at.desc())
   143→    )
   144→    permissions = result.scalars().all()
   145→
   146→    return PermissionListResponse(
   147→        permissions=[PermissionResponse.model_validate(p) for p in permissions],
   148→        count=len(permissions)
   149→    )
   150→
   151→
   152→@router.post("/{name}/permissions", response_model=PermissionResponse, status_code=status.HTTP_201_CREATED)
   153→async def create_permission(name: str, permission: PermissionCreate, db: AsyncSession = Depends(get_db)):
   154→    """Create a new permission for a project."""
   155→    # Verify project exists
   156→    result = await db.execute(select(Project).where(Project.name == name))
   157→    project = result.scalar_one_or_none()
   158→
   159→    if not project:
   160→        raise HTTPException(
   161→            status_code=status.HTTP_404_NOT_FOUND,
   162→            detail=f"Project '{name}' not found"
   163→        )
   164→
   165→    # Check if permission already exists
   166→    result = await db.execute(
   167→        select(Permission).where(and_(
   168→            Permission.project_id == project.id,
   169→            Permission.permission_type == permission.permission_type,
   170→            Permission.permission_value == permission.permission_value
   171→        ))
   172→    )
   173→    existing = result.scalar_one_or_none()
   174→    if existing:
   175→        raise HTTPException(
   176→            status_code=status.HTTP_409_CONFLICT,
   177→            detail=f"Permission already exists"
   178→        )
   179→

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

# ============================================================================
# Permission Endpoints
# ============================================================================

@router.get("/{name}/permissions", response_model=PermissionListResponse)
async def list_permissions(name: str, db: AsyncSession = Depends(get_db)):
    """List all permissions for a project."""
    # Verify project exists
    result = await db.execute(select(Project).where(Project.name == name))
    project = result.scalar_one_or_none()

    if not project:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Project '{name}' not found"
        )

    # Get permissions
    result = await db.execute(
        select(Permission)
        .where(Permission.project_id == project.id)
        .order_by(Permission.created_at.desc())
    )
    permissions = result.scalars().all()

    return PermissionListResponse(
        permissions=[PermissionResponse.model_validate(p) for p in permissions],
        count=len(permissions)
    )

@router.post("/{name}/permissions", response_model=PermissionResponse, status_code=status.HTTP_201_CREATED)
async def create_permission(name: str, permission: PermissionCreate, db: AsyncSession = Depends(get_db)):
    """Create a new permission for a project."""
    # Verify project exists
    result = await db.execute(select(Project).where(Project.name == name))
    project = result.scalar_one_or_none()

    if not project:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Project '{name}' not found"
        )

    # Check if permission already exists
    result = await db.execute(
        select(Permission).where(and_(
            Permission.project_id == project.id,
            Permission.permission_type == permission.permission_type,
            Permission.permission_value == permission.permission_value
        ))
    )
    existing = result.scalar_one_or_none()
    if existing:
        raise HTTPException(
            status_code=status.HTTP_409_CONFLICT,
            detail=f"Permission already exists"
        )


I need to move the import/export endpoints to be before the `/{permission_id}` routes. Let me insert them right after the `create_permission` endpoint:


   175→        raise HTTPException(
   176→            status_code=status.HTTP_409_CONFLICT,
   177→            detail=f"Permission already exists"
   178→        )
   179→
   180→    # Create permission
   181→    db_permission = Permission(
   182→        project_id=project.id,
   183→        permission_type=permission.permission_type,
   184→        permission_value=permission.permission_value,
   185→        granted=permission.granted,
   186→    )
   187→    db.add(db_permission)
   188→    await db.commit()
   189→    await db.refresh(db_permission)
   190→
   191→    return PermissionResponse.model_validate(db_permission)
   192→
   193→
   194→@router.get("/{name}/permissions/{permission_id}", response_model=PermissionResponse)
   195→async def get_permission(name: str, permission_id: int, db: AsyncSession = Depends(get_db)):
   196→    """Get a specific permission by ID."""
   197→    # Verify project exists
   198→    result = await db.execute(select(Project).where(Project.name == name))
   199→    project = result.scalar_one_or_none()
   200→
   201→    if not project:
   202→        raise HTTPException(
   203→            status_code=status.HTTP_404_NOT_FOUND,
   204→            detail=f"Project '{name}' not found"

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

        raise HTTPException(
            status_code=status.HTTP_409_CONFLICT,
            detail=f"Permission already exists"
        )

    # Create permission
    db_permission = Permission(
        project_id=project.id,
        permission_type=permission.permission_type,
        permission_value=permission.permission_value,
        granted=permission.granted,
    )
    db.add(db_permission)
    await db.commit()
    await db.refresh(db_permission)

    return PermissionResponse.model_validate(db_permission)

@router.get("/{name}/permissions/{permission_id}", response_model=PermissionResponse)
async def get_permission(name: str, permission_id: int, db: AsyncSession = Depends(get_db)):
    """Get a specific permission by ID."""
    # Verify project exists
    result = await db.execute(select(Project).where(Project.name == name))
    project = result.scalar_one_or_none()

    if not project:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Project '{name}' not found"


I need to move the import/export endpoints from the bottom of the file to right after `create_permission`. Let me read the full import/export section:


   456→    return PermissionRequestResponse.model_validate(request)
   457→
   458→
   459→# ============================================================================
   460→# Permission Import/Export Endpoints
   461→# ============================================================================
   462→
   463→@router.post("/{name}/permissions/import", response_model=PermissionImportResponse)
   464→async def import_permissions(name: str, import_data: PermissionImportRequest, db: AsyncSession = Depends(get_db)):
   465→    """Import permissions from a configuration file."""
   466→    # Verify project exists
   467→    result = await db.execute(select(Project).where(Project.name == name))
   468→    project = result.scalar_one_or_none()
   469→
   470→    if not project:
   471→        raise HTTPException(
   472→            status_code=status.HTTP_404_NOT_FOUND,
   473→            detail=f"Project '{name}' not found"
   474→        )
   475→
   476→    imported = 0
   477→    skipped = 0
   478→
   479→    # If replace_existing is true, delete all existing permissions first
   480→    if import_data.replace_existing:
   481→        existing_result = await db.execute(
   482→            select(Permission).where(Permission.project_id == project.id)
   483→        )
   484→        existing_permissions = existing_result.scalars().all()
   485→        for perm in existing_permissions:
   486→            await db.delete(perm)
   487→
   488→    # Import each permission
   489→    for perm in import_data.permissions:
   490→        # Check if permission already exists (skip duplicates)
   491→        result = await db.execute(
   492→            select(Permission).where(and_(
   493→                Permission.project_id == project.id,
   494→                Permission.permission_type == perm.permission_type,
   495→                Permission.permission_value == perm.permission_value
   496→            ))
   497→        )
   498→        existing = result.scalar_one_or_none()
   499→
   500→        if existing:
   501→            skipped += 1
   502→            continue
   503→
   504→        # Create new permission
   505→        db_permission = Permission(
   506→            project_id=project.id,
   507→            permission_type=perm.permission_type,
   508→            permission_value=perm.permission_value,
   509→            granted=perm.granted,
   510→        )
   511→        db.add(db_permission)
   512→        imported += 1
   513→
   514→    await db.commit()
   515→
   516→    return PermissionImportResponse(
   517→        imported=imported,
   518→        skipped=skipped,
   519→        message=f"Successfully imported {imported} permissions ({skipped} skipped as duplicates)"
   520→    )
   521→
   522→
   523→@router.get("/{name}/permissions/export", response_model=PermissionExportResponse)
   524→async def export_permissions(name: str, db: AsyncSession = Depends(get_db)):
   525→    """Export permissions to a configuration format."""
   526→    # Verify project exists
   527→    result = await db.execute(select(Project).where(Project.name == name))
   528→    project = result.scalar_one_or_none()
   529→
   530→    if not project:
   531→        raise HTTPException(
   532→            status_code=status.HTTP_404_NOT_FOUND,
   533→            detail=f"Project '{name}' not found"
   534→        )
   535→
   536→    # Get all permissions
   537→    result = await db.execute(
   538→        select(Permission)
   539→        .where(Permission.project_id == project.id)
   540→        .order_by(Permission.permission_type, Permission.permission_value)
   541→    )
   542→    permissions = result.scalars().all()
   543→
   544→    return PermissionExportResponse(
   545→        project_name=name,
   546→        permissions=[
   547→            PermissionExportItem(
   548→                permission_type=p.permission_type,
   549→                permission_value=p.permission_value,
   550→                granted=p.granted
   551→            )
   552→            for p in permissions
   553→        ],
   554→        count=len(permissions)
   555→    )
   556→

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

    return PermissionRequestResponse.model_validate(request)

# ============================================================================
# Permission Import/Export Endpoints
# ============================================================================

@router.post("/{name}/permissions/import", response_model=PermissionImportResponse)
async def import_permissions(name: str, import_data: PermissionImportRequest, db: AsyncSession = Depends(get_db)):
    """Import permissions from a configuration file."""
    # Verify project exists
    result = await db.execute(select(Project).where(Project.name == name))
    project = result.scalar_one_or_none()

    if not project:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Project '{name}' not found"
        )

    imported = 0
    skipped = 0

    # If replace_existing is true, delete all existing permissions first
    if import_data.replace_existing:
        existing_result = await db.execute(
            select(Permission).where(Permission.project_id == project.id)
        )
        existing_permissions = existing_result.scalars().all()
        for perm in existing_permissions:
            await db.delete(perm)

    # Import each permission
    for perm in import_data.permissions:
        # Check if permission already exists (skip duplicates)
        result = await db.execute(
            select(Permission).where(and_(
                Permission.project_id == project.id,
                Permission.permission_type == perm.permission_type,
                Permission.permission_value == perm.permission_value
            ))
        )
        existing = result.scalar_one_or_none()

        if existing:
            skipped += 1
            continue

        # Create new permission
        db_permission = Permission(
            project_id=project.id,
            permission_type=perm.permission_type,
            permission_value=perm.permission_value,
            granted=perm.granted,
        )
        db.add(db_permission)
        imported += 1

    await db.commit()

    return PermissionImportResponse(
        imported=imported,
        skipped=skipped,
        message=f"Successfully imported {imported} permissions ({skipped} skipped as duplicates)"
    )

@router.get("/{name}/permissions/export", response_model=PermissionExportResponse)
async def export_permissions(name: str, db: AsyncSession = Depends(get_db)):
    """Export permissions to a configuration format."""
    # Verify project exists
    result = await db.execute(select(Project).where(Project.name == name))
    project = result.scalar_one_or_none()

    if not project:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Project '{name}' not found"
        )

    # Get all permissions
    result = await db.execute(
        select(Permission)
        .where(Permission.project_id == project.id)
        .order_by(Permission.permission_type, Permission.permission_value)
    )
    permissions = result.scalars().all()

    return PermissionExportResponse(
        project_name=name,
        permissions=[
            PermissionExportItem(
                permission_type=p.permission_type,
                permission_value=p.permission_value,
                granted=p.granted
            )
            for p in permissions
        ],
        count=len(permissions)
    )


I need to remove the import/export section from the end and insert it after `create_permission`. Let me do this in two steps:


Edit

    return PermissionResponse.model_validate(db_permission)

@router.get("/{name}/permissions/{permission_id}", response_model=PermissionResponse)
async def get_permission(name: str, permission_id: int, db: AsyncSession = Depends(get_db)):

    return PermissionResponse.model_validate(db_permission)

# ============================================================================
# Permission Import/Export Endpoints (must be before /{permission_id} routes)
# ============================================================================

@router.get("/{name}/permissions/export", response_model=PermissionExportResponse)
async def export_permissions(name: str, db: AsyncSession = Depends(get_db)):
    """Export permissions to a configuration format."""
    # Verify project exists
    result = await db.execute(select(Project).where(Project.name == name))
    project = result.scalar_one_or_none()

    if not project:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Project '{name}' not found"
        )

    # Get all permissions
    result = await db.execute(
        select(Permission)
        .where(Permission.project_id == project.id)
        .order_by(Permission.permission_type, Permission.permission_value)
    )
    permissions = result.scalars().all()

    return PermissionExportResponse(
        project_name=name,
        permissions=[
            PermissionExportItem(
                permission_type=p.permission_type,
                permission_value=p.permission_value,
                granted=p.granted
            )
            for p in permissions
        ],
        count=len(permissions)
    )

@router.post("/{name}/permissions/import", response_model=PermissionImportResponse)
async def import_permissions(name: str, import_data: PermissionImportRequest, db: AsyncSession = Depends(get_db)):
    """Import permissions from a configuration file."""
    # Verify project exists
    result = await db.execute(select(Project).where(Project.name == name))
    project = result.scalar_one_or_none()

    if not project:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Project '{name}' not found"
        )

    imported = 0
    skipped = 0

    # If replace_existing is true, delete all existing permissions first
    if import_data.replace_existing:
        existing_result = await db.execute(
            select(Permission).where(Permission.project_id == project.id)
        )
        existing_permissions = existing_result.scalars().all()
        for perm in existing_permissions:
            await db.delete(perm)

    # Import each permission
    for perm in import_data.permissions:
        # Check if permission already exists (skip duplicates)
        result = await db.execute(
            select(Permission).where(and_(
                Permission.project_id == project.id,
                Permission.permission_type == perm.permission_type,
                Permission.permission_value == perm.permission_value
            ))
        )
        existing = result.scalar_one_or_none()

        if existing:
            skipped += 1
            continue

        # Create new permission
        db_permission = Permission(
            project_id=project.id,
            permission_type=perm.permission_type,
            permission_value=perm.permission_value,
            granted=perm.granted,
        )
        db.add(db_permission)
        imported += 1

    await db.commit()

    return PermissionImportResponse(
        imported=imported,
        skipped=skipped,
        message=f"Successfully imported {imported} permissions ({skipped} skipped as duplicates)"
    )

# ============================================================================
# Permission ID Endpoints
# ============================================================================

@router.get("/{name}/permissions/{permission_id}", response_model=PermissionResponse)
async def get_permission(name: str, permission_id: int, db: AsyncSession = Depends(get_db)):


The file C:\Users\MikeSwanson\claude-projects\Autocode-remix\Autocode-fork\backend\app\routers\permissions.py has been updated. Here's the result of running `cat -n` on a snippet of the edited file:
   187→    db.add(db_permission)
   188→    await db.commit()
   189→    await db.refresh(db_permission)
   190→
   191→    return PermissionResponse.model_validate(db_permission)
   192→
   193→
   194→# ============================================================================
   195→# Permission Import/Export Endpoints (must be before /{permission_id} routes)
   196→# ============================================================================
   197→
   198→@router.get("/{name}/permissions/export", response_model=PermissionExportResponse)
   199→async def export_permissions(name: str, db: AsyncSession = Depends(get_db)):
   200→    """Export permissions to a configuration format."""
   201→    # Verify project exists
   202→    result = await db.execute(select(Project).where(Project.name == name))
   203→    project = result.scalar_one_or_none()
   204→
   205→    if not project:
   206→        raise HTTPException(
   207→            status_code=status.HTTP_404_NOT_FOUND,
   208→            detail=f"Project '{name}' not found"
   209→        )
   210→
   211→    # Get all permissions
   212→    result = await db.execute(
   213→        select(Permission)
   214→        .where(Permission.project_id == project.id)
   215→        .order_by(Permission.permission_type, Permission.permission_value)
   216→    )
   217→    permissions = result.scalars().all()
   218→
   219→    return PermissionExportResponse(
   220→        project_name=name,
   221→        permissions=[
   222→            PermissionExportItem(
   223→                permission_type=p.permission_type,
   224→                permission_value=p.permission_value,
   225→                granted=p.granted
   226→            )
   227→            for p in permissions
   228→        ],
   229→        count=len(permissions)
   230→    )
   231→
   232→
   233→@router.post("/{name}/permissions/import", response_model=PermissionImportResponse)
   234→async def import_permissions(name: str, import_data: PermissionImportRequest, db: AsyncSession = Depends(get_db)):
   235→    """Import permissions from a configuration file."""
   236→    # Verify project exists
   237→    result = await db.execute(select(Project).where(Project.name == name))
   238→    project = result.scalar_one_or_none()
   239→
   240→    if not project:
   241→        raise HTTPException(
   242→            status_code=status.HTTP_404_NOT_FOUND,
   243→            detail=f"Project '{name}' not found"
   244→        )
   245→
   246→    imported = 0
   247→    skipped = 0
   248→
   249→    # If replace_existing is true, delete all existing permissions first
   250→    if import_data.replace_existing:
   251→        existing_result = await db.execute(
   252→            select(Permission).where(Permission.project_id == project.id)
   253→        )
   254→        existing_permissions = existing_result.scalars().all()
   255→        for perm in existing_permissions:
   256→            await db.delete(perm)
   257→
   258→    # Import each permission
   259→    for perm in import_data.permissions:
   260→        # Check if permission already exists (skip duplicates)
   261→        result = await db.execute(
   262→            select(Permission).where(and_(
   263→                Permission.project_id == project.id,
   264→                Permission.permission_type == perm.permission_type,
   265→                Permission.permission_value == perm.permission_value
   266→            ))
   267→        )
   268→        existing = result.scalar_one_or_none()
   269→
   270→        if existing:
   271→            skipped += 1
   272→            continue
   273→
   274→        # Create new permission
   275→        db_permission = Permission(
   276→            project_id=project.id,
   277→            permission_type=perm.permission_type,
   278→            permission_value=perm.permission_value,
   279→            granted=perm.granted,
   280→        )
   281→        db.add(db_permission)
   282→        imported += 1
   283→
   284→    await db.commit()
   285→
   286→    return PermissionImportResponse(
   287→        imported=imported,
   288→        skipped=skipped,
   289→        message=f"Successfully imported {imported} permissions ({skipped} skipped as duplicates)"
   290→    )
   291→
   292→
   293→# ============================================================================
   294→# Permission ID Endpoints
   295→# ============================================================================
   296→
   297→@router.get("/{name}/permissions/{permission_id}", response_model=PermissionResponse)
   298→async def get_permission(name: str, permission_id: int, db: AsyncSession = Depends(get_db)):
   299→    """Get a specific permission by ID."""
   300→    # Verify project exists
   301→    result = await db.execute(select(Project).where(Project.name == name))
   302→    project = result.scalar_one_or_none()

    return PermissionResponse.model_validate(db_permission)

# ============================================================================
# Permission Import/Export Endpoints (must be before /{permission_id} routes)
# ============================================================================

@router.get("/{name}/permissions/export", response_model=PermissionExportResponse)
async def export_permissions(name: str, db: AsyncSession = Depends(get_db)):
    """Export permissions to a configuration format."""
    # Verify project exists
    result = await db.execute(select(Project).where(Project.name == name))
    project = result.scalar_one_or_none()

    if not project:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Project '{name}' not found"
        )

    # Get all permissions
    result = await db.execute(
        select(Permission)
        .where(Permission.project_id == project.id)
        .order_by(Permission.permission_type, Permission.permission_value)
    )
    permissions = result.scalars().all()

    return PermissionExportResponse(
        project_name=name,
        permissions=[
            PermissionExportItem(
                permission_type=p.permission_type,
                permission_value=p.permission_value,
                granted=p.granted
            )
            for p in permissions
        ],
        count=len(permissions)
    )

@router.post("/{name}/permissions/import", response_model=PermissionImportResponse)
async def import_permissions(name: str, import_data: PermissionImportRequest, db: AsyncSession = Depends(get_db)):
    """Import permissions from a configuration file."""
    # Verify project exists
    result = await db.execute(select(Project).where(Project.name == name))
    project = result.scalar_one_or_none()

    if not project:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Project '{name}' not found"
        )

    imported = 0
    skipped = 0

    # If replace_existing is true, delete all existing permissions first
    if import_data.replace_existing:
        existing_result = await db.execute(
            select(Permission).where(Permission.project_id == project.id)
        )
        existing_permissions = existing_result.scalars().all()
        for perm in existing_permissions:
            await db.delete(perm)

    # Import each permission
    for perm in import_data.permissions:
        # Check if permission already exists (skip duplicates)
        result = await db.execute(
            select(Permission).where(and_(
                Permission.project_id == project.id,
                Permission.permission_type == perm.permission_type,
                Permission.permission_value == perm.permission_value
            ))
        )
        existing = result.scalar_one_or_none()

        if existing:
            skipped += 1
            continue

        # Create new permission
        db_permission = Permission(
            project_id=project.id,
            permission_type=perm.permission_type,
            permission_value=perm.permission_value,
            granted=perm.granted,
        )
        db.add(db_permission)
        imported += 1

    await db.commit()

    return PermissionImportResponse(
        imported=imported,
        skipped=skipped,
        message=f"Successfully imported {imported} permissions ({skipped} skipped as duplicates)"
    )

# ============================================================================
# Permission ID Endpoints
# ============================================================================

@router.get("/{name}/permissions/{permission_id}", response_model=PermissionResponse)
async def get_permission(name: str, permission_id: int, db: AsyncSession = Depends(get_db)):

"""
Permissions Router
==================

API endpoints for permission management within projects.
"""

from datetime import datetime
from typing import Optional, List

from fastapi import APIRouter, Depends, HTTPException, status
from pydantic import BaseModel, Field
from sqlalchemy import select, and_
from sqlalchemy.ext.asyncio import AsyncSession

from ..database import get_db
from ..models import Project, Permission, PermissionRequest

router = APIRouter(prefix="/api/projects", tags=["permissions"])

# ============================================================================
# Pydantic Schemas
# ============================================================================

class PermissionResponse(BaseModel):
    """Schema for permission response."""
    id: int
    project_id: int
    permission_type: str
    permission_value: str
    granted: bool
    created_at: datetime

    class Config:
        from_attributes = True

class PermissionListResponse(BaseModel):
    """Schema for permission list response."""
    permissions: List[PermissionResponse]
    count: int

class PermissionCreate(BaseModel):
    """Schema for creating a permission."""
    permission_type: str = Field(..., min_length=1, max_length=50)
    permission_value: str = Field(..., min_length=1, max_length=500)
    granted: bool = True

class PermissionUpdate(BaseModel):
    """Schema for updating a permission."""
    granted: Optional[bool] = None

class PermissionRequestResponse(BaseModel):
    """Schema for permission request response."""
    id: int
    project_id: int
    feature_id: Optional[int]
    agent_id: str
    permission_type: str
    permission_value: str
    status: str
    requested_at: datetime
    resolved_at: Optional[datetime]

    class Config:
        from_attributes = True

class PermissionRequestListResponse(BaseModel):
    """Schema for permission request list response."""
    requests: List[PermissionRequestResponse]
    count: int

class PermissionRequestCreate(BaseModel):
    """Schema for creating a permission request."""
    agent_id: str = Field(..., min_length=1, max_length=1)  # "A" or "B"
    permission_type: str = Field(..., min_length=1, max_length=50)
    permission_value: str = Field(..., min_length=1, max_length=500)
    feature_id: Optional[int] = None

class PermissionImportItem(BaseModel):
    """Schema for a single permission in import."""
    permission_type: str = Field(..., min_length=1, max_length=50)
    permission_value: str = Field(..., min_length=1, max_length=500)
    granted: bool = True

class PermissionImportRequest(BaseModel):
    """Schema for importing permissions from configuration."""
    permissions: List[PermissionImportItem]
    replace_existing: bool = False  # If true, delete all existing permissions first

class PermissionImportResponse(BaseModel):
    """Schema for import response."""
    imported: int
    skipped: int
    message: str

class PermissionExportItem(BaseModel):
    """Schema for a single permission in export."""
    permission_type: str
    permission_value: str
    granted: bool

class PermissionExportResponse(BaseModel):
    """Schema for export response."""
    project_name: str
    permissions: List[PermissionExportItem]
    count: int

# ============================================================================
# Permission Endpoints
# ============================================================================

@router.get("/{name}/permissions", response_model=PermissionListResponse)
async def list_permissions(name: str, db: AsyncSession = Depends(get_db)):
    """List all permissions for a project."""
    # Verify project exists
    result = await db.execute(select(Project).where(Project.name == name))
    project = result.scalar_one_or_none()

    if not project:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Project '{name}' not found"
        )

    # Get permissions
    result = await db.execute(
        select(Permission)
        .where(Permission.project_id == project.id)
        .order_by(Permission.created_at.desc())
    )
    permissions = result.scalars().all()

    return PermissionListResponse(
        permissions=[PermissionResponse.model_validate(p) for p in permissions],
        count=len(permissions)
    )

@router.post("/{name}/permissions", response_model=PermissionResponse, status_code=status.HTTP_201_CREATED)
async def create_permission(name: str, permission: PermissionCreate, db: AsyncSession = Depends(get_db)):
    """Create a new permission for a project."""
    # Verify project exists
    result = await db.execute(select(Project).where(Project.name == name))
    project = result.scalar_one_or_none()

    if not project:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Project '{name}' not found"
        )

    # Check if permission already exists
    result = await db.execute(
        select(Permission).where(and_(
            Permission.project_id == project.id,
            Permission.permission_type == permission.permission_type,
            Permission.permission_value == permission.permission_value
        ))
    )
    existing = result.scalar_one_or_none()
    if existing:
        raise HTTPException(
            status_code=status.HTTP_409_CONFLICT,
            detail=f"Permission already exists"
        )

    # Create permission
    db_permission = Permission(
        project_id=project.id,
        permission_type=permission.permission_type,
        permission_value=permission.permission_value,
        granted=permission.granted,
    )
    db.add(db_permission)
    await db.commit()
    await db.refresh(db_permission)

    return PermissionResponse.model_validate(db_permission)

@router.get("/{name}/permissions/{permission_id}", response_model=PermissionResponse)
async def get_permission(name: str, permission_id: int, db: AsyncSession = Depends(get_db)):
    """Get a specific permission by ID."""
    # Verify project exists
    result = await db.execute(select(Project).where(Project.name == name))
    project = result.scalar_one_or_none()

    if not project:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Project '{name}' not found"
        )

    # Get permission
    result = await db.execute(
        select(Permission).where(and_(
            Permission.id == permission_id,
            Permission.project_id == project.id
        ))
    )
    permission = result.scalar_one_or_none()

    if not permission:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Permission {permission_id} not found in project '{name}'"
        )

    return PermissionResponse.model_validate(permission)

@router.put("/{name}/permissions/{permission_id}", response_model=PermissionResponse)
async def update_permission(name: str, permission_id: int, permission_update: PermissionUpdate, db: AsyncSession = Depends(get_db)):
    """Update a permission."""
    # Verify project exists
    result = await db.execute(select(Project).where(Project.name == name))
    project = result.scalar_one_or_none()

    if not project:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Project '{name}' not found"
        )

    # Get permission
    result = await db.execute(
        select(Permission).where(and_(
            Permission.id == permission_id,
            Permission.project_id == project.id
        ))
    )
    permission = result.scalar_one_or_none()

    if not permission:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Permission {permission_id} not found in project '{name}'"
        )

    # Update granted status
    if permission_update.granted is not None:
        permission.granted = permission_update.granted

    await db.commit()
    await db.refresh(permission)

    return PermissionResponse.model_validate(permission)

@router.delete("/{name}/permissions/{permission_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_permission(name: str, permission_id: int, db: AsyncSession = Depends(get_db)):
    """Delete a permission."""
    # Verify project exists
    result = await db.execute(select(Project).where(Project.name == name))
    project = result.scalar_one_or_none()

    if not project:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Project '{name}' not found"
        )

    # Get permission
    result = await db.execute(
        select(Permission).where(and_(
            Permission.id == permission_id,
            Permission.project_id == project.id
        ))
    )
    permission = result.scalar_one_or_none()

    if not permission:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Permission {permission_id} not found in project '{name}'"
        )

    await db.delete(permission)
    await db.commit()

# ============================================================================
# Permission Request Endpoints
# ============================================================================

@router.get("/{name}/permission-requests", response_model=PermissionRequestListResponse)
async def list_permission_requests(
    name: str,
    status_filter: Optional[str] = None,
    db: AsyncSession = Depends(get_db)
):
    """List permission requests for a project."""
    # Verify project exists
    result = await db.execute(select(Project).where(Project.name == name))
    project = result.scalar_one_or_none()

    if not project:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Project '{name}' not found"
        )

    # Build query
    query = select(PermissionRequest).where(PermissionRequest.project_id == project.id)

    if status_filter:
        query = query.where(PermissionRequest.status == status_filter)

    query = query.order_by(PermissionRequest.requested_at.desc())

    result = await db.execute(query)
    requests = result.scalars().all()

    return PermissionRequestListResponse(
        requests=[PermissionRequestResponse.model_validate(r) for r in requests],
        count=len(requests)
    )

@router.post("/{name}/permission-requests", response_model=PermissionRequestResponse, status_code=status.HTTP_201_CREATED)
async def create_permission_request(name: str, request: PermissionRequestCreate, db: AsyncSession = Depends(get_db)):
    """Create a new permission request (typically called by agents)."""
    # Verify project exists
    result = await db.execute(select(Project).where(Project.name == name))
    project = result.scalar_one_or_none()

    if not project:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Project '{name}' not found"
        )

    # Create permission request
    db_request = PermissionRequest(
        project_id=project.id,
        feature_id=request.feature_id,
        agent_id=request.agent_id,
        permission_type=request.permission_type,
        permission_value=request.permission_value,
        status="pending",
    )
    db.add(db_request)
    await db.commit()
    await db.refresh(db_request)

    return PermissionRequestResponse.model_validate(db_request)

@router.post("/{name}/permission-requests/{request_id}/grant", response_model=PermissionRequestResponse)
async def grant_permission_request(name: str, request_id: int, db: AsyncSession = Depends(get_db)):
    """Grant a pending permission request."""
    # Verify project exists
    result = await db.execute(select(Project).where(Project.name == name))
    project = result.scalar_one_or_none()

    if not project:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Project '{name}' not found"
        )

    # Get permission request
    result = await db.execute(
        select(PermissionRequest).where(and_(
            PermissionRequest.id == request_id,
            PermissionRequest.project_id == project.id
        ))
    )
    request = result.scalar_one_or_none()

    if not request:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Permission request {request_id} not found"
        )

    if request.status != "pending":
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=f"Permission request is already {request.status}"
        )

    # Update request status
    request.status = "granted"
    request.resolved_at = datetime.utcnow()

    # Create the actual permission
    db_permission = Permission(
        project_id=project.id,
        permission_type=request.permission_type,
        permission_value=request.permission_value,
        granted=True,
    )
    db.add(db_permission)

    await db.commit()
    await db.refresh(request)

    return PermissionRequestResponse.model_validate(request)

@router.post("/{name}/permission-requests/{request_id}/deny", response_model=PermissionRequestResponse)
async def deny_permission_request(name: str, request_id: int, db: AsyncSession = Depends(get_db)):
    """Deny a pending permission request."""
    # Verify project exists
    result = await db.execute(select(Project).where(Project.name == name))
    project = result.scalar_one_or_none()

    if not project:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Project '{name}' not found"
        )

    # Get permission request
    result = await db.execute(
        select(PermissionRequest).where(and_(
            PermissionRequest.id == request_id,
            PermissionRequest.project_id == project.id
        ))
    )
    request = result.scalar_one_or_none()

    if not request:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Permission request {request_id} not found"
        )

    if request.status != "pending":
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=f"Permission request is already {request.status}"
        )

    # Update request status
    request.status = "denied"
    request.resolved_at = datetime.utcnow()

    await db.commit()
    await db.refresh(request)

    return PermissionRequestResponse.model_validate(request)

# ============================================================================
# Permission Import/Export Endpoints
# ============================================================================

@router.post("/{name}/permissions/import", response_model=PermissionImportResponse)
async def import_permissions(name: str, import_data: PermissionImportRequest, db: AsyncSession = Depends(get_db)):
    """Import permissions from a configuration file."""
    # Verify project exists
    result = await db.execute(select(Project).where(Project.name == name))
    project = result.scalar_one_or_none()

    if not project:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Project '{name}' not found"
        )

    imported = 0
    skipped = 0

    # If replace_existing is true, delete all existing permissions first
    if import_data.replace_existing:
        existing_result = await db.execute(
            select(Permission).where(Permission.project_id == project.id)
        )
        existing_permissions = existing_result.scalars().all()
        for perm in existing_permissions:
            await db.delete(perm)

    # Import each permission
    for perm in import_data.permissions:
        # Check if permission already exists (skip duplicates)
        result = await db.execute(
            select(Permission).where(and_(
                Permission.project_id == project.id,
                Permission.permission_type == perm.permission_type,
                Permission.permission_value == perm.permission_value
            ))
        )
        existing = result.scalar_one_or_none()

        if existing:
            skipped += 1
            continue

        # Create new permission
        db_permission = Permission(
            project_id=project.id,
            permission_type=perm.permission_type,
            permission_value=perm.permission_value,
            granted=perm.granted,
        )
        db.add(db_permission)
        imported += 1

    await db.commit()

    return PermissionImportResponse(
        imported=imported,
        skipped=skipped,
        message=f"Successfully imported {imported} permissions ({skipped} skipped as duplicates)"
    )

@router.get("/{name}/permissions/export", response_model=PermissionExportResponse)
async def export_permissions(name: str, db: AsyncSession = Depends(get_db)):
    """Export permissions to a configuration format."""
    # Verify project exists
    result = await db.execute(select(Project).where(Project.name == name))
    project = result.scalar_one_or_none()

    if not project:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Project '{name}' not found"
        )

    # Get all permissions
    result = await db.execute(
        select(Permission)
        .where(Permission.project_id == project.id)
        .order_by(Permission.permission_type, Permission.permission_value)
    )
    permissions = result.scalars().all()

    return PermissionExportResponse(
        project_name=name,
        permissions=[
            PermissionExportItem(
                permission_type=p.permission_type,
                permission_value=p.permission_value,
                granted=p.granted
            )
            for p in permissions
        ],
        count=len(permissions)
    )

+# Permission Import/Export Endpoints (must be before /{permission_id} routes)

+async def export_permissions(name: str, db: AsyncSession = Depends(get_db)):

+    """Export permissions to a configuration format."""

+    result = await db.execute(select(Project).where(Project.name == name))

+    project = result.scalar_one_or_none()

+            status_code=status.HTTP_404_NOT_FOUND,

+            detail=f"Project '{name}' not found"

+        .where(Permission.project_id == project.id)

+        .order_by(Permission.permission_type, Permission.permission_value)

+    permissions = result.scalars().all()

+                permission_type=p.permission_type,

+                permission_value=p.permission_value,

+async def import_permissions(name: str, import_data: PermissionImportRequest, db: AsyncSession = Depends(get_db)):

+    """Import permissions from a configuration file."""

+    # If replace_existing is true, delete all existing permissions first

+        existing_result = await db.execute(

+            select(Permission).where(Permission.project_id == project.id)

+        existing_permissions = existing_result.scalars().all()

+        for perm in existing_permissions:

+    for perm in import_data.permissions:

+        # Check if permission already exists (skip duplicates)

+            select(Permission).where(and_(

+                Permission.project_id == project.id,

+                Permission.permission_type == perm.permission_type,

+                Permission.permission_value == perm.permission_value

+        existing = result.scalar_one_or_none()

+            permission_type=perm.permission_type,

+            permission_value=perm.permission_value,

+        message=f"Successfully imported {imported} permissions ({skipped} skipped as duplicates)"


Now let me remove the duplicate import/export endpoints at the end of the file:


   540→    if not request:
   541→        raise HTTPException(
   542→            status_code=status.HTTP_404_NOT_FOUND,
   543→            detail=f"Permission request {request_id} not found"
   544→        )
   545→
   546→    if request.status != "pending":
   547→        raise HTTPException(
   548→            status_code=status.HTTP_400_BAD_REQUEST,
   549→            detail=f"Permission request is already {request.status}"
   550→        )
   551→
   552→    # Update request status
   553→    request.status = "denied"
   554→    request.resolved_at = datetime.utcnow()
   555→
   556→    await db.commit()
   557→    await db.refresh(request)
   558→
   559→    return PermissionRequestResponse.model_validate(request)
   560→
   561→
   562→# ============================================================================
   563→# Permission Import/Export Endpoints
   564→# ============================================================================
   565→
   566→@router.post("/{name}/permissions/import", response_model=PermissionImportResponse)
   567→async def import_permissions(name: str, import_data: PermissionImportRequest, db: AsyncSession = Depends(get_db)):
   568→    """Import permissions from a configuration file."""
   569→    # Verify project exists
   570→    result = await db.execute(select(Project).where(Project.name == name))
   571→    project = result.scalar_one_or_none()
   572→
   573→    if not project:
   574→        raise HTTPException(
   575→            status_code=status.HTTP_404_NOT_FOUND,
   576→            detail=f"Project '{name}' not found"
   577→        )
   578→
   579→    imported = 0
   580→    skipped = 0
   581→
   582→    # If replace_existing is true, delete all existing permissions first
   583→    if import_data.replace_existing:
   584→        existing_result = await db.execute(
   585→            select(Permission).where(Permission.project_id == project.id)
   586→        )
   587→        existing_permissions = existing_result.scalars().all()
   588→        for perm in existing_permissions:
   589→            await db.delete(perm)
   590→
   591→    # Import each permission
   592→    for perm in import_data.permissions:
   593→        # Check if permission already exists (skip duplicates)
   594→        result = await db.execute(
   595→            select(Permission).where(and_(
   596→                Permission.project_id == project.id,
   597→                Permission.permission_type == perm.permission_type,
   598→                Permission.permission_value == perm.permission_value
   599→            ))
   600→        )
   601→        existing = result.scalar_one_or_none()
   602→
   603→        if existing:
   604→            skipped += 1
   605→            continue
   606→
   607→        # Create new permission
   608→        db_permission = Permission(
   609→            project_id=project.id,
   610→            permission_type=perm.permission_type,
   611→            permission_value=perm.permission_value,
   612→            granted=perm.granted,
   613→        )
   614→        db.add(db_permission)
   615→        imported += 1
   616→
   617→    await db.commit()
   618→
   619→    return PermissionImportResponse(
   620→        imported=imported,
   621→        skipped=skipped,
   622→        message=f"Successfully imported {imported} permissions ({skipped} skipped as duplicates)"
   623→    )
   624→
   625→
   626→@router.get("/{name}/permissions/export", response_model=PermissionExportResponse)
   627→async def export_permissions(name: str, db: AsyncSession = Depends(get_db)):
   628→    """Export permissions to a configuration format."""
   629→    # Verify project exists
   630→    result = await db.execute(select(Project).where(Project.name == name))
   631→    project = result.scalar_one_or_none()
   632→
   633→    if not project:
   634→        raise HTTPException(
   635→            status_code=status.HTTP_404_NOT_FOUND,
   636→            detail=f"Project '{name}' not found"
   637→        )
   638→
   639→    # Get all permissions
   640→    result = await db.execute(
   641→        select(Permission)
   642→        .where(Permission.project_id == project.id)
   643→        .order_by(Permission.permission_type, Permission.permission_value)
   644→    )
   645→    permissions = result.scalars().all()
   646→
   647→    return PermissionExportResponse(
   648→        project_name=name,
   649→        permissions=[
   650→            PermissionExportItem(
   651→                permission_type=p.permission_type,
   652→                permission_value=p.permission_value,
   653→                granted=p.granted
   654→            )
   655→            for p in permissions
   656→        ],
   657→        count=len(permissions)
   658→    )
   659→

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

    if not request:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Permission request {request_id} not found"
        )

    if request.status != "pending":
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=f"Permission request is already {request.status}"
        )

    # Update request status
    request.status = "denied"
    request.resolved_at = datetime.utcnow()

    await db.commit()
    await db.refresh(request)

    return PermissionRequestResponse.model_validate(request)

# ============================================================================
# Permission Import/Export Endpoints
# ============================================================================

@router.post("/{name}/permissions/import", response_model=PermissionImportResponse)
async def import_permissions(name: str, import_data: PermissionImportRequest, db: AsyncSession = Depends(get_db)):
    """Import permissions from a configuration file."""
    # Verify project exists
    result = await db.execute(select(Project).where(Project.name == name))
    project = result.scalar_one_or_none()

    if not project:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Project '{name}' not found"
        )

    imported = 0
    skipped = 0

    # If replace_existing is true, delete all existing permissions first
    if import_data.replace_existing:
        existing_result = await db.execute(
            select(Permission).where(Permission.project_id == project.id)
        )
        existing_permissions = existing_result.scalars().all()
        for perm in existing_permissions:
            await db.delete(perm)

    # Import each permission
    for perm in import_data.permissions:
        # Check if permission already exists (skip duplicates)
        result = await db.execute(
            select(Permission).where(and_(
                Permission.project_id == project.id,
                Permission.permission_type == perm.permission_type,
                Permission.permission_value == perm.permission_value
            ))
        )
        existing = result.scalar_one_or_none()

        if existing:
            skipped += 1
            continue

        # Create new permission
        db_permission = Permission(
            project_id=project.id,
            permission_type=perm.permission_type,
            permission_value=perm.permission_value,
            granted=perm.granted,
        )
        db.add(db_permission)
        imported += 1

    await db.commit()

    return PermissionImportResponse(
        imported=imported,
        skipped=skipped,
        message=f"Successfully imported {imported} permissions ({skipped} skipped as duplicates)"
    )

@router.get("/{name}/permissions/export", response_model=PermissionExportResponse)
async def export_permissions(name: str, db: AsyncSession = Depends(get_db)):
    """Export permissions to a configuration format."""
    # Verify project exists
    result = await db.execute(select(Project).where(Project.name == name))
    project = result.scalar_one_or_none()

    if not project:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Project '{name}' not found"
        )

    # Get all permissions
    result = await db.execute(
        select(Permission)
        .where(Permission.project_id == project.id)
        .order_by(Permission.permission_type, Permission.permission_value)
    )
    permissions = result.scalars().all()

    return PermissionExportResponse(
        project_name=name,
        permissions=[
            PermissionExportItem(
                permission_type=p.permission_type,
                permission_value=p.permission_value,
                granted=p.granted
            )
            for p in permissions
        ],
        count=len(permissions)
    )


    return PermissionRequestResponse.model_validate(request)

# ============================================================================
# Permission Import/Export Endpoints
# ============================================================================

@router.post("/{name}/permissions/import", response_model=PermissionImportResponse)
async def import_permissions(name: str, import_data: PermissionImportRequest, db: AsyncSession = Depends(get_db)):
    """Import permissions from a configuration file."""
    # Verify project exists
    result = await db.execute(select(Project).where(Project.name == name))
    project = result.scalar_one_or_none()

    if not project:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Project '{name}' not found"
        )

    imported = 0
    skipped = 0

    # If replace_existing is true, delete all existing permissions first
    if import_data.replace_existing:
        existing_result = await db.execute(
            select(Permission).where(Permission.project_id == project.id)
        )
        existing_permissions = existing_result.scalars().all()
        for perm in existing_permissions:
            await db.delete(perm)

    # Import each permission
    for perm in import_data.permissions:
        # Check if permission already exists (skip duplicates)
        result = await db.execute(
            select(Permission).where(and_(
                Permission.project_id == project.id,
                Permission.permission_type == perm.permission_type,
                Permission.permission_value == perm.permission_value
            ))
        )
        existing = result.scalar_one_or_none()

        if existing:
            skipped += 1
            continue

        # Create new permission
        db_permission = Permission(
            project_id=project.id,
            permission_type=perm.permission_type,
            permission_value=perm.permission_value,
            granted=perm.granted,
        )
        db.add(db_permission)
        imported += 1

    await db.commit()

    return PermissionImportResponse(
        imported=imported,
        skipped=skipped,
        message=f"Successfully imported {imported} permissions ({skipped} skipped as duplicates)"
    )

@router.get("/{name}/permissions/export", response_model=PermissionExportResponse)
async def export_permissions(name: str, db: AsyncSession = Depends(get_db)):
    """Export permissions to a configuration format."""
    # Verify project exists
    result = await db.execute(select(Project).where(Project.name == name))
    project = result.scalar_one_or_none()

    if not project:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Project '{name}' not found"
        )

    # Get all permissions
    result = await db.execute(
        select(Permission)
        .where(Permission.project_id == project.id)
        .order_by(Permission.permission_type, Permission.permission_value)
    )
    permissions = result.scalars().all()

    return PermissionExportResponse(
        project_name=name,
        permissions=[
            PermissionExportItem(
                permission_type=p.permission_type,
                permission_value=p.permission_value,
                granted=p.granted
            )
            for p in permissions
        ],
        count=len(permissions)
    )