fix: disable sandbox for ~/.claude access, add path input field for hidden folders
- Remove App Sandbox from Release entitlements (developer tool needs filesystem access to ~/.claude/projects — same as VS Code, iTerm2) - Explicitly set get-task-allow=false in entitlements for notarization - Add path input field in header so users can type paths with hidden folders (e.g. ~/.claude/projects) — press Enter or click arrow to scan - Field pre-populated with ~/.claude/projects on launch - Signed, notarized, stapled DMG
This commit is contained in:
parent
5c693bf3d8
commit
53ed5a6cd1
@ -101,13 +101,24 @@ class _HomeScreenState extends State<HomeScreen> {
|
||||
String _searchQuery = '';
|
||||
_Project? _selectedProject;
|
||||
_Project? _customFolderProject;
|
||||
final _pathController = TextEditingController();
|
||||
final _pathFocusNode = FocusNode();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
final home = _getRealHome() ?? '';
|
||||
_pathController.text = '$home/.claude/projects';
|
||||
_scanProjects();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_pathController.dispose();
|
||||
_pathFocusNode.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
/// Returns the real user home directory, even inside App Sandbox.
|
||||
/// In sandbox, HOME points to ~/Library/Containers/<bundleid>/Data.
|
||||
String? _getRealHome() {
|
||||
@ -291,6 +302,35 @@ class _HomeScreenState extends State<HomeScreen> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Resolve a path string, expanding ~ to the home directory.
|
||||
String _resolvePath(String input) {
|
||||
final home = _getRealHome() ?? Platform.environment['HOME'] ?? '';
|
||||
var path = input.trim();
|
||||
if (path.startsWith('~/')) {
|
||||
path = '$home${path.substring(1)}';
|
||||
} else if (path == '~') {
|
||||
path = home;
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
Future<void> _scanFromPathInput() async {
|
||||
final resolved = _resolvePath(_pathController.text);
|
||||
final dir = Directory(resolved);
|
||||
if (await dir.exists()) {
|
||||
await _scanFolder(resolved);
|
||||
} else {
|
||||
if (mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('Folder not found: $resolved'),
|
||||
backgroundColor: AppColors.error,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _pickFolder() async {
|
||||
final result = await FilePicker.platform.getDirectoryPath(
|
||||
dialogTitle: 'Select a folder containing Claude session files',
|
||||
@ -498,7 +538,54 @@ class _HomeScreenState extends State<HomeScreen> {
|
||||
: '${_projects.length} projects',
|
||||
style: const TextStyle(fontSize: 12, color: AppColors.textMuted),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
// Path input field
|
||||
SizedBox(
|
||||
width: 320,
|
||||
child: TextField(
|
||||
controller: _pathController,
|
||||
focusNode: _pathFocusNode,
|
||||
style: const TextStyle(
|
||||
fontSize: 12,
|
||||
color: AppColors.textPrimary,
|
||||
fontFamily: 'JetBrains Mono',
|
||||
),
|
||||
decoration: InputDecoration(
|
||||
hintText: '~/ .claude/projects',
|
||||
hintStyle: const TextStyle(
|
||||
fontSize: 12,
|
||||
color: AppColors.textMuted,
|
||||
fontFamily: 'JetBrains Mono',
|
||||
),
|
||||
isDense: true,
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
horizontal: 10,
|
||||
vertical: 8,
|
||||
),
|
||||
filled: true,
|
||||
fillColor: AppColors.surface,
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
borderSide: const BorderSide(color: AppColors.surfaceBorder),
|
||||
),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
borderSide: const BorderSide(color: AppColors.surfaceBorder),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
borderSide: const BorderSide(color: AppColors.assistant),
|
||||
),
|
||||
suffixIcon: IconButton(
|
||||
icon: const Icon(Icons.arrow_forward, size: 14,
|
||||
color: AppColors.textMuted),
|
||||
tooltip: 'Scan this folder',
|
||||
onPressed: _scanFromPathInput,
|
||||
),
|
||||
),
|
||||
onSubmitted: (_) => _scanFromPathInput(),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
ElevatedButton.icon(
|
||||
onPressed: _loadSingleFile,
|
||||
icon: const Icon(Icons.insert_drive_file_outlined, size: 14),
|
||||
|
||||
@ -724,6 +724,7 @@
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
"DEVELOPMENT_TEAM[sdk=macosx*]" = LD76P8L42W;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
CODE_SIGN_ALLOW_ENTITLEMENTS_MODIFICATION = YES;
|
||||
OTHER_CODE_SIGN_FLAGS = "--timestamp --options runtime";
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
|
||||
@ -2,11 +2,7 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.app-sandbox</key>
|
||||
<true/>
|
||||
<key>com.apple.security.files.user-selected.read-only</key>
|
||||
<true/>
|
||||
<key>com.apple.security.files.home-directory.read-only</key>
|
||||
<true/>
|
||||
<key>com.apple.security.get-task-allow</key>
|
||||
<false/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user