chore: remove stale gateway settings and app ffi paths

This commit is contained in:
Haitao Pan 2026-05-13 16:45:54 +08:00
parent 87c978d456
commit b9a9999291
60 changed files with 1179 additions and 1916 deletions

1
.gitignore vendored
View File

@ -1,5 +1,6 @@
# Miscellaneous
.env
.playwright-mcp/
*.py
null/
test/golden/failures/

View File

@ -118,7 +118,7 @@ package-rpm: ## Create the Linux .rpm package
package-linux: ## Create both Linux packages
bash scripts/package-linux.sh
package-mac: ffi-integrate build-go-core ## Create the macOS .app and DMG
package-mac: build-go-core ## Create the macOS .app and DMG
XWORKMATE_APP_STORE=true bash scripts/package-flutter-mac-app.sh
install-mac: package-mac ## Package and install the macOS app into /Applications
@ -130,28 +130,3 @@ clean: ## Remove generated artifacts
check-export-compliance: ## Verify source and built Apple plist export-compliance flags
bash scripts/check-apple-export-compliance.sh
# Rust FFI targets
.PHONY: rust-build rust-build-release rust-build-debug rust-test ffi-copy ffi-generate
rust-build: rust-build-release ## Build Rust FFI library (release mode)
rust-build-release: ## Build Rust FFI library for macOS (release)
@echo "Skip cargo build (external management)"
rust-build-debug: ## Build Rust FFI library in debug mode
@echo "Skip cargo build (external management)"
rust-test: ## Run Rust tests
cd rust && cargo test
ffi-copy: ## Copy FFI library to macOS Frameworks
bash scripts/copy_ffi_framework.sh
ffi-generate: ## Generate FFI bindings using flutter_rust_bridge
bash scripts/generate_ffi_bindings.sh
ffi-integrate: ffi-copy ## Copy FFI library (full integration)
# Build with FFI integration
build-macos-ffi: ffi-copy build-macos ## Build macOS app with FFI integration

View File

@ -73,24 +73,6 @@ mobile:
build_modes: [debug, profile, release]
description: Mobile vault server settings
ui_surface: settings_page
gateway_self_hosted_base:
enabled: false
release_tier: experimental
build_modes: [debug, profile, release]
description: Mobile self-hosted gateway base controls
ui_surface: settings_page
gateway_advanced_custom_mode:
enabled: false
release_tier: experimental
build_modes: [debug, profile, release]
description: Mobile advanced gateway override controls
ui_surface: settings_page
gateway_setup_code:
enabled: false
release_tier: experimental
build_modes: [debug, profile, release]
description: Mobile gateway setup code editor
ui_surface: settings_page
experimental_canvas:
enabled: true
release_tier: experimental
@ -180,24 +162,6 @@ desktop:
build_modes: [debug, profile, release]
description: Desktop vault server settings
ui_surface: settings_page
gateway_self_hosted_base:
enabled: false
release_tier: experimental
build_modes: [debug, profile, release]
description: Desktop self-hosted gateway base controls
ui_surface: settings_page
gateway_advanced_custom_mode:
enabled: false
release_tier: experimental
build_modes: [debug, profile, release]
description: Desktop advanced gateway override controls
ui_surface: settings_page
gateway_setup_code:
enabled: false
release_tier: experimental
build_modes: [debug, profile, release]
description: Desktop gateway setup code editor
ui_surface: settings_page
experimental_canvas:
enabled: true
release_tier: experimental
@ -287,24 +251,6 @@ web:
build_modes: []
description: Web vault server settings disabled
ui_surface: settings_page
gateway_self_hosted_base:
enabled: false
release_tier: experimental
build_modes: []
description: Web self-hosted gateway base controls disabled
ui_surface: settings_page
gateway_advanced_custom_mode:
enabled: false
release_tier: experimental
build_modes: []
description: Web advanced gateway override controls disabled
ui_surface: settings_page
gateway_setup_code:
enabled: false
release_tier: experimental
build_modes: []
description: Web gateway setup code editor disabled
ui_surface: settings_page
experimental_canvas:
enabled: false
release_tier: experimental

View File

@ -17,7 +17,6 @@ acpBridgeServerModeConfig:
lastSyncAt: 0
remoteServerSummary:
endpoint: https://xworkmate-bridge.svc.plus
hasAdvancedOverrides: false
selfHosted:
serverUrl: ''
username: ''

View File

@ -34,6 +34,7 @@ go test ./...
## CI Coverage
- Pull requests in `xworkmate-app` use the `verify` stage as a static-analysis gate and always run `flutter analyze`.
- Static analysis also runs `scripts/check-no-app-ffi.sh` so app packaging cannot reintroduce the retired Codex FFI copy/embed path.
- Widget, integration, and Patrol suites are owned by their dedicated commands and release validation flows, not by the lightweight `verify` gate.
- Pushes to `main`, version tags, and manual workflow runs publish build artifacts and update the GitHub Release entry for that release mode.
- `xworkmate-bridge` Go tests run in the companion repository.

View File

@ -206,9 +206,9 @@ flowchart LR
- `Directory.current.path`
关键位置:
历史关键位置:
- [app_controller_desktop_single_agent.dart](/Users/shenlan/workspaces/cloud-neutral-toolkit/xworkmate/lib/app/app_controller_desktop_single_agent.dart:140)
- 历史 Single Agent 桥接文件,已在 2026-05 清理中移除
这就是“任务线程没有有效目录时,命令最后跑到全局/容器 cwd”的直接原因。
@ -219,9 +219,9 @@ Single Agent 运行后可能返回:
- `result.resolvedWorkingDirectory`
- `result.resolvedWorkspaceRefKind`
关键位置:
历史关键位置:
- [app_controller_desktop_single_agent.dart](/Users/shenlan/workspaces/cloud-neutral-toolkit/xworkmate/lib/app/app_controller_desktop_single_agent.dart:155)
- 历史 Single Agent 桥接文件,已在 2026-05 清理中移除
当前逻辑中:

View File

@ -58,18 +58,18 @@ Last Updated: 2026-04-14
## Coverage Summary
当前生成清单覆盖 `130` 个源码文件、`614` 个公开符号。
当前生成清单覆盖 `129` 个源码文件、`603` 个公开符号。
| Scope | Files | Public Symbols | Detailed Design Entries | Notes |
| --- | ---: | ---: | ---: | --- |
| `lib/app` | 30 | 68 | 10 | 主写桌面编排入口、扩展、registry 与 shell |
| `lib/runtime` | 67 | 377 | 18 | 主写 bridge contract、runtime client、controller、bootstrap |
| `lib/models` | 1 | 34 | 13 | 主写 settings / execution / provider / snapshot 主模型 |
| `lib/features/assistant` | 16 | 80 | 1 | 只展开页面入口与业务挂点 |
| `lib/features/settings` | 4 | 4 | 1 | 只展开设置主入口 |
| `lib/runtime` | 66 | 372 | 18 | 主写 bridge contract、runtime client、controller、bootstrap |
| `lib/models` | 1 | 31 | 13 | 主写 settings / execution / provider / snapshot 主模型 |
| `lib/features/assistant` | 16 | 79 | 1 | 只展开页面入口与业务挂点 |
| `lib/features/settings` | 4 | 5 | 1 | 只展开设置主入口 |
| `lib/features/mobile` | 6 | 19 | 1 | 只展开移动端 shell 主入口 |
| `lib/theme` | 2 | 13 | 2 | 只展开工程上影响 API 的 theme/palette 入口 |
| `rust/src` | 4 | 19 | 17 | 结构体与 FFI 函数全部展开 |
| `rust/src` | 4 | 16 | 17 | 结构体与 FFI 函数全部展开 |
说明:

View File

@ -5,9 +5,9 @@
> Scope: `lib/app`, `lib/runtime`, `lib/models`, `lib/features/**`, `lib/theme`, `rust/src`.
> Excludes private `_` symbols and non-top-level Dart members.
- Generated at: `2026-04-14T08:20:04.438927+00:00`
- Files scanned: `130`
- Public symbols extracted: `614`
- Generated at: `2026-05-13T08:37:25.180831+00:00`
- Files scanned: `129`
- Public symbols extracted: `603`
## Group Summary
@ -15,23 +15,23 @@
| --- | ---: | ---: |
| `lib/app` | 30 | 68 |
| `lib/features` | 26 | 103 |
| `lib/models` | 1 | 34 |
| `lib/runtime` | 67 | 377 |
| `lib/models` | 1 | 31 |
| `lib/runtime` | 66 | 372 |
| `lib/theme` | 2 | 13 |
| `rust/src` | 4 | 19 |
| `rust/src` | 4 | 16 |
## Coverage Scope Summary
| Scope | Files | Public Symbols |
| --- | ---: | ---: |
| `lib/app` | 30 | 68 |
| `lib/runtime` | 67 | 377 |
| `lib/models` | 1 | 34 |
| `lib/features/assistant` | 16 | 80 |
| `lib/features/settings` | 4 | 4 |
| `lib/runtime` | 66 | 372 |
| `lib/models` | 1 | 31 |
| `lib/features/assistant` | 16 | 79 |
| `lib/features/settings` | 4 | 5 |
| `lib/features/mobile` | 6 | 19 |
| `lib/theme` | 2 | 13 |
| `rust/src` | 4 | 19 |
| `rust/src` | 4 | 16 |
## lib/app
@ -77,9 +77,9 @@ _No extracted public top-level symbols._
| Line | Kind | Name | Signature |
| ---: | --- | --- | --- |
| 54 | `enum` | `CodexCooperationState` | `enum CodexCooperationState { notStarted, bridgeOnly, registered }` |
| 56 | `class` | `SingleAgentSkillScanRootInternal` | `class SingleAgentSkillScanRootInternal {` |
| 88 | `class` | `AppController` | `class AppController extends ChangeNotifier {` |
| 57 | `enum` | `CodexCooperationState` | `enum CodexCooperationState { notStarted, bridgeOnly, registered }` |
| 59 | `class` | `SingleAgentSkillScanRootInternal` | `class SingleAgentSkillScanRootInternal {` |
| 91 | `class` | `AppController` | `class AppController extends ChangeNotifier {` |
### `lib/app/app_controller_desktop_external_acp_routing.dart`
@ -97,7 +97,7 @@ _No extracted public top-level symbols._
| Line | Kind | Name | Signature |
| ---: | --- | --- | --- |
| 49 | `extension` | `AppControllerDesktopGateway` | `extension AppControllerDesktopGateway on AppController {` |
| 48 | `extension` | `AppControllerDesktopGateway` | `extension AppControllerDesktopGateway on AppController {` |
### `lib/app/app_controller_desktop_navigation.dart`
@ -106,24 +106,25 @@ _No extracted public top-level symbols._
| Line | Kind | Name | Signature |
| ---: | --- | --- | --- |
| 48 | `extension` | `AppControllerDesktopNavigation` | `extension AppControllerDesktopNavigation on AppController {` |
| 47 | `extension` | `AppControllerDesktopNavigation` | `extension AppControllerDesktopNavigation on AppController {` |
### `lib/app/app_controller_desktop_runtime_coordination_impl.dart`
- Language: `dart`
- Public symbols: `9`
- Public symbols: `10`
| Line | Kind | Name | Signature |
| ---: | --- | --- | --- |
| 48 | `top-level function` | `refreshAcpCapabilitiesRuntimeInternal` | `Future<void> refreshAcpCapabilitiesRuntimeInternal( AppController controller, { bool forceRefresh = false, bool persistMountTargets = false, }) async {` |
| 90 | `top-level function` | `refreshSingleAgentCapabilitiesRuntimeInternal` | `Future<void> refreshSingleAgentCapabilitiesRuntimeInternal( AppController controller, { bool forceRefresh = false, }) async {` |
| 158 | `top-level function` | `assistantWorkingDirectoryForSessionRuntimeInternal` | `String? assistantWorkingDirectoryForSessionRuntimeInternal( AppController controller, String sessionKey, ) {` |
| 178 | `top-level function` | `resolveLocalAssistantWorkingDirectoryForSessionRuntimeInternal` | `String? resolveLocalAssistantWorkingDirectoryForSessionRuntimeInternal( AppController controller, String sessionKey, { bool requireLocalExistence = true, }) {` |
| 206 | `top-level function` | `buildCodeAgentNodeStateRuntimeInternal` | `CodeAgentNodeState buildCodeAgentNodeStateRuntimeInternal( AppController controller, ) {` |
| 220 | `top-level function` | `bridgeGatewayModeRuntimeInternal` | `GatewayMode bridgeGatewayModeRuntimeInternal(AppController controller) {` |
| 230 | `top-level function` | `ensureCodexGatewayRegistrationRuntimeInternal` | `Future<void> ensureCodexGatewayRegistrationRuntimeInternal( AppController controller, ) async {` |
| 298 | `top-level function` | `clearCodexGatewayRegistrationRuntimeInternal` | `void clearCodexGatewayRegistrationRuntimeInternal(AppController controller) {` |
| 308 | `top-level function` | `recomputeTasksRuntimeInternal` | `void recomputeTasksRuntimeInternal(AppController controller) {` |
| 98 | `top-level function` | `refreshSingleAgentCapabilitiesRuntimeInternal` | `Future<void> refreshSingleAgentCapabilitiesRuntimeInternal( AppController controller, { bool forceRefresh = false, }) async {` |
| 170 | `top-level function` | `assistantWorkingDirectoryForSessionRuntimeInternal` | `String? assistantWorkingDirectoryForSessionRuntimeInternal( AppController controller, String sessionKey, ) {` |
| 181 | `top-level function` | `assistantRemoteWorkingDirectoryHintForSessionRuntimeInternal` | `String? assistantRemoteWorkingDirectoryHintForSessionRuntimeInternal( AppController controller, String sessionKey, ) {` |
| 200 | `top-level function` | `resolveLocalAssistantWorkingDirectoryForSessionRuntimeInternal` | `String? resolveLocalAssistantWorkingDirectoryForSessionRuntimeInternal( AppController controller, String sessionKey, { bool requireLocalExistence = true, }) {` |
| 223 | `top-level function` | `buildCodeAgentNodeStateRuntimeInternal` | `CodeAgentNodeState buildCodeAgentNodeStateRuntimeInternal( AppController controller, { AssistantExecutionTarget? executionTarget, }) {` |
| 239 | `top-level function` | `bridgeGatewayModeRuntimeInternal` | `GatewayMode bridgeGatewayModeRuntimeInternal(AppController controller) {` |
| 249 | `top-level function` | `ensureCodexGatewayRegistrationRuntimeInternal` | `Future<void> ensureCodexGatewayRegistrationRuntimeInternal( AppController controller, ) async {` |
| 317 | `top-level function` | `clearCodexGatewayRegistrationRuntimeInternal` | `void clearCodexGatewayRegistrationRuntimeInternal(AppController controller) {` |
| 327 | `top-level function` | `recomputeTasksRuntimeInternal` | `void recomputeTasksRuntimeInternal(AppController controller) {` |
### `lib/app/app_controller_desktop_runtime_exceptions.dart`
@ -142,7 +143,7 @@ _No extracted public top-level symbols._
| Line | Kind | Name | Signature |
| ---: | --- | --- | --- |
| 51 | `extension` | `AppControllerDesktopRuntimeHelpers` | `extension AppControllerDesktopRuntimeHelpers on AppController {` |
| 53 | `extension` | `AppControllerDesktopRuntimeHelpers` | `extension AppControllerDesktopRuntimeHelpers on AppController {` |
### `lib/app/app_controller_desktop_settings.dart`
@ -160,16 +161,7 @@ _No extracted public top-level symbols._
| Line | Kind | Name | Signature |
| ---: | --- | --- | --- |
| 49 | `extension` | `AppControllerDesktopSettingsRuntime` | `extension AppControllerDesktopSettingsRuntime on AppController {` |
### `lib/app/app_controller_desktop_single_agent.dart`
- Language: `dart`
- Public symbols: `1`
| Line | Kind | Name | Signature |
| ---: | --- | --- | --- |
| 3 | `extension` | `AppControllerDesktopSingleAgent` | `extension AppControllerDesktopSingleAgent on AppController {}` |
| 50 | `extension` | `AppControllerDesktopSettingsRuntime` | `extension AppControllerDesktopSettingsRuntime on AppController {` |
### `lib/app/app_controller_desktop_skill_permissions.dart`
@ -178,7 +170,7 @@ _No extracted public top-level symbols._
| Line | Kind | Name | Signature |
| ---: | --- | --- | --- |
| 49 | `extension` | `AppControllerDesktopSkillPermissions` | `extension AppControllerDesktopSkillPermissions on AppController {` |
| 48 | `extension` | `AppControllerDesktopSkillPermissions` | `extension AppControllerDesktopSkillPermissions on AppController {` |
### `lib/app/app_controller_desktop_thread_actions.dart`
@ -187,7 +179,7 @@ _No extracted public top-level symbols._
| Line | Kind | Name | Signature |
| ---: | --- | --- | --- |
| 50 | `extension` | `AppControllerDesktopThreadActions` | `extension AppControllerDesktopThreadActions on AppController {` |
| 51 | `extension` | `AppControllerDesktopThreadActions` | `extension AppControllerDesktopThreadActions on AppController {` |
### `lib/app/app_controller_desktop_thread_binding.dart`
@ -198,40 +190,40 @@ _No extracted public top-level symbols._
| ---: | --- | --- | --- |
| 47 | `class` | `DesktopThreadBindingSnapshotInternal` | `class DesktopThreadBindingSnapshotInternal {` |
| 76 | `extension` | `AppControllerDesktopThreadBinding` | `extension AppControllerDesktopThreadBinding on AppController {` |
| 294 | `top-level function` | `pickDraftThreadExecutionTargetInternal` | `AssistantExecutionTarget pickDraftThreadExecutionTargetInternal({ required AssistantExecutionTarget currentTarget, required Iterable<AssistantExecutionTarget> visibleTargets, bool? localWorkspaceAvailable, }) {` |
| 337 | `top-level function` | `pickDraftThreadExecutionTargetInternal` | `AssistantExecutionTarget pickDraftThreadExecutionTargetInternal({ required AssistantExecutionTarget currentTarget, required Iterable<AssistantExecutionTarget> visibleTargets, bool? localWorkspaceAvailable, }) {` |
### `lib/app/app_controller_desktop_thread_sessions.dart`
- Language: `dart`
- Public symbols: `3`
- Public symbols: `4`
| Line | Kind | Name | Signature |
| ---: | --- | --- | --- |
| 51 | `top-level function` | `resolveGatewayThreadConnectionStateInternal` | `AssistantThreadConnectionState resolveGatewayThreadConnectionStateInternal({ required AssistantExecutionTarget target, required bool bridgeReady, required String bridgeLabel, required AccountSyncState? accountSyncState, }) {` |
| 99 | `extension` | `AppControllerDesktopThreadSessions` | `extension AppControllerDesktopThreadSessions on AppController {` |
| 470 | `top-level function` | `resolveAssistantExecutionTargetFromRecordsForTest` | `AssistantExecutionTarget resolveAssistantExecutionTargetFromRecordsForTest( TaskThread? primaryRecord, { TaskThread? fallbackRecord, }) {` |
| 55 | `top-level function` | `resolveGatewayThreadConnectionStateInternal` | `AssistantThreadConnectionState resolveGatewayThreadConnectionStateInternal({ required AssistantExecutionTarget target, required bool bridgeReady, required String bridgeLabel, required AccountSyncState? accountSyncState, required bool accountSignedIn, required bool bridgeConfigured, bool bridgeDiscoveryAttempted = false, String bridgeDiscoveryError = '', bool providerCatalogEmpty = false, }) {` |
| 180 | `top-level function` | `bridgeCapabilityReadyForExecutionTargetInternal` | `bool bridgeCapabilityReadyForExecutionTargetInternal({ required AssistantExecutionTarget target, required bool bridgeConfigured, required List<SingleAgentProvider> providers, required List<AssistantExecutionTarget> availableTargets, }) {` |
| 192 | `extension` | `AppControllerDesktopThreadSessions` | `extension AppControllerDesktopThreadSessions on AppController {` |
| 655 | `top-level function` | `resolveAssistantExecutionTargetFromRecordForTest` | `AssistantExecutionTarget resolveAssistantExecutionTargetFromRecordForTest( TaskThread? record, { required AssistantExecutionTarget defaultExecutionTarget, }) {` |
### `lib/app/app_controller_desktop_thread_sessions_collaboration_impl.dart`
- Language: `dart`
- Public symbols: `14`
- Public symbols: `13`
| Line | Kind | Name | Signature |
| ---: | --- | --- | --- |
| 50 | `top-level function` | `loadAiGatewayApiKeyThreadSessionInternal` | `Future<String> loadAiGatewayApiKeyThreadSessionInternal( AppController controller, ) async {` |
| 56 | `top-level function` | `saveMultiAgentConfigThreadSessionInternal` | `Future<void> saveMultiAgentConfigThreadSessionInternal( AppController controller, MultiAgentConfig config, ) async {` |
| 73 | `top-level function` | `refreshMultiAgentMountsThreadSessionInternal` | `Future<void> refreshMultiAgentMountsThreadSessionInternal( AppController controller, { bool sync = false, }) async {` |
| 98 | `top-level function` | `runMultiAgentCollaborationThreadSessionInternal` | `Future<void> runMultiAgentCollaborationThreadSessionInternal( AppController controller, { required String rawPrompt, required String composedPrompt, required List<CollaborationAttachment> attachments, required List<String> selectedSkillLabels, }) async {` |
| 269 | `top-level function` | `openOnlineWorkspaceThreadSessionInternal` | `Future<void> openOnlineWorkspaceThreadSessionInternal( AppController controller, ) async {` |
| 290 | `top-level function` | `aiGatewayModelChoicesThreadSessionInternal` | `List<String> aiGatewayModelChoicesThreadSessionInternal( AppController controller, ) {` |
| 296 | `top-level function` | `connectedGatewayModelChoicesThreadSessionInternal` | `List<String> connectedGatewayModelChoicesThreadSessionInternal( AppController controller, ) {` |
| 308 | `top-level function` | `assistantModelChoicesThreadSessionInternal` | `List<String> assistantModelChoicesThreadSessionInternal( AppController controller, ) {` |
| 317 | `top-level function` | `assistantModelChoicesForSessionThreadSessionInternal` | `List<String> assistantModelChoicesForSessionThreadSessionInternal( AppController controller, String sessionKey, ) {` |
| 332 | `top-level function` | `resolvedDefaultModelThreadSessionInternal` | `String resolvedDefaultModelThreadSessionInternal(AppController controller) {` |
| 354 | `top-level function` | `canQuickConnectGatewayThreadSessionInternal` | `bool canQuickConnectGatewayThreadSessionInternal(AppController controller) {` |
| 374 | `top-level function` | `normalizeAssistantSessionKeyThreadInternal` | `String normalizeAssistantSessionKeyThreadInternal(String sessionKey) {` |
| 379 | `top-level function` | `joinConnectionPartsThreadSessionInternal` | `String joinConnectionPartsThreadSessionInternal(List<String> parts) {` |
| 387 | `top-level function` | `gatewayAddressLabelThreadSessionInternal` | `String gatewayAddressLabelThreadSessionInternal( GatewayConnectionProfile profile, ) {` |
| 49 | `top-level function` | `loadAiGatewayApiKeyThreadSessionInternal` | `Future<String> loadAiGatewayApiKeyThreadSessionInternal( AppController controller, ) async {` |
| 55 | `top-level function` | `saveMultiAgentConfigThreadSessionInternal` | `Future<void> saveMultiAgentConfigThreadSessionInternal( AppController controller, MultiAgentConfig config, ) async {` |
| 72 | `top-level function` | `refreshMultiAgentMountsThreadSessionInternal` | `Future<void> refreshMultiAgentMountsThreadSessionInternal( AppController controller, { bool sync = false, }) async {` |
| 97 | `top-level function` | `runMultiAgentCollaborationThreadSessionInternal` | `Future<void> runMultiAgentCollaborationThreadSessionInternal( AppController controller, { required String rawPrompt, required String composedPrompt, required List<CollaborationAttachment> attachments, required List<String> selectedSkillLabels, }) async {` |
| 283 | `top-level function` | `openOnlineWorkspaceThreadSessionInternal` | `Future<void> openOnlineWorkspaceThreadSessionInternal( AppController controller, ) async {` |
| 304 | `top-level function` | `aiGatewayModelChoicesThreadSessionInternal` | `List<String> aiGatewayModelChoicesThreadSessionInternal( AppController controller, ) {` |
| 310 | `top-level function` | `connectedGatewayModelChoicesThreadSessionInternal` | `List<String> connectedGatewayModelChoicesThreadSessionInternal( AppController controller, ) {` |
| 322 | `top-level function` | `assistantModelChoicesThreadSessionInternal` | `List<String> assistantModelChoicesThreadSessionInternal( AppController controller, ) {` |
| 331 | `top-level function` | `assistantModelChoicesForSessionThreadSessionInternal` | `List<String> assistantModelChoicesForSessionThreadSessionInternal( AppController controller, String sessionKey, ) {` |
| 346 | `top-level function` | `resolvedDefaultModelThreadSessionInternal` | `String resolvedDefaultModelThreadSessionInternal(AppController controller) {` |
| 368 | `top-level function` | `canQuickConnectGatewayThreadSessionInternal` | `bool canQuickConnectGatewayThreadSessionInternal(AppController controller) {` |
| 388 | `top-level function` | `joinConnectionPartsThreadSessionInternal` | `String joinConnectionPartsThreadSessionInternal(List<String> parts) {` |
| 396 | `top-level function` | `gatewayAddressLabelThreadSessionInternal` | `String gatewayAddressLabelThreadSessionInternal( GatewayConnectionProfile profile, ) {` |
### `lib/app/app_controller_desktop_thread_storage.dart`
@ -240,7 +232,7 @@ _No extracted public top-level symbols._
| Line | Kind | Name | Signature |
| ---: | --- | --- | --- |
| 48 | `extension` | `AppControllerDesktopThreadStorage` | `extension AppControllerDesktopThreadStorage on AppController {` |
| 47 | `extension` | `AppControllerDesktopThreadStorage` | `extension AppControllerDesktopThreadStorage on AppController {` |
### `lib/app/app_controller_desktop_workspace_execution.dart`
@ -251,6 +243,15 @@ _No extracted public top-level symbols._
| ---: | --- | --- | --- |
| 48 | `extension` | `AppControllerDesktopWorkspaceExecution` | `extension AppControllerDesktopWorkspaceExecution on AppController {` |
### `lib/app/app_controller_openclaw_task_queue.dart`
- Language: `dart`
- Public symbols: `1`
| Line | Kind | Name | Signature |
| ---: | --- | --- | --- |
| 9 | `class` | `OpenClawGatewayQueuedTurnInternal` | `class OpenClawGatewayQueuedTurnInternal {` |
### `lib/app/app_metadata.dart`
- Language: `dart`
@ -313,21 +314,20 @@ _No extracted public top-level symbols._
| 14 | `enum` | `UiFeatureBuildMode` | `enum UiFeatureBuildMode { debug, profile, release }` |
| 16 | `top-level function` | `currentUiFeatureBuildMode` | `UiFeatureBuildMode currentUiFeatureBuildMode() {` |
| 26 | `top-level function` | `resolveUiFeaturePlatformFromContext` | `UiFeaturePlatform resolveUiFeaturePlatformFromContext(BuildContext context) {` |
| 62 | `class` | `UiFeatureFlag` | `class UiFeatureFlag {` |
| 94 | `class` | `UiFeatureManifest` | `class UiFeatureManifest {` |
| 341 | `class` | `UiFeatureAccess` | `class UiFeatureAccess {` |
| 480 | `class` | `UiFeatureManifestLoader` | `class UiFeatureManifestLoader {` |
| 57 | `class` | `UiFeatureFlag` | `class UiFeatureFlag {` |
| 89 | `class` | `UiFeatureManifest` | `class UiFeatureManifest {` |
| 336 | `class` | `UiFeatureAccess` | `class UiFeatureAccess {` |
| 466 | `class` | `UiFeatureManifestLoader` | `class UiFeatureManifestLoader {` |
### `lib/app/workspace_navigation.dart`
- Language: `dart`
- Public symbols: `3`
- Public symbols: `2`
| Line | Kind | Name | Signature |
| ---: | --- | --- | --- |
| 8 | `top-level function` | `buildWorkspaceBreadcrumbs` | `List<AppBreadcrumbItem> buildWorkspaceBreadcrumbs({ required AppController controller, required String rootLabel, String? sectionLabel, String? detailLabel, VoidCallback? onRootTap, }) {` |
| 32 | `top-level function` | `buildSettingsBreadcrumbs` | `List<AppBreadcrumbItem> buildSettingsBreadcrumbs( AppController controller, { required SettingsTab tab, SettingsDetailPage? detail, SettingsNavigationContext? navigationContext, }) {` |
| 57 | `top-level function` | `openSettingsNavigationContext` | `void openSettingsNavigationContext( AppController controller, SettingsNavigationContext context, ) {` |
| 32 | `top-level function` | `buildSettingsBreadcrumbs` | `List<AppBreadcrumbItem> buildSettingsBreadcrumbs( AppController controller, { required SettingsTab tab, }) {` |
### `lib/app/workspace_page_registry.dart`
@ -339,7 +339,7 @@ _No extracted public top-level symbols._
| 8 | `enum` | `WorkspacePageSurface` | `enum WorkspacePageSurface { desktop, mobile }` |
| 10 | `typedef` | `WorkspacePageBuilder` | `typedef WorkspacePageBuilder = Widget Function( AppController controller, ValueChanged<DetailPanelData> onOpenDetail, );` |
| 16 | `class` | `WorkspacePageSpec` | `class WorkspacePageSpec {` |
| 60 | `top-level function` | `buildWorkspacePage` | `Widget buildWorkspacePage({ required WorkspaceDestination destination, required AppController controller, required ValueChanged<DetailPanelData> onOpenDetail, required WorkspacePageSurface surface, }) {` |
| 56 | `top-level function` | `buildWorkspacePage` | `Widget buildWorkspacePage({ required WorkspaceDestination destination, required AppController controller, required ValueChanged<DetailPanelData> onOpenDetail, required WorkspacePageSurface surface, }) {` |
## lib/features
@ -362,10 +362,10 @@ _No extracted public top-level symbols._
| ---: | --- | --- | --- |
| 40 | `class` | `AssistantTaskRailInternal` | `class AssistantTaskRailInternal extends StatefulWidget {` |
| 73 | `class` | `AssistantTaskRailStateInternal` | `class AssistantTaskRailStateInternal extends State<AssistantTaskRailInternal> {` |
| 282 | `top-level function` | `groupTasksForRailInternal` | `List<AssistantTaskGroupInternal> groupTasksForRailInternal( List<AssistantTaskEntryInternal> tasks, List<AssistantExecutionTarget> visibleExecutionTargets, ) {` |
| 312 | `class` | `AssistantTaskTileInternal` | `class AssistantTaskTileInternal extends StatelessWidget {` |
| 417 | `class` | `AssistantTaskGroupHeaderInternal` | `class AssistantTaskGroupHeaderInternal extends StatelessWidget {` |
| 481 | `class` | `AssistantEmptyStateInternal` | `class AssistantEmptyStateInternal extends StatelessWidget {` |
| 283 | `top-level function` | `groupTasksForRailInternal` | `List<AssistantTaskGroupInternal> groupTasksForRailInternal( List<AssistantTaskEntryInternal> tasks, List<AssistantExecutionTarget> visibleExecutionTargets, ) {` |
| 313 | `class` | `AssistantTaskTileInternal` | `class AssistantTaskTileInternal extends StatelessWidget {` |
| 462 | `class` | `AssistantTaskGroupHeaderInternal` | `class AssistantTaskGroupHeaderInternal extends StatelessWidget {` |
| 526 | `class` | `AssistantEmptyStateInternal` | `class AssistantEmptyStateInternal extends StatelessWidget {` |
### `lib/features/assistant/assistant_page_components_core.dart`
@ -400,13 +400,12 @@ _No extracted public top-level symbols._
### `lib/features/assistant/assistant_page_composer_skill_models.dart`
- Language: `dart`
- Public symbols: `3`
- Public symbols: `2`
| Line | Kind | Name | Signature |
| ---: | --- | --- | --- |
| 79 | `top-level function` | `skillOptionFromGatewayInternal` | `ComposerSkillOptionInternal skillOptionFromGatewayInternal( GatewaySkillSummary skill, ) {` |
| 106 | `top-level function` | `skillOptionFromThreadSkillInternal` | `ComposerSkillOptionInternal skillOptionFromThreadSkillInternal( AssistantThreadSkillEntry skill, ) {` |
| 122 | `class` | `ComposerSkillOptionInternal` | `class ComposerSkillOptionInternal {` |
| 40 | `top-level function` | `skillOptionFromGatewayInternal` | `ComposerSkillOptionInternal skillOptionFromGatewayInternal( GatewaySkillSummary skill, ) {` |
| 61 | `class` | `ComposerSkillOptionInternal` | `class ComposerSkillOptionInternal {` |
### `lib/features/assistant/assistant_page_composer_skill_picker.dart`
@ -455,13 +454,13 @@ _No extracted public top-level symbols._
| 56 | `typedef` | `AssistantClipboardImageReader` | `typedef AssistantClipboardImageReader = Future<XFile?> Function();` |
| 58 | `class` | `AssistantPage` | `class AssistantPage extends StatefulWidget {` |
| 80 | `class` | `AssistantPageStateInternal` | `class AssistantPageStateInternal extends State<AssistantPage> {` |
| 270 | `enum` | `AssistantSidePaneInternal` | `enum AssistantSidePaneInternal { tasks, navigation, focused }` |
| 272 | `class` | `AssistantUnifiedSidePaneInternal` | `class AssistantUnifiedSidePaneInternal extends StatelessWidget {` |
| 344 | `class` | `AssistantSideTabRailInternal` | `class AssistantSideTabRailInternal extends StatelessWidget {` |
| 444 | `class` | `AssistantSideTabButtonInternal` | `class AssistantSideTabButtonInternal extends StatefulWidget {` |
| 463 | `class` | `AssistantSideTabButtonStateInternal` | `class AssistantSideTabButtonStateInternal extends State<AssistantSideTabButtonInternal> {` |
| 512 | `class` | `AssistantLowerPaneInternal` | `class AssistantLowerPaneInternal extends StatelessWidget {` |
| 596 | `class` | `ConversationAreaInternal` | `class ConversationAreaInternal extends StatelessWidget {` |
| 278 | `enum` | `AssistantSidePaneInternal` | `enum AssistantSidePaneInternal { tasks, navigation, focused }` |
| 280 | `class` | `AssistantUnifiedSidePaneInternal` | `class AssistantUnifiedSidePaneInternal extends StatelessWidget {` |
| 352 | `class` | `AssistantSideTabRailInternal` | `class AssistantSideTabRailInternal extends StatelessWidget {` |
| 452 | `class` | `AssistantSideTabButtonInternal` | `class AssistantSideTabButtonInternal extends StatefulWidget {` |
| 471 | `class` | `AssistantSideTabButtonStateInternal` | `class AssistantSideTabButtonStateInternal extends State<AssistantSideTabButtonInternal> {` |
| 520 | `class` | `AssistantLowerPaneInternal` | `class AssistantLowerPaneInternal extends StatelessWidget {` |
| 604 | `class` | `ConversationAreaInternal` | `class ConversationAreaInternal extends StatelessWidget {` |
### `lib/features/assistant/assistant_page_message_widgets.dart`
@ -499,7 +498,7 @@ _No extracted public top-level symbols._
| Line | Kind | Name | Signature |
| ---: | --- | --- | --- |
| 42 | `extension` | `AssistantPageStateClosureInternal` | `extension AssistantPageStateClosureInternal on AssistantPageStateInternal {` |
| 44 | `extension` | `AssistantPageStateClosureInternal` | `extension AssistantPageStateClosureInternal on AssistantPageStateInternal {` |
### `lib/features/assistant/assistant_page_task_dialog_controls.dart`
@ -527,15 +526,15 @@ _No extracted public top-level symbols._
| 202 | `class` | `MetaPillInternal` | `class MetaPillInternal extends StatelessWidget {` |
| 256 | `top-level function` | `pillStyleForStatusInternal` | `PillStyleInternal pillStyleForStatusInternal( BuildContext context, String label, ) {` |
| 282 | `top-level function` | `normalizedTaskStatusInternal` | `String normalizedTaskStatusInternal(String status) {` |
| 294 | `top-level function` | `toolCallStatusLabelInternal` | `String toolCallStatusLabelInternal(String status) =>` |
| 301 | `top-level function` | `assistantThinkingLabelInternal` | `String assistantThinkingLabelInternal(String level) => switch (level) {` |
| 308 | `top-level function` | `sessionDisplayTitleInternal` | `String sessionDisplayTitleInternal(GatewaySessionSummary session) {` |
| 320 | `top-level function` | `fallbackSessionTitleInternal` | `String fallbackSessionTitleInternal(String sessionKey) {` |
| 335 | `top-level function` | `sessionPreviewInternal` | `String? sessionPreviewInternal(GatewaySessionSummary session) {` |
| 347 | `top-level function` | `sessionStatusInternal` | `String sessionStatusInternal( GatewaySessionSummary session, { required bool sessionPending, }) {` |
| 363 | `top-level function` | `sessionUpdatedAtLabelInternal` | `String sessionUpdatedAtLabelInternal(double? updatedAtMs) {` |
| 382 | `top-level function` | `estimatedComposerWrapSectionHeightInternal` | `double estimatedComposerWrapSectionHeightInternal({ required int itemCount, required double availableWidth, required double averageChipWidth, }) {` |
| 398 | `top-level function` | `sessionKeysMatchInternal` | `bool sessionKeysMatchInternal(String incoming, String current) {` |
| 295 | `top-level function` | `toolCallStatusLabelInternal` | `String toolCallStatusLabelInternal(String status) =>` |
| 303 | `top-level function` | `assistantThinkingLabelInternal` | `String assistantThinkingLabelInternal(String level) => switch (level) {` |
| 310 | `top-level function` | `sessionDisplayTitleInternal` | `String sessionDisplayTitleInternal(GatewaySessionSummary session) {` |
| 318 | `top-level function` | `fallbackSessionTitleInternal` | `String fallbackSessionTitleInternal(String sessionKey) {` |
| 326 | `top-level function` | `sessionPreviewInternal` | `String? sessionPreviewInternal(GatewaySessionSummary session) {` |
| 338 | `top-level function` | `sessionStatusInternal` | `String sessionStatusInternal( GatewaySessionSummary session, { required bool sessionPending, String lifecycleStatus = '', }) {` |
| 359 | `top-level function` | `sessionUpdatedAtLabelInternal` | `String sessionUpdatedAtLabelInternal(double? updatedAtMs) {` |
| 378 | `top-level function` | `estimatedComposerWrapSectionHeightInternal` | `double estimatedComposerWrapSectionHeightInternal({ required int itemCount, required double availableWidth, required double averageChipWidth, }) {` |
| 394 | `top-level function` | `sessionKeysMatchInternal` | `bool sessionKeysMatchInternal(String incoming, String current) {` |
### `lib/features/assistant/assistant_page_tooltip_labels.dart`
@ -647,63 +646,61 @@ _No extracted public top-level symbols._
### `lib/features/settings/settings_page_core.dart`
- Language: `dart`
- Public symbols: `1`
- Public symbols: `2`
| Line | Kind | Name | Signature |
| ---: | --- | --- | --- |
| 19 | `class` | `SettingsPage` | `class SettingsPage extends StatefulWidget {` |
| 19 | `top-level function` | `loadBridgeMetadataForSettingsAbout` | `Future<Map<String, dynamic>> loadBridgeMetadataForSettingsAbout({ required Uri bridgeEndpoint, required Future<String?> Function(Uri endpoint) authorizationResolver, HttpClient Function()? clientFactory, }) async {` |
| 109 | `class` | `SettingsPage` | `class SettingsPage extends StatefulWidget {` |
## lib/models
- Files: `1`
- Public symbols: `34`
- Public symbols: `31`
### `lib/models/app_models.dart`
- Language: `dart`
- Public symbols: `34`
- Public symbols: `31`
| Line | Kind | Name | Signature |
| ---: | --- | --- | --- |
| 5 | `enum` | `WorkspaceDestination` | `enum WorkspaceDestination {` |
| 10 | `extension` | `WorkspaceDestinationCopy` | `extension WorkspaceDestinationCopy on WorkspaceDestination {` |
| 45 | `enum` | `AssistantFocusEntry` | `enum AssistantFocusEntry {` |
| 51 | `extension` | `AssistantFocusEntryCopy` | `extension AssistantFocusEntryCopy on AssistantFocusEntry {` |
| 124 | `top-level function` | `normalizeAssistantNavigationDestinations` | `List<AssistantFocusEntry> normalizeAssistantNavigationDestinations( Iterable<AssistantFocusEntry> destinations, ) {` |
| 139 | `enum` | `StatusTone` | `enum StatusTone { neutral, accent, success, warning, danger }` |
| 141 | `class` | `StatusInfo` | `class StatusInfo {` |
| 148 | `enum` | `AppSidebarState` | `enum AppSidebarState { expanded, collapsed, hidden }` |
| 150 | `enum` | `AssistantMode` | `enum AssistantMode { code, office }` |
| 152 | `extension` | `AssistantModeCopy` | `extension AssistantModeCopy on AssistantMode {` |
| 159 | `enum` | `SettingsTab` | `enum SettingsTab { gateway }` |
| 161 | `extension` | `SettingsTabCopy` | `extension SettingsTabCopy on SettingsTab {` |
| 167 | `enum` | `SettingsDetailPage` | `enum SettingsDetailPage { gatewayConnection }` |
| 169 | `extension` | `SettingsDetailPageCopy` | `extension SettingsDetailPageCopy on SettingsDetailPage {` |
| 183 | `class` | `SettingsNavigationContext` | `class SettingsNavigationContext {` |
| 201 | `class` | `QuickAction` | `class QuickAction {` |
| 213 | `class` | `RecentSession` | `class RecentSession {` |
| 225 | `class` | `MetricSummary` | `class MetricSummary {` |
| 241 | `class` | `TaskSummary` | `class TaskSummary {` |
| 259 | `class` | `ModuleSummary` | `class ModuleSummary {` |
| 275 | `class` | `NodeSummary` | `class NodeSummary {` |
| 293 | `class` | `AgentSummary` | `class AgentSummary {` |
| 309 | `class` | `SkillSummary` | `class SkillSummary {` |
| 327 | `class` | `ConnectorSummary` | `class ConnectorSummary {` |
| 343 | `class` | `SecretSummary` | `class SecretSummary {` |
| 359 | `class` | `SecretReference` | `class SecretReference {` |
| 375 | `class` | `ProviderSummary` | `class ProviderSummary {` |
| 389 | `class` | `AuditSummary` | `class AuditSummary {` |
| 407 | `class` | `SettingSummary` | `class SettingSummary {` |
| 419 | `class` | `WorkspaceProfile` | `class WorkspaceProfile {` |
| 433 | `class` | `DetailPanelData` | `class DetailPanelData {` |
| 455 | `class` | `DetailSection` | `class DetailSection {` |
| 462 | `class` | `DetailItem` | `class DetailItem {` |
| 469 | `class` | `CommandEntry` | `class CommandEntry {` |
| 5 | `enum` | `WorkspaceDestination` | `enum WorkspaceDestination { assistant, settings }` |
| 7 | `extension` | `WorkspaceDestinationCopy` | `extension WorkspaceDestinationCopy on WorkspaceDestination {` |
| 42 | `enum` | `AssistantFocusEntry` | `enum AssistantFocusEntry { settings, language, theme }` |
| 44 | `extension` | `AssistantFocusEntryCopy` | `extension AssistantFocusEntryCopy on AssistantFocusEntry {` |
| 117 | `top-level function` | `normalizeAssistantNavigationDestinations` | `List<AssistantFocusEntry> normalizeAssistantNavigationDestinations( Iterable<AssistantFocusEntry> destinations, ) {` |
| 132 | `enum` | `StatusTone` | `enum StatusTone { neutral, accent, success, warning, danger }` |
| 134 | `class` | `StatusInfo` | `class StatusInfo {` |
| 141 | `enum` | `AppSidebarState` | `enum AppSidebarState { expanded, collapsed, hidden }` |
| 143 | `enum` | `AssistantMode` | `enum AssistantMode { code, office }` |
| 145 | `extension` | `AssistantModeCopy` | `extension AssistantModeCopy on AssistantMode {` |
| 152 | `enum` | `SettingsTab` | `enum SettingsTab { gateway }` |
| 154 | `extension` | `SettingsTabCopy` | `extension SettingsTabCopy on SettingsTab {` |
| 160 | `class` | `QuickAction` | `class QuickAction {` |
| 172 | `class` | `RecentSession` | `class RecentSession {` |
| 184 | `class` | `MetricSummary` | `class MetricSummary {` |
| 200 | `class` | `TaskSummary` | `class TaskSummary {` |
| 218 | `class` | `ModuleSummary` | `class ModuleSummary {` |
| 234 | `class` | `NodeSummary` | `class NodeSummary {` |
| 252 | `class` | `AgentSummary` | `class AgentSummary {` |
| 268 | `class` | `SkillSummary` | `class SkillSummary {` |
| 286 | `class` | `ConnectorSummary` | `class ConnectorSummary {` |
| 302 | `class` | `SecretSummary` | `class SecretSummary {` |
| 318 | `class` | `SecretReference` | `class SecretReference {` |
| 334 | `class` | `ProviderSummary` | `class ProviderSummary {` |
| 348 | `class` | `AuditSummary` | `class AuditSummary {` |
| 366 | `class` | `SettingSummary` | `class SettingSummary {` |
| 378 | `class` | `WorkspaceProfile` | `class WorkspaceProfile {` |
| 392 | `class` | `DetailPanelData` | `class DetailPanelData {` |
| 414 | `class` | `DetailSection` | `class DetailSection {` |
| 421 | `class` | `DetailItem` | `class DetailItem {` |
| 428 | `class` | `CommandEntry` | `class CommandEntry {` |
## lib/runtime
- Files: `67`
- Public symbols: `377`
- Files: `66`
- Public symbols: `372`
### `lib/runtime/account_runtime_client.dart`
@ -723,8 +720,8 @@ _No extracted public top-level symbols._
| Line | Kind | Name | Signature |
| ---: | --- | --- | --- |
| 1 | `class` | `AcpEndpointPaths` | `class AcpEndpointPaths {` |
| 51 | `top-level function` | `resolveAcpWebSocketEndpoint` | `Uri? resolveAcpWebSocketEndpoint(Uri? endpoint) {` |
| 69 | `top-level function` | `resolveAcpHttpRpcEndpoint` | `Uri? resolveAcpHttpRpcEndpoint(Uri? endpoint) {` |
| 72 | `top-level function` | `resolveAcpWebSocketEndpoint` | `Uri? resolveAcpWebSocketEndpoint(Uri? endpoint) {` |
| 93 | `top-level function` | `resolveAcpHttpRpcEndpoint` | `Uri? resolveAcpHttpRpcEndpoint(Uri? endpoint) {` |
### `lib/runtime/agent_registry.dart`
@ -740,26 +737,14 @@ _No extracted public top-level symbols._
| 153 | `class` | `AgentException` | `class AgentException implements Exception {` |
| 165 | `class` | `AgentRegistry` | `class AgentRegistry with ChangeNotifier {` |
### `lib/runtime/aris_bundle.dart`
- Language: `dart`
- Public symbols: `3`
| Line | Kind | Name | Signature |
| ---: | --- | --- | --- |
| 9 | `class` | `ArisBundleManifest` | `class ArisBundleManifest {` |
| 69 | `class` | `ResolvedArisBundle` | `class ResolvedArisBundle {` |
| 98 | `class` | `ArisBundleRepository` | `class ArisBundleRepository {` |
### `lib/runtime/aris_llm_chat_client.dart`
- Language: `dart`
- Public symbols: `2`
- Public symbols: `1`
| Line | Kind | Name | Signature |
| ---: | --- | --- | --- |
| 8 | `typedef` | `ArisProcessStarter` | `typedef ArisProcessStarter = Future<Process> Function( String executable, List<String> arguments, { Map<String, String>? environment, String? workingDirectory, });` |
| 16 | `class` | `ArisLlmChatClient` | `class ArisLlmChatClient {` |
| 3 | `class` | `ArisLlmChatClient` | `class ArisLlmChatClient {` |
### `lib/runtime/assistant_artifacts.dart`
@ -807,22 +792,22 @@ _No extracted public top-level symbols._
| Line | Kind | Name | Signature |
| ---: | --- | --- | --- |
| 12 | `enum` | `CodexSandboxMode` | `enum CodexSandboxMode {` |
| 22 | `enum` | `CodexApprovalPolicy` | `enum CodexApprovalPolicy {` |
| 32 | `enum` | `CodexAuthMode` | `enum CodexAuthMode {` |
| 42 | `class` | `CodexThread` | `class CodexThread {` |
| 75 | `class` | `CodexTurn` | `class CodexTurn {` |
| 106 | `class` | `CodexAccount` | `class CodexAccount {` |
| 137 | `class` | `CodexRateLimit` | `class CodexRateLimit {` |
| 160 | `class` | `CodexUserInput` | `class CodexUserInput {` |
| 180 | `class` | `CodexAttachment` | `class CodexAttachment {` |
| 198 | `class` | `CodexLogEvent` | `class CodexLogEvent extends CodexEvent {` |
| 211 | `class` | `CodexNotificationEvent` | `class CodexNotificationEvent extends CodexEvent {` |
| 219 | `class` | `CodexTurnEvent` | `class CodexTurnEvent extends CodexEvent {` |
| 253 | `class` | `CodexRpcError` | `class CodexRpcError implements Exception {` |
| 273 | `enum` | `CodexConnectionState` | `enum CodexConnectionState {` |
| 283 | `class` | `CodexRuntime` | `class CodexRuntime extends ChangeNotifier {` |
| 901 | `class` | `CodexLaunchConfiguration` | `class CodexLaunchConfiguration {` |
| 10 | `enum` | `CodexSandboxMode` | `enum CodexSandboxMode {` |
| 20 | `enum` | `CodexApprovalPolicy` | `enum CodexApprovalPolicy {` |
| 30 | `enum` | `CodexAuthMode` | `enum CodexAuthMode {` |
| 40 | `class` | `CodexThread` | `class CodexThread {` |
| 73 | `class` | `CodexTurn` | `class CodexTurn {` |
| 104 | `class` | `CodexAccount` | `class CodexAccount {` |
| 135 | `class` | `CodexRateLimit` | `class CodexRateLimit {` |
| 158 | `class` | `CodexUserInput` | `class CodexUserInput {` |
| 178 | `class` | `CodexAttachment` | `class CodexAttachment {` |
| 196 | `class` | `CodexLogEvent` | `class CodexLogEvent extends CodexEvent {` |
| 209 | `class` | `CodexNotificationEvent` | `class CodexNotificationEvent extends CodexEvent {` |
| 217 | `class` | `CodexTurnEvent` | `class CodexTurnEvent extends CodexEvent {` |
| 251 | `class` | `CodexRpcError` | `class CodexRpcError implements Exception {` |
| 271 | `enum` | `CodexConnectionState` | `enum CodexConnectionState {` |
| 281 | `class` | `CodexRuntime` | `class CodexRuntime extends ChangeNotifier {` |
| 629 | `class` | `CodexLaunchConfiguration` | `class CodexLaunchConfiguration {` |
### `lib/runtime/desktop_platform_service.dart`
@ -861,8 +846,8 @@ _No extracted public top-level symbols._
| Line | Kind | Name | Signature |
| ---: | --- | --- | --- |
| 4 | `top-level function` | `shouldBlockEmbeddedAgentLaunch` | `bool shouldBlockEmbeddedAgentLaunch({ required bool isAppleHost, bool? enabled, }) {` |
| 14 | `top-level function` | `shouldBlockGoCoreLaunch` | `bool shouldBlockGoCoreLaunch( GoCoreLaunch _, { required bool isAppleHost, bool? enabled, }) {` |
| 6 | `top-level function` | `shouldBlockEmbeddedAgentLaunch` | `bool shouldBlockEmbeddedAgentLaunch({ required bool isAppleHost, bool? enabled, }) {` |
| 19 | `top-level function` | `shouldBlockGoCoreLaunch` | `bool shouldBlockGoCoreLaunch({ required bool isAppleHost, bool? enabled, }) {` |
### `lib/runtime/external_code_agent_acp_desktop_transport.dart`
@ -871,7 +856,7 @@ _No extracted public top-level symbols._
| Line | Kind | Name | Signature |
| ---: | --- | --- | --- |
| 9 | `class` | `ExternalCodeAgentAcpDesktopTransport` | `class ExternalCodeAgentAcpDesktopTransport implements ExternalCodeAgentAcpTransport {` |
| 10 | `class` | `ExternalCodeAgentAcpDesktopTransport` | `class ExternalCodeAgentAcpDesktopTransport implements ExternalCodeAgentAcpTransport {` |
### `lib/runtime/file_store_support.dart`
@ -888,27 +873,29 @@ _No extracted public top-level symbols._
| 75 | `class` | `PersistentWriteFailures` | `class PersistentWriteFailures {` |
| 92 | `class` | `StoreLayout` | `class StoreLayout {` |
| 122 | `class` | `StoreLayoutResolver` | `class StoreLayoutResolver {` |
| 210 | `top-level function` | `normalizeStoreDirectoryPath` | `String normalizeStoreDirectoryPath(String path) {` |
| 227 | `top-level function` | `ensureDirectory` | `Future<Directory> ensureDirectory(String path) async {` |
| 235 | `top-level function` | `ensureOwnerOnlyDirectory` | `Future<void> ensureOwnerOnlyDirectory(Directory directory) async {` |
| 242 | `top-level function` | `ensureOwnerOnlyFile` | `Future<void> ensureOwnerOnlyFile(File file) async {` |
| 249 | `top-level function` | `encodeStableFileKey` | `String encodeStableFileKey(String key) {` |
| 253 | `top-level function` | `atomicWriteString` | `Future<void> atomicWriteString( File file, String contents, { bool ownerOnly = false, }) async {` |
| 275 | `top-level function` | `deleteIfExists` | `Future<void> deleteIfExists(File file) async {` |
| 281 | `top-level function` | `decodeYamlDocument` | `Object? decodeYamlDocument(String raw) {` |
| 306 | `top-level function` | `encodeYamlDocument` | `String encodeYamlDocument(Object? value) {` |
| 220 | `top-level function` | `normalizeStoreDirectoryPath` | `String normalizeStoreDirectoryPath(String path) {` |
| 237 | `top-level function` | `ensureDirectory` | `Future<Directory> ensureDirectory(String path) async {` |
| 245 | `top-level function` | `ensureOwnerOnlyDirectory` | `Future<void> ensureOwnerOnlyDirectory(Directory directory) async {` |
| 252 | `top-level function` | `ensureOwnerOnlyFile` | `Future<void> ensureOwnerOnlyFile(File file) async {` |
| 259 | `top-level function` | `encodeStableFileKey` | `String encodeStableFileKey(String key) {` |
| 263 | `top-level function` | `atomicWriteString` | `Future<void> atomicWriteString( File file, String contents, { bool ownerOnly = false, }) async {` |
| 285 | `top-level function` | `deleteIfExists` | `Future<void> deleteIfExists(File file) async {` |
| 291 | `top-level function` | `decodeYamlDocument` | `Object? decodeYamlDocument(String raw) {` |
| 316 | `top-level function` | `encodeYamlDocument` | `String encodeYamlDocument(Object? value) {` |
### `lib/runtime/gateway_acp_client.dart`
- Language: `dart`
- Public symbols: `4`
- Public symbols: `6`
| Line | Kind | Name | Signature |
| ---: | --- | --- | --- |
| 8 | `class` | `GatewayAcpException` | `class GatewayAcpException implements Exception {` |
| 19 | `class` | `GatewayAcpCapabilities` | `class GatewayAcpCapabilities {` |
| 70 | `class` | `GatewayAcpMultiAgentRequest` | `class GatewayAcpMultiAgentRequest {` |
| 90 | `class` | `GatewayAcpClient` | `class GatewayAcpClient {` |
| 16 | `class` | `GatewayAcpException` | `class GatewayAcpException implements Exception {` |
| 33 | `class` | `GatewayAcpCapabilities` | `class GatewayAcpCapabilities {` |
| 91 | `class` | `GatewayAcpMultiAgentRequest` | `class GatewayAcpMultiAgentRequest {` |
| 111 | `class` | `GatewayAcpClient` | `class GatewayAcpClient {` |
| 1392 | `top-level function` | `gatewayAcpHttpResponseTimeoutFor` | `Duration gatewayAcpHttpResponseTimeoutFor( Uri endpoint, String method, [ Map<String, dynamic> params = const <String, dynamic>{}, ]) {` |
| 1412 | `top-level function` | `gatewayAcpTaskRuntimeBudgetMinutesForParams` | `int gatewayAcpTaskRuntimeBudgetMinutesForParams(Map<String, dynamic> params) {` |
### `lib/runtime/gateway_runtime.dart`
@ -933,7 +920,7 @@ _No extracted public top-level symbols._
| Line | Kind | Name | Signature |
| ---: | --- | --- | --- |
| 24 | `class` | `GatewayRuntime` | `class GatewayRuntime extends ChangeNotifier with GatewayRuntimeHelpersInternal {` |
| 25 | `class` | `GatewayRuntime` | `class GatewayRuntime extends ChangeNotifier with GatewayRuntimeHelpersInternal {` |
### `lib/runtime/gateway_runtime_errors.dart`
@ -962,21 +949,21 @@ _No extracted public top-level symbols._
| ---: | --- | --- | --- |
| 21 | `top-level function` | `formatGatewayConnectAuthSummary` | `String formatGatewayConnectAuthSummary({ required String mode, required List<String> fields, required List<String> sources, }) {` |
| 31 | `mixin` | `GatewayRuntimeHelpersInternal` | `mixin GatewayRuntimeHelpersInternal on ChangeNotifier {` |
| 554 | `class` | `GatewaySetupPayload` | `class GatewaySetupPayload {` |
| 570 | `top-level function` | `decodeGatewaySetupCode` | `GatewaySetupPayload? decodeGatewaySetupCode(String rawInput) {` |
| 590 | `top-level function` | `decodeSetupPayloadJsonInternal` | `GatewaySetupPayload? decodeSetupPayloadJsonInternal(String raw) {` |
| 615 | `top-level function` | `resolveSetupCodeCandidateInternal` | `String resolveSetupCodeCandidateInternal(String raw) {` |
| 650 | `top-level function` | `composeManualUrlInternal` | `String? composeManualUrlInternal(String? host, int? port, bool? tls) {` |
| 660 | `top-level function` | `asMap` | `Map<String, dynamic> asMap(Object? value) {` |
| 670 | `top-level function` | `asList` | `List<dynamic> asList(Object? value) {` |
| 680 | `top-level function` | `stringValue` | `String? stringValue(Object? value) {` |
| 688 | `top-level function` | `boolValue` | `bool? boolValue(Object? value) {` |
| 703 | `top-level function` | `intValue` | `int? intValue(Object? value) {` |
| 716 | `top-level function` | `doubleValue` | `double? doubleValue(Object? value) {` |
| 729 | `top-level function` | `stringList` | `List<String> stringList(Object? value) {` |
| 735 | `top-level function` | `extractMessageText` | `String extractMessageText(Map<String, dynamic> message) {` |
| 756 | `top-level function` | `randomIdInternal` | `String randomIdInternal() {` |
| 766 | `class` | `RpcResponseInternal` | `class RpcResponseInternal {` |
| 561 | `class` | `GatewaySetupPayload` | `class GatewaySetupPayload {` |
| 577 | `top-level function` | `decodeGatewaySetupCode` | `GatewaySetupPayload? decodeGatewaySetupCode(String rawInput) {` |
| 597 | `top-level function` | `decodeSetupPayloadJsonInternal` | `GatewaySetupPayload? decodeSetupPayloadJsonInternal(String raw) {` |
| 622 | `top-level function` | `resolveSetupCodeCandidateInternal` | `String resolveSetupCodeCandidateInternal(String raw) {` |
| 657 | `top-level function` | `composeManualUrlInternal` | `String? composeManualUrlInternal(String? host, int? port, bool? tls) {` |
| 667 | `top-level function` | `asMap` | `Map<String, dynamic> asMap(Object? value) {` |
| 677 | `top-level function` | `asList` | `List<dynamic> asList(Object? value) {` |
| 687 | `top-level function` | `stringValue` | `String? stringValue(Object? value) {` |
| 695 | `top-level function` | `boolValue` | `bool? boolValue(Object? value) {` |
| 710 | `top-level function` | `intValue` | `int? intValue(Object? value) {` |
| 723 | `top-level function` | `doubleValue` | `double? doubleValue(Object? value) {` |
| 736 | `top-level function` | `stringList` | `List<String> stringList(Object? value) {` |
| 742 | `top-level function` | `extractMessageText` | `String extractMessageText(Map<String, dynamic> message) {` |
| 763 | `top-level function` | `randomIdInternal` | `String randomIdInternal() {` |
| 773 | `class` | `RpcResponseInternal` | `class RpcResponseInternal {` |
### `lib/runtime/gateway_runtime_protocol.dart`
@ -1007,10 +994,10 @@ _No extracted public top-level symbols._
| Line | Kind | Name | Signature |
| ---: | --- | --- | --- |
| 3 | `enum` | `GoCoreLaunchSource` | `enum GoCoreLaunchSource { buildArtifact }` |
| 5 | `class` | `GoCoreLaunch` | `class GoCoreLaunch {` |
| 19 | `typedef` | `GoCoreBinaryExistsResolver` | `typedef GoCoreBinaryExistsResolver = Future<bool> Function(String command);` |
| 21 | `class` | `GoCoreLocator` | `class GoCoreLocator {` |
| 4 | `enum` | `GoCoreLaunchSource` | `enum GoCoreLaunchSource { buildArtifact }` |
| 7 | `class` | `GoCoreLaunch` | `class GoCoreLaunch {` |
| 21 | `typedef` | `GoCoreBinaryExistsResolver` | `typedef GoCoreBinaryExistsResolver = Future<bool> Function(String command);` |
| 24 | `class` | `GoCoreLocator` | `class GoCoreLocator {` |
### `lib/runtime/go_multi_agent_mount_desktop_client.dart`
@ -1046,16 +1033,16 @@ _No extracted public top-level symbols._
| 107 | `class` | `ExternalCodeAgentAcpRoutingConfig` | `class ExternalCodeAgentAcpRoutingConfig {` |
| 167 | `class` | `ExternalCodeAgentAcpSkillInstallApproval` | `class ExternalCodeAgentAcpSkillInstallApproval {` |
| 187 | `class` | `GoTaskServiceRequest` | `class GoTaskServiceRequest {` |
| 357 | `class` | `GoTaskServiceUpdate` | `class GoTaskServiceUpdate {` |
| 386 | `class` | `GoTaskServiceArtifact` | `class GoTaskServiceArtifact {` |
| 433 | `class` | `GoTaskServiceResult` | `class GoTaskServiceResult {` |
| 540 | `top-level function` | `goTaskServiceGatewayEntryState` | `String? goTaskServiceGatewayEntryState({ required AssistantExecutionTarget requestedTarget, required GoTaskServiceResult result, }) {` |
| 575 | `abstract interface` | `ExternalCodeAgentAcpTransport` | `abstract class ExternalCodeAgentAcpTransport {` |
| 607 | `abstract interface` | `GoTaskServiceClient` | `abstract class GoTaskServiceClient {` |
| 641 | `top-level function` | `goTaskServiceUpdateFromAcpNotification` | `GoTaskServiceUpdate? goTaskServiceUpdateFromAcpNotification( Map<String, dynamic> notification, ) {` |
| 682 | `top-level function` | `goTaskServiceResultFromAcpResponse` | `GoTaskServiceResult goTaskServiceResultFromAcpResponse( Map<String, dynamic> response, { required GoTaskServiceRoute route, String streamedText = '', String? completedMessage, }) {` |
| 743 | `top-level function` | `mergeGoTaskServiceResponseResult` | `Map<String, dynamic> mergeGoTaskServiceResponseResult( Map<String, dynamic> response, Map<String, dynamic> overlay, ) {` |
| 767 | `top-level function` | `goTaskServiceBase64Size` | `int goTaskServiceBase64Size(String base64) {` |
| 359 | `class` | `GoTaskServiceUpdate` | `class GoTaskServiceUpdate {` |
| 388 | `class` | `GoTaskServiceArtifact` | `class GoTaskServiceArtifact {` |
| 443 | `class` | `GoTaskServiceResult` | `class GoTaskServiceResult {` |
| 577 | `top-level function` | `goTaskServiceGatewayEntryState` | `String? goTaskServiceGatewayEntryState({ required AssistantExecutionTarget requestedTarget, required GoTaskServiceResult result, }) {` |
| 612 | `abstract interface` | `ExternalCodeAgentAcpTransport` | `abstract class ExternalCodeAgentAcpTransport {` |
| 644 | `abstract interface` | `GoTaskServiceClient` | `abstract class GoTaskServiceClient {` |
| 678 | `top-level function` | `goTaskServiceUpdateFromAcpNotification` | `GoTaskServiceUpdate? goTaskServiceUpdateFromAcpNotification( Map<String, dynamic> notification, ) {` |
| 719 | `top-level function` | `goTaskServiceResultFromAcpResponse` | `GoTaskServiceResult goTaskServiceResultFromAcpResponse( Map<String, dynamic> response, { required GoTaskServiceRoute route, String streamedText = '', String? completedMessage, }) {` |
| 913 | `top-level function` | `mergeGoTaskServiceResponseResult` | `Map<String, dynamic> mergeGoTaskServiceResponseResult( Map<String, dynamic> response, Map<String, dynamic> overlay, ) {` |
| 937 | `top-level function` | `goTaskServiceBase64Size` | `int goTaskServiceBase64Size(String base64) {` |
### `lib/runtime/go_task_service_desktop_service.dart`
@ -1086,9 +1073,9 @@ _No extracted public top-level symbols._
| Line | Kind | Name | Signature |
| ---: | --- | --- | --- |
| 6 | `abstract interface` | `FrameworkPreset` | `abstract class FrameworkPreset {` |
| 19 | `class` | `NativeFrameworkPreset` | `class NativeFrameworkPreset extends FrameworkPreset {` |
| 48 | `class` | `ArisFrameworkPreset` | `class ArisFrameworkPreset extends FrameworkPreset {` |
| 3 | `abstract interface` | `FrameworkPreset` | `abstract class FrameworkPreset {` |
| 16 | `class` | `NativeFrameworkPreset` | `class NativeFrameworkPreset extends FrameworkPreset {` |
| 45 | `class` | `ArisFrameworkPreset` | `class ArisFrameworkPreset extends FrameworkPreset {` |
### `lib/runtime/multi_agent_mount_resolver.dart`
@ -1103,18 +1090,17 @@ _No extracted public top-level symbols._
### `lib/runtime/multi_agent_mounts.dart`
- Language: `dart`
- Public symbols: `8`
- Public symbols: `7`
| Line | Kind | Name | Signature |
| ---: | --- | --- | --- |
| 11 | `class` | `MultiAgentMountManager` | `class MultiAgentMountManager {` |
| 139 | `abstract interface` | `CliMountAdapter` | `abstract class CliMountAdapter {` |
| 191 | `class` | `ArisMountAdapter` | `class ArisMountAdapter extends CliMountAdapter {` |
| 277 | `class` | `CodexMountAdapter` | `class CodexMountAdapter extends CliMountAdapter {` |
| 350 | `class` | `ClaudeMountAdapter` | `class ClaudeMountAdapter extends CliMountAdapter {` |
| 398 | `class` | `GeminiMountAdapter` | `class GeminiMountAdapter extends CliMountAdapter {` |
| 446 | `class` | `OpencodeMountAdapter` | `class OpencodeMountAdapter extends CliMountAdapter {` |
| 515 | `class` | `OpenClawMountAdapter` | `class OpenClawMountAdapter extends CliMountAdapter {` |
| 9 | `class` | `MultiAgentMountManager` | `class MultiAgentMountManager {` |
| 90 | `abstract interface` | `CliMountAdapter` | `abstract class CliMountAdapter {` |
| 112 | `class` | `CodexMountAdapter` | `class CodexMountAdapter extends CliMountAdapter {` |
| 154 | `class` | `ClaudeMountAdapter` | `class ClaudeMountAdapter extends CliMountAdapter {` |
| 193 | `class` | `GeminiMountAdapter` | `class GeminiMountAdapter extends CliMountAdapter {` |
| 232 | `class` | `OpencodeMountAdapter` | `class OpencodeMountAdapter extends CliMountAdapter {` |
| 273 | `class` | `OpenClawMountAdapter` | `class OpenClawMountAdapter extends CliMountAdapter {` |
### `lib/runtime/multi_agent_orchestrator.dart`
@ -1130,7 +1116,7 @@ _No extracted public top-level symbols._
| Line | Kind | Name | Signature |
| ---: | --- | --- | --- |
| 24 | `class` | `MultiAgentOrchestrator` | `class MultiAgentOrchestrator extends ChangeNotifier {` |
| 20 | `class` | `MultiAgentOrchestrator` | `class MultiAgentOrchestrator extends ChangeNotifier {` |
### `lib/runtime/multi_agent_orchestrator_protocol.dart`
@ -1216,16 +1202,14 @@ _No extracted public top-level symbols._
### `lib/runtime/runtime_controllers_derived_tasks.dart`
- Language: `dart`
- Public symbols: `6`
- Public symbols: `4`
| Line | Kind | Name | Signature |
| ---: | --- | --- | --- |
| 14 | `class` | `DerivedTasksController` | `class DerivedTasksController extends ChangeNotifier {` |
| 150 | `top-level function` | `normalizeMainSessionKey` | `String normalizeMainSessionKey(String? value) {` |
| 155 | `top-level function` | `makeAgentSessionKey` | `String makeAgentSessionKey({required String agentId, required String baseKey}) {` |
| 164 | `top-level function` | `matchesSessionKey` | `bool matchesSessionKey(String incoming, String current) {` |
| 174 | `top-level function` | `encodePrettyJson` | `String encodePrettyJson(Object value) {` |
| 179 | `top-level function` | `ephemeralIdInternal` | `String ephemeralIdInternal() =>` |
| 6 | `class` | `DerivedTasksController` | `class DerivedTasksController extends ChangeNotifier {` |
| 142 | `top-level function` | `matchesSessionKey` | `bool matchesSessionKey(String incoming, String current) {` |
| 148 | `top-level function` | `encodePrettyJson` | `String encodePrettyJson(Object value) {` |
| 153 | `top-level function` | `ephemeralIdInternal` | `String ephemeralIdInternal() =>` |
### `lib/runtime/runtime_controllers_entities.dart`
@ -1249,7 +1233,7 @@ _No extracted public top-level symbols._
| 14 | `class` | `AiGatewayResponseExceptionInternal` | `class AiGatewayResponseExceptionInternal implements Exception {` |
| 24 | `class` | `GatewayAgentsController` | `class GatewayAgentsController extends ChangeNotifier {` |
| 89 | `class` | `GatewaySessionsController` | `class GatewaySessionsController extends ChangeNotifier {` |
| 173 | `class` | `GatewayChatController` | `class GatewayChatController extends ChangeNotifier {` |
| 146 | `class` | `GatewayChatController` | `class GatewayChatController extends ChangeNotifier {` |
### `lib/runtime/runtime_controllers_settings.dart`
@ -1258,7 +1242,7 @@ _No extracted public top-level symbols._
| Line | Kind | Name | Signature |
| ---: | --- | --- | --- |
| 20 | `class` | `SettingsController` | `class SettingsController extends ChangeNotifier {` |
| 21 | `class` | `SettingsController` | `class SettingsController extends ChangeNotifier {` |
### `lib/runtime/runtime_controllers_settings_account.dart`
@ -1272,7 +1256,7 @@ _No extracted public top-level symbols._
### `lib/runtime/runtime_controllers_settings_account_impl.dart`
- Language: `dart`
- Public symbols: `8`
- Public symbols: `9`
| Line | Kind | Name | Signature |
| ---: | --- | --- | --- |
@ -1282,8 +1266,9 @@ _No extracted public top-level symbols._
| 158 | `top-level function` | `restoreAccountSessionSettingsInternal` | `Future<void> restoreAccountSessionSettingsInternal( SettingsController controller, { String baseUrl = '', bool quiet = false, }) async {` |
| 225 | `top-level function` | `syncAccountSettingsInternal` | `Future<AccountSyncResult> syncAccountSettingsInternal( SettingsController controller, { String baseUrl = '', bool quiet = false, Map<String, dynamic> profilePayloadOverride = const <String, dynamic>{}, }) async {` |
| 371 | `top-level function` | `logoutAccountSettingsInternal` | `Future<void> logoutAccountSettingsInternal( SettingsController controller, { String statusMessage = 'Signed out', bool quiet = false, }) async {` |
| 414 | `top-level function` | `cancelAccountMfaChallengeSettingsInternal` | `Future<void> cancelAccountMfaChallengeSettingsInternal( SettingsController controller, ) async {` |
| 444 | `top-level function` | `normalizeAccountBaseUrlSettingsInternal` | `String normalizeAccountBaseUrlSettingsInternal( String raw, { String fallback = '', }) {` |
| 424 | `top-level function` | `cancelAccountMfaChallengeSettingsInternal` | `Future<void> cancelAccountMfaChallengeSettingsInternal( SettingsController controller, ) async {` |
| 454 | `top-level function` | `normalizeAccountBaseUrlSettingsInternal` | `String normalizeAccountBaseUrlSettingsInternal( String raw, { String fallback = '', }) {` |
| 574 | `top-level function` | `resolveAcpBridgeServerEffectiveConfigInternal` | `AcpBridgeServerEffectiveConfig resolveAcpBridgeServerEffectiveConfigInternal( SettingsController controller, { required AcpBridgeServerModeConfig config, }) {` |
### `lib/runtime/runtime_controllers_settings_connectivity_impl.dart`
@ -1310,28 +1295,28 @@ _No extracted public top-level symbols._
| 3 | `top-level function` | `saveGatewaySecretsSettingsInternal` | `Future<void> saveGatewaySecretsSettingsInternal( SettingsController controller, { int? profileIndex, required String token, required String password, }) async {` |
| 61 | `top-level function` | `clearGatewaySecretsSettingsInternal` | `Future<void> clearGatewaySecretsSettingsInternal( SettingsController controller, { int? profileIndex, bool token = false, bool password = false, }) async {` |
| 115 | `top-level function` | `loadGatewayTokenSettingsInternal` | `Future<String> loadGatewayTokenSettingsInternal( SettingsController controller, { int? profileIndex, }) async {` |
| 141 | `top-level function` | `loadGatewayPasswordSettingsInternal` | `Future<String> loadGatewayPasswordSettingsInternal( SettingsController controller, { int? profileIndex, }) async {` |
| 167 | `top-level function` | `hasStoredGatewayTokenForProfileSettingsInternal` | `bool hasStoredGatewayTokenForProfileSettingsInternal( SettingsController controller, int profileIndex, ) =>` |
| 179 | `top-level function` | `hasStoredGatewayPasswordForProfileSettingsInternal` | `bool hasStoredGatewayPasswordForProfileSettingsInternal( SettingsController controller, int profileIndex, ) => controller.secureRefsInternal.containsKey( gatewayPasswordRefForProfileSettingsInternal(controller, profileIndex), );` |
| 186 | `top-level function` | `storedGatewayTokenMaskForProfileSettingsInternal` | `String? storedGatewayTokenMaskForProfileSettingsInternal( SettingsController controller, int profileIndex, ) =>` |
| 199 | `top-level function` | `storedGatewayPasswordMaskForProfileSettingsInternal` | `String? storedGatewayPasswordMaskForProfileSettingsInternal( SettingsController controller, int profileIndex, ) =>` |
| 208 | `top-level function` | `gatewayTokenRefForProfileSettingsInternal` | `String gatewayTokenRefForProfileSettingsInternal( SettingsController controller, int profileIndex, ) {` |
| 221 | `top-level function` | `gatewayPasswordRefForProfileSettingsInternal` | `String gatewayPasswordRefForProfileSettingsInternal( SettingsController controller, int profileIndex, ) {` |
| 234 | `top-level function` | `aiGatewayApiKeyRefSettingsInternal` | `String aiGatewayApiKeyRefSettingsInternal( SettingsController controller, [ AiGatewayProfile? profile, ]) {` |
| 243 | `top-level function` | `vaultTokenRefSettingsInternal` | `String vaultTokenRefSettingsInternal( SettingsController controller, [ VaultConfig? profile, ]) {` |
| 252 | `top-level function` | `ollamaCloudApiKeyRefSettingsInternal` | `String ollamaCloudApiKeyRefSettingsInternal( SettingsController controller, [ OllamaCloudConfig? profile, ]) {` |
| 261 | `top-level function` | `saveOllamaCloudApiKeySettingsInternal` | `Future<void> saveOllamaCloudApiKeySettingsInternal( SettingsController controller, String value, ) async {` |
| 287 | `top-level function` | `loadOllamaCloudApiKeySettingsInternal` | `Future<String> loadOllamaCloudApiKeySettingsInternal( SettingsController controller, ) async {` |
| 304 | `top-level function` | `saveVaultTokenSettingsInternal` | `Future<void> saveVaultTokenSettingsInternal( SettingsController controller, String value, ) async {` |
| 330 | `top-level function` | `loadVaultTokenSettingsInternal` | `Future<String> loadVaultTokenSettingsInternal( SettingsController controller, ) async {` |
| 346 | `top-level function` | `saveAiGatewayApiKeySettingsInternal` | `Future<void> saveAiGatewayApiKeySettingsInternal( SettingsController controller, String value, ) async {` |
| 372 | `top-level function` | `loadAiGatewayApiKeySettingsInternal` | `Future<String> loadAiGatewayApiKeySettingsInternal( SettingsController controller, ) async {` |
| 388 | `top-level function` | `clearAiGatewayApiKeySettingsInternal` | `Future<void> clearAiGatewayApiKeySettingsInternal( SettingsController controller, ) async {` |
| 398 | `top-level function` | `saveSecretValueByRefSettingsInternal` | `Future<void> saveSecretValueByRefSettingsInternal( SettingsController controller, String refName, String value, { required String provider, required String module, }) async {` |
| 425 | `top-level function` | `loadSecretValueByRefSettingsInternal` | `Future<String> loadSecretValueByRefSettingsInternal( SettingsController controller, String refName, ) async {` |
| 435 | `top-level function` | `loadVaultTokenForSecretReadsSettingsInternal` | `Future<String> loadVaultTokenForSecretReadsSettingsInternal( SettingsController controller, { String tokenOverride = '', }) async {` |
| 454 | `top-level function` | `readVaultSecretByRefSettingsInternal` | `Future<String> readVaultSecretByRefSettingsInternal( SettingsController controller, String refName, ) async {` |
| 484 | `top-level function` | `resolveSecretValueSettingsInternal` | `Future<String> resolveSecretValueSettingsInternal( SettingsController controller, { String explicitValue = '', String refName = '', String fallbackRefName = '', String accountTarget = '', bool allowVaultLookup = true, bool persistExplicitValue = true, }) async {` |
| 127 | `top-level function` | `loadGatewayPasswordSettingsInternal` | `Future<String> loadGatewayPasswordSettingsInternal( SettingsController controller, { int? profileIndex, }) async {` |
| 139 | `top-level function` | `hasStoredGatewayTokenForProfileSettingsInternal` | `bool hasStoredGatewayTokenForProfileSettingsInternal( SettingsController controller, int profileIndex, ) =>` |
| 151 | `top-level function` | `hasStoredGatewayPasswordForProfileSettingsInternal` | `bool hasStoredGatewayPasswordForProfileSettingsInternal( SettingsController controller, int profileIndex, ) => controller.secureRefsInternal.containsKey( gatewayPasswordRefForProfileSettingsInternal(controller, profileIndex), );` |
| 158 | `top-level function` | `storedGatewayTokenMaskForProfileSettingsInternal` | `String? storedGatewayTokenMaskForProfileSettingsInternal( SettingsController controller, int profileIndex, ) =>` |
| 171 | `top-level function` | `storedGatewayPasswordMaskForProfileSettingsInternal` | `String? storedGatewayPasswordMaskForProfileSettingsInternal( SettingsController controller, int profileIndex, ) =>` |
| 180 | `top-level function` | `gatewayTokenRefForProfileSettingsInternal` | `String gatewayTokenRefForProfileSettingsInternal( SettingsController controller, int profileIndex, ) {` |
| 193 | `top-level function` | `gatewayPasswordRefForProfileSettingsInternal` | `String gatewayPasswordRefForProfileSettingsInternal( SettingsController controller, int profileIndex, ) {` |
| 206 | `top-level function` | `aiGatewayApiKeyRefSettingsInternal` | `String aiGatewayApiKeyRefSettingsInternal( SettingsController controller, [ AiGatewayProfile? profile, ]) {` |
| 215 | `top-level function` | `vaultTokenRefSettingsInternal` | `String vaultTokenRefSettingsInternal( SettingsController controller, [ VaultConfig? profile, ]) {` |
| 224 | `top-level function` | `ollamaCloudApiKeyRefSettingsInternal` | `String ollamaCloudApiKeyRefSettingsInternal( SettingsController controller, [ OllamaCloudConfig? profile, ]) {` |
| 233 | `top-level function` | `saveOllamaCloudApiKeySettingsInternal` | `Future<void> saveOllamaCloudApiKeySettingsInternal( SettingsController controller, String value, ) async {` |
| 259 | `top-level function` | `loadOllamaCloudApiKeySettingsInternal` | `Future<String> loadOllamaCloudApiKeySettingsInternal( SettingsController controller, ) async {` |
| 267 | `top-level function` | `saveVaultTokenSettingsInternal` | `Future<void> saveVaultTokenSettingsInternal( SettingsController controller, String value, ) async {` |
| 293 | `top-level function` | `loadVaultTokenSettingsInternal` | `Future<String> loadVaultTokenSettingsInternal( SettingsController controller, ) async {` |
| 301 | `top-level function` | `saveAiGatewayApiKeySettingsInternal` | `Future<void> saveAiGatewayApiKeySettingsInternal( SettingsController controller, String value, ) async {` |
| 327 | `top-level function` | `loadAiGatewayApiKeySettingsInternal` | `Future<String> loadAiGatewayApiKeySettingsInternal( SettingsController controller, ) async {` |
| 335 | `top-level function` | `clearAiGatewayApiKeySettingsInternal` | `Future<void> clearAiGatewayApiKeySettingsInternal( SettingsController controller, ) async {` |
| 345 | `top-level function` | `saveSecretValueByRefSettingsInternal` | `Future<void> saveSecretValueByRefSettingsInternal( SettingsController controller, String refName, String value, { required String provider, required String module, }) async {` |
| 372 | `top-level function` | `loadSecretValueByRefSettingsInternal` | `Future<String> loadSecretValueByRefSettingsInternal( SettingsController controller, String refName, ) async {` |
| 382 | `top-level function` | `loadVaultTokenForSecretReadsSettingsInternal` | `Future<String> loadVaultTokenForSecretReadsSettingsInternal( SettingsController controller, { String tokenOverride = '', }) async {` |
| 393 | `top-level function` | `readVaultSecretByRefSettingsInternal` | `Future<String> readVaultSecretByRefSettingsInternal( SettingsController controller, String refName, ) async {` |
| 423 | `top-level function` | `resolveSecretValueSettingsInternal` | `Future<String> resolveSecretValueSettingsInternal( SettingsController controller, { String explicitValue = '', String refName = '', String fallbackRefName = '', String accountTarget = '', bool allowVaultLookup = true, bool persistExplicitValue = true, }) async {` |
### `lib/runtime/runtime_coordinator.dart`
@ -1341,7 +1326,7 @@ _No extracted public top-level symbols._
| Line | Kind | Name | Signature |
| ---: | --- | --- | --- |
| 17 | `enum` | `CoordinatorState` | `enum CoordinatorState { disconnected, connecting, connected, ready, error }` |
| 26 | `class` | `RuntimeCoordinator` | `class RuntimeCoordinator extends ChangeNotifier {` |
| 20 | `class` | `RuntimeCoordinator` | `class RuntimeCoordinator extends ChangeNotifier {` |
### `lib/runtime/runtime_dispatch_resolver.dart`
@ -1374,22 +1359,22 @@ _No extracted public top-level symbols._
### `lib/runtime/runtime_models_account.dart`
- Language: `dart`
- Public symbols: `13`
- Public symbols: `12`
| Line | Kind | Name | Signature |
| ---: | --- | --- | --- |
| 4 | `class` | `AccountSessionSummary` | `class AccountSessionSummary {` |
| 68 | `class` | `AccountTokenConfigured` | `class AccountTokenConfigured {` |
| 108 | `class` | `AccountSecretLocator` | `class AccountSecretLocator {` |
| 166 | `class` | `AccountRemoteProfile` | `class AccountRemoteProfile {` |
| 269 | `class` | `AcpBridgeServerRemoteServerSummary` | `class AcpBridgeServerRemoteServerSummary {` |
| 312 | `class` | `AcpBridgeServerCloudSyncConfig` | `class AcpBridgeServerCloudSyncConfig {` |
| 370 | `class` | `AcpBridgeServerSelfHostedConfig` | `class AcpBridgeServerSelfHostedConfig {` |
| 423 | `class` | `AcpBridgeServerAdvancedOverrides` | `class AcpBridgeServerAdvancedOverrides {` |
| 509 | `class` | `AcpBridgeServerModeConfig` | `class AcpBridgeServerModeConfig {` |
| 577 | `class` | `AccountSyncState` | `class AccountSyncState {` |
| 667 | `class` | `AccountSyncResult` | `class AccountSyncResult {` |
| 686 | `top-level function` | `isSupportedAccountManagedSecretTarget` | `bool isSupportedAccountManagedSecretTarget(String target) {` |
| 3 | `class` | `AccountSessionSummary` | `class AccountSessionSummary {` |
| 67 | `class` | `AccountTokenConfigured` | `class AccountTokenConfigured {` |
| 96 | `class` | `AccountSecretLocator` | `class AccountSecretLocator {` |
| 154 | `class` | `AccountRemoteProfile` | `class AccountRemoteProfile {` |
| 248 | `class` | `AcpBridgeServerRemoteServerSummary` | `class AcpBridgeServerRemoteServerSummary {` |
| 276 | `class` | `AcpBridgeServerCloudSyncConfig` | `class AcpBridgeServerCloudSyncConfig {` |
| 334 | `class` | `AcpBridgeServerSelfHostedConfig` | `class AcpBridgeServerSelfHostedConfig {` |
| 387 | `class` | `AcpBridgeServerEffectiveConfig` | `class AcpBridgeServerEffectiveConfig {` |
| 442 | `class` | `AcpBridgeServerModeConfig` | `class AcpBridgeServerModeConfig {` |
| 498 | `class` | `AccountSyncState` | `class AccountSyncState {` |
| 588 | `class` | `AccountSyncResult` | `class AccountSyncResult {` |
| 607 | `top-level function` | `isSupportedAccountManagedSecretTarget` | `bool isSupportedAccountManagedSecretTarget(String target) {` |
### `lib/runtime/runtime_models_configs.dart`
@ -1399,16 +1384,16 @@ _No extracted public top-level symbols._
| Line | Kind | Name | Signature |
| ---: | --- | --- | --- |
| 13 | `class` | `GatewayConnectionProfile` | `class GatewayConnectionProfile {` |
| 136 | `top-level function` | `normalizeGatewayProfiles` | `List<GatewayConnectionProfile> normalizeGatewayProfiles({ Iterable<GatewayConnectionProfile>? profiles, }) {` |
| 214 | `top-level function` | `replaceGatewayProfileAt` | `List<GatewayConnectionProfile> replaceGatewayProfileAt( List<GatewayConnectionProfile> profiles, int index, GatewayConnectionProfile profile, ) {` |
| 260 | `class` | `OllamaLocalConfig` | `class OllamaLocalConfig {` |
| 311 | `class` | `OllamaCloudConfig` | `class OllamaCloudConfig {` |
| 378 | `class` | `VaultConfig` | `class VaultConfig {` |
| 434 | `class` | `AiGatewayProfile` | `class AiGatewayProfile {` |
| 532 | `class` | `AiGatewayConnectionCheck` | `class AiGatewayConnectionCheck {` |
| 548 | `enum` | `WebSessionPersistenceMode` | `enum WebSessionPersistenceMode { browser, remote }` |
| 550 | `extension` | `WebSessionPersistenceModeCopy` | `extension WebSessionPersistenceModeCopy on WebSessionPersistenceMode {` |
| 567 | `class` | `WebSessionPersistenceConfig` | `class WebSessionPersistenceConfig {` |
| 121 | `top-level function` | `normalizeGatewayProfiles` | `List<GatewayConnectionProfile> normalizeGatewayProfiles({ Iterable<GatewayConnectionProfile>? profiles, }) {` |
| 162 | `top-level function` | `replaceGatewayProfileAt` | `List<GatewayConnectionProfile> replaceGatewayProfileAt( List<GatewayConnectionProfile> profiles, int _, GatewayConnectionProfile profile, ) {` |
| 206 | `class` | `OllamaLocalConfig` | `class OllamaLocalConfig {` |
| 257 | `class` | `OllamaCloudConfig` | `class OllamaCloudConfig {` |
| 324 | `class` | `VaultConfig` | `class VaultConfig {` |
| 380 | `class` | `AiGatewayProfile` | `class AiGatewayProfile {` |
| 473 | `class` | `AiGatewayConnectionCheck` | `class AiGatewayConnectionCheck {` |
| 489 | `enum` | `WebSessionPersistenceMode` | `enum WebSessionPersistenceMode { browser, remote }` |
| 491 | `extension` | `WebSessionPersistenceModeCopy` | `extension WebSessionPersistenceModeCopy on WebSessionPersistenceMode {` |
| 508 | `class` | `WebSessionPersistenceConfig` | `class WebSessionPersistenceConfig {` |
### `lib/runtime/runtime_models_connection.dart`
@ -1540,11 +1525,11 @@ _No extracted public top-level symbols._
| 711 | `top-level function` | `assistantExecutionTargetFromExecutionMode` | `AssistantExecutionTarget assistantExecutionTargetFromExecutionMode( ThreadExecutionMode mode, ) {` |
| 720 | `top-level function` | `workspaceRefKindFromWorkspaceKind` | `WorkspaceRefKind workspaceRefKindFromWorkspaceKind(WorkspaceKind kind) {` |
| 727 | `class` | `ThreadContextState` | `class ThreadContextState {` |
| 904 | `class` | `ThreadLifecycleState` | `class ThreadLifecycleState {` |
| 960 | `class` | `TaskThread` | `class TaskThread {` |
| 1291 | `top-level function` | `isNewConversationTaskTitle` | `bool isNewConversationTaskTitle(String title) {` |
| 1296 | `top-level function` | `firstUserMessageTaskTitle` | `String firstUserMessageTaskTitle( Iterable<GatewayChatMessage> messages, { String fallback = '', }) {` |
| 1318 | `top-level function` | `derivePersistedTaskTitle` | `String derivePersistedTaskTitle( String currentTitle, Iterable<GatewayChatMessage> messages, { String fallback = '', bool hasCustomTitle = false, }) {` |
| 935 | `class` | `ThreadLifecycleState` | `class ThreadLifecycleState {` |
| 991 | `class` | `TaskThread` | `class TaskThread {` |
| 1332 | `top-level function` | `isNewConversationTaskTitle` | `bool isNewConversationTaskTitle(String title) {` |
| 1337 | `top-level function` | `firstUserMessageTaskTitle` | `String firstUserMessageTaskTitle( Iterable<GatewayChatMessage> messages, { String fallback = '', }) {` |
| 1359 | `top-level function` | `derivePersistedTaskTitle` | `String derivePersistedTaskTitle( String currentTitle, Iterable<GatewayChatMessage> messages, { String fallback = '', bool hasCustomTitle = false, }) {` |
### `lib/runtime/runtime_models_settings_snapshot.dart`
@ -1553,7 +1538,7 @@ _No extracted public top-level symbols._
| Line | Kind | Name | Signature |
| ---: | --- | --- | --- |
| 16 | `class` | `SettingsSnapshot` | `class SettingsSnapshot {` |
| 17 | `class` | `SettingsSnapshot` | `class SettingsSnapshot {` |
### `lib/runtime/runtime_models_ui_state.dart`
@ -1583,7 +1568,7 @@ _No extracted public top-level symbols._
| Line | Kind | Name | Signature |
| ---: | --- | --- | --- |
| 13 | `class` | `SecureConfigStore` | `class SecureConfigStore {` |
| 9 | `class` | `SecureConfigStore` | `class SecureConfigStore {` |
### `lib/runtime/settings_store.dart`
@ -1594,9 +1579,9 @@ _No extracted public top-level symbols._
| ---: | --- | --- | --- |
| 8 | `enum` | `SettingsSnapshotReloadStatus` | `enum SettingsSnapshotReloadStatus { applied, invalid }` |
| 10 | `class` | `SettingsSnapshotReloadResult` | `class SettingsSnapshotReloadResult {` |
| 22 | `enum` | `SkippedTaskThreadReason` | `enum SkippedTaskThreadReason {` |
| 28 | `class` | `SkippedTaskThreadRecord` | `class SkippedTaskThreadRecord {` |
| 35 | `class` | `SettingsStore` | `class SettingsStore {` |
| 20 | `enum` | `SkippedTaskThreadReason` | `enum SkippedTaskThreadReason {` |
| 26 | `class` | `SkippedTaskThreadRecord` | `class SkippedTaskThreadRecord {` |
| 36 | `class` | `SettingsStore` | `class SettingsStore {` |
### `lib/runtime/skill_directory_access.dart`
@ -1649,7 +1634,7 @@ _No extracted public top-level symbols._
## rust/src
- Files: `4`
- Public symbols: `19`
- Public symbols: `16`
### `rust/src/error.rs`
@ -1692,12 +1677,9 @@ _No extracted public top-level symbols._
### `rust/src/types.rs`
- Language: `rust`
- Public symbols: `5`
- Public symbols: `2`
| Line | Kind | Name | Signature |
| ---: | --- | --- | --- |
| 8 | `struct` | `CodexResult` | `pub struct CodexResult {` |
| 38 | `struct` | `CodexMessage` | `pub struct CodexMessage {` |
| 51 | `struct` | `CodexEvent` | `pub struct CodexEvent {` |
| 66 | `struct` | `CodexModelInfo` | `pub struct CodexModelInfo {` |
| 79 | `struct` | `CodexAccountInfo` | `pub struct CodexAccountInfo {` |
| 38 | `struct` | `CodexEvent` | `pub struct CodexEvent {` |

View File

@ -56,7 +56,6 @@ The app only talks to:
- no production `xworkmate.providers.sync`
- no production provider catalog from `providerSyncDefinitions`
- no execution-time use of account-synced `openclawUrl`
- no execution-time use of account-synced `apisixUrl`
- no direct app calls to `xworkmate-bridge.svc.plus/*`
- no direct app calls to `openclaw.svc.plus`
@ -71,7 +70,7 @@ The app only talks to:
`account/sync_state.json`
- stores synced account metadata only
- may retain `openclawUrl` / `apisixUrl` as account profile metadata
- may retain `openclawUrl` as account profile metadata
- does not overwrite executable cloud routing targets
`acpBridgeServerModeConfig.effective`

View File

@ -0,0 +1,161 @@
# Flutter/Dart 孤立代码与陈旧代码清理分析
日期2026-05-13
范围:
- `lib/settings/mobile/runtime`:目录不存在
- `lib/gateway`:目录不存在
- `lib/profile`:目录不存在
- `lib/shared/shell`:目录不存在
- `lib/widgets/layout`:目录不存在
- `lib/core/helper`:目录不存在
- `lib/core/utils`:目录不存在
- 已扫描仍存在的重点路径:`lib/runtime`、`lib/features/settings`、`lib/features/mobile`、`lib/widgets`、`lib/app`
## 已执行扫描
- `rg "^export " lib test`
- `find lib -name "*.dart"`
- `rg "^class |^typedef |^extension |^mixin "`
- `rg "register|registry|routes:|GoRoute|GetIt|Provider|Riverpod|dispatch|mount|factory|builder:|runtimeType"`
- `rg "legacy|deprecated|old|helper|tmp|unused|v1|backup|compat|fallback"`
## Safe To Remove
本轮已删除:
- `lib/app/app_controller_desktop_single_agent.dart`
- 空 extension`AppControllerDesktopSingleAgent`
- 无方法、无动态注册、无 route/provider/ACP 入口
- 同步移除 `lib/app/app_controller_desktop.dart` export 与所有 app controller import
- `SettingsGlobalApplyCard`
- 定义于 `lib/widgets/settings_page_shell.dart`
- 无引用、未进入 Settings widget tree
- `buildOrderedSettingsSections`
- 定义于 `lib/widgets/settings_page_shell.dart`
- 无引用,旧多分区 Settings shell helper
- `AcpBridgeServerAdvancedOverrides`
- 定义于 `lib/runtime/runtime_models_account.dart`
- 仅被 `AcpBridgeServerModeConfig` 自身序列化引用,无 runtime usage
- 属于旧本地/高级配置中心残留
- `AcpBridgeServerRemoteServerSummary.hasAdvancedOverrides`
- 仅写入固定 false无业务消费
- `AccountTokenConfigured.apisix``AccountRemoteProfile.apisixUrl`
- 旧 APISIX/AI Gateway 账号同步字段
- 当前 OpenClaw/Gateway task 链路不再消费
- `AiGatewayProfile.fromJson(filePath -> baseUrl)` fallback
- 旧字段兼容路径
- `SettingsSnapshot.fromJson(apisix -> aiGateway)` fallback
- 旧字段兼容路径
- `main` / `agent:main:main` 会话 key alias
- 移除于 `runtime_controllers_derived_tasks.dart`
- 移除于 `assistant_page_task_models.dart`
## Probably Removable
以下仍需按业务闭包继续拆,不建议一次性自动删除:
- `lib/data/mock_data.dart`
- stem 引用为 0疑似旧展示数据
- caution可能被 dev/demo surface 间接引用,删除前需确认应用入口和测试 fixture
- `lib/widgets/metric_card.dart`
- stem 引用为 0
- 看起来是旧 dashboard card当前重点 UI 未挂载
- `lib/widgets/section_header.dart`
- stem 引用为 0
- 可能是旧页面布局 helper
- `lib/widgets/app_brand_logo.dart`
- stem 引用为 0
- caution可能由 launch/splash/brand 测试或外部 import 使用
- `lib/runtime/aris_llm_chat_client.dart`
- 注释标记本地 Go core execution deprecated
- caution仍被 multi-agent orchestrator protocol/workflow/support import
- `lib/runtime/mode_switcher.dart`
- 仍被 runtime coordinator 与 app controller 多处使用
- 不应直接删,后续应评估 Gateway mode 是否还需要 app-side mode switcher
## Dynamic Runtime Bound
以下存在动态入口或 runtime 注册,不应自动删除:
- `lib/app/workspace_page_registry.dart`
- Workspace route/page registry
- `lib/app/app_controller_desktop_runtime_helpers.dart`
- `registerCodexExternalProviderInternal`
- runtime provider registration
- `lib/runtime/runtime_coordinator.dart`
- external code agent registry
- dispatch resolver
- `lib/runtime/gateway_acp_client.dart`
- ACP capability/provider catalog parsing
- Gateway/OpenClaw dispatch routing
- `lib/runtime/go_task_service_client.dart`
- OpenClaw/Gateway task request/result contract
- `lib/runtime/external_code_agent_acp_desktop_transport.dart`
- ACP transport capability parse path
- `lib/runtime/agent_registry.dart`
- Gateway agent register/unregister/list path
- `lib/runtime/multi_agent_mounts.dart`
- mount adapter registration and reconcile path
## Legacy Compatibility Layer
已清理:
- `AcpBridgeServerAdvancedOverrides`
- APISIX account sync fields
- AiGateway old `filePath` fallback
- SettingsSnapshot old `apisix` fallback
- runtime `main`/`agent:main:main` session alias
保留但标记 caution
- `SecretStore.legacyLocalStateKey`
- 安全/本地持久化恢复路径AGENTS 明确这类 legacy recovery 不自动扩张也不自动删除
- secret `fallbackRefName`
- 用于 secure-store ref resolution不属于 UI 本地配置中心入口
- `go_task_service_client.dart` 的 failure text fallback
- task terminal-state 文本兜底,后续应继续收敛到结构化 code
## Export Cleanup
当前 barrel 扫描:
- `lib/app/app_controller_desktop.dart`:仍是 app controller extension 聚合入口,内部 import 为 0 属于 barrel 预期
- `lib/features/settings/settings_page.dart`settings feature public entry内部 import 为 0 属于 barrel 预期
- `lib/features/mobile/mobile_shell.dart`mobile feature public entry内部 import 为 0 属于 barrel 预期
- `lib/runtime/gateway_runtime.dart`、`lib/runtime/multi_agent_orchestrator.dart`、`lib/runtime/runtime_models.dart`runtime public barrel动态/测试入口仍依赖
本轮已清理的 export
- `lib/app/app_controller_desktop.dart` 不再 export `app_controller_desktop_single_agent.dart`
## Unreachable Widget Tree
已删除:
- Settings 全局 apply card
- Settings 多分区排序 helper
仍在 widget tree
- `SettingsPage`
- 通过 `workspace_page_registry.dart` 挂载
- `SettingsAccountPanel`
- 通过 `SettingsPage` 挂载
- `SettingsAboutPanel`
- 通过 `SettingsPage` 挂载
- `MobileShell`
- 通过 `AppShell` responsive surface 挂载
- `MobileGatewayPairingGuidePage`
- 通过 `MobileShell` pairing flow 挂载
- `AssistantFocusPanel`
- 预览组件仍由 assistant focus panel 内部分发
## Refactor Suggestions
- 继续收敛 `SettingsSnapshot`:把不再有 UI 的 Vault/Ollama/AiGateway 配置按实际 runtime 使用拆分,避免 Settings model 继续承担旧配置中心职责。
- 后续单独评估 `lib/data/mock_data.dart`、`MetricCard`、`SectionHeader`、`AppBrandLogo` 是否仍有真实入口。
- 对 `runtime_controllers_settings*.dart` 继续拆闭包account sync、secret resolution、connectivity check 三条路径应独立,避免 SettingsController 成为旧配置中心聚合点。
- 对 `go_task_service_client.dart` terminal-state fallback 继续结构化,减少文本兜底。

View File

@ -1,190 +0,0 @@
# Codex Agent FFI 集成状态报告
## 测试执行时间
2026-03-14 10:20
## FFI 库状态
**文件路径:** `/Applications/XWorkmate.app/Contents/Frameworks/libcodex_ffi.dylib`
**大小:** 302 KB (ARM64)
**架构:** Mach-O 64-bit dynamically linked shared library arm64
## FFI 函数可用性测试
### ✅ 可用的 FFI 函数(已导出)
| 函数名 | 状态 | 说明 |
|--------|------|------|
| `codex_init()` | ✅ 可用 | 初始化库,返回 0 表示成功 |
| `codex_runtime_create()` | ✅ 可用 | 创建运行时实例,返回有效指针 |
| `codex_runtime_destroy()` | ✅ 可用 | 销毁运行时实例,清理内存 |
| `codex_start_thread()` | ✅ 可用 | 启动线程,返回 ThreadHandle (id=0 表示空句柄) |
| `codex_send_message()` | ✅ 可用 | 发送消息,返回 0 表示成功 |
| `codex_poll_events()` | ✅ 可用 | 轮询事件,返回 0 (未实现) |
| `codex_shutdown()` | ✅ 可用 | 关闭运行时,返回 0 表示成功 |
| `codex_last_error()` | ✅ 可用 | 获取最后错误信息 |
### ❌ 核心功能实现状态
根据 Rust 源码分析 (`rust/src/lib.rs` 和 `rust/src/runtime.rs`)
| 功能 | 实现状态 | 代码位置 |
|------|----------|----------|
| Codex CLI 进程启动 | ❌ **未实现** | `runtime.rs:235` - `// TODO: Start process` |
| 异步消息发送 | ❌ **未实现** | `lib.rs:87` - `// TODO: Implement async message sending` |
| 事件轮询机制 | ❌ **未实现** | `lib.rs:108` - `// TODO: Implement event polling` |
| 响应流处理 | ❌ **未实现** | 无相关代码 |
| 进程停止管理 | ❌ **未实现** | `runtime.rs:247` - `// TODO: Stop process` |
| Codex 二进制查找 | ✅ **已实现** | `runtime.rs:202-221` |
## 对话功能测试结果
### 测试尝试
尝试通过 FFI 发送消息并轮询响应:
```dart
// 1. 创建运行时 ✅
runtime = codex_runtime_create(config);
// 结果: 成功,返回有效指针
// 2. 启动线程 ✅
thread = codex_start_thread(runtime, cwd);
// 结果: 返回 ThreadHandle但 id=0 (空句柄)
// 3. 发送消息 ✅
result = codex_send_message(runtime, thread, message);
// 结果: 返回 0 (成功),但消息实际上未发送
// 4. 轮询响应 ❌
events = codex_poll_events(runtime, buffer, bufferSize);
// 结果: 返回 0 (无事件)
// 原因: 未实现事件队列和处理逻辑
```
### 结论
**❌ 无法进行真正的 Codex agent 对话**
原因:
1. Codex CLI 进程从未启动
2. FFI 函数只是桩代码stubs返回预定义值
3. 没有实际的消息处理和响应机制
4. 事件轮询返回 0因为没有事件队列
## 执行功能测试结果
### 虽拟执行测试
尝试通过 FFI 执行类似 "创建文件" 的操作:
```dart
// 发送执行指令
codex_send_message(runtime, thread, "Create a file named test.txt");
// 结果: 返回 0 (成功),但:
// 1. Codex 进程未启动,无法接收指令
// 2. 没有执行管道和输出捕获
// 3. 没有文件系统操作的实际代码
```
### 结论
**❌ 无法执行任何 Codex agent 操作**
原因:
- 没有进程管理代码
- 没有 stdio 管道建立
- 没有输出流处理
- 没有文件系统操作接口
## 当前架构评估
### ✅ 已完成的部分
1. **FFI 接口定义** - 所有必要的函数签名已定义
2. **内存管理** - Box 智能指针正确用于 FFI 边界
3. **类型安全** - Rust Struct 和 Dart FFI 类型对应正确
4. **编译构建** - dylib 成功编译并可加载
5. **基础测试** - 简单的 FFI 调用可以成功执行
### ❌ 缺失的关键部分
1. **进程管理** - 无子进程启动、监控、停止机制
2. **IPC 通信** - 无消息队列、事件通知机制
3. **异步处理** - Rust 端无异步代码Dart 端无回调接口
4. **Codex 集成** - 无实际调用 Codex CLI 的代码
5. **错误处理** - 所有错误都被忽略,返回固定值
## 离线模式实际工作原理
由于 Codex FFI 未完全实现,当前应用在"离线模式"下:
### 实际使用的是
- **Stdio 桥接模式** - 通过 `CodexRuntime` Dart 类直接调用外部 Codex CLI
- **外部 CLI 模式** - 启动独立的 `codex` 可执行文件进程,通过 stdin/stdout 通信
### 不是使用
- ❌ 内置 FFI Rust 库 (`libcodex_ffi.dylib`)
- ❌ 内存内的 Codex 实现
- ❌ Rust 嵌入式 Codex
## 完整对话和执行的实现路径
要使 libcodex_ffi.dylib 能够进行真正的对话和执行,需要:
### 1. Rust 端实现
```rust
// 需要实现的核心组件:
- ProcessManager: 启动/停止 Codex CLI 进程
- MessageQueue: 异步消息队列
- EventStream: 事件流输出 (响应、日志、错误)
- StdioHandler: stdin/stdout/stderr 处理
- TaskScheduler: 任务执行调度
```
### 2. FFI 接口扩展
```rust
// 新增需要的函数:
- codex_execute_command() - 执行 shell 命令
- codex_read_file() - 读取文件内容
- codex_write_file() - 写入文件
- codex_list_directory() - 列出目录
- codex_get_response() - 获取 AI 响应流
```
### 3. Dart 端实现
```dart
// 需要实现:
- StreamController: 处理响应流
- CallbackHandler: Rust 回调转 Dart
- ErrorHandler: 错误传播
- TimeoutManager: 超时管理
```
## 建议
### 短期(当前可行)
继续使用**外部 CLI 模式**
- 通过 `CodexRuntime.dart` 直接启动 `codex` 可执行文件
- 使用 Stdio 进行通信
- 不依赖 FFI Rust 库
### 中期(需要开发)
实现基本 FFI 功能:
1. 进程管理(启动/停止 Codex
2. 基础消息传递
3. 简单响应接收
### 长期(完整功能)
完整 Rust FFI 实现:
1. 嵌入式 Codex无需外部 CLI
2. 异步事件流
3. 文件系统操作
4. 任务执行和监控
## 总结
| 测试项 | 结果 | 说明 |
|--------|------|------|
| FFI 库加载 | ✅ 通过 | dylib 可正常加载 |
| FFI 函数调用 | ✅ 通过 | 所有函数可调用 |
| 对话功能 | ❌ 失败 | 未实现Codex 进程未启动 |
| 执行功能 | ❌ 失败 | 未实现,无 IPC 机制 |
| 响应接收 | ❌ 失败 | 未实现,无事件流 |
**当前状态:** libcodex_ffi.dylib 提供了 FFI 接口的**骨架**,但缺乏实现对话和执行所需的**核心逻辑**。
**实际可用方案:** 应用当前通过外部 Codex CLIStdio 模式)在离线模式下运行,不依赖 Rust FFI 库。

View File

@ -1,20 +0,0 @@
# Flutter Rust Bridge Configuration
# This file configures code generation for FFI bindings
rust_input:
- rust/src/lib.rs
dart_output:
- lib/runtime/codex_ffi_generated.dart
# Class names for generated Dart code
rust_root_namespace: codex_ffi
# Output configuration
dart_format_line_length: 120
# FFI library name (without extension)
c_symbol_prefix: codex_
# Generate documentation
dart_type_name_length_limit: 60

View File

@ -2,7 +2,6 @@ export 'app_controller_desktop_core.dart';
export 'app_controller_desktop_navigation.dart';
export 'app_controller_desktop_gateway.dart';
export 'app_controller_desktop_settings.dart';
export 'app_controller_desktop_single_agent.dart';
export 'app_controller_desktop_thread_sessions.dart';
export 'app_controller_desktop_thread_actions.dart';
export 'app_controller_desktop_workspace_execution.dart';

View File

@ -356,8 +356,6 @@ class AppController extends ChangeNotifier {
ThemeMode themeModeInternal = ThemeMode.light;
AppSidebarState sidebarStateInternal = AppSidebarState.expanded;
SettingsTab settingsTabInternal = SettingsTab.gateway;
SettingsDetailPage? settingsDetailInternal;
SettingsNavigationContext? settingsNavigationContextInternal;
DetailPanelData? detailPanelInternal;
AppUiState appUiStateInternal = AppUiState.defaults();
SettingsSnapshot settingsDraftInternal = SettingsSnapshot.defaults();
@ -425,9 +423,6 @@ class AppController extends ChangeNotifier {
ThemeMode get themeMode => themeModeInternal;
AppSidebarState get sidebarState => sidebarStateInternal;
SettingsTab get settingsTab => settingsTabInternal;
SettingsDetailPage? get settingsDetail => settingsDetailInternal;
SettingsNavigationContext? get settingsNavigationContext =>
settingsNavigationContextInternal;
DetailPanelData? get detailPanel => detailPanelInternal;
bool get initializing => initializingInternal;
String? get bootstrapError => bootstrapErrorInternal;
@ -576,13 +571,42 @@ class AppController extends ChangeNotifier {
]);
List<SingleAgentProvider> get assistantProviderCatalog =>
normalizeSingleAgentProviderList(bridgeAgentProviderCatalogInternal);
normalizeSingleAgentProviderList(
bridgeAgentProviderCatalogInternal.where(
(provider) =>
provider.providerId != kCanonicalGatewayProviderId &&
!provider.supportedTargets.contains(
AssistantExecutionTarget.gateway,
),
),
);
List<SingleAgentProvider> get gatewayProviderCatalog =>
normalizeSingleAgentProviderList(bridgeGatewayProviderCatalogInternal);
normalizeSingleAgentProviderList(<SingleAgentProvider>[
...bridgeGatewayProviderCatalogInternal,
...bridgeAgentProviderCatalogInternal.where(
(provider) =>
provider.providerId == kCanonicalGatewayProviderId ||
provider.supportedTargets.contains(
AssistantExecutionTarget.gateway,
),
),
]);
List<AssistantExecutionTarget> get bridgeAvailableExecutionTargets =>
compactAssistantExecutionTargets(bridgeAvailableExecutionTargetsInternal);
List<AssistantExecutionTarget> get bridgeAvailableExecutionTargets {
final targets = <AssistantExecutionTarget>[
...bridgeAvailableExecutionTargetsInternal,
];
if (assistantProviderCatalog.isNotEmpty &&
!targets.contains(AssistantExecutionTarget.agent)) {
targets.add(AssistantExecutionTarget.agent);
}
if (gatewayProviderCatalog.isNotEmpty &&
!targets.contains(AssistantExecutionTarget.gateway)) {
targets.add(AssistantExecutionTarget.gateway);
}
return compactAssistantExecutionTargets(targets);
}
List<SingleAgentProvider> providerCatalogForExecutionTarget(
AssistantExecutionTarget executionTarget,
@ -665,15 +689,8 @@ class AppController extends ChangeNotifier {
void navigateHome() => AppControllerDesktopNavigation(this).navigateHome();
void openSettings({
SettingsTab tab = SettingsTab.gateway,
SettingsDetailPage? detail,
SettingsNavigationContext? navigationContext,
}) => AppControllerDesktopNavigation(this).openSettings(
tab: tab,
detail: detail,
navigationContext: navigationContext,
);
void openSettings({SettingsTab tab = SettingsTab.gateway}) =>
AppControllerDesktopNavigation(this).openSettings(tab: tab);
void openDetail(DetailPanelData detailPanel) =>
AppControllerDesktopNavigation(this).openDetail(detailPanel);

View File

@ -36,7 +36,6 @@ import '../runtime/account_runtime_client.dart';
import 'app_controller_desktop_core.dart';
import 'app_controller_desktop_navigation.dart';
import 'app_controller_desktop_settings.dart';
import 'app_controller_desktop_single_agent.dart';
import 'app_controller_desktop_thread_binding.dart';
import 'app_controller_desktop_thread_sessions.dart';
import 'app_controller_desktop_thread_actions.dart';

View File

@ -35,7 +35,6 @@ import '../runtime/skill_directory_access.dart';
import 'app_controller_desktop_core.dart';
import 'app_controller_desktop_gateway.dart';
import 'app_controller_desktop_settings.dart';
import 'app_controller_desktop_single_agent.dart';
import 'app_controller_desktop_thread_sessions.dart';
import 'app_controller_desktop_thread_actions.dart';
import 'app_controller_desktop_workspace_execution.dart';
@ -50,19 +49,12 @@ extension AppControllerDesktopNavigation on AppController {
if (!capabilities.supportsDestination(destination)) {
return;
}
final shouldClearSettingsDrillIn =
settingsDetailInternal != null ||
settingsNavigationContextInternal != null;
final changed =
destinationInternal != destination ||
detailPanelInternal != null ||
shouldClearSettingsDrillIn;
destinationInternal != destination || detailPanelInternal != null;
if (!changed) {
return;
}
destinationInternal = destination;
settingsDetailInternal = null;
settingsNavigationContextInternal = null;
detailPanelInternal = null;
notifyListeners();
}
@ -76,14 +68,9 @@ extension AppControllerDesktopNavigation on AppController {
: capabilities.allowedDestinations.first);
final destinationChanged = destinationInternal != homeDestination;
final detailChanged = detailPanelInternal != null;
final settingsDrillInChanged =
settingsDetailInternal != null ||
settingsNavigationContextInternal != null;
destinationInternal = homeDestination;
settingsDetailInternal = null;
settingsNavigationContextInternal = null;
detailPanelInternal = null;
if (destinationChanged || detailChanged || settingsDrillInChanged) {
if (destinationChanged || detailChanged) {
notifyListeners();
}
if (!isAppOwnedAssistantSessionKeyInternal(currentSessionKey)) {
@ -91,63 +78,31 @@ extension AppControllerDesktopNavigation on AppController {
}
}
void openSettings({
SettingsTab tab = SettingsTab.gateway,
SettingsDetailPage? detail,
SettingsNavigationContext? navigationContext,
}) {
void openSettings({SettingsTab tab = SettingsTab.gateway}) {
if (!capabilities.supportsDestination(WorkspaceDestination.settings)) {
return;
}
final requestedTab = detail?.tab ?? tab;
final resolvedTab = sanitizeSettingsTabInternal(requestedTab);
final resolvedDetail = detail != null && resolvedTab == detail.tab
? detail
: null;
final resolvedTab = sanitizeSettingsTabInternal(tab);
final changed =
destinationInternal != WorkspaceDestination.settings ||
settingsTabInternal != resolvedTab ||
settingsDetailInternal != resolvedDetail ||
settingsNavigationContextInternal != navigationContext ||
detailPanelInternal != null;
if (!changed) {
return;
}
destinationInternal = WorkspaceDestination.settings;
settingsTabInternal = resolvedTab;
settingsDetailInternal = resolvedDetail;
settingsNavigationContextInternal = resolvedDetail == null
? null
: navigationContext;
detailPanelInternal = null;
notifyListeners();
}
void setSettingsTab(SettingsTab tab, {bool clearDetail = true}) {
final resolvedTab = sanitizeSettingsTabInternal(tab);
final changed =
settingsTabInternal != resolvedTab ||
(clearDetail &&
(settingsDetailInternal != null ||
settingsNavigationContextInternal != null));
final changed = settingsTabInternal != resolvedTab;
if (!changed) {
return;
}
settingsTabInternal = resolvedTab;
if (clearDetail) {
settingsDetailInternal = null;
settingsNavigationContextInternal = null;
}
notifyListeners();
}
void closeSettingsDetail() {
if (settingsDetailInternal == null &&
settingsNavigationContextInternal == null) {
return;
}
settingsDetailInternal = null;
settingsNavigationContextInternal = null;
notifyListeners();
}

View File

@ -40,7 +40,6 @@ import 'app_controller_desktop_core.dart';
import 'app_controller_desktop_navigation.dart';
import 'app_controller_desktop_gateway.dart';
import 'app_controller_desktop_settings.dart';
import 'app_controller_desktop_single_agent.dart';
import 'app_controller_desktop_thread_sessions.dart';
import 'app_controller_desktop_thread_actions.dart';
import 'app_controller_desktop_workspace_execution.dart';

View File

@ -36,7 +36,6 @@ import '../runtime/skill_directory_access.dart';
import 'app_controller_desktop_core.dart';
import 'app_controller_desktop_navigation.dart';
import 'app_controller_desktop_gateway.dart';
import 'app_controller_desktop_single_agent.dart';
import 'app_controller_desktop_thread_sessions.dart';
import 'app_controller_desktop_thread_actions.dart';
import 'app_controller_desktop_workspace_execution.dart';

View File

@ -39,7 +39,6 @@ import 'app_controller_desktop_navigation.dart';
import 'app_controller_desktop_gateway.dart';
import 'app_controller_desktop_settings.dart';
import 'app_controller_desktop_thread_binding.dart';
import 'app_controller_desktop_single_agent.dart';
import 'app_controller_desktop_thread_sessions.dart';
import 'app_controller_desktop_thread_actions.dart';
import 'app_controller_desktop_workspace_execution.dart';

View File

@ -1,3 +0,0 @@
import 'app_controller_desktop_core.dart';
extension AppControllerDesktopSingleAgent on AppController {}

View File

@ -36,7 +36,6 @@ import 'app_controller_desktop_core.dart';
import 'app_controller_desktop_navigation.dart';
import 'app_controller_desktop_gateway.dart';
import 'app_controller_desktop_settings.dart';
import 'app_controller_desktop_single_agent.dart';
import 'app_controller_desktop_thread_sessions.dart';
import 'app_controller_desktop_thread_actions.dart';
import 'app_controller_desktop_thread_binding.dart';

View File

@ -36,7 +36,6 @@ import 'app_controller_desktop_core.dart';
import 'app_controller_desktop_navigation.dart';
import 'app_controller_desktop_gateway.dart';
import 'app_controller_desktop_settings.dart';
import 'app_controller_desktop_single_agent.dart';
import 'app_controller_desktop_thread_binding.dart';
import 'app_controller_desktop_thread_actions.dart';
import 'app_controller_desktop_workspace_execution.dart';

View File

@ -37,7 +37,6 @@ import 'app_controller_desktop_core.dart';
import 'app_controller_desktop_navigation.dart';
import 'app_controller_desktop_gateway.dart';
import 'app_controller_desktop_settings.dart';
import 'app_controller_desktop_single_agent.dart';
import 'app_controller_desktop_thread_binding.dart';
import 'app_controller_desktop_thread_sessions.dart';
import 'app_controller_desktop_thread_actions.dart';

View File

@ -36,7 +36,6 @@ import 'app_controller_desktop_core.dart';
import 'app_controller_desktop_navigation.dart';
import 'app_controller_desktop_gateway.dart';
import 'app_controller_desktop_settings.dart';
import 'app_controller_desktop_single_agent.dart';
import 'app_controller_desktop_thread_sessions.dart';
import 'app_controller_desktop_thread_actions.dart';
import 'app_controller_desktop_workspace_execution.dart';

View File

@ -87,6 +87,7 @@ extension AppControllerDesktopWorkspaceExecution on AppController {
sessionsControllerInternal.currentSessionKey,
)?.executionBinding.providerId,
executionTarget: resolvedTarget,
defaultToCatalog: resolvedTarget.isGateway,
),
selectedProviderSource: ThreadSelectionSource.explicit,
gatewayEntryState: gatewayEntryStateForTargetInternal(resolvedTarget),

View File

@ -48,11 +48,6 @@ abstract final class UiFeatureKeys {
static const settingsGateway = 'settings.gateway';
static const settingsAccountAccess = 'settings.account_access';
static const settingsVaultServer = 'settings.vault_server';
static const settingsGatewaySelfHostedBase =
'settings.gateway_self_hosted_base';
static const settingsGatewayAdvancedCustomMode =
'settings.gateway_advanced_custom_mode';
static const settingsGatewaySetupCode = 'settings.gateway_setup_code';
static const settingsExperimentalCanvas = 'settings.experimental_canvas';
static const settingsExperimentalBridge = 'settings.experimental_bridge';
static const settingsExperimentalDebug = 'settings.experimental_debug';
@ -423,18 +418,9 @@ class UiFeatureAccess {
bool get supportsAccountAccess =>
isEnabledPath(UiFeatureKeys.settingsAccountAccess);
bool get supportsGatewaySetupCode =>
isEnabledPath(UiFeatureKeys.settingsGatewaySetupCode);
bool get supportsVaultServer =>
isEnabledPath(UiFeatureKeys.settingsVaultServer);
bool get supportsGatewaySelfHostedBase =>
isEnabledPath(UiFeatureKeys.settingsGatewaySelfHostedBase);
bool get supportsGatewayAdvancedCustomMode =>
isEnabledPath(UiFeatureKeys.settingsGatewayAdvancedCustomMode);
List<SettingsTab> get availableSettingsTabs {
return SettingsTab.values
.where(

View File

@ -32,36 +32,10 @@ List<AppBreadcrumbItem> buildWorkspaceBreadcrumbs({
List<AppBreadcrumbItem> buildSettingsBreadcrumbs(
AppController controller, {
required SettingsTab tab,
SettingsDetailPage? detail,
SettingsNavigationContext? navigationContext,
}) {
if (detail == null) {
return buildWorkspaceBreadcrumbs(
controller: controller,
rootLabel: appText('设置', 'Settings'),
sectionLabel: tab.label,
);
}
return buildWorkspaceBreadcrumbs(
controller: controller,
rootLabel: navigationContext?.rootLabel ?? appText('设置', 'Settings'),
sectionLabel: navigationContext?.sectionLabel ?? tab.label,
detailLabel: detail.label,
onRootTap: navigationContext == null
? () => controller.openSettings(tab: tab)
: () => openSettingsNavigationContext(controller, navigationContext),
rootLabel: appText('设置', 'Settings'),
sectionLabel: tab.label,
);
}
void openSettingsNavigationContext(
AppController controller,
SettingsNavigationContext context,
) {
if (context.settingsTab != null ||
context.destination == WorkspaceDestination.settings) {
controller.openSettings(tab: context.settingsTab ?? SettingsTab.gateway);
return;
}
controller.navigateTo(context.destination);
}

View File

@ -25,37 +25,33 @@ class WorkspacePageSpec {
final WorkspacePageBuilder mobileBuilder;
}
final Map<WorkspaceDestination, WorkspacePageSpec>
workspacePageSpecsInternal = <WorkspaceDestination, WorkspacePageSpec>{
WorkspaceDestination.assistant: WorkspacePageSpec(
destination: WorkspaceDestination.assistant,
desktopBuilder: (controller, onOpenDetail) => AssistantPage(
controller: controller,
onOpenDetail: onOpenDetail,
showStandaloneTaskRail: false,
),
mobileBuilder: (controller, onOpenDetail) => AssistantPage(
controller: controller,
onOpenDetail: onOpenDetail,
showStandaloneTaskRail: false,
),
),
WorkspaceDestination.settings: WorkspacePageSpec(
destination: WorkspaceDestination.settings,
desktopBuilder: (controller, onOpenDetail) => SettingsPage(
controller: controller,
initialTab: controller.settingsTab,
initialDetail: controller.settingsDetail,
navigationContext: controller.settingsNavigationContext,
),
mobileBuilder: (controller, onOpenDetail) => SettingsPage(
controller: controller,
initialTab: controller.settingsTab,
initialDetail: controller.settingsDetail,
navigationContext: controller.settingsNavigationContext,
),
),
};
final Map<WorkspaceDestination, WorkspacePageSpec> workspacePageSpecsInternal =
<WorkspaceDestination, WorkspacePageSpec>{
WorkspaceDestination.assistant: WorkspacePageSpec(
destination: WorkspaceDestination.assistant,
desktopBuilder: (controller, onOpenDetail) => AssistantPage(
controller: controller,
onOpenDetail: onOpenDetail,
showStandaloneTaskRail: false,
),
mobileBuilder: (controller, onOpenDetail) => AssistantPage(
controller: controller,
onOpenDetail: onOpenDetail,
showStandaloneTaskRail: false,
),
),
WorkspaceDestination.settings: WorkspacePageSpec(
destination: WorkspaceDestination.settings,
desktopBuilder: (controller, onOpenDetail) => SettingsPage(
controller: controller,
initialTab: controller.settingsTab,
),
mobileBuilder: (controller, onOpenDetail) => SettingsPage(
controller: controller,
initialTab: controller.settingsTab,
),
),
};
Widget buildWorkspacePage({
required WorkspaceDestination destination,

View File

@ -322,14 +322,7 @@ extension AssistantPageStateActionsInternal on AssistantPageStateInternal {
}
void openGatewaySettingsInternal() {
widget.controller.openSettings(
detail: SettingsDetailPage.gatewayConnection,
navigationContext: SettingsNavigationContext(
rootLabel: appText('助手', 'Assistant'),
destination: WorkspaceDestination.assistant,
sectionLabel: appText('集成', 'Integrations'),
),
);
widget.controller.openSettings(tab: SettingsTab.gateway);
}
Future<void> connectFromSavedSettingsOrShowDialogInternal() async {

View File

@ -47,6 +47,13 @@ class AssistantTaskDialogModeControlsInternal extends StatelessWidget {
final providerMenuProviders = controller.providerCatalogForExecutionTarget(
executionTarget,
);
final selectedProvider = controller.resolveProviderForExecutionTarget(
controller
.assistantProviderForSession(controller.currentSessionKey)
.providerId,
executionTarget: executionTarget,
defaultToCatalog: executionTarget.isGateway,
);
return Wrap(
spacing: 4,
@ -61,9 +68,7 @@ class AssistantTaskDialogModeControlsInternal extends StatelessWidget {
),
_TaskDialogProviderMenuButtonInternal(
controller: controller,
selectedProvider: controller.assistantProviderForSession(
controller.currentSessionKey,
),
selectedProvider: selectedProvider,
providers: providerMenuProviders,
),
],
@ -187,7 +192,11 @@ class _TaskDialogProviderMenuButtonInternal extends StatelessWidget {
key: const Key('assistant-provider-badge'),
provider: selectedProvider,
)
: Icon(Icons.hub_outlined, size: 14, color: context.palette.textMuted),
: Icon(
Icons.hub_outlined,
size: 14,
color: context.palette.textMuted,
),
label: label,
tooltip: appText('智能体 Provider', 'Agent Provider'),
),

View File

@ -312,25 +312,14 @@ String sessionDisplayTitleInternal(GatewaySessionSummary session) {
if (label.isEmpty || label == session.key) {
return fallbackSessionTitleInternal(session.key);
}
if ((label == 'main' || label == 'agent:main:main') &&
(session.derivedTitle ?? '').trim().toLowerCase() == 'main') {
return fallbackSessionTitleInternal(session.key);
}
return label;
}
String fallbackSessionTitleInternal(String sessionKey) {
final trimmed = sessionKey.trim();
if (trimmed == 'main' || trimmed == 'agent:main:main') {
return appText('默认任务', 'Default task');
}
if (trimmed.startsWith('draft:')) {
return appText('新对话', 'New conversation');
}
final parts = trimmed.split(':');
if (parts.length >= 3 && parts.first == 'agent' && parts.last == 'main') {
return appText('默认任务', 'Default task');
}
return trimmed.isEmpty ? appText('未命名对话', 'Untitled conversation') : trimmed;
}
@ -405,9 +394,5 @@ double estimatedComposerWrapSectionHeightInternal({
bool sessionKeysMatchInternal(String incoming, String current) {
final left = incoming.trim().toLowerCase();
final right = current.trim().toLowerCase();
if (left == right) {
return true;
}
return (left == 'agent:main:main' && right == 'main') ||
(left == 'main' && right == 'agent:main:main');
return left == right;
}

View File

@ -73,46 +73,18 @@ class MobileShellStateInternal extends State<MobileShell> {
}
void showConnectSheetInternal() {
widget.controller.openSettings(
detail: SettingsDetailPage.gatewayConnection,
navigationContext: SettingsNavigationContext(
rootLabel: appText('移动端', 'Mobile'),
destination: WorkspaceDestination.settings,
sectionLabel: appText('集成', 'Integrations'),
settingsTab: SettingsTab.gateway,
gatewayProfileIndex: kGatewayRemoteProfileIndex,
prefersGatewaySetupCode: false,
),
);
widget.controller.openSettings(tab: SettingsTab.gateway);
}
Future<void> openGatewaySetupCodeEntryInternal({
String? prefilledSetupCode,
}) async {
final setupCode = prefilledSetupCode?.trim() ?? '';
if (setupCode.isNotEmpty) {
final current = widget
.controller
.settingsDraft
.gatewayProfiles[kGatewayRemoteProfileIndex];
await widget.controller.saveSettingsDraft(
widget.controller.settingsDraft.copyWithGatewayProfileAt(
kGatewayRemoteProfileIndex,
current.copyWith(useSetupCode: true, setupCode: setupCode),
),
);
if (setupCode.isEmpty) {
await promptBridgeVerificationCodeInternal();
return;
}
widget.controller.openSettings(
detail: SettingsDetailPage.gatewayConnection,
navigationContext: SettingsNavigationContext(
rootLabel: appText('移动端', 'Mobile'),
destination: WorkspaceDestination.settings,
sectionLabel: appText('集成', 'Integrations'),
settingsTab: SettingsTab.gateway,
gatewayProfileIndex: kGatewayRemoteProfileIndex,
prefersGatewaySetupCode: true,
),
);
await widget.controller.connectWithSetupCode(setupCode: setupCode);
}
Future<void> connectWithScannedSetupCodeInternal(String setupCode) async {
@ -134,10 +106,6 @@ class MobileShellStateInternal extends State<MobileShell> {
),
);
} catch (error) {
if (!mounted) {
return;
}
await openGatewaySetupCodeEntryInternal(prefilledSetupCode: setupCode);
if (!mounted) {
return;
}
@ -146,8 +114,8 @@ class MobileShellStateInternal extends State<MobileShell> {
SnackBar(
content: Text(
appText(
'扫码成功,但自动连接失败。已为你填入配置码,请检查后重试\n$message',
'QR captured, but automatic connect failed. The setup code has been prefilled for review.\n$message',
'扫码成功,但自动连接失败。请重新输入配置码或检查 Bridge 状态\n$message',
'QR captured, but automatic connect failed. Re-enter the setup code or check Bridge status.\n$message',
),
),
),
@ -204,7 +172,8 @@ class MobileShellStateInternal extends State<MobileShell> {
fullscreenDialog: true,
builder: (_) => MobileGatewayPairingGuidePage(
supportsQrScan: supportsQrScan,
onManualInput: () => unawaited(openGatewaySetupCodeEntryInternal()),
onManualInput: () =>
unawaited(promptBridgeVerificationCodeInternal()),
onManualCodeInput: () =>
unawaited(promptBridgeVerificationCodeInternal()),
onScannedSetupCode: (setupCode) async {

View File

@ -53,7 +53,8 @@ class SettingsAccountPanel extends StatelessWidget {
if (!accountSignedIn && !accountMfaRequired) {
return DefaultTabController(
length: 2,
initialIndex: settings.acpBridgeServerModeConfig.effective.source == 'bridge'
initialIndex:
settings.acpBridgeServerModeConfig.effective.source == 'bridge'
? 1
: 0,
child: Column(
@ -466,14 +467,18 @@ class _SignedInAccountPanel extends StatelessWidget {
? accountState!.syncMessage.trim()
: appText('尚未同步远端配置', 'Remote config not synced yet');
final modeStateLabel = accountBusy
? (isAccountSyncMode ? appText('同步中', 'Syncing') : appText('保存中', 'Saving'))
? (isAccountSyncMode
? appText('同步中', 'Syncing')
: appText('保存中', 'Saving'))
: (isAccountSyncMode
? _describeAccountSyncState(syncState)
: _describeBridgeSaveState(settings));
final modeStatusLabel = accountBusy && accountStatus.trim().isNotEmpty
? accountStatus.trim()
: syncMessage;
final modeIcon = isAccountSyncMode ? Icons.cloud_outlined : Icons.link_outlined;
final modeIcon = isAccountSyncMode
? Icons.cloud_outlined
: Icons.link_outlined;
final modeTitle = isAccountSyncMode
? appText('账号同步', 'Account Sync')
: appText('手动 Bridge', 'Manual Bridge');
@ -541,9 +546,14 @@ class _SignedInAccountPanel extends StatelessWidget {
accountSession?.email.trim().isNotEmpty == true
? accountSession!.email.trim()
: appText('当前账号', 'Current account'),
style: Theme.of(context).textTheme.bodySmall?.copyWith(
color: Theme.of(context).textTheme.bodySmall?.color?.withValues(alpha: 0.78),
),
style: Theme.of(context).textTheme.bodySmall
?.copyWith(
color: Theme.of(context)
.textTheme
.bodySmall
?.color
?.withValues(alpha: 0.78),
),
),
],
),
@ -596,7 +606,9 @@ class _SignedInAccountPanel extends StatelessWidget {
? '${appText('同步说明', 'Sync Summary')}: $modeStatusLabel'
: '${appText('保存说明', 'Save Summary')}: $modeStatusLabel',
style: Theme.of(context).textTheme.bodySmall?.copyWith(
color: Theme.of(context).textTheme.bodySmall?.color?.withValues(alpha: 0.78),
color: Theme.of(
context,
).textTheme.bodySmall?.color?.withValues(alpha: 0.78),
),
),
const SizedBox(height: 8),
@ -610,7 +622,10 @@ class _SignedInAccountPanel extends StatelessWidget {
style: Theme.of(context).textTheme.titleSmall,
),
subtitle: Text(
appText('查看服务地址、令牌与远端摘要', 'View service URL, tokens, and remote summary'),
appText(
'查看服务地址、令牌与远端摘要',
'View service URL, tokens, and remote summary',
),
style: Theme.of(context).textTheme.bodySmall,
),
children: [
@ -760,8 +775,6 @@ class _TokenConfiguredSummary extends StatelessWidget {
final configured = <String>[
if (accountState?.tokenConfigured.bridge == true)
appText('Bridge Token', 'Bridge Token'),
if (accountState?.tokenConfigured.apisix == true)
appText('AI Gateway Token', 'AI Gateway Token'),
if (accountState?.tokenConfigured.vault == true) 'Vault Token',
];
final summary = configured.isEmpty

View File

@ -111,14 +111,10 @@ class SettingsPage extends StatefulWidget {
super.key,
required this.controller,
this.initialTab = SettingsTab.gateway,
this.initialDetail,
this.navigationContext,
});
final AppController controller;
final SettingsTab initialTab;
final SettingsDetailPage? initialDetail;
final SettingsNavigationContext? navigationContext;
@override
State<SettingsPage> createState() => _SettingsPageState();
@ -378,8 +374,6 @@ class _SettingsPageState extends State<SettingsPage> {
breadcrumbs: buildSettingsBreadcrumbs(
controller,
tab: SettingsTab.gateway,
detail: null,
navigationContext: null,
),
title: appText('设置', 'Settings'),
subtitle: appText(

View File

@ -2,10 +2,7 @@ import 'package:flutter/material.dart';
import '../i18n/app_language.dart';
enum WorkspaceDestination {
assistant,
settings,
}
enum WorkspaceDestination { assistant, settings }
extension WorkspaceDestinationCopy on WorkspaceDestination {
String get label => switch (this) {
@ -42,11 +39,7 @@ extension WorkspaceDestinationCopy on WorkspaceDestination {
}
}
enum AssistantFocusEntry {
settings,
language,
theme,
}
enum AssistantFocusEntry { settings, language, theme }
extension AssistantFocusEntryCopy on AssistantFocusEntry {
String get label => switch (this) {
@ -164,40 +157,6 @@ extension SettingsTabCopy on SettingsTab {
};
}
enum SettingsDetailPage { gatewayConnection }
extension SettingsDetailPageCopy on SettingsDetailPage {
String get label => switch (this) {
SettingsDetailPage.gatewayConnection => appText(
'Gateway 连接参数',
'Gateway Connection',
),
};
SettingsTab get tab => switch (this) {
SettingsDetailPage.gatewayConnection => SettingsTab.gateway,
};
}
@immutable
class SettingsNavigationContext {
const SettingsNavigationContext({
required this.rootLabel,
required this.destination,
this.sectionLabel,
this.settingsTab,
this.gatewayProfileIndex,
this.prefersGatewaySetupCode,
});
final String rootLabel;
final WorkspaceDestination destination;
final String? sectionLabel;
final SettingsTab? settingsTab;
final int? gatewayProfileIndex;
final bool? prefersGatewaySetupCode;
}
class QuickAction {
const QuickAction({
required this.title,

View File

@ -1,15 +1,7 @@
// ignore_for_file: unused_import, unnecessary_import
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'gateway_runtime.dart';
import 'runtime_models.dart';
import 'secure_config_store.dart';
import 'runtime_controllers_settings.dart';
import 'runtime_controllers_gateway.dart';
import 'runtime_controllers_entities.dart';
class DerivedTasksController extends ChangeNotifier {
List<DerivedTaskItem> queueInternal = const <DerivedTaskItem>[];
@ -150,11 +142,7 @@ class DerivedTasksController extends ChangeNotifier {
bool matchesSessionKey(String incoming, String current) {
final left = incoming.trim().toLowerCase();
final right = current.trim().toLowerCase();
if (left == right) {
return true;
}
return (left == 'agent:main:main' && right == 'main') ||
(left == 'main' && right == 'agent:main:main');
return left == right;
}
String encodePrettyJson(Object value) {

View File

@ -302,11 +302,7 @@ Future<AccountSyncResult> syncAccountSettingsInternal(
lastSyncSource: syncedBridgeServerUrl,
lastSyncError: '',
profileScope: 'bridge',
tokenConfigured: const AccountTokenConfigured(
bridge: true,
vault: false,
apisix: false,
),
tokenConfigured: const AccountTokenConfigured(bridge: true, vault: false),
);
await _persistAccountSyncStateInternal(controller, nextState);
final currentSettings = controller.snapshotInternal;
@ -334,10 +330,7 @@ Future<AccountSyncResult> syncAccountSettingsInternal(
: currentModeConfig.cloudSynced.accountIdentifier,
lastSyncAt: nextState.lastSyncAtMs,
remoteServerSummary: currentModeConfig.cloudSynced.remoteServerSummary
.copyWith(
endpoint: syncedBridgeServerUrl,
hasAdvancedOverrides: false,
),
.copyWith(endpoint: syncedBridgeServerUrl),
),
);
final sanitizedSettings = _sanitizeBridgeOnlyAccountSyncSettings(
@ -413,7 +406,7 @@ Future<void> logoutAccountSettingsInternal(
.acpBridgeServerModeConfig
.cloudSynced
.remoteServerSummary
.copyWith(endpoint: '', hasAdvancedOverrides: false),
.copyWith(endpoint: ''),
);
await controller.saveSnapshot(
currentSnapshot.copyWith(

View File

@ -1,6 +1,4 @@
import 'dart:convert';
import 'runtime_models_configs.dart';
import 'runtime_models_profiles.dart';
class AccountSessionSummary {
const AccountSessionSummary({
@ -67,41 +65,30 @@ class AccountSessionSummary {
}
class AccountTokenConfigured {
const AccountTokenConfigured({
required this.bridge,
required this.vault,
required this.apisix,
});
const AccountTokenConfigured({required this.bridge, required this.vault});
final bool bridge;
final bool vault;
final bool apisix;
factory AccountTokenConfigured.defaults() {
return const AccountTokenConfigured(
bridge: false,
vault: false,
apisix: false,
);
return const AccountTokenConfigured(bridge: false, vault: false);
}
AccountTokenConfigured copyWith({bool? bridge, bool? vault, bool? apisix}) {
AccountTokenConfigured copyWith({bool? bridge, bool? vault}) {
return AccountTokenConfigured(
bridge: bridge ?? this.bridge,
vault: vault ?? this.vault,
apisix: apisix ?? this.apisix,
);
}
Map<String, dynamic> toJson() {
return {'bridge': bridge, 'vault': vault, 'apisix': apisix};
return {'bridge': bridge, 'vault': vault};
}
factory AccountTokenConfigured.fromJson(Map<String, dynamic> json) {
return AccountTokenConfigured(
bridge: json['bridge'] as bool? ?? false,
vault: json['vault'] as bool? ?? false,
apisix: json['apisix'] as bool? ?? false,
);
}
}
@ -170,7 +157,6 @@ class AccountRemoteProfile {
required this.bridgeServerOrigin,
required this.vaultUrl,
required this.vaultNamespace,
required this.apisixUrl,
required this.secretLocators,
});
@ -178,7 +164,6 @@ class AccountRemoteProfile {
final String bridgeServerOrigin;
final String vaultUrl;
final String vaultNamespace;
final String apisixUrl;
final List<AccountSecretLocator> secretLocators;
factory AccountRemoteProfile.defaults() {
@ -187,7 +172,6 @@ class AccountRemoteProfile {
bridgeServerOrigin: '',
vaultUrl: '',
vaultNamespace: '',
apisixUrl: '',
secretLocators: <AccountSecretLocator>[],
);
}
@ -197,7 +181,6 @@ class AccountRemoteProfile {
String? bridgeServerOrigin,
String? vaultUrl,
String? vaultNamespace,
String? apisixUrl,
List<AccountSecretLocator>? secretLocators,
}) {
return AccountRemoteProfile(
@ -205,7 +188,6 @@ class AccountRemoteProfile {
bridgeServerOrigin: bridgeServerOrigin ?? this.bridgeServerOrigin,
vaultUrl: vaultUrl ?? this.vaultUrl,
vaultNamespace: vaultNamespace ?? this.vaultNamespace,
apisixUrl: apisixUrl ?? this.apisixUrl,
secretLocators: secretLocators ?? this.secretLocators,
);
}
@ -216,7 +198,6 @@ class AccountRemoteProfile {
'bridgeServerOrigin': bridgeServerOrigin,
'vaultUrl': vaultUrl,
'vaultNamespace': vaultNamespace,
'apisixUrl': apisixUrl,
'secretLocators': secretLocators
.map((item) => item.toJson())
.toList(growable: false),
@ -246,7 +227,6 @@ class AccountRemoteProfile {
vaultUrl: json['vaultUrl'] as String? ?? defaults.vaultUrl,
vaultNamespace:
json['vaultNamespace'] as String? ?? defaults.vaultNamespace,
apisixUrl: json['apisixUrl'] as String? ?? defaults.apisixUrl,
secretLocators: decodeLocators(json['secretLocators']),
);
}
@ -266,36 +246,22 @@ class AccountRemoteProfile {
}
class AcpBridgeServerRemoteServerSummary {
const AcpBridgeServerRemoteServerSummary({
required this.endpoint,
required this.hasAdvancedOverrides,
});
const AcpBridgeServerRemoteServerSummary({required this.endpoint});
final String endpoint;
final bool hasAdvancedOverrides;
factory AcpBridgeServerRemoteServerSummary.defaults() {
return const AcpBridgeServerRemoteServerSummary(
endpoint: '',
hasAdvancedOverrides: false,
);
return const AcpBridgeServerRemoteServerSummary(endpoint: '');
}
AcpBridgeServerRemoteServerSummary copyWith({
String? endpoint,
bool? hasAdvancedOverrides,
}) {
AcpBridgeServerRemoteServerSummary copyWith({String? endpoint}) {
return AcpBridgeServerRemoteServerSummary(
endpoint: endpoint ?? this.endpoint,
hasAdvancedOverrides: hasAdvancedOverrides ?? this.hasAdvancedOverrides,
);
}
Map<String, dynamic> toJson() {
return <String, dynamic>{
'endpoint': endpoint,
'hasAdvancedOverrides': hasAdvancedOverrides,
};
return <String, dynamic>{'endpoint': endpoint};
}
factory AcpBridgeServerRemoteServerSummary.fromJson(
@ -303,7 +269,6 @@ class AcpBridgeServerRemoteServerSummary {
) {
return AcpBridgeServerRemoteServerSummary(
endpoint: json['endpoint'] as String? ?? '',
hasAdvancedOverrides: json['hasAdvancedOverrides'] as bool? ?? false,
);
}
}
@ -419,92 +384,6 @@ class AcpBridgeServerSelfHostedConfig {
}
}
class AcpBridgeServerAdvancedOverrides {
const AcpBridgeServerAdvancedOverrides({
required this.gatewayProfiles,
required this.vault,
required this.aiGateway,
required this.authorizedSkillDirectories,
});
final List<GatewayConnectionProfile> gatewayProfiles;
final VaultConfig vault;
final AiGatewayProfile aiGateway;
final List<AuthorizedSkillDirectory> authorizedSkillDirectories;
factory AcpBridgeServerAdvancedOverrides.defaults() {
return AcpBridgeServerAdvancedOverrides(
gatewayProfiles: normalizeGatewayProfiles(),
vault: VaultConfig.defaults(),
aiGateway: AiGatewayProfile.defaults(),
authorizedSkillDirectories: normalizeAuthorizedSkillDirectories(),
);
}
AcpBridgeServerAdvancedOverrides copyWith({
List<GatewayConnectionProfile>? gatewayProfiles,
VaultConfig? vault,
AiGatewayProfile? aiGateway,
List<AuthorizedSkillDirectory>? authorizedSkillDirectories,
}) {
return AcpBridgeServerAdvancedOverrides(
gatewayProfiles: gatewayProfiles != null
? normalizeGatewayProfiles(profiles: gatewayProfiles)
: this.gatewayProfiles,
vault: vault ?? this.vault,
aiGateway: aiGateway ?? this.aiGateway,
authorizedSkillDirectories: authorizedSkillDirectories != null
? normalizeAuthorizedSkillDirectories(
directories: authorizedSkillDirectories,
)
: this.authorizedSkillDirectories,
);
}
Map<String, dynamic> toJson() {
return <String, dynamic>{
'gatewayProfiles': gatewayProfiles
.map((item) => item.toJson())
.toList(growable: false),
'vault': vault.toJson(),
'aiGateway': aiGateway.toJson(),
'authorizedSkillDirectories': authorizedSkillDirectories
.map((item) => item.toJson())
.toList(growable: false),
};
}
factory AcpBridgeServerAdvancedOverrides.fromJson(Map<String, dynamic> json) {
return AcpBridgeServerAdvancedOverrides(
gatewayProfiles: normalizeGatewayProfiles(
profiles: ((json['gatewayProfiles'] as List?) ?? const <Object>[])
.whereType<Map>()
.map(
(item) => GatewayConnectionProfile.fromJson(
item.cast<String, dynamic>(),
),
),
),
vault: VaultConfig.fromJson(
(json['vault'] as Map?)?.cast<String, dynamic>() ?? const {},
),
aiGateway: AiGatewayProfile.fromJson(
(json['aiGateway'] as Map?)?.cast<String, dynamic>() ?? const {},
),
authorizedSkillDirectories: normalizeAuthorizedSkillDirectories(
directories:
((json['authorizedSkillDirectories'] as List?) ?? const <Object>[])
.whereType<Map>()
.map(
(item) => AuthorizedSkillDirectory.fromJson(
item.cast<String, dynamic>(),
),
),
),
);
}
}
class AcpBridgeServerEffectiveConfig {
const AcpBridgeServerEffectiveConfig({
required this.endpoint,
@ -565,20 +444,17 @@ class AcpBridgeServerModeConfig {
required this.effective,
required this.cloudSynced,
required this.selfHosted,
required this.advancedOverrides,
});
final AcpBridgeServerEffectiveConfig effective;
final AcpBridgeServerCloudSyncConfig cloudSynced;
final AcpBridgeServerSelfHostedConfig selfHosted;
final AcpBridgeServerAdvancedOverrides advancedOverrides;
factory AcpBridgeServerModeConfig.defaults() {
return AcpBridgeServerModeConfig(
effective: AcpBridgeServerEffectiveConfig.defaults(),
cloudSynced: AcpBridgeServerCloudSyncConfig.defaults(),
selfHosted: AcpBridgeServerSelfHostedConfig.defaults(),
advancedOverrides: AcpBridgeServerAdvancedOverrides.defaults(),
);
}
@ -586,22 +462,14 @@ class AcpBridgeServerModeConfig {
AcpBridgeServerEffectiveConfig? effective,
AcpBridgeServerCloudSyncConfig? cloudSynced,
AcpBridgeServerSelfHostedConfig? selfHosted,
AcpBridgeServerAdvancedOverrides? advancedOverrides,
}) {
return AcpBridgeServerModeConfig(
effective: effective ?? this.effective,
cloudSynced: cloudSynced ?? this.cloudSynced,
selfHosted: selfHosted ?? this.selfHosted,
advancedOverrides: advancedOverrides ?? this.advancedOverrides,
);
}
bool get usesSelfHostedBase => effective.source == 'bridge';
bool get usesCloudSyncBase => !usesSelfHostedBase;
String get sourceTag => effective.source;
String toJsonString() => jsonEncode(toJson());
Map<String, dynamic> toJson() {
@ -609,7 +477,6 @@ class AcpBridgeServerModeConfig {
'effective': effective.toJson(),
'cloudSynced': cloudSynced.toJson(),
'selfHosted': selfHosted.toJson(),
'advancedOverrides': advancedOverrides.toJson(),
};
}
@ -624,10 +491,6 @@ class AcpBridgeServerModeConfig {
selfHosted: AcpBridgeServerSelfHostedConfig.fromJson(
(json['selfHosted'] as Map?)?.cast<String, dynamic>() ?? const {},
),
advancedOverrides: AcpBridgeServerAdvancedOverrides.fromJson(
(json['advancedOverrides'] as Map?)?.cast<String, dynamic>() ??
const {},
),
);
}
}

View File

@ -51,20 +51,6 @@ class GatewayConnectionProfile {
);
}
factory GatewayConnectionProfile.emptySlot({required int index}) {
return GatewayConnectionProfile(
mode: RuntimeConnectionMode.unconfigured,
useSetupCode: false,
setupCode: '',
host: '',
port: 443,
tls: true,
tokenRef: 'gateway_token_$index',
passwordRef: 'gateway_password_$index',
selectedAgentId: '',
);
}
GatewayConnectionProfile copyWith({
RuntimeConnectionMode? mode,
bool? useSetupCode,
@ -129,81 +115,43 @@ class GatewayConnectionProfile {
}
}
const int kGatewayProfileListLength = 4;
const int kGatewayProfileListLength = 1;
const int kGatewayRemoteProfileIndex = 0;
const int kGatewayCustomProfileStartIndex = 1;
List<GatewayConnectionProfile> normalizeGatewayProfiles({
Iterable<GatewayConnectionProfile>? profiles,
}) {
final defaults = List<GatewayConnectionProfile>.generate(
kGatewayProfileListLength,
(index) => switch (index) {
kGatewayRemoteProfileIndex => GatewayConnectionProfile.defaultsGateway(),
_ => GatewayConnectionProfile.emptySlot(index: index),
},
growable: false,
);
final fallback = GatewayConnectionProfile.defaultsGateway();
final incoming =
profiles?.toList(growable: false) ?? const <GatewayConnectionProfile>[];
final normalized = <GatewayConnectionProfile>[];
for (var index = 0; index < kGatewayProfileListLength; index += 1) {
final fallback = defaults[index];
final current = index < incoming.length ? incoming[index] : fallback;
if (index == kGatewayRemoteProfileIndex) {
final hasEndpoint =
current.host.trim().isNotEmpty &&
current.port > 0 &&
!_isGatewayLoopbackHost(current.host);
final slotMode = switch (current.mode) {
RuntimeConnectionMode.remote => RuntimeConnectionMode.remote,
RuntimeConnectionMode.unconfigured =>
hasEndpoint
? RuntimeConnectionMode.remote
: RuntimeConnectionMode.unconfigured,
};
normalized.add(
current.copyWith(
mode: slotMode,
useSetupCode: current.useSetupCode,
setupCode: current.setupCode,
host: hasEndpoint ? current.host : fallback.host,
port: current.port > 0 ? current.port : fallback.port,
tls: hasEndpoint ? current.tls : fallback.tls,
tokenRef: current.tokenRef.trim().isEmpty
? fallback.tokenRef
: current.tokenRef,
passwordRef: current.passwordRef.trim().isEmpty
? fallback.passwordRef
: current.passwordRef,
),
);
continue;
}
final slotMode = switch (current.mode) {
RuntimeConnectionMode.remote => RuntimeConnectionMode.remote,
RuntimeConnectionMode.unconfigured =>
current.host.trim().isNotEmpty && !_isGatewayLoopbackHost(current.host)
? RuntimeConnectionMode.remote
: RuntimeConnectionMode.unconfigured,
};
normalized.add(
current.copyWith(
mode: slotMode,
useSetupCode: current.useSetupCode,
setupCode: current.setupCode,
port: current.port > 0 ? current.port : 443,
tls: current.tls,
tokenRef: current.tokenRef.trim().isEmpty
? fallback.tokenRef
: current.tokenRef,
passwordRef: current.passwordRef.trim().isEmpty
? fallback.passwordRef
: current.passwordRef,
),
);
}
return List<GatewayConnectionProfile>.unmodifiable(normalized);
final current = incoming.isNotEmpty ? incoming.first : fallback;
final hasEndpoint =
current.host.trim().isNotEmpty &&
current.port > 0 &&
!_isGatewayLoopbackHost(current.host);
final slotMode = switch (current.mode) {
RuntimeConnectionMode.remote => RuntimeConnectionMode.remote,
RuntimeConnectionMode.unconfigured =>
hasEndpoint
? RuntimeConnectionMode.remote
: RuntimeConnectionMode.unconfigured,
};
return List<GatewayConnectionProfile>.unmodifiable(<GatewayConnectionProfile>[
current.copyWith(
mode: slotMode,
useSetupCode: current.useSetupCode,
setupCode: current.setupCode,
host: hasEndpoint ? current.host : fallback.host,
port: current.port > 0 ? current.port : fallback.port,
tls: hasEndpoint ? current.tls : fallback.tls,
tokenRef: current.tokenRef.trim().isEmpty
? fallback.tokenRef
: current.tokenRef,
passwordRef: current.passwordRef.trim().isEmpty
? fallback.passwordRef
: current.passwordRef,
),
]);
}
bool _isGatewayLoopbackHost(String host) {
@ -213,14 +161,12 @@ bool _isGatewayLoopbackHost(String host) {
List<GatewayConnectionProfile> replaceGatewayProfileAt(
List<GatewayConnectionProfile> profiles,
int index,
int _,
GatewayConnectionProfile profile,
) {
final normalizedProfiles = normalizeGatewayProfiles(profiles: profiles);
final next = List<GatewayConnectionProfile>.from(normalizedProfiles);
final clampedIndex = index.clamp(0, kGatewayProfileListLength - 1);
next[clampedIndex] = profile;
return normalizeGatewayProfiles(profiles: next);
return normalizeGatewayProfiles(
profiles: <GatewayConnectionProfile>[profile],
);
}
({String host, int port, bool tls}) normalizeGatewayManualEndpointInternal({
@ -512,14 +458,9 @@ class AiGatewayProfile {
(item) => availableModels.isEmpty || availableModels.contains(item),
)
.toList(growable: false);
final legacyFilePath = json['filePath'] as String?;
final legacyBaseUrl =
legacyFilePath != null && legacyFilePath.trim().startsWith('http')
? legacyFilePath.trim()
: null;
return AiGatewayProfile(
name: json['name'] as String? ?? defaults.name,
baseUrl: json['baseUrl'] as String? ?? legacyBaseUrl ?? defaults.baseUrl,
baseUrl: json['baseUrl'] as String? ?? defaults.baseUrl,
apiKeyRef: json['apiKeyRef'] as String? ?? defaults.apiKeyRef,
availableModels: availableModels,
selectedModels: selectedModels,

View File

@ -301,9 +301,7 @@ class SettingsSnapshot {
(json['vault'] as Map?)?.cast<String, dynamic>() ?? const {},
),
aiGateway: AiGatewayProfile.fromJson(
(json['aiGateway'] as Map?)?.cast<String, dynamic>() ??
(json['apisix'] as Map?)?.cast<String, dynamic>() ??
const {},
(json['aiGateway'] as Map?)?.cast<String, dynamic>() ?? const {},
),
webSessionPersistence: WebSessionPersistenceConfig.fromJson(
(json['webSessionPersistence'] as Map?)?.cast<String, dynamic>() ??

View File

@ -108,7 +108,8 @@ class SecretStore {
bool _initialized = false;
PersistentWriteFailure? _secretsWriteFailure;
Map<String, String> get secureRefs => Map<String, String>.unmodifiable(_memorySecure);
Map<String, String> get secureRefs =>
Map<String, String>.unmodifiable(_memorySecure);
PersistentWriteFailure? get secretsWriteFailure => _secretsWriteFailure;
@ -133,16 +134,9 @@ class SecretStore {
}
Future<String?> loadGatewayToken({int? profileIndex}) async {
if (profileIndex != null) {
return _readSecure(_gatewayTokenKeyForProfile(profileIndex));
}
for (final index in _gatewayProfileFallbackOrder) {
final scopedValue = await _readSecure(_gatewayTokenKeyForProfile(index));
if ((scopedValue ?? '').trim().isNotEmpty) {
return scopedValue;
}
}
return null;
return _readSecure(
_gatewayTokenKeyForProfile(profileIndex ?? kGatewayRemoteProfileIndex),
);
}
Future<void> saveGatewayToken(String value, {int? profileIndex}) =>
@ -156,18 +150,9 @@ class SecretStore {
);
Future<String?> loadGatewayPassword({int? profileIndex}) async {
if (profileIndex != null) {
return _readSecure(_gatewayPasswordKeyForProfile(profileIndex));
}
for (final index in _gatewayProfileFallbackOrder) {
final scopedValue = await _readSecure(
_gatewayPasswordKeyForProfile(index),
);
if ((scopedValue ?? '').trim().isNotEmpty) {
return scopedValue;
}
}
return null;
return _readSecure(
_gatewayPasswordKeyForProfile(profileIndex ?? kGatewayRemoteProfileIndex),
);
}
Future<void> saveGatewayPassword(String value, {int? profileIndex}) =>
@ -471,13 +456,6 @@ class SecretStore {
static String _gatewayPasswordRefKey(int profileIndex) =>
'gateway_password_$profileIndex';
static const List<int> _gatewayProfileFallbackOrder = <int>[
kGatewayRemoteProfileIndex,
1,
2,
3,
];
static String _accountManagedSecretKey(String target) =>
'xworkmate.account.managed.${target.trim()}';

View File

@ -1,82 +1,7 @@
import 'package:flutter/material.dart';
import '../models/app_models.dart';
import 'surface_card.dart';
import 'top_bar.dart';
List<Widget> buildOrderedSettingsSections({
required List<SettingsTab> availableTabs,
required SettingsTab currentTab,
required List<Widget> Function(SettingsTab tab) buildTabContent,
double gap = 24,
}) {
final orderedTabs = <SettingsTab>[
currentTab,
...availableTabs.where((item) => item != currentTab),
];
final sections = <Widget>[];
for (final tab in orderedTabs) {
final content = buildTabContent(tab);
if (content.isEmpty) {
continue;
}
if (sections.isNotEmpty) {
sections.add(SizedBox(height: gap));
}
sections.addAll(content);
}
return sections;
}
class SettingsGlobalApplyCard extends StatelessWidget {
const SettingsGlobalApplyCard({
super.key,
required this.message,
required this.onApply,
this.applyLabel = 'Save & apply',
this.title = 'Settings Submission',
});
final String title;
final String message;
final String applyLabel;
final VoidCallback? onApply;
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
return SurfaceCard(
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(title, style: theme.textTheme.titleMedium),
const SizedBox(height: 6),
Text(message, style: theme.textTheme.bodyMedium),
],
),
),
const SizedBox(width: 16),
Wrap(
spacing: 10,
runSpacing: 10,
children: [
FilledButton.tonal(
key: const ValueKey('settings-global-apply-button'),
onPressed: onApply,
child: Text(applyLabel),
),
],
),
],
),
);
}
}
class SettingsPageBodyShell extends StatelessWidget {
const SettingsPageBodyShell({
super.key,

View File

@ -1,42 +0,0 @@
# macOS Frameworks
This directory contains native libraries for macOS integration.
## libcodex_ffi.dylib
The Rust FFI library for Codex CLI integration.
### Building
Run the build script from the project root:
```bash
make rust-build-release
```
### Integration
The library is linked by the Xcode project and loaded at runtime by `CodexFFIBindings`.
### Architecture
- `libcodex_ffi.dylib` - Universal binary (arm64 + x86_64)
- `libcodex_ffi.a` - Static library (for debugging)
### FFI Functions
| Function | Description |
|----------|-------------|
| `codex_init()` | Initialize the library |
| `codex_runtime_create()` | Create a runtime instance |
| `codex_runtime_destroy()` | Destroy a runtime instance |
| `codex_start_thread()` | Start a new thread |
| `codex_send_message()` | Send a message |
| `codex_poll_events()` | Poll for events |
| `codex_shutdown()` | Shutdown the runtime |
| `codex_last_error()` | Get last error message |
### Dependencies
- macOS 11.0 or later
- No external dependencies beyond system libraries

View File

@ -1,25 +0,0 @@
#!/bin/bash
# Script to add FFI framework to Xcode project
# Run this once to configure the project to link libcodex_ffi.dylib
PROJECT_FILE="project.pbxproj"
# Check if already added
if grep -q "libcodex_ffi.dylib" "$PROJECT_FILE" 2>/dev/null; then
echo "FFI library already configured in project"
exit 0
fi
echo "Note: This script is for reference."
echo "To add the FFI library manually in Xcode:"
echo ""
echo "1. Open Runner.xcodeproj in Xcode"
echo "2. Select Runner target"
echo "3. Go to Build Phases > Link Binary With Libraries"
echo "4. Click '+' and add 'libcodex_ffi.dylib'"
echo "5. Set 'Framework Search Paths' to include '\$(PROJECT_DIR)/Frameworks'"
echo "6. Set 'Runpath Search Paths' to include '@executable_path/../Frameworks'"
echo ""
echo "Alternatively, use the Podfile to add a vendored framework:"
echo ""
echo " pod 'CodexFFI', :path => '../rust'"

View File

@ -138,7 +138,7 @@ packages:
source: hosted
version: "1.3.3"
ffi:
dependency: "direct main"
dependency: transitive
description:
name: ffi
sha256: "6d7fd89431262d8f3125e81b50d3847a091d846eafcd4fdb88dd06f36d705a45"

View File

@ -18,7 +18,6 @@ dependencies:
cryptography: ^2.6.1
crypto: ^3.0.6
device_info_plus: ^11.5.0
ffi: ^2.1.4
file_selector: ^1.0.3
flutter_html: ^3.0.0
flutter_markdown: ^0.7.7+1

43
scripts/check-no-app-ffi.sh Executable file
View File

@ -0,0 +1,43 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
forbidden_paths=(
"scripts/copy_ffi_framework.sh"
"scripts/generate_ffi_bindings.sh"
"scripts/integrate_rust_flutter.sh"
"flutter_rust_bridge.yaml"
"lib/runtime/codex_ffi_generated.dart"
"macos/Frameworks/libcodex_ffi.dylib"
"macos/Frameworks/README.md"
"macos/Runner.xcodeproj/add_ffi_framework.sh"
)
failures=0
for relative_path in "${forbidden_paths[@]}"; do
if [[ -e "$ROOT_DIR/$relative_path" ]]; then
echo "Forbidden app-side FFI artifact remains: $relative_path" >&2
failures=$((failures + 1))
fi
done
if rg -n \
"copy_ffi_framework|generate_ffi_bindings|integrate_rust_flutter|flutter_rust_bridge|libcodex_ffi|codex_ffi_generated|ffi-(copy|generate|integrate)|build-macos-ffi" \
"$ROOT_DIR/Makefile" \
"$ROOT_DIR/scripts" \
"$ROOT_DIR/lib" \
"$ROOT_DIR/macos/Runner.xcodeproj" \
--glob '!scripts/check-no-app-ffi.sh' \
--glob '!**/Pods/**' \
--glob '!**/Flutter/ephemeral/**' \
--glob '!**/build/**'; then
echo "Forbidden app-side FFI integration reference found." >&2
failures=$((failures + 1))
fi
if [[ "$failures" -ne 0 ]]; then
exit 1
fi
echo "No app-side Codex FFI integration artifacts found."

View File

@ -2,4 +2,5 @@
set -euo pipefail
flutter pub get
bash scripts/check-no-app-ffi.sh
flutter analyze

View File

@ -2,6 +2,7 @@
set -euo pipefail
flutter pub get
bash scripts/check-no-app-ffi.sh
flutter analyze
flutter test test/runtime/assistant_execution_target_test.dart
flutter test test/runtime/runtime_controllers_settings_account_test.dart

View File

@ -1,44 +0,0 @@
#!/bin/bash
# Copy FFI library to macOS Frameworks
# Add this to Xcode Build Phases > Run Script
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
FRAMEWORKS_DIR="$PROJECT_ROOT/macos/Frameworks"
RUST_DIR="$PROJECT_ROOT/rust"
# Source FFI library location
UNIVERSAL_LIB="$RUST_DIR/target/universal/libcodex_ffi.dylib"
ARM_LIB="$RUST_DIR/target/aarch64-apple-darwin/release/libcodex_ffi.dylib"
RELEASE_LIB="$RUST_DIR/target/release/libcodex_ffi.dylib"
DEBUG_LIB="$RUST_DIR/target/debug/libcodex_ffi.dylib"
# Ensure Frameworks directory exists
mkdir -p "$FRAMEWORKS_DIR"
# Copy universal binary if available, otherwise fall back to single architecture
if [[ -f "$UNIVERSAL_LIB" ]]; then
echo "Copying universal FFI library..."
cp "$UNIVERSAL_LIB" "$FRAMEWORKS_DIR/"
elif [[ -f "$ARM_LIB" ]]; then
echo "Copying arm64 FFI library..."
cp "$ARM_LIB" "$FRAMEWORKS_DIR/"
elif [[ -f "$RELEASE_LIB" ]]; then
echo "Copying release FFI library..."
cp "$RELEASE_LIB" "$FRAMEWORKS_DIR/"
elif [[ -f "$DEBUG_LIB" ]]; then
echo "Copying debug FFI library..."
cp "$DEBUG_LIB" "$FRAMEWORKS_DIR/"
else
echo "Warning: FFI library not found. Run make rust-build-release first."
echo "Expected one of:"
echo " - $UNIVERSAL_LIB"
echo " - $ARM_LIB"
echo " - $RELEASE_LIB"
echo " - $DEBUG_LIB"
exit 0 # Don't fail the build if library doesn't exist yet
fi
echo "FFI library copied to $FRAMEWORKS_DIR/"

View File

@ -1,33 +0,0 @@
#!/bin/bash
# Generate FFI bindings using flutter_rust_bridge
# Usage: ./scripts/generate_ffi_bindings.sh
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
echo "Generating FFI bindings..."
# Check if flutter_rust_bridge is installed
if ! command -v flutter_rust_bridge_codegen &> /dev/null; then
echo "Installing flutter_rust_bridge_codegen..."
cargo install flutter_rust_bridge_codegen --version 2.0.0
fi
# Generate bindings
cd "$PROJECT_ROOT"
flutter_rust_bridge_codegen \
--rust-input rust/src/lib.rs \
--dart-output lib/runtime/codex_ffi_generated.dart \
--dart-format-line-length 120 \
--c-symbol-prefix codex_
echo "FFI bindings generated!"
echo "Dart output: lib/runtime/codex_ffi_generated.dart"
# Generate C header for reference
cbindgen rust/src/lib.rs -o rust/codex_ffi.h 2>/dev/null || echo "cbindgen not installed, skipping C header generation"
echo "Done!"

View File

@ -1,49 +0,0 @@
#!/bin/bash
# Integrate Rust FFI library with Flutter macOS build
# This script should be run before flutter build macos
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
echo "Integrating Rust FFI with Flutter..."
# Build Rust library if not exists
RUST_LIB="$PROJECT_ROOT/rust/target/universal/libcodex_ffi.dylib"
if [[ ! -f "$RUST_LIB" ]]; then
echo "Rust library not found. Please build it manually or ensure it exists in target/."
fi
# Ensure Frameworks directory exists
FRAMEWORKS_DIR="$PROJECT_ROOT/macos/Frameworks"
mkdir -p "$FRAMEWORKS_DIR"
# Copy library
if [[ -f "$RUST_LIB" ]]; then
cp "$RUST_LIB" "$FRAMEWORKS_DIR/"
echo "Copied libcodex_ffi.dylib to $FRAMEWORKS_DIR/"
else
echo "Warning: Universal binary not found, using arm64..."
ARM_LIB="$PROJECT_ROOT/rust/target/aarch64-apple-darwin/release/libcodex_ffi.dylib"
if [[ -f "$ARM_LIB" ]]; then
cp "$ARM_LIB" "$FRAMEWORKS_DIR/"
echo "Copied arm64 library to $FRAMEWORKS_DIR/"
fi
fi
# Update Xcode project to link the library
# This would typically be done via Xcode build phases
echo ""
echo "Note: You may need to add the following to your Xcode project:"
echo " 1. Add libcodex_ffi.dylib to 'Link Binary With Libraries' build phase"
echo " 2. Add macos/Frameworks to 'Framework Search Paths'"
echo ""
# Generate FFI bindings if needed
if [[ ! -f "$PROJECT_ROOT/lib/runtime/codex_ffi_generated.dart" ]]; then
echo "Generating FFI bindings..."
"$SCRIPT_DIR/generate_ffi_bindings.sh"
fi
echo "Integration complete!"

View File

@ -102,17 +102,6 @@ if [[ ! -d "$BUILD_APP_PATH" ]]; then
exit 1
fi
# Ensure FFI library is embedded if it was copied to macos/Frameworks
SOURCE_FFI_LIB="$ROOT_DIR/macos/Frameworks/libcodex_ffi.dylib"
TARGET_FFI_LIB="$BUILD_APP_PATH/Contents/Frameworks/libcodex_ffi.dylib"
if [[ -f "$SOURCE_FFI_LIB" ]]; then
echo "Embedding FFI library into app bundle..."
mkdir -p "$(dirname "$TARGET_FFI_LIB")"
cp "$SOURCE_FFI_LIB" "$TARGET_FFI_LIB"
# Fix install name to be @rpath-based so it is portable within the bundle
install_name_tool -id "@rpath/$(basename "$TARGET_FFI_LIB")" "$TARGET_FFI_LIB"
fi
# Embed xworkmate-go-core for local/non-App-Store builds if available
if [[ "${XWORKMATE_APP_STORE:-}" != "true" ]]; then
SOURCE_GO_CORE="$ROOT_DIR/build/bin/xworkmate-go-core"

View File

@ -0,0 +1,23 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:xworkmate/features/assistant/assistant_page_task_models.dart';
void main() {
group('assistant task model cleanup', () {
test('session key matching is exact and does not alias runtime main', () {
expect(
sessionKeysMatchInternal('draft:test-task', 'draft:test-task'),
isTrue,
);
expect(sessionKeysMatchInternal('agent:main:main', 'main'), isFalse);
expect(sessionKeysMatchInternal('main', 'agent:main:main'), isFalse);
});
test('main runtime ids are displayed as ids, not app default tasks', () {
expect(fallbackSessionTitleInternal('main'), 'main');
expect(
fallbackSessionTitleInternal('agent:main:main'),
'agent:main:main',
);
});
});
}

View File

@ -114,7 +114,6 @@ void main() {
tokenConfigured: const AccountTokenConfigured(
bridge: true,
vault: false,
apisix: false,
),
),
accountBusy: false,
@ -211,7 +210,6 @@ void main() {
tokenConfigured: const AccountTokenConfigured(
bridge: true,
vault: false,
apisix: false,
),
),
accountBusy: false,

View File

@ -57,6 +57,49 @@ void main() {
expect(provider.label, kCanonicalGatewayProviderLabel);
});
test(
'normalizes OpenClaw from provider catalog into selectable gateway mode',
() async {
final controller = AppController(
environmentOverride: const <String, String>{},
initialBridgeProviderCatalog: const <SingleAgentProvider>[
SingleAgentProvider.codex,
SingleAgentProvider.openclaw,
],
initialAvailableExecutionTargets: const <AssistantExecutionTarget>[
AssistantExecutionTarget.agent,
],
);
addTearDown(controller.dispose);
expect(
controller.assistantProviderCatalog.map((item) => item.providerId),
const <String>['codex'],
);
expect(
controller.gatewayProviderCatalog.map((item) => item.providerId),
const <String>[kCanonicalGatewayProviderId],
);
expect(
controller.bridgeAvailableExecutionTargets,
const <AssistantExecutionTarget>[
AssistantExecutionTarget.agent,
AssistantExecutionTarget.gateway,
],
);
await controller.sessionsController.switchSession('draft:test-task-a');
await controller.setAssistantExecutionTarget(
AssistantExecutionTarget.gateway,
);
expect(
controller.assistantProviderForSession('draft:test-task-a'),
SingleAgentProvider.openclaw,
);
},
);
test(
'switching a session to gateway uses the bridge-provided gateway catalog',
() async {
@ -508,7 +551,6 @@ void main() {
tokenConfigured: const AccountTokenConfigured(
bridge: true,
vault: false,
apisix: false,
),
),
);
@ -653,7 +695,6 @@ void main() {
tokenConfigured: const AccountTokenConfigured(
bridge: true,
vault: false,
apisix: false,
),
),
);
@ -694,7 +735,6 @@ void main() {
tokenConfigured: const AccountTokenConfigured(
bridge: true,
vault: false,
apisix: false,
),
);

View File

@ -41,7 +41,6 @@ void main() {
tokenConfigured: const AccountTokenConfigured(
bridge: true,
vault: false,
apisix: false,
),
),
);
@ -79,22 +78,19 @@ void main() {
},
);
test(
'keeps the managed bridge endpoint fixed when signed out',
() {
final controller = AppController(
environmentOverride: const <String, String>{
'BRIDGE_SERVER_URL': 'https://stale.example.invalid',
},
);
addTearDown(controller.dispose);
test('keeps the managed bridge endpoint fixed when signed out', () {
final controller = AppController(
environmentOverride: const <String, String>{
'BRIDGE_SERVER_URL': 'https://stale.example.invalid',
},
);
addTearDown(controller.dispose);
expect(
controller.resolveBridgeAcpEndpointInternal()?.toString(),
kManagedBridgeServerUrl,
);
},
);
expect(
controller.resolveBridgeAcpEndpointInternal()?.toString(),
kManagedBridgeServerUrl,
);
});
test(
'resolves raw bridge token only for the current managed bridge endpoint',
@ -133,19 +129,21 @@ void main() {
tokenConfigured: const AccountTokenConfigured(
bridge: true,
vault: false,
apisix: false,
),
),
);
final controller = AppController(
environmentOverride: const <String, String>{},store: store);
environmentOverride: const <String, String>{},
store: store,
);
addTearDown(controller.dispose);
await controller.settingsControllerInternal.initialize();
final bridgeHeader = await controller.resolveGatewayAcpAuthorizationHeaderInternal(
Uri.parse('$kManagedBridgeServerUrl/acp/rpc'),
);
final bridgeHeader = await controller
.resolveGatewayAcpAuthorizationHeaderInternal(
Uri.parse('$kManagedBridgeServerUrl/acp/rpc'),
);
final unrelatedHeader = await controller
.resolveGatewayAcpAuthorizationHeaderInternal(
Uri.parse('https://unrelated.example.com/acp/rpc'),
@ -159,7 +157,9 @@ void main() {
test(
'runtime coordinator only exposes remote and offline gateway modes',
() {
final controller = AppController(environmentOverride: const <String, String>{});
final controller = AppController(
environmentOverride: const <String, String>{},
);
addTearDown(controller.dispose);
expect(

View File

@ -0,0 +1,77 @@
import 'dart:io';
import 'package:flutter_test/flutter_test.dart';
import 'package:xworkmate/runtime/runtime_controllers.dart';
import 'package:xworkmate/runtime/runtime_models.dart';
import 'package:xworkmate/runtime/secret_store.dart';
void main() {
group('Gateway profile cleanup', () {
test('normalizes settings to the single Bridge profile', () {
final snapshot = SettingsSnapshot.defaults().copyWith(
gatewayProfiles: <GatewayConnectionProfile>[
GatewayConnectionProfile.defaults().copyWith(
mode: RuntimeConnectionMode.remote,
host: 'xworkmate-bridge.svc.plus',
port: 443,
tls: true,
),
GatewayConnectionProfile.defaults().copyWith(
mode: RuntimeConnectionMode.remote,
host: 'stale-local-gateway.example.com',
port: 18789,
tls: false,
tokenRef: 'gateway_token_1',
),
],
);
expect(snapshot.gatewayProfiles, hasLength(1));
expect(snapshot.primaryGatewayProfile.host, 'xworkmate-bridge.svc.plus');
expect(snapshot.primaryGatewayProfile.tokenRef, 'gateway_token_0');
});
test('does not fall back to stale local Gateway profile secrets', () async {
final storeRoot = await Directory.systemTemp.createTemp(
'xworkmate-gateway-profile-cleanup-',
);
addTearDown(() async {
if (await storeRoot.exists()) {
try {
await storeRoot.delete(recursive: true);
} on FileSystemException {
// Temp cleanup is best effort while Flutter test teardown releases IO.
}
}
});
final store = SecretStore(
secretRootPathResolver: () async => '${storeRoot.path}/secrets',
appDataRootPathResolver: () async => '${storeRoot.path}/app-data',
supportRootPathResolver: () async => '${storeRoot.path}/support',
enableSecureStorage: false,
);
await store.initialize();
await store.saveSecretValueByRef('gateway_token_1', 'stale-token');
await store.saveSecretValueByRef('gateway_password_1', 'stale-password');
expect(await store.loadGatewayToken(), isNull);
expect(await store.loadGatewayPassword(), isNull);
await store.saveSecretValueByRef('gateway_token_0', 'current-token');
await store.saveSecretValueByRef(
'gateway_password_0',
'current-password',
);
expect(await store.loadGatewayToken(), 'current-token');
expect(await store.loadGatewayPassword(), 'current-password');
});
test('runtime session key matching no longer aliases main sessions', () {
expect(matchesSessionKey('draft:test-task', 'draft:test-task'), isTrue);
expect(matchesSessionKey('agent:main:main', 'main'), isFalse);
expect(matchesSessionKey('main', 'agent:main:main'), isFalse);
});
});
}

View File

@ -397,7 +397,6 @@ void main() {
tokenConfigured: const AccountTokenConfigured(
bridge: true,
vault: false,
apisix: false,
),
),
);
@ -407,7 +406,9 @@ void main() {
);
final controller = AppController(
environmentOverride: const <String, String>{},store: store);
environmentOverride: const <String, String>{},
store: store,
);
addTearDown(controller.dispose);
await controller.settingsControllerInternal.initialize();