-
Notifications
You must be signed in to change notification settings - Fork 2
Mobile files tab + CTO pipeline + multi-service fixes #103
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,67 +1,71 @@ | ||
| # Architecture | ||
|
|
||
| Architectural decisions, patterns discovered, and design principles. | ||
| Architectural decisions, patterns discovered, and conventions. | ||
|
|
||
| **What belongs here:** Architectural patterns, data flow, component organization, design decisions. | ||
| **What belongs here:** Architectural patterns, component relationships, design decisions. | ||
|
|
||
| --- | ||
|
|
||
| ## iOS App Architecture | ||
| ## iOS App Structure | ||
|
|
||
| ### Pattern: MVVM-like with Shared Service | ||
| - `SyncService` is the shared `@MainActor ObservableObject` injected via `.environmentObject()` | ||
| - Views own local `@State` for UI concerns | ||
| - Views call into `SyncService` for remote operations and data fetching | ||
| - Data flow: `SyncService` → `DatabaseService` (SQLite) → `localStateRevision` increment → SwiftUI reactivity via `.task(id: syncService.localStateRevision)` | ||
|
|
||
| ### File Structure | ||
| ``` | ||
| ADE/ | ||
| apps/ios/ADE/ | ||
| ├── App/ | ||
| │ ├── ADEApp.swift # App entry point, UIKit theme config | ||
| │ └── ContentView.swift # Root TabView, Settings tab, design system components | ||
| ├── Views/ | ||
| │ ├── LanesTabView.swift # ~3,706 lines - complete | ||
| │ ├── FilesTabView.swift # ~500 lines - baseline | ||
| │ ├── WorkTabView.swift # ~300 lines - baseline | ||
| │ └── PRsTabView.swift # ~500 lines - baseline | ||
| │ ├── ADEApp.swift # @main entry, scene setup | ||
| │ └── ContentView.swift # TabView with 5 tabs: Lanes, Files, Work, PRs, Settings | ||
| ├── Models/ | ||
| │ └── RemoteModels.swift # ~700 lines - all domain models | ||
| │ └── RemoteModels.swift # All data models for WebSocket communication | ||
| ├── Services/ | ||
| │ ├── Database.swift # ~1,949 lines - SQLite + cr-sqlite sync | ||
| │ ├── KeychainService.swift # ~50 lines - token persistence | ||
| │ └── SyncService.swift # ~1,781 lines - WebSocket + Bonjour + RPC | ||
| └── Resources/ | ||
| └── DatabaseBootstrap.sql # ~2,260 lines - full schema | ||
| │ ├── SyncService.swift # WebSocket client, all API calls to desktop | ||
| │ ├── Database.swift # CRSQLite local database | ||
| │ └── KeychainService.swift # Secure credential storage | ||
| ├── Views/ | ||
| │ ├── Components/ | ||
| │ │ ├── ADEDesignSystem.swift # Glass morphism, semantic colors, motion system | ||
| │ │ └── FilesCodeSupport.swift # Syntax highlighting (13 languages), language detection | ||
| │ ├── Files/ | ||
| │ │ ├── FilesTabView.swift # Root tab: workspace picker, navigation shell | ||
| │ │ ├── FileTreeView.swift # Directory screen, tree rows, breadcrumbs | ||
| │ │ ├── FileTreeViewModel.swift # Tree state, expand/collapse, child loading | ||
| │ │ ├── FileOperationsHelper.swift # Shared types, path helpers, validation | ||
| │ │ ├── FileSearchView.swift # Search sheet UI, result rows | ||
| │ │ ├── FileSearchViewModel.swift # Debounced quick-open and text search | ||
| │ │ ├── FileViewerView.swift # File editor/viewer screen | ||
| │ │ ├── FileViewerViewModel.swift # Load, save, diff, find/replace state | ||
| │ │ ├── FileViewerChromeViews.swift # Header, mode control, info sheet | ||
| │ │ ├── FileViewerCodeEditorView.swift # UITextView code editor with gutter | ||
| │ │ ├── FileViewerHelpers.swift # Pure functions: line numbers, find/replace | ||
| │ │ └── FileViewerRenderingViews.swift # Binary preview, syntax view, diff, image | ||
| │ ├── LanesTabView.swift | ||
| │ ├── PRsTabView.swift | ||
| │ └── WorkTabView.swift | ||
| ├── Resources/ | ||
| │ └── DatabaseBootstrap.sql | ||
| ├── Assets.xcassets | ||
| └── Info.plist | ||
| ``` | ||
|
|
||
| ### Database | ||
| - Direct SQLite3 C API (no ORM) | ||
| - cr-sqlite change tracking with custom triggers (insert/update/delete) | ||
| - Bidirectional changeset sync via WebSocket | ||
| - Site ID management (persistent 128-bit random) | ||
| - Full bootstrap SQL schema (~2,260 lines) mirroring desktop | ||
| ## Communication Architecture | ||
|
|
||
| The iOS app communicates with the desktop over WebSocket using a typed envelope protocol: | ||
|
|
||
| 1. **file_request / file_response** — File operations (listTree, readFile, writeText, createFile, createDirectory, rename, deletePath, quickOpen, searchText) | ||
| 2. **command / command_ack / command_result** — Git operations and atomic writes | ||
|
|
||
| All API calls go through `SyncService.swift` methods. Workers must NOT create new API calls — only use existing methods. | ||
|
|
||
| ### Networking | ||
| - Raw `URLSessionWebSocketTask` — no third-party dependencies | ||
| - JSON envelopes with optional gzip compression (>4KB) | ||
| - Heartbeat ping/pong protocol | ||
| - Auto-reconnect with exponential backoff | ||
| - Bonjour (`NetServiceBrowser`) for LAN discovery | ||
| - Connection-scoped async work in `SyncService` must be tied to the active socket/session: store long-lived tasks so `disconnect()` and host switching can cancel them, and ignore stale send/receive callbacks unless they still belong to the current `socket` | ||
| ## Key Data Models (RemoteModels.swift) | ||
|
|
||
| ### Command Routing | ||
| - State-only operations: write locally → cr-sqlite syncs to host | ||
| - Execution operations: send command via WebSocket → host executes → state syncs back | ||
| - Offline command queue: persisted to UserDefaults, flushed on reconnect | ||
| - `FileTreeNode` — { name, path, type, hasChildren, children, changeStatus, size } | ||
| - `SyncFileBlob` — { path, size, mimeType, encoding, isBinary, content, languageId } | ||
| - `FilesWorkspace` — { id, kind, laneId, name, rootPath, isReadOnlyByDefault } | ||
| - `FilesQuickOpenItem` — { path, score } | ||
| - `FilesSearchTextMatch` — { path, line, column, preview } | ||
|
|
||
| ### Key Model Types (RemoteModels.swift) | ||
| - `RemoteLane`, `RemoteLaneDetail`, `LaneStateSnapshot` | ||
| - `RemoteTerminalSession`, `SessionHistoryEntry` | ||
| - `PullRequestRow`, `PullRequestSnapshot`, `PRDetailPayload` | ||
| - `RemoteFileNode`, `RemoteSearchResult` | ||
| - `ChatMessage`, `ToolCallResult` | ||
| ## Design System (ADEDesignSystem.swift) | ||
|
|
||
| ### Adding New Swift Files | ||
| New .swift files MUST be added to the Xcode project by editing `ADE.xcodeproj/project.pbxproj`. | ||
| Both `PBXFileReference` and `PBXSourcesBuildPhase` sections need entries. | ||
| - iOS 26 liquid glass effects via `.glassEffect()` modifiers | ||
| - Semantic color tokens: `adeAccent`, `adeSecondaryText`, `adeBackground`, etc. | ||
| - Motion system with spring animations | ||
| - Glass card component for grouped content | ||
| - Workers should use these tokens, not hard-coded colors |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,7 @@ | ||
| commands: | ||
| build: cd apps/ios && xcodebuild -project ADE.xcodeproj -scheme ADE -destination 'platform=iOS Simulator,id=2107A402-C2A7-4323-AF26-74A0AC406C44' -derivedDataPath /tmp/ade-build build | ||
| test: cd apps/ios && xcodebuild -project ADE.xcodeproj -scheme ADE -destination 'platform=iOS Simulator,id=2107A402-C2A7-4323-AF26-74A0AC406C44' -derivedDataPath /tmp/ade-build test | ||
| typecheck: cd apps/ios && xcodebuild -project ADE.xcodeproj -scheme ADE -destination 'platform=iOS Simulator,id=2107A402-C2A7-4323-AF26-74A0AC406C44' -derivedDataPath /tmp/ade-build build | ||
| lint: cd apps/ios && xcodebuild -project ADE.xcodeproj -scheme ADE -destination 'platform=iOS Simulator,id=2107A402-C2A7-4323-AF26-74A0AC406C44' -derivedDataPath /tmp/ade-build analyze | ||
| build: xcodebuild build -project apps/ios/ADE.xcodeproj -scheme ADE -destination 'platform=iOS Simulator,name=iPhone 17 Pro Max' -configuration Debug CODE_SIGNING_ALLOWED=NO 2>&1 | tail -5 | ||
| test: xcodebuild test -project apps/ios/ADE.xcodeproj -scheme ADE -destination 'platform=iOS Simulator,name=iPhone 17 Pro Max' -configuration Debug CODE_SIGNING_ALLOWED=NO 2>&1 | tail -40 | ||
| build_full: xcodebuild build -project apps/ios/ADE.xcodeproj -scheme ADE -destination 'platform=iOS Simulator,name=iPhone 17 Pro Max' -configuration Debug CODE_SIGNING_ALLOWED=NO | ||
| test_full: xcodebuild test -project apps/ios/ADE.xcodeproj -scheme ADE -destination 'platform=iOS Simulator,name=iPhone 17 Pro Max' -configuration Debug CODE_SIGNING_ALLOWED=NO | ||
|
Comment on lines
+2
to
+5
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
# Verify available destinations for this scheme on the runner.
xcodebuild -project apps/ios/ADE.xcodeproj -scheme ADE -showdestinations | sed -n '1,220p'
# Verify whether the hard-coded name exists.
xcodebuild -project apps/ios/ADE.xcodeproj -scheme ADE -showdestinations | rg -n "iPhone 17 Pro Max" || trueRepository: arul28/ADE Length of output: 104 🏁 Script executed: # Check if the services.yaml file exists and examine its content
find . -name "services.yaml" -o -name "synthesis.json" | head -20Repository: arul28/ADE Length of output: 188 🏁 Script executed: # If services.yaml exists, read it
if [ -f ".factory/services.yaml" ]; then
echo "=== .factory/services.yaml ==="
cat -n ".factory/services.yaml"
else
echo ".factory/services.yaml not found"
fiRepository: arul28/ADE Length of output: 898 🏁 Script executed: # Check for synthesis.json file
if [ -f ".factory/validation/foundation/scrutiny/synthesis.json" ]; then
echo "=== .factory/validation/foundation/scrutiny/synthesis.json ==="
cat -n ".factory/validation/foundation/scrutiny/synthesis.json" | head -80
else
echo "synthesis.json not found"
fiRepository: arul28/ADE Length of output: 2277 Avoid hard-coding a simulator name that may not exist on CI images. Lines 2–5 hard-code 💡 Proposed fix- build: xcodebuild build -project apps/ios/ADE.xcodeproj -scheme ADE -destination 'platform=iOS Simulator,name=iPhone 17 Pro Max' -configuration Debug CODE_SIGNING_ALLOWED=NO 2>&1 | tail -5
- test: xcodebuild test -project apps/ios/ADE.xcodeproj -scheme ADE -destination 'platform=iOS Simulator,name=iPhone 17 Pro Max' -configuration Debug CODE_SIGNING_ALLOWED=NO 2>&1 | tail -40
- build_full: xcodebuild build -project apps/ios/ADE.xcodeproj -scheme ADE -destination 'platform=iOS Simulator,name=iPhone 17 Pro Max' -configuration Debug CODE_SIGNING_ALLOWED=NO
- test_full: xcodebuild test -project apps/ios/ADE.xcodeproj -scheme ADE -destination 'platform=iOS Simulator,name=iPhone 17 Pro Max' -configuration Debug CODE_SIGNING_ALLOWED=NO
+ build: xcodebuild build -project apps/ios/ADE.xcodeproj -scheme ADE -destination "${IOS_DESTINATION:-platform=iOS Simulator}" -configuration Debug CODE_SIGNING_ALLOWED=NO 2>&1 | tail -5
+ test: xcodebuild test -project apps/ios/ADE.xcodeproj -scheme ADE -destination "${IOS_DESTINATION:-platform=iOS Simulator}" -configuration Debug CODE_SIGNING_ALLOWED=NO 2>&1 | tail -40
+ build_full: xcodebuild build -project apps/ios/ADE.xcodeproj -scheme ADE -destination "${IOS_DESTINATION:-platform=iOS Simulator}" -configuration Debug CODE_SIGNING_ALLOWED=NO
+ test_full: xcodebuild test -project apps/ios/ADE.xcodeproj -scheme ADE -destination "${IOS_DESTINATION:-platform=iOS Simulator}" -configuration Debug CODE_SIGNING_ALLOWED=NO🤖 Prompt for AI Agents |
||
|
|
||
| services: {} | ||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -18,6 +18,7 @@ __pycache__/ | |||||
| *.db | ||||||
|
|
||||||
| # Build outputs | ||||||
| build/ | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Scope On Line 21, Proposed fix- build/
+ /build/📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||
| /apps/mcp-server/dist/ | ||||||
| /apps/desktop/release/ | ||||||
| /apps/desktop/dist/ | ||||||
|
|
||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: arul28/ADE
Length of output: 362
🏁 Script executed:
Repository: arul28/ADE
Length of output: 36
🏁 Script executed:
Repository: arul28/ADE
Length of output: 746
🏁 Script executed:
Repository: arul28/ADE
Length of output: 867
🏁 Script executed:
Repository: arul28/ADE
Length of output: 36
🏁 Script executed:
Repository: arul28/ADE
Length of output: 63
🏁 Script executed:
cat -n .factory/library/architecture.md | head -100Repository: arul28/ADE
Length of output: 3795
🏁 Script executed:
Repository: arul28/ADE
Length of output: 36
🏁 Script executed:
Repository: arul28/ADE
Length of output: 344
🏁 Script executed:
Repository: arul28/ADE
Length of output: 4525
🏁 Script executed:
Repository: arul28/ADE
Length of output: 36
🏁 Script executed:
cat README.md | head -100Repository: arul28/ADE
Length of output: 4860
🏁 Script executed:
Repository: arul28/ADE
Length of output: 36
🏁 Script executed:
Repository: arul28/ADE
Length of output: 36
🏁 Script executed:
Repository: arul28/ADE
Length of output: 482
🏁 Script executed:
Repository: arul28/ADE
Length of output: 8383
🏁 Script executed:
Repository: arul28/ADE
Length of output: 15783
🏁 Script executed:
rg "commands:" -B 10 -A 10 --type yamlRepository: arul28/ADE
Length of output: 36
🏁 Script executed:
Repository: arul28/ADE
Length of output: 74
Preserve
xcodebuildfailure status when piping totail.Lines 2–3 pipe
xcodebuildoutput totail, which masks build and test failures by returningtail's exit code (0) instead ofxcodebuild's. This can cause failed builds/tests to be marked as passing in CI.Proposed fix
Additionally, lines 2–5 hard-code the simulator device name
iPhone 17 Pro Max. CI environments may not have this specific device available. Consider using a UUID-based destination or a variable to support flexible environments.📝 Committable suggestion
🤖 Prompt for AI Agents