Files
clide/app/lib/main.dart
T
jpmschweitzerandClaude Opus 4.6 16ecf51091 redesign welcome as full-screen overlay with recent projects
Welcome screen is now a full-window overlay that covers the IDE
when no project is open. Two-column layout: START actions (open
folder, clone from git, start Claude session) with keyboard
shortcut hints, and RECENT projects list showing name, path,
branch, and relative timestamp. Status line shows version, daemon
connection state, and active theme.

ProjectManager tracks up to 10 recent projects with path, branch
name, and last-opened time, persisted as JSON in app.recentProjects.
Boot chain: try last project → try cwd → show welcome. Clicking a
recent project opens it directly into Claude.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-22 23:35:21 +02:00

141 lines
5.1 KiB
Dart

import 'package:clide_app/app.dart';
import 'package:clide_app/builtin/canvas/canvas.dart';
import 'package:clide_app/builtin/claude/claude.dart';
import 'package:clide_app/builtin/claude_control/claude_control.dart';
import 'package:clide_app/builtin/decisions/decisions.dart';
import 'package:clide_app/builtin/default_layout/default_layout.dart';
import 'package:clide_app/builtin/diff/diff.dart';
import 'package:clide_app/builtin/editor/editor.dart';
import 'package:clide_app/builtin/extensions_ui/extensions_ui.dart';
import 'package:clide_app/builtin/files/files.dart';
import 'package:clide_app/builtin/git/git.dart';
import 'package:clide_app/builtin/grammars_core/grammars_core.dart';
import 'package:clide_app/builtin/graph/graph.dart';
import 'package:clide_app/builtin/ipc_status/ipc_status.dart';
import 'package:clide_app/builtin/keybindings_ui/keybindings_ui.dart';
import 'package:clide_app/builtin/markdown/markdown.dart';
import 'package:clide_app/builtin/pql/pql.dart';
import 'package:clide_app/builtin/problems/problems.dart';
import 'package:clide_app/builtin/settings_ui/settings_ui.dart';
import 'package:clide_app/builtin/terminal/terminal.dart';
import 'package:clide_app/builtin/theme_picker/theme_picker.dart';
import 'package:clide_app/builtin/tickets/tickets.dart';
import 'package:clide_app/builtin/todos/todos.dart';
import 'package:clide_app/builtin/welcome/welcome.dart';
import 'dart:io' show Directory, Platform;
import 'package:clide_app/kernel/kernel.dart';
import 'package:clide_app/kernel/src/syntax/tree_sitter_ffi.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart' show rootBundle;
import 'package:flutter/widgets.dart';
Future<void> main() async {
final binding = WidgetsFlutterBinding.ensureInitialized();
binding.ensureSemantics();
TreeSitterLib.init();
final appDir = await _resolveAppDir();
final themes = await _loadBundledThemes();
final services = await KernelServices.boot(
appDir: appDir,
bundledThemes: themes,
i18nLoader: AssetCatalogLoader(bundle: rootBundle),
preloadNamespaces: _tier0Namespaces,
// The local unix-socket daemon is desktop-only. On web the
// connection indicator stays `disconnected` — that's the honest
// state: the Flutter-web build can't reach a local socket.
autoStartDaemonClient: !kIsWeb,
socketPath: kIsWeb ? '/clide-web-no-socket' : null,
);
// Register every built-in. Tier 0 activates only the four that do
// real work; the rest compile in as stubs so the extensions-ui can
// list them when Tier 6 lands.
services.extensions
..register(DefaultLayoutExtension())
..register(WelcomeExtension())
..register(IpcStatusExtension())
..register(ThemePickerExtension())
..register(ClaudeExtension())
..register(TerminalExtension())
..register(FilesExtension())
..register(EditorExtension())
..register(GrammarsCoreExtension())
..register(MarkdownExtension())
..register(DiffExtension())
..register(GitExtension())
..register(PqlExtension())
..register(TodosExtension())
..register(ProblemsExtension())
..register(CanvasExtension())
..register(GraphExtension())
..register(SettingsUiExtension())
..register(ExtensionsUiExtension())
..register(KeybindingsUiExtension())
..register(DecisionsExtension())
..register(TicketsExtension())
..register(ClaudeControlExtension());
await services.extensions.activateAll();
if (!kIsWeb) {
await services.project.loadRecents();
var opened = await services.project.openLast();
if (!opened) {
opened = await services.project.open(Directory.current.path);
}
if (opened) {
services.panels.activateTab(Slots.workspace, 'claude.primary');
}
}
runApp(ClideApp(services: services));
}
/// Resolve the app-settings directory.
///
/// On web we don't touch the filesystem — hand back a sentinel dir so
/// `SettingsStore.load()` silently no-ops (its read-file helper returns
/// `{}` when the file doesn't exist).
Future<Directory> _resolveAppDir() async {
if (kIsWeb) return Directory('/clide-web-no-disk');
final home = Platform.environment['HOME'] ?? '/tmp';
final xdg = Platform.environment['XDG_CONFIG_HOME'] ?? '$home/.config';
final dir = Directory('$xdg/clide');
await dir.create(recursive: true);
return dir;
}
Future<List<ThemeDefinition>> _loadBundledThemes() async {
const loader = ThemeLoader();
const paths = [
'lib/kernel/src/theme/themes/clide.yaml',
'lib/kernel/src/theme/themes/midnight.yaml',
'lib/kernel/src/theme/themes/paper.yaml',
'lib/kernel/src/theme/themes/terminal.yaml',
];
final out = <ThemeDefinition>[];
for (final p in paths) {
out.add(await loader.fromAsset(rootBundle, p));
}
return out;
}
/// Every Tier-0 extension that ships an i18n catalog. Extensions
/// registered but not active (the 17 stubs) don't preload — their
/// catalogs load lazily on activate in later tiers.
const List<String> _tier0Namespaces = [
'builtin.default-layout',
'builtin.welcome',
'builtin.ipc-status',
'builtin.theme-picker',
'builtin.terminal',
'builtin.files',
'builtin.claude',
'builtin.editor',
];