feat(welcome): New project flow + per-repo account roadblock (T-488)

The UI half of the new-project flow (story T-486). A "New project…" welcome
action opens a dialog (location + name) that dispatches project.new (T-487),
opens the result, and announces it on projectCreatedChannel. The Claude
extension consumes that and shows the account roadblock — the embedded
per-workspace picker + accounts list, so a fresh project gets bound to an
account (or Default) right at birth.

The two halves stay decoupled: the welcome builtin only publishes the event
(no claude import); the claude builtin owns the account dialog. Only freshly-
created projects announce, so existing opens are never prompted.

Closes T-488. The non-repo "initialize as a project" path (T-489) is next.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-28 08:35:30 +02:00
co-authored by Claude Opus 4.8
parent adaf8966dc
commit 25430686cc
11 changed files with 439 additions and 0 deletions
+15
View File
@@ -4,6 +4,7 @@ import 'dart:io';
import 'package:clide/clide.dart';
import 'package:clide/builtin/claude/src/account_registry.dart';
import 'package:clide/builtin/claude/src/account_login_dialog.dart';
import 'package:clide/builtin/claude/src/account_roadblock_dialog.dart';
import 'package:clide/builtin/claude/src/account_settings_control.dart';
import 'package:clide/builtin/claude/src/activity_cluster.dart' show foldLevelFromName, kActivityFoldLevelKey, nextFoldLevel;
import 'package:clide/builtin/claude/src/claude_config.dart';
@@ -20,6 +21,7 @@ import 'package:clide/builtin/claude/src/session_storage.dart';
import 'package:clide/builtin/claude/src/ticket_pick_up.dart';
import 'package:clide/builtin/claude/src/transcript_reader.dart' show ImageMessage;
import 'package:clide/src/daemon/claude_account_commands.dart' show accountActionChannel;
import 'package:clide/src/daemon/project_commands.dart' show projectCreatedChannel;
import 'package:clide/src/daemon/image_commands.dart' show imageShowChannel;
import 'package:clide/builtin/claude/src/team_chat_sidebar.dart' show TeamChatPane;
import 'package:clide/builtin/claude/src/team_panel_host.dart';
@@ -530,6 +532,19 @@ class ClaudeExtension extends ClideExtension {
// writes the registry then publishes here; only the UI layer can respawn
// the workspace's panes onto the newly-bound account or delete a config dir.
_subs.add(ctx.messages.subscribe(channel: accountActionChannel).listen(_onAccountAction));
// A freshly-created project (T-488) announces itself once it's open; show the
// per-repo account roadblock so the user binds it now (existing opens, which
// never announce, are never prompted).
_subs.add(ctx.messages.subscribe(channel: projectCreatedChannel).listen(_onProjectCreated));
}
void _onProjectCreated(Message m) {
final dir = m.data['dir'] as String?;
final ctx = _ctx;
if (dir == null || ctx == null) return;
final name = dir.split('/').where((s) => s.isNotEmpty).lastOrNull ?? dir;
ctx.dialog.show<Object>((c, dismiss) => ClaudeAccountRoadblockDialog(projectName: name, onClose: dismiss));
}
/// Side-effects for the `claude account` verbs (T-480). The dispatcher does