From 5b9fa90fe75bf8dd941f6089d7bc53aeee774b98 Mon Sep 17 00:00:00 2001 From: leo Date: Wed, 4 Nov 2026 18:42:44 +0800 Subject: [PATCH] The Claude Code CLI no longer suggested: without it, BaoCode's own core MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The built-in core showed a suggestion over the composer to switch to the Claude Code CLI (downloaded where the machine has none): it is gone. With the setting unset, the core is the CLI where Claude Code is on this machine, else the built-in one, as before; Settings → General now says so rather than that the CLI is the default and downloaded. Co-Authored-By: BaoCode --- lib/chat/chat_screen.dart | 31 ------ lib/chat/panels/claude_core_hint.dart | 94 ------------------- .../claude_code/claude_core_setting.dart | 8 +- lib/l10n/app_en.arb | 7 +- lib/l10n/app_localizations.dart | 22 +---- lib/l10n/app_localizations_en.dart | 14 +-- lib/l10n/app_localizations_zh.dart | 14 +-- lib/l10n/app_zh.arb | 7 +- lib/main.dart | 4 +- test/chat/claude_core_hint_test.dart | 59 ------------ 10 files changed, 13 insertions(+), 247 deletions(-) delete mode 100644 lib/chat/panels/claude_core_hint.dart delete mode 100644 test/chat/claude_core_hint_test.dart diff --git a/lib/chat/chat_screen.dart b/lib/chat/chat_screen.dart index f9004db0b..b3c0ba608 100644 --- a/lib/chat/chat_screen.dart +++ b/lib/chat/chat_screen.dart @@ -11,7 +11,6 @@ import '../base/mouse_navigation.dart'; import '../channel/channel_setup.dart'; import '../ide/ide_menu.dart'; import '../kernel/kernel_types.dart'; -import '../kernel/claude_code/claude_path_setting.dart' show installLocalClaude; import '../keybindings/chat_keybindings.dart'; import '../l10n/l10n.dart'; import '../models/model_welcome.dart'; @@ -42,7 +41,6 @@ import 'composer/composer_embeds.dart'; import 'composer/composer_mock_data.dart'; import 'composer/file_mentions.dart'; import 'panels/activity_strip.dart'; -import 'panels/claude_core_hint.dart'; import 'panels/health_banner.dart'; import 'panels/interaction_panel.dart'; import 'panels/limit_reset_panel.dart'; @@ -538,33 +536,6 @@ class _ChatScreenState extends State _composerKey.currentState?.focus(); } - /// Whether the conversation is a Claude Code one on this machine, whose - /// core may be BaoCode's own ([ClaudeCoreHint]). - bool get _localClaudeCode => - !kIsWeb && - _session.kernel.id == 'claude-code' && - switch (_session.kernelContext.cwd) { - final cwd? => RemoteLocation.hostOf(cwd) == null, - null => true, - }; - - /// The CLI picked from [ClaudeCoreHint]: the session moves to it now - /// when at rest, downloaded first where there is none (as - /// [ClaudeInstallBanner] shows); else it is downloaded meanwhile, for - /// the session to move to it as it starts again. - void _movedToCli() { - if (!_session.isStreaming && _session.pendingInteraction == null) { - _session.restart(); - return; - } - unawaited( - installLocalClaude().catchError((Object error) { - // Said again by the session that starts on it. - debugPrint('Claude Code not downloaded: $error'); - }), - ); - } - /// The sequence of the plan writing last shown. int? _planShown; @@ -1448,8 +1419,6 @@ class _ChatScreenState extends State // Claude Code being downloaded for this machine, or put on // a remote project's host. ClaudeInstallBanner(location: _session.kernelContext.cwd), - // BaoCode's own core picked: the CLI suggested. - if (_localClaudeCode) ClaudeCoreHint(onSwitched: _movedToCli), // Reset credits of the model's ChatGPT accounts about to // expire: a plan to use them. ResetCreditsHint(model: _session.models?.selected.id), diff --git a/lib/chat/panels/claude_core_hint.dart b/lib/chat/panels/claude_core_hint.dart deleted file mode 100644 index 32bfe6f00..000000000 --- a/lib/chat/panels/claude_core_hint.dart +++ /dev/null @@ -1,94 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/material.dart'; - -import '../../kernel/claude_code/claude_core_setting.dart'; -import '../../l10n/l10n.dart'; -import '../../theme/app_theme.dart'; -import '../../theme/codicons.dart'; -import 'interaction_panel.dart'; - -/// Over the composer of a Claude Code chat while the core picked is -/// BaoCode's own: the Claude Code CLI suggested, with a way to switch to -/// it ([onSwitched] once picked, for the session to move to it). Not -/// shown again in this run once put off. Nothing otherwise. -class ClaudeCoreHint extends StatefulWidget { - const ClaudeCoreHint({super.key, required this.onSwitched}); - - final VoidCallback onSwitched; - - /// Put off with "Not now", in every chat until the app starts again. - @visibleForTesting - static final putOff = ValueNotifier(false); - - @override - State createState() => _ClaudeCoreHintState(); -} - -class _ClaudeCoreHintState extends State { - void _switch() { - unawaited( - ClaudeCore.pick(ClaudeCore.cli).then( - (_) { - if (mounted) widget.onSwitched(); - }, - onError: (Object error) { - // A settings file that does not parse is left as it is; its - // error is shown. - debugPrint('${ClaudeCore.settingKey} not kept: $error'); - }, - ), - ); - } - - @override - Widget build(BuildContext context) { - return ListenableBuilder( - listenable: Listenable.merge([ClaudeCore.changes, ClaudeCoreHint.putOff]), - builder: (context, _) { - if (ClaudeCoreHint.putOff.value || - ClaudeCore.current() != ClaudeCore.builtin) { - return const SizedBox.shrink(); - } - final accent = AppColors.accent; - return Padding( - padding: const EdgeInsets.only(bottom: 8), - child: Container( - padding: const EdgeInsets.fromLTRB(12, 9, 10, 9), - decoration: BoxDecoration( - color: accent.withValues(alpha: .08), - borderRadius: BorderRadius.circular(10), - border: Border.all(color: accent.withValues(alpha: .35)), - ), - child: Row( - children: [ - Icon(Codicons.sparkle, size: 15, color: accent), - const SizedBox(width: 8), - Expanded( - child: Text( - context.l10n.claudeCoreHint, - style: TextStyle( - color: AppColors.textPrimary, - fontSize: 12.5, - ), - ), - ), - const SizedBox(width: 8), - PanelButton( - label: context.l10n.claudeCoreHintLater, - onTap: () => ClaudeCoreHint.putOff.value = true, - ), - const SizedBox(width: 6), - PanelButton( - label: context.l10n.claudeCoreHintSwitch, - primary: true, - onTap: _switch, - ), - ], - ), - ), - ); - }, - ); - } -} diff --git a/lib/kernel/claude_code/claude_core_setting.dart b/lib/kernel/claude_code/claude_core_setting.dart index e03696485..70afa0f97 100644 --- a/lib/kernel/claude_code/claude_core_setting.dart +++ b/lib/kernel/claude_code/claude_core_setting.dart @@ -16,8 +16,8 @@ enum ClaudeCore { static const settingKey = 'claudeCode.core'; /// When the setting is unset, or not one of these: the CLI where Claude - /// Code is on this machine, else the built-in core (which suggests the - /// CLI, see ClaudeCoreHint): nothing is downloaded unasked. + /// Code is on this machine, else the built-in core. Nothing is downloaded + /// unasked, nor the CLI suggested. static ClaudeCore get fallback => cliInstalled() ? cli : builtin; /// Whether Claude Code is on this machine, as last looked; main() points @@ -35,10 +35,6 @@ enum ClaudeCore { /// settings.json. static Listenable changes = const _Never(); - /// Keeps [core] as the setting, for the sessions to come; main() points - /// it at settings.json. - static Future Function(ClaudeCore core) pick = (_) async {}; - /// Why [builtin] has nothing to run on: no upstream turned on. static const noModel = 'No model to run on: BaoCode\'s own core runs on the upstreams of ' diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 7de850703..5135b23b7 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -2453,7 +2453,7 @@ "@generalSettingsClaudeCore": { "description": "Settings → General → Claude Code row: what runs Claude Code sessions, BaoCode's built-in core (written in Dart) or the Claude Code CLI." }, - "generalSettingsClaudeCoreDescription": "Claude Code CLI: Anthropic's own program, with this machine's sign-in and setup; pick it to use a Claude subscription. Built-in: comes with BaoCode, and uses only the models added in Settings → Models. The CLI is the default, downloaded for you if this machine has none. Changes apply to new sessions.", + "generalSettingsClaudeCoreDescription": "Claude Code CLI: Anthropic's own program, with this machine's sign-in and setup; pick it to use a Claude subscription. Built-in: comes with BaoCode, and uses only the models added in Settings → Models. By default, the CLI where this machine has Claude Code, else the built-in core; the CLI, picked where there is none, is downloaded for you. Changes apply to new sessions.", "generalSettingsClaudeCoreBuiltin": "Built-in", "@generalSettingsClaudeCoreBuiltin": { "description": "Claude Code core choice: BaoCode's own agent core, written in Dart and run inside the app." @@ -4392,7 +4392,7 @@ } } }, - "claudePathMissing": "None found yet: Claude Code is downloaded as the first conversation starts.", + "claudePathMissing": "None found yet: with the Claude Code CLI picked, it is downloaded as the first conversation starts.", "generalSettingsIdeWindows": "Fast Ide Windows", "generalSettingsIdeWindowsDescription": "Where the Fast Ide opens: in the main window in place of the chat, one folder at a time, or in windows of its own, one per folder (New Window, ⇧⌘N / Ctrl+Shift+N, opens an empty one). Applies at once. (window.ideWindows)", "generalSettingsIdeWindowsSeparate": "Separate windows", @@ -7351,9 +7351,6 @@ "modelWelcomeStart": "Start Chatting", "healthNoModel": "Pick a model to start: add an upstream and its models are ready to use.", "modelSetUp": "Set Up a Model", - "claudeCoreHint": "This chat runs on BaoCode's built-in core. We recommend the Claude Code core for the fullest experience; it's downloaded for you if needed.", - "claudeCoreHintSwitch": "Switch to Claude Code", - "claudeCoreHintLater": "Not Now", "remoteAddServer": "Add SSH Server...", "remoteEditServer": "Edit", "settingsSectionSsh": "SSH Servers", diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart index 494f0ff34..1288a029e 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -6173,7 +6173,7 @@ abstract class AppLocalizations { /// No description provided for @generalSettingsClaudeCoreDescription. /// /// In en, this message translates to: - /// **'Claude Code CLI: Anthropic\'s own program, with this machine\'s sign-in and setup; pick it to use a Claude subscription. Built-in: comes with BaoCode, and uses only the models added in Settings → Models. The CLI is the default, downloaded for you if this machine has none. Changes apply to new sessions.'** + /// **'Claude Code CLI: Anthropic\'s own program, with this machine\'s sign-in and setup; pick it to use a Claude subscription. Built-in: comes with BaoCode, and uses only the models added in Settings → Models. By default, the CLI where this machine has Claude Code, else the built-in core; the CLI, picked where there is none, is downloaded for you. Changes apply to new sessions.'** String get generalSettingsClaudeCoreDescription; /// Claude Code core choice: BaoCode's own agent core, written in Dart and run inside the app. @@ -9702,7 +9702,7 @@ abstract class AppLocalizations { /// No description provided for @claudePathMissing. /// /// In en, this message translates to: - /// **'None found yet: Claude Code is downloaded as the first conversation starts.'** + /// **'None found yet: with the Claude Code CLI picked, it is downloaded as the first conversation starts.'** String get claudePathMissing; /// No description provided for @generalSettingsIdeWindows. @@ -16903,24 +16903,6 @@ abstract class AppLocalizations { /// **'Set Up a Model'** String get modelSetUp; - /// No description provided for @claudeCoreHint. - /// - /// In en, this message translates to: - /// **'This chat runs on BaoCode\'s built-in core. We recommend the Claude Code core for the fullest experience; it\'s downloaded for you if needed.'** - String get claudeCoreHint; - - /// No description provided for @claudeCoreHintSwitch. - /// - /// In en, this message translates to: - /// **'Switch to Claude Code'** - String get claudeCoreHintSwitch; - - /// No description provided for @claudeCoreHintLater. - /// - /// In en, this message translates to: - /// **'Not Now'** - String get claudeCoreHintLater; - /// No description provided for @remoteAddServer. /// /// In en, this message translates to: diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index a637267f7..64734343e 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -3647,7 +3647,7 @@ class AppLocalizationsEn extends AppLocalizations { @override String get generalSettingsClaudeCoreDescription => - 'Claude Code CLI: Anthropic\'s own program, with this machine\'s sign-in and setup; pick it to use a Claude subscription. Built-in: comes with BaoCode, and uses only the models added in Settings → Models. The CLI is the default, downloaded for you if this machine has none. Changes apply to new sessions.'; + 'Claude Code CLI: Anthropic\'s own program, with this machine\'s sign-in and setup; pick it to use a Claude subscription. Built-in: comes with BaoCode, and uses only the models added in Settings → Models. By default, the CLI where this machine has Claude Code, else the built-in core; the CLI, picked where there is none, is downloaded for you. Changes apply to new sessions.'; @override String get generalSettingsClaudeCoreBuiltin => 'Built-in'; @@ -6025,7 +6025,7 @@ class AppLocalizationsEn extends AppLocalizations { @override String get claudePathMissing => - 'None found yet: Claude Code is downloaded as the first conversation starts.'; + 'None found yet: with the Claude Code CLI picked, it is downloaded as the first conversation starts.'; @override String get generalSettingsIdeWindows => 'Fast Ide Windows'; @@ -10356,16 +10356,6 @@ class AppLocalizationsEn extends AppLocalizations { @override String get modelSetUp => 'Set Up a Model'; - @override - String get claudeCoreHint => - 'This chat runs on BaoCode\'s built-in core. We recommend the Claude Code core for the fullest experience; it\'s downloaded for you if needed.'; - - @override - String get claudeCoreHintSwitch => 'Switch to Claude Code'; - - @override - String get claudeCoreHintLater => 'Not Now'; - @override String get remoteAddServer => 'Add SSH Server...'; diff --git a/lib/l10n/app_localizations_zh.dart b/lib/l10n/app_localizations_zh.dart index 46da996e4..7db747e79 100644 --- a/lib/l10n/app_localizations_zh.dart +++ b/lib/l10n/app_localizations_zh.dart @@ -3498,7 +3498,7 @@ class AppLocalizationsZh extends AppLocalizations { @override String get generalSettingsClaudeCoreDescription => - 'Claude Code CLI:Anthropic 官方程序,沿用本机的登录和配置,用 Claude 订阅请选它。内置:BaoCode 自带,只用 设置 → 模型 里添加的模型。默认用 CLI,本机没有时会自动下载。改动对新开的会话生效。'; + 'Claude Code CLI:Anthropic 官方程序,沿用本机的登录和配置,用 Claude 订阅请选它。内置:BaoCode 自带,只用 设置 → 模型 里添加的模型。默认:本机装有 Claude Code 时用 CLI,没有时用内置内核;选 CLI 而本机没有时会自动下载。改动对新开的会话生效。'; @override String get generalSettingsClaudeCoreBuiltin => '内置'; @@ -5637,7 +5637,7 @@ class AppLocalizationsZh extends AppLocalizations { } @override - String get claudePathMissing => '尚未找到:开始第一个对话时会自动下载 Claude Code。'; + String get claudePathMissing => '尚未找到:选用 Claude Code CLI 后,开始第一个对话时会自动下载。'; @override String get generalSettingsIdeWindows => 'Fast Ide 窗口'; @@ -9803,16 +9803,6 @@ class AppLocalizationsZh extends AppLocalizations { @override String get modelSetUp => '设置模型'; - @override - String get claudeCoreHint => - '当前用的是 BaoCode 内置内核。推荐换成 Claude Code 内核,体验更完整;没安装的话会自动帮你下载。'; - - @override - String get claudeCoreHintSwitch => '切换到 Claude Code'; - - @override - String get claudeCoreHintLater => '暂不'; - @override String get remoteAddServer => '新增 SSH 服务器…'; diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb index e2dc23bf2..f1bb4b905 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -1012,7 +1012,7 @@ "generalSettingsCommitAttribution": "提交署名", "generalSettingsCommitAttributionDescription": "Agent 在它写的提交和 Pull Request 中添加的署名。更改对之后启动的 Agent 生效;目前仅支持 Claude Code。", "generalSettingsClaudeCore": "内核", - "generalSettingsClaudeCoreDescription": "Claude Code CLI:Anthropic 官方程序,沿用本机的登录和配置,用 Claude 订阅请选它。内置:BaoCode 自带,只用 设置 → 模型 里添加的模型。默认用 CLI,本机没有时会自动下载。改动对新开的会话生效。", + "generalSettingsClaudeCoreDescription": "Claude Code CLI:Anthropic 官方程序,沿用本机的登录和配置,用 Claude 订阅请选它。内置:BaoCode 自带,只用 设置 → 模型 里添加的模型。默认:本机装有 Claude Code 时用 CLI,没有时用内置内核;选 CLI 而本机没有时会自动下载。改动对新开的会话生效。", "generalSettingsClaudeCoreBuiltin": "内置", "generalSettingsClaudeCoreCli": "Claude Code CLI", "generalSettingsQueuedMessages": "工作中发送的消息", @@ -1599,7 +1599,7 @@ "claudePathInUse": "当前使用:{path}({version})", "claudePathInUseUnknown": "当前使用:{path}", "claudePathInUseDownloaded": "当前使用:BaoCode 下载的 Claude Code {version}", - "claudePathMissing": "尚未找到:开始第一个对话时会自动下载 Claude Code。", + "claudePathMissing": "尚未找到:选用 Claude Code CLI 后,开始第一个对话时会自动下载。", "generalSettingsIdeWindows": "Fast Ide 窗口", "generalSettingsIdeWindowsDescription": "Fast Ide 在哪里打开:在主窗口中替换对话,一次一个文件夹;或独立窗口,每个文件夹一个(新建窗口 ⇧⌘N / Ctrl+Shift+N 打开一个空窗口)。立即生效。(window.ideWindows)", "generalSettingsIdeWindowsSeparate": "独立窗口", @@ -2807,9 +2807,6 @@ "modelWelcomeStart": "开始对话", "healthNoModel": "选一个模型就能开始:添加一个上游,它的模型就能直接用了。", "modelSetUp": "设置模型", - "claudeCoreHint": "当前用的是 BaoCode 内置内核。推荐换成 Claude Code 内核,体验更完整;没安装的话会自动帮你下载。", - "claudeCoreHintSwitch": "切换到 Claude Code", - "claudeCoreHintLater": "暂不", "remoteAddServer": "新增 SSH 服务器…", "remoteEditServer": "编辑", "settingsSectionSsh": "SSH 服务器", diff --git a/lib/main.dart b/lib/main.dart index 7aa3c2b20..cb5c7970b 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -522,14 +522,12 @@ void followSettingsFiles(SettingsFiles files) { // Settings → General → Claude Code: the core sessions run on (BaoCode's // own, or the CLI), read as each agent starts. Unset, the CLI where it // is installed (looked for on the app's PATH, then the shell's), else - // the built-in core, which suggests the CLI. + // the built-in core. ClaudeCore.cliInstalled = localClaudeInstalled; unawaited(lookForLocalClaude()); ClaudeCore.current = () => ClaudeCore.parse(files.settings[ClaudeCore.settingKey]); ClaudeCore.changes = files.settings; - ClaudeCore.pick = (core) => - files.settings.update(ClaudeCore.settingKey, core.name); // Settings → Models: the upstreams, kept in settings.json. ModelProviders.current = ModelProviders.settings(files.settings); // Claude Code's own models as it last listed them: in the picker diff --git a/test/chat/claude_core_hint_test.dart b/test/chat/claude_core_hint_test.dart deleted file mode 100644 index 788e2a871..000000000 --- a/test/chat/claude_core_hint_test.dart +++ /dev/null @@ -1,59 +0,0 @@ -import 'package:baocode/chat/panels/claude_core_hint.dart'; -import 'package:baocode/kernel/claude_code/claude_core_setting.dart'; -import 'package:baocode/l10n/app_localizations.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - late ValueNotifier setting; - late int switched; - - setUp(() { - setting = ValueNotifier(ClaudeCore.builtin); - switched = 0; - ClaudeCore.current = () => setting.value; - ClaudeCore.changes = setting; - ClaudeCore.pick = (core) async => setting.value = core; - }); - - tearDown(() { - ClaudeCore.current = () => ClaudeCore.cli; - ClaudeCore.changes = ValueNotifier(0); - ClaudeCore.pick = (_) async {}; - ClaudeCoreHint.putOff.value = false; - }); - - Future pump(WidgetTester tester) => tester.pumpWidget( - MaterialApp( - localizationsDelegates: AppLocalizations.localizationsDelegates, - supportedLocales: AppLocalizations.supportedLocales, - home: Scaffold(body: ClaudeCoreHint(onSwitched: () => switched++)), - ), - ); - - testWidgets('on the built-in core: the CLI suggested; switching picks ' - 'it, and the hint goes', (tester) async { - await pump(tester); - expect(find.textContaining('built-in core'), findsOneWidget); - await tester.tap(find.text('Switch to Claude Code')); - await tester.pump(); - expect(setting.value, ClaudeCore.cli); - expect(switched, 1); - expect(find.textContaining('built-in core'), findsNothing); - }); - - testWidgets('on the CLI: nothing', (tester) async { - setting.value = ClaudeCore.cli; - await pump(tester); - expect(find.textContaining('built-in core'), findsNothing); - }); - - testWidgets('put off: gone, the core left as it is', (tester) async { - await pump(tester); - await tester.tap(find.text('Not Now')); - await tester.pump(); - expect(find.textContaining('built-in core'), findsNothing); - expect(setting.value, ClaudeCore.builtin); - expect(switched, 0); - }); -}