fix: streamline gateway settings and mac packaging cleanup

This commit is contained in:
Haitao Pan 2026-04-09 11:39:00 +08:00
parent 0fb0ccdf17
commit 235d41c5fe
4 changed files with 54 additions and 127 deletions

View File

@ -1,4 +1,5 @@
PODS:
- CocoaAsyncSocket (7.6.5)
- device_info_plus (0.0.1):
- Flutter
- file_selector_ios (0.0.1):
@ -58,6 +59,10 @@ PODS:
- nanopb/encode (3.30910.0)
- package_info_plus (0.4.5):
- Flutter
- patrol (0.0.1):
- CocoaAsyncSocket (~> 7.6)
- Flutter
- FlutterMacOS
- PromisesObjC (2.4.0)
- shared_preferences_foundation (0.0.1):
- Flutter
@ -73,11 +78,13 @@ DEPENDENCIES:
- irondash_engine_context (from `.symlinks/plugins/irondash_engine_context/ios`)
- mobile_scanner (from `.symlinks/plugins/mobile_scanner/ios`)
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
- patrol (from `.symlinks/plugins/patrol/darwin`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
- super_native_extensions (from `.symlinks/plugins/super_native_extensions/ios`)
SPEC REPOS:
trunk:
- CocoaAsyncSocket
- GoogleDataTransport
- GoogleMLKit
- GoogleToolboxForMac
@ -105,12 +112,15 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/mobile_scanner/ios"
package_info_plus:
:path: ".symlinks/plugins/package_info_plus/ios"
patrol:
:path: ".symlinks/plugins/patrol/darwin"
shared_preferences_foundation:
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"
super_native_extensions:
:path: ".symlinks/plugins/super_native_extensions/ios"
SPEC CHECKSUMS:
CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99
device_info_plus: 21fcca2080fbcd348be798aa36c3e5ed849eefbe
file_selector_ios: ec57ec07954363dd730b642e765e58f199bb621a
Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467
@ -128,6 +138,7 @@ SPEC CHECKSUMS:
mobile_scanner: af8f71879eaba2bbcb4d86c6a462c3c0e7f23036
nanopb: fad817b59e0457d11a5dfbde799381cd727c1275
package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
patrol: cea8074f183a2a4232d0ebd10569ae05149ada42
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb
super_native_extensions: b763c02dc3a8fd078389f410bf15149179020cb4

View File

@ -37,13 +37,6 @@ extension SettingsPageGatewayMixinInternal on SettingsPageStateInternal {
) {
if (!widget.showSectionTabs) {
return [
buildGatewayOverviewCardInternal(
context,
controller,
settings,
uiFeatures,
),
const SizedBox(height: 16),
buildOnlineAccountCardInternal(context, controller, settings),
const SizedBox(height: 16),
buildAcpBridgeServerModeCardInternal(
@ -95,13 +88,6 @@ extension SettingsPageGatewayMixinInternal on SettingsPageStateInternal {
),
};
return [
buildGatewayOverviewCardInternal(
context,
controller,
settings,
uiFeatures,
),
const SizedBox(height: 16),
SectionTabs(
items: <String>[
appText('用户登录状态', 'User Login State'),
@ -145,10 +131,10 @@ extension SettingsPageGatewayMixinInternal on SettingsPageStateInternal {
GatewayIntegrationSubTabInternal.llm => const <Widget>[],
GatewayIntegrationSubTabInternal.acp => const <Widget>[],
GatewayIntegrationSubTabInternal.skills => const <Widget>[],
GatewayIntegrationSubTabInternal.advancedConfig =>
uiFeatures.supportsGatewayAdvancedCustomMode
? <Widget>[
...buildGatewayAdvancedSectionsInternal(
GatewayIntegrationSubTabInternal.advancedConfig =>
uiFeatures.supportsGatewayAdvancedCustomMode
? <Widget>[
...buildGatewayAdvancedSectionsInternal(
context,
controller,
settings,
@ -160,85 +146,6 @@ extension SettingsPageGatewayMixinInternal on SettingsPageStateInternal {
];
}
Widget buildGatewayOverviewCardInternal(
BuildContext context,
AppController controller,
SettingsSnapshot settings,
UiFeatureAccess uiFeatures,
) {
final accountController = controller.settingsController;
final modeConfig = settings.acpBridgeServerModeConfig;
final supportsSelfHosted = uiFeatures.supportsGatewaySelfHostedBase;
final supportsAdvancedOverrides =
uiFeatures.supportsGatewayAdvancedCustomMode;
final loginStatus = accountController.accountMfaRequired
? appText('MFA 待验证', 'MFA pending')
: accountController.accountBusy
? appText('登录中', 'Signing in')
: accountController.accountSignedIn
? appText('已登录', 'Signed in')
: appText('未登录', 'Signed out');
final defaultSource = supportsSelfHosted && modeConfig.usesSelfHostedBase
? appText('自建服务', 'Self-hosted')
: appText('svc.plus 提供', 'svc.plus provided');
final hasAdvancedOverrides =
supportsAdvancedOverrides &&
modeConfig.mode == AcpBridgeServerMode.advancedCustom;
return SurfaceCard(
key: const ValueKey('gateway-configuration-overview-card'),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
appText('最终生效配置概览', 'Effective Configuration Overview'),
style: Theme.of(context).textTheme.titleLarge,
),
const SizedBox(height: 8),
Text(
supportsAdvancedOverrides
? appText(
'先确认登录状态,再确定默认连接来源,最后按需用高级自定义模式覆盖默认配置。',
'Confirm login state first, choose the default connection source second, then apply advanced custom overrides only where needed.',
)
: appText(
'先确认登录状态,再查看当前默认连接来源。',
'Confirm login state first, then review the current default connection source.',
),
),
const SizedBox(height: 16),
Wrap(
spacing: 12,
runSpacing: 12,
children: [
StatusChipInternal(
key: const ValueKey('gateway-overview-login-status'),
label: '${appText('登录状态', 'Login')}: $loginStatus',
tone: accountController.accountSignedIn
? StatusChipToneInternal.ready
: StatusChipToneInternal.idle,
),
StatusChipInternal(
key: const ValueKey('gateway-overview-default-source'),
label:
'${appText('默认连接来源', 'Default Source')}: $defaultSource',
tone: StatusChipToneInternal.ready,
),
if (supportsAdvancedOverrides)
StatusChipInternal(
key: const ValueKey('gateway-overview-advanced-override'),
label:
'${appText('高级覆盖', 'Advanced Override')}: ${hasAdvancedOverrides ? appText('已启用', 'Enabled') : appText('未启用', 'Disabled')}',
tone: hasAdvancedOverrides
? StatusChipToneInternal.ready
: StatusChipToneInternal.idle,
),
],
),
],
),
);
}
List<Widget> buildGatewayAdvancedSectionsInternal(
BuildContext context,
AppController controller,

View File

@ -14,6 +14,32 @@ FLUTTER_BUILD_STATE_DIR="${ROOT_DIR}/.dart_tool/flutter_build"
MACOS_BUILD_DIR="${ROOT_DIR}/build/macos"
NATIVE_ASSETS_DIR="${ROOT_DIR}/build/native_assets"
remove_tree_with_retries() {
local path="$1"
local attempts="${2:-5}"
local delay_seconds="${3:-1}"
local try=1
[[ -e "$path" ]] || return 0
while (( try <= attempts )); do
chmod -R u+w "$path" 2>/dev/null || true
rm -rf "$path" 2>/dev/null || true
if [[ ! -e "$path" ]]; then
return 0
fi
if (( try == attempts )); then
echo "Failed to remove generated path after ${attempts} attempts: $path" >&2
return 1
fi
sleep "$delay_seconds"
((try++))
done
}
if [[ ! -f "$PUBSPEC_PATH" ]]; then
echo "Missing pubspec: $PUBSPEC_PATH" >&2
exit 1
@ -40,7 +66,9 @@ echo "Building $APP_NAME $APP_VERSION ($APP_BUILD) for macOS..."
# Flutter caches native-asset installation state under .dart_tool/flutter_build,
# but Xcode consumes the copied frameworks from build/native_assets/macos.
# Reset both locations so packaging cannot reuse a stale stamp or stale layout.
rm -rf "$FLUTTER_BUILD_STATE_DIR" "$MACOS_BUILD_DIR" "$NATIVE_ASSETS_DIR"
remove_tree_with_retries "$FLUTTER_BUILD_STATE_DIR"
remove_tree_with_retries "$MACOS_BUILD_DIR"
remove_tree_with_retries "$NATIVE_ASSETS_DIR"
BUILD_ARGS=(
flutter build macos

View File

@ -234,15 +234,15 @@ void main() {
expect(
find.byKey(const ValueKey('gateway-configuration-overview-card')),
findsOneWidget,
findsNothing,
);
expect(
find.byKey(const ValueKey('gateway-overview-login-status')),
findsOneWidget,
findsNothing,
);
expect(
find.byKey(const ValueKey('gateway-overview-default-source')),
findsOneWidget,
findsNothing,
);
expect(
find.byKey(const ValueKey('gateway-overview-advanced-override')),
@ -415,7 +415,7 @@ void main() {
expect(find.byKey(const ValueKey('account-base-url-field')), findsOneWidget);
expect(find.byKey(const ValueKey('account-username-field')), findsOneWidget);
expect(find.byKey(const ValueKey('account-password-field')), findsOneWidget);
expect(find.byKey(const ValueKey('acp-bridge-mode-cloud')), findsNothing);
expect(find.byKey(const ValueKey('acp-bridge-mode-cloud')), findsOneWidget);
expect(
find.byKey(const ValueKey('acp-bridge-mode-self-hosted')),
findsNothing,
@ -437,9 +437,6 @@ void main() {
await _pumpSettingsPage(tester, controller, tab: SettingsTab.gateway);
await tester.tap(find.byKey(const ValueKey('section-tab-高级自定义模式')));
await tester.pumpAndSettle();
expect(find.text('Vault Server'), findsAtLeastNWidgets(1));
expect(find.text('VAULT_SERVER_URL'), findsOneWidget);
expect(
@ -460,9 +457,6 @@ void main() {
await _pumpSettingsPage(tester, controller, tab: SettingsTab.gateway);
await tester.tap(find.byKey(const ValueKey('section-tab-高级自定义模式')));
await tester.pumpAndSettle();
expect(find.text('外部 ACP Server Endpoint'), findsOneWidget);
expect(find.textContaining('Codex'), findsWidgets);
expect(find.textContaining('OpenCode'), findsWidgets);
@ -496,9 +490,6 @@ void main() {
await _pumpSettingsPage(tester, controller, tab: SettingsTab.gateway);
await tester.tap(find.byKey(const ValueKey('section-tab-高级自定义模式')));
await tester.pumpAndSettle();
await _ensureVisible(
tester,
find.byKey(const ValueKey('external-acp-provider-add-button')),
@ -536,9 +527,6 @@ void main() {
await _pumpSettingsPage(tester, controller, tab: SettingsTab.gateway);
await tester.tap(find.byKey(const ValueKey('section-tab-高级自定义模式')));
await tester.pumpAndSettle();
expect(find.text('~/.agents/skills'), findsOneWidget);
expect(find.text('/Users/tester/.agents/skills'), findsOneWidget);
expect(find.text('~/.codex/skills'), findsOneWidget);
@ -569,8 +557,6 @@ void main() {
);
await _pumpSettingsPage(tester, controller, tab: SettingsTab.gateway);
await tester.tap(find.byKey(const ValueKey('section-tab-高级自定义模式')));
await tester.pumpAndSettle();
await _ensureVisible(
tester,
find.byKey(const ValueKey('skill-directory-batch-add-button')),
@ -629,8 +615,6 @@ paths:
);
await _pumpSettingsPage(tester, controller, tab: SettingsTab.gateway);
await tester.tap(find.byKey(const ValueKey('section-tab-高级自定义模式')));
await tester.pumpAndSettle();
await _ensureVisible(
tester,
find.byKey(const ValueKey('skill-directory-batch-add-button')),
@ -672,8 +656,6 @@ paths:
);
await _pumpSettingsPage(tester, controller, tab: SettingsTab.gateway);
await tester.tap(find.byKey(const ValueKey('section-tab-高级自定义模式')));
await tester.pumpAndSettle();
await _ensureVisible(
tester,
find.byKey(const ValueKey('skill-directory-batch-add-button')),
@ -712,11 +694,14 @@ paths:
testWidgets('SettingsPage gateway sections can collapse individually', (
WidgetTester tester,
) async {
final controller = await createTestController(tester);
final controller = await createTestController(
tester,
uiFeatureManifest: _gatewayAdvancedManifestInternal(),
);
await _pumpSettingsPage(tester, controller, tab: SettingsTab.gateway);
await tester.tap(find.byTooltip('折叠').first);
await tester.tap(find.text('OpenClaw Gateway').first);
await tester.pumpAndSettle();
expect(find.byKey(const ValueKey('gateway-host-field')), findsNothing);
@ -726,7 +711,7 @@ paths:
findsNothing,
);
await tester.tap(find.byTooltip('展开').first);
await tester.tap(find.text('OpenClaw Gateway').first);
await tester.pumpAndSettle();
expect(find.byKey(const ValueKey('gateway-host-field')), findsOneWidget);
@ -746,8 +731,6 @@ paths:
);
await _pumpSettingsPage(tester, controller, tab: SettingsTab.gateway);
await tester.tap(find.byKey(const ValueKey('section-tab-高级自定义模式')));
await tester.pumpAndSettle();
await _ensureVisible(tester, find.text('外部 ACP Server Endpoint'));
await tester.tap(find.text('外部 ACP Server Endpoint').first);
@ -791,8 +774,6 @@ paths:
);
await _pumpSettingsPage(tester, controller, tab: SettingsTab.gateway);
await tester.tap(find.byKey(const ValueKey('section-tab-高级自定义模式')));
await tester.pumpAndSettle();
final labelField = find.byKey(
ValueKey('external-acp-label-${customProfile.providerKey}'),