Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/apps/mobile/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,11 @@ UiState or an Intent declared there, and no module above it is visible to them.
`./gradlew compileKotlinIosSimulatorArm64` for iOS. Run iOS pure Swift
infrastructure checks from the repository root with
`(cd src/apps/mobile/ios && ./Testing/run-pure-swift-tests.sh)`.
The isolated native streaming fixture (no remote requests) is covered by
`xcodebuild -project src/apps/mobile/ios/OpenBitFun.xcodeproj -scheme OpenBitFun -configuration Debug -destination 'platform=iOS Simulator,name=iPhone 16 Plus' -parallel-testing-enabled NO -only-testing:OpenBitFunUITests/StreamingPresentationUITests test`.
Run it on one phone and one iPad destination when changing timeline layout,
streaming reveal, keyboard dismissal, or history anchoring. The Debug-only
launch argument `--streaming-regression` opens the same deterministic fixture.
`local.properties` holds
the local SDK path and is not committed.
- The Android app builds from `android/`: `./gradlew :app:assembleDebug` and
Expand Down
14 changes: 10 additions & 4 deletions src/apps/mobile/ios/OpenBitFun.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
A10000000000000000000004 /* SidebarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B10000000000000000000004 /* SidebarView.swift */; };
A10000000000000000000005 /* ConversationHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = B10000000000000000000005 /* ConversationHeader.swift */; };
A10000000000000000000006 /* ChatTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B10000000000000000000006 /* ChatTimelineView.swift */; };
A90000000000000000000004 /* TimelineScrollController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B90000000000000000000004 /* TimelineScrollController.swift */; };
A10000000000000000000007 /* ComposerBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = B10000000000000000000007 /* ComposerBar.swift */; };
A10000000000000000000008 /* MobileShellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B10000000000000000000008 /* MobileShellView.swift */; };
A10000000000000000000010 /* MobileCoreAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B10000000000000000000010 /* MobileCoreAdapter.swift */; };
Expand Down Expand Up @@ -48,6 +49,8 @@
A10000000000000000000040 /* SpeechInputController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B10000000000000000000040; };
A10000000000000000000041 = {isa = PBXBuildFile; fileRef = B10000000000000000000041; };
A91000000000000000000001 = {isa = PBXBuildFile; fileRef = B91000000000000000000001; };
A90000000000000000000002 /* RemoteHomePresentation.swift in Sources */ = {isa = PBXBuildFile; fileRef = B90000000000000000000002 /* RemoteHomePresentation.swift */; };
A90000000000000000000003 /* StreamingTextState.swift in Sources */ = {isa = PBXBuildFile; fileRef = B90000000000000000000003 /* StreamingTextState.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand All @@ -63,6 +66,7 @@
B10000000000000000000004 /* SidebarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidebarView.swift; sourceTree = "<group>"; };
B10000000000000000000005 /* ConversationHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationHeader.swift; sourceTree = "<group>"; };
B10000000000000000000006 /* ChatTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatTimelineView.swift; sourceTree = "<group>"; };
B90000000000000000000004 /* TimelineScrollController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineScrollController.swift; sourceTree = "<group>"; };
B10000000000000000000007 /* ComposerBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposerBar.swift; sourceTree = "<group>"; };
B10000000000000000000008 /* MobileShellView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MobileShellView.swift; sourceTree = "<group>"; };
B10000000000000000000010 /* MobileCoreAdapter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MobileCoreAdapter.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -99,6 +103,8 @@
B10000000000000000000041 = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TaskCompletionNotifier.swift; sourceTree = "<group>"; };
B91000000000000000000001 = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenBitFun/Features/Shell/MiniAppsView.swift; sourceTree = SOURCE_ROOT; };
B91000000000000000000002 = {isa = PBXFileReference; lastKnownFileType = folder; path = OpenBitFun/Resources/MiniApps; sourceTree = SOURCE_ROOT; };
B90000000000000000000002 /* RemoteHomePresentation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoteHomePresentation.swift; sourceTree = "<group>"; };
B90000000000000000000003 /* StreamingTextState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StreamingTextState.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand All @@ -115,7 +121,7 @@
D10000000000000000000013 /* Settings */ = {isa = PBXGroup; children = (B10000000000000000000032 /* AppSettingsView.swift */); path = Settings; sourceTree = "<group>"; };
D10000000000000000000014 /* Pairing */ = {isa = PBXGroup; children = (B10000000000000000000033 /* PairingSheet.swift */); path = Pairing; sourceTree = "<group>"; };
D10000000000000000000015 /* Account */ = {isa = PBXGroup; children = (B10000000000000000000035 /* AccountSettingsView.swift */); path = Account; sourceTree = "<group>"; };
D10000000000000000000004 /* Chat */ = {isa = PBXGroup; children = (B10000000000000000000030 /* ConversationHomeViews.swift */, B10000000000000000000005 /* ConversationHeader.swift */, B10000000000000000000006 /* ChatTimelineView.swift */, B10000000000000000000007 /* ComposerBar.swift */); path = Chat; sourceTree = "<group>"; };
D10000000000000000000004 /* Chat */ = {isa = PBXGroup; children = (B90000000000000000000004 /* TimelineScrollController.swift */, B10000000000000000000030 /* ConversationHomeViews.swift */, B10000000000000000000005 /* ConversationHeader.swift */, B10000000000000000000006 /* ChatTimelineView.swift */, B10000000000000000000007 /* ComposerBar.swift */); path = Chat; sourceTree = "<group>"; };
D10000000000000000000005 /* Shell */ = {isa = PBXGroup; children = (B90000000000000000000001 /* StartupBrandReveal.swift */, B10000000000000000000003 /* OpenBitFunTheme.swift */, B10000000000000000000004 /* SidebarView.swift */, B10000000000000000000008 /* MobileShellView.swift */, B10000000000000000000019 /* SessionActionComponents.swift */, B10000000000000000000020 /* RemoteCreateSessionView.swift */, B10000000000000000000021 /* RemoteFilePreviewView.swift */, B10000000000000000000022 /* RemoteSettingsViews.swift */); path = Shell; sourceTree = "<group>"; };
D10000000000000000000011 /* Resources */ = {isa = PBXGroup; children = (B10000000000000000000016 /* Localizable.xcstrings */); path = Resources; sourceTree = "<group>"; };
D10000000000000000000016 /* Presentation */ = {isa = PBXGroup; children = (D10000000000000000000018 /* Models */); path = Presentation; sourceTree = "<group>"; };
Expand All @@ -124,7 +130,7 @@
D10000000000000000000009 /* Products */ = {isa = PBXGroup; children = (B10000000000000000000000 /* OpenBitFun.app */, B20000000000000000000000 /* OpenBitFunUITests.xctest */); name = Products; sourceTree = "<group>"; };
D20000000000000000000001 /* OpenBitFunUITests */ = {isa = PBXGroup; children = (B20000000000000000000001 /* RemoteCodeSessionSendUITests.swift */); path = OpenBitFunUITests; sourceTree = "<group>"; };
D10000000000000000000010 /* DesignSystem */ = {isa = PBXGroup; children = (B10000000000000000000013 /* GeneratedMobileDesignTokens.swift */, B10000000000000000000014 /* GeneratedMobilePreviewScenarios.swift */, B10000000000000000000015 /* MobileDesignGallery.swift */, B10000000000000000000018 /* AdaptiveModalComponents.swift */); path = DesignSystem; sourceTree = "<group>"; };
D10000000000000000000008 /* Infrastructure */ = {isa = PBXGroup; children = (B10000000000000000000002 /* MobileAppModel.swift */, B10000000000000000000010 /* MobileCoreAdapter.swift */, B10000000000000000000017 /* MobileLocalization.swift */, B10000000000000000000024 /* MobileAppModel+FilePreview.swift */, B10000000000000000000025 /* MobileAppModel+Account.swift */, B10000000000000000000026 /* MobileAppModel+RemoteSession.swift */, B10000000000000000000027 /* MobileAppModel+GeneralChat.swift */, B10000000000000000000028 /* RemoteAuthorityGate.swift */, B10000000000000000000029 /* AccountFailureCopy.swift */, D10000000000000000000017 /* Platform */); path = Infrastructure; sourceTree = "<group>"; };
D10000000000000000000008 /* Infrastructure */ = {isa = PBXGroup; children = (B90000000000000000000003 /* StreamingTextState.swift */, B90000000000000000000002, B10000000000000000000002 /* MobileAppModel.swift */, B10000000000000000000010 /* MobileCoreAdapter.swift */, B10000000000000000000017 /* MobileLocalization.swift */, B10000000000000000000024 /* MobileAppModel+FilePreview.swift */, B10000000000000000000025 /* MobileAppModel+Account.swift */, B10000000000000000000026 /* MobileAppModel+RemoteSession.swift */, B10000000000000000000027 /* MobileAppModel+GeneralChat.swift */, B10000000000000000000028 /* RemoteAuthorityGate.swift */, B10000000000000000000029 /* AccountFailureCopy.swift */, D10000000000000000000017 /* Platform */); path = Infrastructure; sourceTree = "<group>"; };
/* End PBXGroup section */

/* Begin PBXNativeTarget section */
Expand All @@ -140,7 +146,7 @@
C91000000000000000000001 = {isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = (); inputPaths = (); outputPaths = ("$(TARGET_BUILD_DIR)/$(UNLOCALIZED_RESOURCES_FOLDER_PATH)/MiniApps"); alwaysOutOfDate = 1; runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "export PATH=\"/opt/homebrew/bin:/usr/local/bin:$PATH\"\nnode \"$SRCROOT/../miniapps/generate.cjs\" ios \"$TARGET_BUILD_DIR/$UNLOCALIZED_RESOURCES_FOLDER_PATH/MiniApps\"\n"; };
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
C10000000000000000000002 /* Sources */ = {isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = (A91000000000000000000001, A90000000000000000000001, A10000000000000000000041, A10000000000000000000040, A10000000000000000000001, A10000000000000000000002, A10000000000000000000003, A10000000000000000000004, A10000000000000000000005, A10000000000000000000006, A10000000000000000000007, A10000000000000000000008, A10000000000000000000010, A10000000000000000000013, A10000000000000000000014, A10000000000000000000015, A10000000000000000000017, A10000000000000000000018, A10000000000000000000019, A10000000000000000000020, A10000000000000000000021, A10000000000000000000022, A10000000000000000000024, A10000000000000000000025, A10000000000000000000026, A10000000000000000000027, A10000000000000000000028, A10000000000000000000029, A10000000000000000000030, A10000000000000000000031, A10000000000000000000032, A10000000000000000000033, A10000000000000000000034, A10000000000000000000035, A10000000000000000000036, A10000000000000000000037, A10000000000000000000038); runOnlyForDeploymentPostprocessing = 0; };
C10000000000000000000002 /* Sources */ = {isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = (A91000000000000000000001, A90000000000000000000003, A90000000000000000000004, A90000000000000000000002, A90000000000000000000001, A10000000000000000000041, A10000000000000000000040, A10000000000000000000001, A10000000000000000000002, A10000000000000000000003, A10000000000000000000004, A10000000000000000000005, A10000000000000000000006, A10000000000000000000007, A10000000000000000000008, A10000000000000000000010, A10000000000000000000013, A10000000000000000000014, A10000000000000000000015, A10000000000000000000017, A10000000000000000000018, A10000000000000000000019, A10000000000000000000020, A10000000000000000000021, A10000000000000000000022, A10000000000000000000024, A10000000000000000000025, A10000000000000000000026, A10000000000000000000027, A10000000000000000000028, A10000000000000000000029, A10000000000000000000030, A10000000000000000000031, A10000000000000000000032, A10000000000000000000033, A10000000000000000000034, A10000000000000000000035, A10000000000000000000036, A10000000000000000000037, A10000000000000000000038); runOnlyForDeploymentPostprocessing = 0; };
C20000000000000000000002 /* Sources */ = {isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = (A20000000000000000000001 /* RemoteCodeSessionSendUITests.swift in Sources */); runOnlyForDeploymentPostprocessing = 0; };
/* End PBXSourcesBuildPhase section */

Expand All @@ -156,7 +162,7 @@
/* Begin XCBuildConfiguration section */
F10000000000000000000003 /* Debug */ = {isa = XCBuildConfiguration; buildSettings = {ALWAYS_SEARCH_USER_PATHS = NO; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; DEVELOPMENT_TEAM = ""; FRAMEWORK_SEARCH_PATHS = ( "$(SRCROOT)/../shared/core-feature/build/XCFrameworks/debug" ); INFOPLIST_FILE = OpenBitFun/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 16.0; PRODUCT_BUNDLE_IDENTIFIER = com.openbitfun.mobile.ios; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; };
F10000000000000000000004 /* Release */ = {isa = XCBuildConfiguration; buildSettings = {ALWAYS_SEARCH_USER_PATHS = NO; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; DEVELOPMENT_TEAM = ""; FRAMEWORK_SEARCH_PATHS = ( "$(SRCROOT)/../shared/core-feature/build/XCFrameworks/debug" ); INFOPLIST_FILE = OpenBitFun/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 16.0; PRODUCT_BUNDLE_IDENTIFIER = com.openbitfun.mobile.ios; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; };
F10000000000000000000005 /* Target Debug */ = {isa = XCBuildConfiguration; buildSettings = {SDKROOT = iphoneos; }; name = Debug; };
F10000000000000000000005 /* Target Debug */ = {isa = XCBuildConfiguration; buildSettings = { SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) DEBUG";SDKROOT = iphoneos; }; name = Debug; };
F10000000000000000000006 /* Target Release */ = {isa = XCBuildConfiguration; buildSettings = {SDKROOT = iphoneos; }; name = Release; };
F20000000000000000000002 /* UI Test Debug */ = {isa = XCBuildConfiguration; buildSettings = {CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = ""; GENERATE_INFOPLIST_FILE = YES; IPHONEOS_DEPLOYMENT_TARGET = 16.0; PRODUCT_BUNDLE_IDENTIFIER = com.openbitfun.mobile.ios.ui-tests; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; TEST_TARGET_NAME = OpenBitFun; }; name = Debug; };
F20000000000000000000003 /* UI Test Release */ = {isa = XCBuildConfiguration; buildSettings = {CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = ""; GENERATE_INFOPLIST_FILE = YES; IPHONEOS_DEPLOYMENT_TARGET = 16.0; PRODUCT_BUNDLE_IDENTIFIER = com.openbitfun.mobile.ios.ui-tests; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; TEST_TARGET_NAME = OpenBitFun; }; name = Release; };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@ import Foundation

@MainActor
enum MobileLaunchConfiguration {
static var streamingRegressionPreview: Bool {
#if DEBUG
ProcessInfo.processInfo.arguments.contains("--streaming-regression")
#else
false
#endif
}

static var pairingAccountPreview: Bool { ProcessInfo.processInfo.arguments.contains("--pairing-account") }
static var pairingManualPreview: Bool { ProcessInfo.processInfo.arguments.contains("--pairing-manual") }
static func makeModel() -> MobileAppModel {
Expand All @@ -13,7 +21,7 @@ enum MobileLaunchConfiguration {
ChatMessage(id: UUID(), role: .user, text: "你好"),
ChatMessage(id: UUID(), role: .assistant, text: "这是 OpenBitFun 的移动端会话界面。你可以从手机连接桌面端,查看工作区、会话和 Agent 的执行状态。")
],
connectCore: !ProcessInfo.processInfo.arguments.contains("--harness-preview") && designPreviewScenario() == nil
connectCore: !streamingRegressionPreview && !ProcessInfo.processInfo.arguments.contains("--harness-preview") && designPreviewScenario() == nil
)
return configure(model)
}
Expand Down
6 changes: 5 additions & 1 deletion src/apps/mobile/ios/OpenBitFun/App/OpenBitFunApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@ struct OpenBitFunApp: App {

var body: some Scene {
WindowGroup {
if let scenario = designPreviewScenario {
if MobileLaunchConfiguration.streamingRegressionPreview {
#if DEBUG
StreamingRegressionView()
#endif
} else if let scenario = designPreviewScenario {
MobileDesignGallery(scenario: scenario)
.preferredColorScheme(scenario.appearance == "dark" ? .dark : .light)
} else {
Expand Down
Loading