openuispec 0.2.10 → 0.2.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/check/index.ts +17 -0
- package/cli/index.ts +21 -3
- package/cli/init.ts +224 -10
- package/docs/cli.md +13 -8
- package/docs/file-formats.md +36 -0
- package/docs/implementation-notes.md +7 -0
- package/drift/index.ts +281 -40
- package/mcp-server/index.ts +179 -119
- package/mcp-server/screenshot.ts +19 -4
- package/package.json +5 -2
- package/prepare/index.ts +155 -18
- package/schema/openuispec.schema.json +59 -0
- package/schema/semantic-lint.ts +25 -1
- package/scripts/take-all-screenshots.ts +507 -0
- package/spec/openuispec-v0.1.md +13 -0
- package/status/index.ts +72 -2
- package/examples/social-app/.mcp.json +0 -10
- package/examples/social-app/AGENTS.md +0 -124
- package/examples/social-app/CLAUDE.md +0 -124
- package/examples/social-app/backend/.gitkeep +0 -1
- package/examples/social-app/generated/android/social-app/app/.paparazzi-hashes.json +0 -3
- package/examples/social-app/generated/android/social-app/app/build.gradle.kts +0 -94
- package/examples/social-app/generated/android/social-app/app/src/main/AndroidManifest.xml +0 -26
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/AppContainer.kt +0 -20
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/MainActivity.kt +0 -35
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/SocialAppApplication.kt +0 -13
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/data/MockData.kt +0 -98
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/data/preferences/AppPreferences.kt +0 -19
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/data/preferences/DataStorePreferencesRepository.kt +0 -68
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/data/preferences/PreferencesRepository.kt +0 -15
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/model/Models.kt +0 -34
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/MainShell.kt +0 -390
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/components/Components.kt +0 -234
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/components/ContractPrimitives.kt +0 -641
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/navigation/RootComponent.kt +0 -113
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/screens/ChatDetailScreen.kt +0 -212
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/screens/CreatePostScreen.kt +0 -113
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/screens/DiscoverScreen.kt +0 -137
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/screens/EditProfileScreen.kt +0 -180
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/screens/HomeFeedScreen.kt +0 -169
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/screens/MessagesInboxScreen.kt +0 -85
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/screens/NotificationsScreen.kt +0 -74
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/screens/PostDetailScreen.kt +0 -293
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/screens/ProfileSelfScreen.kt +0 -116
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/screens/SearchResultsScreen.kt +0 -161
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/screens/SettingsScreen.kt +0 -164
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/screens/SettingsStore.kt +0 -95
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/screens/UserProfileScreen.kt +0 -123
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/theme/Color.kt +0 -33
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/theme/Shape.kt +0 -41
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/theme/Spacing.kt +0 -20
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/theme/Theme.kt +0 -82
- package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/theme/Type.kt +0 -60
- package/examples/social-app/generated/android/social-app/app/src/main/res/drawable/ic_launcher_foreground.xml +0 -9
- package/examples/social-app/generated/android/social-app/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +0 -5
- package/examples/social-app/generated/android/social-app/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +0 -5
- package/examples/social-app/generated/android/social-app/app/src/main/res/values/strings.xml +0 -91
- package/examples/social-app/generated/android/social-app/app/src/main/res/values/themes.xml +0 -10
- package/examples/social-app/generated/android/social-app/app/src/main/res/values-ru/strings.xml +0 -79
- package/examples/social-app/generated/android/social-app/app/src/main/res/values-uz/strings.xml +0 -79
- package/examples/social-app/generated/android/social-app/app/src/main/xml/AndroidManifest.xml +0 -23
- package/examples/social-app/generated/android/social-app/app/src/test/kotlin/com/social/app/screenshots/HomeFeedScreenshotTest.kt +0 -34
- package/examples/social-app/generated/android/social-app/build.gradle.kts +0 -7
- package/examples/social-app/generated/android/social-app/gradle/libs.versions.toml +0 -50
- package/examples/social-app/generated/android/social-app/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/examples/social-app/generated/android/social-app/gradle/wrapper/gradle-wrapper.properties +0 -8
- package/examples/social-app/generated/android/social-app/gradle.properties +0 -11
- package/examples/social-app/generated/android/social-app/gradlew +0 -248
- package/examples/social-app/generated/android/social-app/settings.gradle.kts +0 -27
- package/examples/social-app/generated/web/social-app/index.html +0 -12
- package/examples/social-app/generated/web/social-app/package-lock.json +0 -2517
- package/examples/social-app/generated/web/social-app/package.json +0 -27
- package/examples/social-app/generated/web/social-app/src/app/App.tsx +0 -58
- package/examples/social-app/generated/web/social-app/src/components/Shell.tsx +0 -259
- package/examples/social-app/generated/web/social-app/src/components/cards.tsx +0 -317
- package/examples/social-app/generated/web/social-app/src/components/ui.tsx +0 -340
- package/examples/social-app/generated/web/social-app/src/flows/CreatePostFlow.tsx +0 -86
- package/examples/social-app/generated/web/social-app/src/i18n.tsx +0 -59
- package/examples/social-app/generated/web/social-app/src/lib/icons.tsx +0 -85
- package/examples/social-app/generated/web/social-app/src/lib/tokens.ts +0 -70
- package/examples/social-app/generated/web/social-app/src/lib/utils.ts +0 -97
- package/examples/social-app/generated/web/social-app/src/locales/en.json +0 -67
- package/examples/social-app/generated/web/social-app/src/locales/ru.json +0 -67
- package/examples/social-app/generated/web/social-app/src/locales/uz.json +0 -67
- package/examples/social-app/generated/web/social-app/src/main.tsx +0 -16
- package/examples/social-app/generated/web/social-app/src/screens/ChatDetailScreen.tsx +0 -90
- package/examples/social-app/generated/web/social-app/src/screens/DiscoverScreen.tsx +0 -86
- package/examples/social-app/generated/web/social-app/src/screens/EditProfileScreen.tsx +0 -57
- package/examples/social-app/generated/web/social-app/src/screens/HomeFeedScreen.tsx +0 -103
- package/examples/social-app/generated/web/social-app/src/screens/MessagesInboxScreen.tsx +0 -52
- package/examples/social-app/generated/web/social-app/src/screens/NotificationsScreen.tsx +0 -41
- package/examples/social-app/generated/web/social-app/src/screens/PostDetailScreen.tsx +0 -115
- package/examples/social-app/generated/web/social-app/src/screens/ProfileSelfScreen.tsx +0 -57
- package/examples/social-app/generated/web/social-app/src/screens/ProfileUserScreen.tsx +0 -76
- package/examples/social-app/generated/web/social-app/src/screens/SearchResultsScreen.tsx +0 -96
- package/examples/social-app/generated/web/social-app/src/screens/SettingsScreen.tsx +0 -79
- package/examples/social-app/generated/web/social-app/src/state/store.ts +0 -592
- package/examples/social-app/generated/web/social-app/src/styles.css +0 -125
- package/examples/social-app/generated/web/social-app/src/vite-env.d.ts +0 -1
- package/examples/social-app/generated/web/social-app/tsconfig.json +0 -22
- package/examples/social-app/generated/web/social-app/tsconfig.node.json +0 -13
- package/examples/social-app/generated/web/social-app/tsconfig.node.tsbuildinfo +0 -1
- package/examples/social-app/generated/web/social-app/tsconfig.tsbuildinfo +0 -1
- package/examples/social-app/generated/web/social-app/vite.config.d.ts +0 -2
- package/examples/social-app/generated/web/social-app/vite.config.js +0 -6
- package/examples/social-app/generated/web/social-app/vite.config.ts +0 -7
- package/examples/social-app/package.json +0 -13
- package/examples/social-app/take-web-screenshots.ts +0 -97
- package/examples/taskflow/.codex/config.toml +0 -4
- package/examples/taskflow/.mcp.json +0 -10
- package/examples/taskflow/AGENTS.md +0 -124
- package/examples/taskflow/CLAUDE.md +0 -124
- package/examples/taskflow/backend/.gitkeep +0 -1
- package/examples/taskflow/generated/android/TaskFlow/README.md +0 -43
- package/examples/taskflow/generated/android/TaskFlow/app/build.gradle.kts +0 -76
- package/examples/taskflow/generated/android/TaskFlow/app/proguard-rules.pro +0 -1
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/AndroidManifest.xml +0 -21
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/java/uz/rsteam/taskflow/MainActivity.kt +0 -19
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/java/uz/rsteam/taskflow/TaskFlowApp.kt +0 -283
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/java/uz/rsteam/taskflow/model/DomainModels.kt +0 -106
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/java/uz/rsteam/taskflow/model/SampleData.kt +0 -57
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/java/uz/rsteam/taskflow/ui/components/Common.kt +0 -109
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/java/uz/rsteam/taskflow/ui/screens/HomeScreen.kt +0 -112
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/java/uz/rsteam/taskflow/ui/screens/ProjectsScreen.kt +0 -61
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/java/uz/rsteam/taskflow/ui/screens/SettingsScreen.kt +0 -82
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/java/uz/rsteam/taskflow/ui/screens/TaskDetailScreen.kt +0 -111
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/java/uz/rsteam/taskflow/ui/sheets/Sheets.kt +0 -77
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/java/uz/rsteam/taskflow/ui/theme/Color.kt +0 -30
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/java/uz/rsteam/taskflow/ui/theme/Theme.kt +0 -86
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/java/uz/rsteam/taskflow/ui/theme/Type.kt +0 -57
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/res/values/strings.xml +0 -155
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/res/values/themes.xml +0 -4
- package/examples/taskflow/generated/android/TaskFlow/build.gradle.kts +0 -5
- package/examples/taskflow/generated/android/TaskFlow/gradle/gradle-daemon-jvm.properties +0 -12
- package/examples/taskflow/generated/android/TaskFlow/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/examples/taskflow/generated/android/TaskFlow/gradle/wrapper/gradle-wrapper.properties +0 -7
- package/examples/taskflow/generated/android/TaskFlow/gradle.properties +0 -4
- package/examples/taskflow/generated/android/TaskFlow/gradlew +0 -18
- package/examples/taskflow/generated/android/TaskFlow/gradlew.bat +0 -12
- package/examples/taskflow/generated/android/TaskFlow/settings.gradle.kts +0 -18
- package/examples/taskflow/generated/ios/TaskFlow/README.md +0 -21
- package/examples/taskflow/generated/ios/TaskFlow/Resources/en.lproj/Localizable.strings +0 -115
- package/examples/taskflow/generated/ios/TaskFlow/Sources/TaskFlow/App/TaskFlowApp.swift +0 -24
- package/examples/taskflow/generated/ios/TaskFlow/Sources/TaskFlow/Components/AppChrome.swift +0 -150
- package/examples/taskflow/generated/ios/TaskFlow/Sources/TaskFlow/Flows/TaskEditorSheet.swift +0 -220
- package/examples/taskflow/generated/ios/TaskFlow/Sources/TaskFlow/Models/DomainModels.swift +0 -122
- package/examples/taskflow/generated/ios/TaskFlow/Sources/TaskFlow/Screens/CalendarView.swift +0 -21
- package/examples/taskflow/generated/ios/TaskFlow/Sources/TaskFlow/Screens/HomeView.swift +0 -201
- package/examples/taskflow/generated/ios/TaskFlow/Sources/TaskFlow/Screens/ProfileEditView.swift +0 -48
- package/examples/taskflow/generated/ios/TaskFlow/Sources/TaskFlow/Screens/ProjectDetailView.swift +0 -59
- package/examples/taskflow/generated/ios/TaskFlow/Sources/TaskFlow/Screens/ProjectsView.swift +0 -63
- package/examples/taskflow/generated/ios/TaskFlow/Sources/TaskFlow/Screens/SettingsView.swift +0 -85
- package/examples/taskflow/generated/ios/TaskFlow/Sources/TaskFlow/Screens/TaskDetailView.swift +0 -219
- package/examples/taskflow/generated/ios/TaskFlow/Sources/TaskFlow/Support/AppModel.swift +0 -320
- package/examples/taskflow/generated/ios/TaskFlow/Sources/TaskFlow/Support/AppSupport.swift +0 -41
- package/examples/taskflow/generated/ios/TaskFlow/project.yml +0 -31
- package/examples/taskflow/generated/web/TaskFlow/README.md +0 -19
- package/examples/taskflow/generated/web/TaskFlow/index.html +0 -12
- package/examples/taskflow/generated/web/TaskFlow/package-lock.json +0 -1908
- package/examples/taskflow/generated/web/TaskFlow/package.json +0 -24
- package/examples/taskflow/generated/web/TaskFlow/src/App.tsx +0 -58
- package/examples/taskflow/generated/web/TaskFlow/src/AppShell.tsx +0 -55
- package/examples/taskflow/generated/web/TaskFlow/src/components/Common.tsx +0 -82
- package/examples/taskflow/generated/web/TaskFlow/src/components/Modals.tsx +0 -191
- package/examples/taskflow/generated/web/TaskFlow/src/components/Nav.tsx +0 -41
- package/examples/taskflow/generated/web/TaskFlow/src/generated/messages.ts +0 -131
- package/examples/taskflow/generated/web/TaskFlow/src/hooks.ts +0 -25
- package/examples/taskflow/generated/web/TaskFlow/src/i18n.ts +0 -39
- package/examples/taskflow/generated/web/TaskFlow/src/locales.en.json +0 -111
- package/examples/taskflow/generated/web/TaskFlow/src/main.tsx +0 -13
- package/examples/taskflow/generated/web/TaskFlow/src/screens/HomeScreen.tsx +0 -111
- package/examples/taskflow/generated/web/TaskFlow/src/screens/ProjectsScreen.tsx +0 -82
- package/examples/taskflow/generated/web/TaskFlow/src/screens/SettingsScreens.tsx +0 -132
- package/examples/taskflow/generated/web/TaskFlow/src/screens/TaskDetail.tsx +0 -105
- package/examples/taskflow/generated/web/TaskFlow/src/store.ts +0 -216
- package/examples/taskflow/generated/web/TaskFlow/src/styles.css +0 -617
- package/examples/taskflow/generated/web/TaskFlow/src/types.ts +0 -64
- package/examples/taskflow/generated/web/TaskFlow/src/utils.ts +0 -78
- package/examples/taskflow/generated/web/TaskFlow/tsconfig.json +0 -21
- package/examples/taskflow/generated/web/TaskFlow/vite.config.ts +0 -6
- package/examples/todo-orbit/.codex/config.toml +0 -4
- package/examples/todo-orbit/.mcp.json +0 -10
- package/examples/todo-orbit/AGENTS.md +0 -124
- package/examples/todo-orbit/CLAUDE.md +0 -124
- package/examples/todo-orbit/backend/.gitkeep +0 -1
- package/examples/todo-orbit/generated/android/Todo Orbit/README.md +0 -14
- package/examples/todo-orbit/generated/android/Todo Orbit/app/build.gradle.kts +0 -58
- package/examples/todo-orbit/generated/android/Todo Orbit/app/proguard-rules.pro +0 -1
- package/examples/todo-orbit/generated/android/Todo Orbit/app/src/main/AndroidManifest.xml +0 -20
- package/examples/todo-orbit/generated/android/Todo Orbit/app/src/main/java/uz/rsteam/todoorbit/MainActivity.kt +0 -14
- package/examples/todo-orbit/generated/android/Todo Orbit/app/src/main/java/uz/rsteam/todoorbit/TodoOrbitApp.kt +0 -345
- package/examples/todo-orbit/generated/android/Todo Orbit/app/src/main/java/uz/rsteam/todoorbit/support/AppLogic.kt +0 -231
- package/examples/todo-orbit/generated/android/Todo Orbit/app/src/main/java/uz/rsteam/todoorbit/support/Models.kt +0 -169
- package/examples/todo-orbit/generated/android/Todo Orbit/app/src/main/java/uz/rsteam/todoorbit/support/Strings.kt +0 -8
- package/examples/todo-orbit/generated/android/Todo Orbit/app/src/main/java/uz/rsteam/todoorbit/ui/components/CommonComponents.kt +0 -236
- package/examples/todo-orbit/generated/android/Todo Orbit/app/src/main/java/uz/rsteam/todoorbit/ui/screens/AnalyticsScreen.kt +0 -193
- package/examples/todo-orbit/generated/android/Todo Orbit/app/src/main/java/uz/rsteam/todoorbit/ui/screens/SettingsScreen.kt +0 -102
- package/examples/todo-orbit/generated/android/Todo Orbit/app/src/main/java/uz/rsteam/todoorbit/ui/screens/TasksScreen.kt +0 -347
- package/examples/todo-orbit/generated/android/Todo Orbit/app/src/main/java/uz/rsteam/todoorbit/ui/sheets/EditorSheets.kt +0 -347
- package/examples/todo-orbit/generated/android/Todo Orbit/app/src/main/java/uz/rsteam/todoorbit/ui/theme/TodoOrbitTheme.kt +0 -59
- package/examples/todo-orbit/generated/android/Todo Orbit/app/src/main/res/values/strings.xml +0 -149
- package/examples/todo-orbit/generated/android/Todo Orbit/app/src/main/res/values-ru/strings.xml +0 -155
- package/examples/todo-orbit/generated/android/Todo Orbit/build.gradle.kts +0 -4
- package/examples/todo-orbit/generated/android/Todo Orbit/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/examples/todo-orbit/generated/android/Todo Orbit/gradle/wrapper/gradle-wrapper.properties +0 -7
- package/examples/todo-orbit/generated/android/Todo Orbit/gradle.properties +0 -4
- package/examples/todo-orbit/generated/android/Todo Orbit/gradlew +0 -248
- package/examples/todo-orbit/generated/android/Todo Orbit/gradlew.bat +0 -93
- package/examples/todo-orbit/generated/android/Todo Orbit/settings.gradle.kts +0 -18
- package/examples/todo-orbit/generated/ios/Todo Orbit/.screenshot-uitest/Sources/ScreenshotUITest.swift +0 -36
- package/examples/todo-orbit/generated/ios/Todo Orbit/README.md +0 -29
- package/examples/todo-orbit/generated/ios/Todo Orbit/Resources/en.lproj/Localizable.strings +0 -119
- package/examples/todo-orbit/generated/ios/Todo Orbit/Resources/ru.lproj/Localizable.strings +0 -119
- package/examples/todo-orbit/generated/ios/Todo Orbit/Sources/TodoOrbit/App/TodoOrbitApp.swift +0 -50
- package/examples/todo-orbit/generated/ios/Todo Orbit/Sources/TodoOrbit/Components/OrbitChrome.swift +0 -204
- package/examples/todo-orbit/generated/ios/Todo Orbit/Sources/TodoOrbit/Components/SchedulePreviewView.swift +0 -126
- package/examples/todo-orbit/generated/ios/Todo Orbit/Sources/TodoOrbit/Components/TrendChartView.swift +0 -70
- package/examples/todo-orbit/generated/ios/Todo Orbit/Sources/TodoOrbit/Flows/RecurringRuleSheet.swift +0 -126
- package/examples/todo-orbit/generated/ios/Todo Orbit/Sources/TodoOrbit/Flows/TaskEditorSheet.swift +0 -61
- package/examples/todo-orbit/generated/ios/Todo Orbit/Sources/TodoOrbit/Models/DomainModels.swift +0 -238
- package/examples/todo-orbit/generated/ios/Todo Orbit/Sources/TodoOrbit/Screens/AnalyticsView.swift +0 -94
- package/examples/todo-orbit/generated/ios/Todo Orbit/Sources/TodoOrbit/Screens/SettingsView.swift +0 -76
- package/examples/todo-orbit/generated/ios/Todo Orbit/Sources/TodoOrbit/Screens/TasksHomeView.swift +0 -364
- package/examples/todo-orbit/generated/ios/Todo Orbit/Sources/TodoOrbit/Support/AppModel.swift +0 -324
- package/examples/todo-orbit/generated/ios/Todo Orbit/TodoOrbit.xcodeproj/project.pbxproj +0 -439
- package/examples/todo-orbit/generated/ios/Todo Orbit/TodoOrbit.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -7
- package/examples/todo-orbit/generated/ios/Todo Orbit/TodoOrbit.xcodeproj/xcshareddata/xcschemes/TodoOrbit.xcscheme +0 -89
- package/examples/todo-orbit/generated/ios/Todo Orbit/project.yml +0 -32
- package/examples/todo-orbit/generated/web/Todo Orbit/index.html +0 -16
- package/examples/todo-orbit/generated/web/Todo Orbit/package-lock.json +0 -1087
- package/examples/todo-orbit/generated/web/Todo Orbit/package.json +0 -24
- package/examples/todo-orbit/generated/web/Todo Orbit/src/App.tsx +0 -2167
- package/examples/todo-orbit/generated/web/Todo Orbit/src/main.tsx +0 -13
- package/examples/todo-orbit/generated/web/Todo Orbit/src/styles.css +0 -926
- package/examples/todo-orbit/generated/web/Todo Orbit/tsconfig.json +0 -19
- package/examples/todo-orbit/generated/web/Todo Orbit/vite.config.ts +0 -6
package/prepare/index.ts
CHANGED
|
@@ -21,10 +21,17 @@ import {
|
|
|
21
21
|
readManifest,
|
|
22
22
|
readProjectName,
|
|
23
23
|
readStatus,
|
|
24
|
+
hasDriftChanges,
|
|
25
|
+
readSharedLayerState,
|
|
26
|
+
readTargetStructure,
|
|
24
27
|
resolveOutputDir,
|
|
28
|
+
sharedLayersForTarget,
|
|
29
|
+
specCategory,
|
|
30
|
+
computeSharedDrift,
|
|
25
31
|
type FileExplanation,
|
|
26
32
|
type ExplainResult,
|
|
27
33
|
type SemanticChange,
|
|
34
|
+
type SharedLayerConfig,
|
|
28
35
|
} from "../drift/index.js";
|
|
29
36
|
|
|
30
37
|
interface PrepareItem {
|
|
@@ -116,6 +123,20 @@ interface PrepareBootstrapBundle {
|
|
|
116
123
|
reference_examples: string[];
|
|
117
124
|
}
|
|
118
125
|
|
|
126
|
+
interface SharedLayerInfo {
|
|
127
|
+
name: string;
|
|
128
|
+
platforms: string[];
|
|
129
|
+
language: string;
|
|
130
|
+
root: string;
|
|
131
|
+
paths: Record<string, string>;
|
|
132
|
+
scope: string;
|
|
133
|
+
tracks: string[];
|
|
134
|
+
already_generated: boolean;
|
|
135
|
+
generated_by_target: string | null;
|
|
136
|
+
has_drift: boolean;
|
|
137
|
+
guidance: string;
|
|
138
|
+
}
|
|
139
|
+
|
|
119
140
|
interface SpecFileContent {
|
|
120
141
|
path: string;
|
|
121
142
|
category: string;
|
|
@@ -135,6 +156,11 @@ export interface PrepareResult {
|
|
|
135
156
|
commit: string | null;
|
|
136
157
|
branch: string | null;
|
|
137
158
|
};
|
|
159
|
+
baseline_status?: {
|
|
160
|
+
output_exists: boolean;
|
|
161
|
+
snapshot_exists: boolean;
|
|
162
|
+
action_needed: string | null;
|
|
163
|
+
};
|
|
138
164
|
summary: {
|
|
139
165
|
changed: number;
|
|
140
166
|
added: number;
|
|
@@ -143,6 +169,7 @@ export interface PrepareResult {
|
|
|
143
169
|
changes_available: boolean;
|
|
144
170
|
explanation_note?: string;
|
|
145
171
|
items: PrepareItem[];
|
|
172
|
+
shared_layers?: SharedLayerInfo[];
|
|
146
173
|
bootstrap?: PrepareBootstrapBundle;
|
|
147
174
|
spec_contents?: SpecFileContent[];
|
|
148
175
|
next_steps: string[];
|
|
@@ -316,13 +343,88 @@ function resolveBackendRoot(projectDir: string, manifest: Record<string, any>):
|
|
|
316
343
|
return resolve(projectDir, backendRoot);
|
|
317
344
|
}
|
|
318
345
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
346
|
+
// Use specCategory from drift/index.ts (imported above) instead of a local duplicate.
|
|
347
|
+
const categorizeSpecFile = specCategory;
|
|
348
|
+
|
|
349
|
+
function buildSharedLayerInfos(projectDir: string, target: string, layers?: SharedLayerConfig[]): SharedLayerInfo[] {
|
|
350
|
+
const resolvedLayers = layers ?? sharedLayersForTarget(projectDir, target);
|
|
351
|
+
if (resolvedLayers.length === 0) return [];
|
|
352
|
+
|
|
353
|
+
return resolvedLayers.map((layer) => {
|
|
354
|
+
const state = readSharedLayerState(layer);
|
|
355
|
+
const alreadyGenerated = state !== null;
|
|
356
|
+
|
|
357
|
+
// Only compute hash-based drift when tracks are configured
|
|
358
|
+
let hasDrift = false;
|
|
359
|
+
if (layer.tracks.length > 0) {
|
|
360
|
+
const driftResult = computeSharedDrift(projectDir, layer);
|
|
361
|
+
hasDrift = driftResult.state !== null && hasDriftChanges(driftResult.drift);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
let guidance: string;
|
|
365
|
+
if (alreadyGenerated && !hasDrift) {
|
|
366
|
+
guidance = `Shared code already generated by ${state!.generated_by_target} — read existing code, don't regenerate.`;
|
|
367
|
+
} else if (alreadyGenerated && hasDrift) {
|
|
368
|
+
guidance = `Generated by ${state!.generated_by_target} but spec has drifted — review shared code for needed updates.`;
|
|
369
|
+
} else {
|
|
370
|
+
guidance = `Generate shared layer alongside ${target} platform code.`;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
return {
|
|
374
|
+
name: layer.name,
|
|
375
|
+
platforms: layer.platforms,
|
|
376
|
+
language: layer.language,
|
|
377
|
+
root: layer.root,
|
|
378
|
+
paths: layer.paths,
|
|
379
|
+
scope: layer.scope,
|
|
380
|
+
tracks: layer.tracks,
|
|
381
|
+
already_generated: alreadyGenerated,
|
|
382
|
+
generated_by_target: state?.generated_by_target ?? null,
|
|
383
|
+
has_drift: hasDrift,
|
|
384
|
+
guidance,
|
|
385
|
+
};
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
function collectSharedLayerPaths(layers: SharedLayerConfig[]): string[] {
|
|
390
|
+
const paths: string[] = [];
|
|
391
|
+
for (const layer of layers) {
|
|
392
|
+
paths.push(layer.root);
|
|
393
|
+
for (const p of Object.values(layer.paths)) {
|
|
394
|
+
paths.push(resolve(layer.root, p));
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
return paths;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
function dedupeExistingPaths(candidates: string[]): string[] {
|
|
401
|
+
const seen = new Set<string>();
|
|
402
|
+
return candidates
|
|
403
|
+
.map((c) => resolve(c))
|
|
404
|
+
.filter((c) => existsSync(c))
|
|
405
|
+
.filter((c) => {
|
|
406
|
+
if (seen.has(c)) return false;
|
|
407
|
+
seen.add(c);
|
|
408
|
+
return true;
|
|
409
|
+
});
|
|
323
410
|
}
|
|
324
411
|
|
|
325
|
-
function suggestCodeRoots(target: string, outputDir: string): string[] {
|
|
412
|
+
function suggestCodeRoots(target: string, outputDir: string, projectDir?: string, sharedLayers?: SharedLayerConfig[]): string[] {
|
|
413
|
+
const layers = sharedLayers ?? (projectDir ? sharedLayersForTarget(projectDir, target) : []);
|
|
414
|
+
|
|
415
|
+
// When generation.structure is defined for the target, use it instead of heuristics
|
|
416
|
+
if (projectDir) {
|
|
417
|
+
const structure = readTargetStructure(projectDir, target);
|
|
418
|
+
if (structure) {
|
|
419
|
+
const candidates = [
|
|
420
|
+
structure.root,
|
|
421
|
+
...Object.values(structure.paths).map((p) => resolve(structure.root, p)),
|
|
422
|
+
...collectSharedLayerPaths(layers),
|
|
423
|
+
];
|
|
424
|
+
return dedupeExistingPaths(candidates);
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
326
428
|
const candidates: string[] = [];
|
|
327
429
|
|
|
328
430
|
if (target === "web") {
|
|
@@ -340,15 +442,8 @@ function suggestCodeRoots(target: string, outputDir: string): string[] {
|
|
|
340
442
|
candidates.push(outputDir);
|
|
341
443
|
}
|
|
342
444
|
|
|
343
|
-
|
|
344
|
-
return candidates
|
|
345
|
-
.map((candidate) => resolve(candidate))
|
|
346
|
-
.filter((candidate) => existsSync(candidate))
|
|
347
|
-
.filter((candidate) => {
|
|
348
|
-
if (seen.has(candidate)) return false;
|
|
349
|
-
seen.add(candidate);
|
|
350
|
-
return true;
|
|
351
|
-
});
|
|
445
|
+
candidates.push(...collectSharedLayerPaths(layers));
|
|
446
|
+
return dedupeExistingPaths(candidates);
|
|
352
447
|
}
|
|
353
448
|
|
|
354
449
|
function walkFiles(root: string, files: string[], depth = 0): void {
|
|
@@ -506,7 +601,7 @@ function buildBootstrapNotes(category: string, target: string, specStatus: strin
|
|
|
506
601
|
return notes;
|
|
507
602
|
}
|
|
508
603
|
|
|
509
|
-
function generationRules(target: string, outputDir: string, manifest: Record<string, any
|
|
604
|
+
function generationRules(target: string, outputDir: string, manifest: Record<string, any>, sharedLayers?: SharedLayerInfo[]): string[] {
|
|
510
605
|
const outputFormat = manifest.generation?.output_format?.[target] ?? {};
|
|
511
606
|
const rules = [
|
|
512
607
|
"Read openuispec.yaml first, then follow the referenced spec files instead of inventing structure from memory.",
|
|
@@ -523,6 +618,31 @@ function generationRules(target: string, outputDir: string, manifest: Record<str
|
|
|
523
618
|
);
|
|
524
619
|
}
|
|
525
620
|
|
|
621
|
+
if (sharedLayers && sharedLayers.length > 0) {
|
|
622
|
+
for (const layer of sharedLayers) {
|
|
623
|
+
if (layer.already_generated) {
|
|
624
|
+
rules.push(
|
|
625
|
+
`Shared layer "${layer.name}" already generated by ${layer.generated_by_target}. Read the existing code under ${layer.root} instead of regenerating it.`
|
|
626
|
+
);
|
|
627
|
+
} else {
|
|
628
|
+
rules.push(
|
|
629
|
+
`Generate shared layer "${layer.name}" (${layer.language}) under ${layer.root} alongside ${target} platform code.`
|
|
630
|
+
);
|
|
631
|
+
}
|
|
632
|
+
if (layer.scope) {
|
|
633
|
+
rules.push(
|
|
634
|
+
`Shared layer "${layer.name}" scope: ${layer.scope}`
|
|
635
|
+
);
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
// Include target structure scope when defined
|
|
641
|
+
const structure = manifest.generation?.structure?.[target];
|
|
642
|
+
if (structure?.scope) {
|
|
643
|
+
rules.push(`Target "${target}" scope: ${structure.scope}`);
|
|
644
|
+
}
|
|
645
|
+
|
|
526
646
|
return rules;
|
|
527
647
|
}
|
|
528
648
|
|
|
@@ -1065,8 +1185,10 @@ function buildBootstrapPrepareResult(cwd: string, target: string, includeContent
|
|
|
1065
1185
|
const platformDef = readPlatformDefinition(projectDir, manifest, target);
|
|
1066
1186
|
const platformConfig = buildPlatformConfig(target, platformDef);
|
|
1067
1187
|
const outputFormat = manifest.generation?.output_format?.[target] ?? {};
|
|
1068
|
-
const
|
|
1188
|
+
const sharedLayerConfigs = sharedLayersForTarget(projectDir, target);
|
|
1189
|
+
const codeRoots = suggestCodeRoots(target, outputDir, projectDir, sharedLayerConfigs);
|
|
1069
1190
|
const missingDecisions = missingPlatformDecisions(target, platformDef);
|
|
1191
|
+
const sharedLayerInfos = buildSharedLayerInfos(projectDir, target, sharedLayerConfigs);
|
|
1070
1192
|
const backendRoot = resolveBackendRoot(projectDir, manifest);
|
|
1071
1193
|
const backendContextReady = true; // backend is optional — not a generation blocker
|
|
1072
1194
|
const pendingUserConfirmation = platformConfig.stack_confirmation.requires_user_confirmation;
|
|
@@ -1103,6 +1225,10 @@ function buildBootstrapPrepareResult(cwd: string, target: string, includeContent
|
|
|
1103
1225
|
);
|
|
1104
1226
|
}
|
|
1105
1227
|
|
|
1228
|
+
const outputDirExists = existsSync(outputDir);
|
|
1229
|
+
const snapshotPath = join(outputDir, ".openuispec-state.json");
|
|
1230
|
+
const snapshotFileExists = existsSync(snapshotPath);
|
|
1231
|
+
|
|
1106
1232
|
return {
|
|
1107
1233
|
mode: "bootstrap",
|
|
1108
1234
|
project: projectName,
|
|
@@ -1116,6 +1242,13 @@ function buildBootstrapPrepareResult(cwd: string, target: string, includeContent
|
|
|
1116
1242
|
commit: null,
|
|
1117
1243
|
branch: null,
|
|
1118
1244
|
},
|
|
1245
|
+
baseline_status: {
|
|
1246
|
+
output_exists: outputDirExists,
|
|
1247
|
+
snapshot_exists: snapshotFileExists,
|
|
1248
|
+
action_needed: outputDirExists && !snapshotFileExists
|
|
1249
|
+
? `Baseline pending — when satisfied with the generated output, run: openuispec drift --snapshot --target ${target}`
|
|
1250
|
+
: null,
|
|
1251
|
+
},
|
|
1119
1252
|
summary: {
|
|
1120
1253
|
changed: 0,
|
|
1121
1254
|
added: 0,
|
|
@@ -1124,6 +1257,7 @@ function buildBootstrapPrepareResult(cwd: string, target: string, includeContent
|
|
|
1124
1257
|
changes_available: false,
|
|
1125
1258
|
explanation_note: "No snapshot exists yet. This is a first-time generation bundle.",
|
|
1126
1259
|
items: [],
|
|
1260
|
+
...(sharedLayerInfos.length > 0 ? { shared_layers: sharedLayerInfos } : {}),
|
|
1127
1261
|
...(includeContents ? { spec_contents: readAllSpecContents(projectDir) } : {}),
|
|
1128
1262
|
bootstrap: {
|
|
1129
1263
|
output_exists: existsSync(outputDir),
|
|
@@ -1141,7 +1275,7 @@ function buildBootstrapPrepareResult(cwd: string, target: string, includeContent
|
|
|
1141
1275
|
supported_locales: manifest.i18n?.supported_locales ?? [],
|
|
1142
1276
|
},
|
|
1143
1277
|
spec_files: bootstrapSpecFiles(projectDir, target),
|
|
1144
|
-
generation_rules: generationRules(target, outputDir, manifest),
|
|
1278
|
+
generation_rules: generationRules(target, outputDir, manifest, sharedLayerInfos),
|
|
1145
1279
|
generation_constraints: generationConstraints(target, platformConfig),
|
|
1146
1280
|
generation_warnings: generationWarnings(target, platformConfig),
|
|
1147
1281
|
reference_examples: referenceExamples(),
|
|
@@ -1153,8 +1287,10 @@ function buildBootstrapPrepareResult(cwd: string, target: string, includeContent
|
|
|
1153
1287
|
function buildUpdatePrepareResult(cwd: string, target: string, includeContents: boolean = false): PrepareResult {
|
|
1154
1288
|
const { projectDir, projectName, result } = loadTargetDrift(cwd, target, false, true);
|
|
1155
1289
|
const outputDir = resolveOutputDir(projectDir, projectName, target);
|
|
1156
|
-
const
|
|
1290
|
+
const sharedLayerConfigs = sharedLayersForTarget(projectDir, target);
|
|
1291
|
+
const codeRoots = suggestCodeRoots(target, outputDir, projectDir, sharedLayerConfigs);
|
|
1157
1292
|
const manifest = readManifest(projectDir);
|
|
1293
|
+
const sharedLayerInfos = buildSharedLayerInfos(projectDir, target, sharedLayerConfigs);
|
|
1158
1294
|
const platformDef = readPlatformDefinition(projectDir, manifest, target);
|
|
1159
1295
|
const platformConfig = buildPlatformConfig(target, platformDef);
|
|
1160
1296
|
const outputFormat = manifest.generation?.output_format?.[target] ?? {};
|
|
@@ -1195,6 +1331,7 @@ function buildUpdatePrepareResult(cwd: string, target: string, includeContents:
|
|
|
1195
1331
|
changes_available: result.explanation?.available ?? false,
|
|
1196
1332
|
explanation_note: result.explanation?.note,
|
|
1197
1333
|
items,
|
|
1334
|
+
...(sharedLayerInfos.length > 0 ? { shared_layers: sharedLayerInfos } : {}),
|
|
1198
1335
|
...(includeContents ? { spec_contents: readAllSpecContents(projectDir) } : {}),
|
|
1199
1336
|
next_steps: nextSteps,
|
|
1200
1337
|
};
|
|
@@ -152,6 +152,65 @@
|
|
|
152
152
|
},
|
|
153
153
|
"additionalProperties": true
|
|
154
154
|
}
|
|
155
|
+
},
|
|
156
|
+
"shared": {
|
|
157
|
+
"type": "object",
|
|
158
|
+
"description": "Named shared code layers that span multiple targets (e.g. KMP common modules)",
|
|
159
|
+
"additionalProperties": {
|
|
160
|
+
"type": "object",
|
|
161
|
+
"properties": {
|
|
162
|
+
"platforms": {
|
|
163
|
+
"type": "array",
|
|
164
|
+
"items": { "type": "string" }
|
|
165
|
+
},
|
|
166
|
+
"language": {
|
|
167
|
+
"type": "string"
|
|
168
|
+
},
|
|
169
|
+
"root": {
|
|
170
|
+
"type": "string"
|
|
171
|
+
},
|
|
172
|
+
"paths": {
|
|
173
|
+
"type": "object",
|
|
174
|
+
"additionalProperties": { "type": "string" }
|
|
175
|
+
},
|
|
176
|
+
"tracks": {
|
|
177
|
+
"type": "array",
|
|
178
|
+
"description": "Spec categories this shared layer tracks for drift. Must be explicit — choose which categories actually affect the shared code.",
|
|
179
|
+
"items": {
|
|
180
|
+
"type": "string",
|
|
181
|
+
"enum": ["manifest", "tokens", "contracts", "screens", "flows", "platform", "locales"]
|
|
182
|
+
}
|
|
183
|
+
},
|
|
184
|
+
"scope": {
|
|
185
|
+
"type": "string",
|
|
186
|
+
"description": "What code belongs in this shared layer (e.g. 'Business logic, data models, repositories, API clients, view models. No UI rendering.')"
|
|
187
|
+
}
|
|
188
|
+
},
|
|
189
|
+
"required": ["platforms", "language", "root", "scope"],
|
|
190
|
+
"additionalProperties": false
|
|
191
|
+
}
|
|
192
|
+
},
|
|
193
|
+
"structure": {
|
|
194
|
+
"type": "object",
|
|
195
|
+
"description": "Per-target output directory structure (overrides heuristic code root discovery)",
|
|
196
|
+
"additionalProperties": {
|
|
197
|
+
"type": "object",
|
|
198
|
+
"properties": {
|
|
199
|
+
"root": {
|
|
200
|
+
"type": "string"
|
|
201
|
+
},
|
|
202
|
+
"paths": {
|
|
203
|
+
"type": "object",
|
|
204
|
+
"additionalProperties": { "type": "string" }
|
|
205
|
+
},
|
|
206
|
+
"scope": {
|
|
207
|
+
"type": "string",
|
|
208
|
+
"description": "What code belongs in this target directory (e.g. 'Pure SwiftUI views and navigation. All business logic comes from the shared layer.')"
|
|
209
|
+
}
|
|
210
|
+
},
|
|
211
|
+
"required": ["root"],
|
|
212
|
+
"additionalProperties": false
|
|
213
|
+
}
|
|
155
214
|
}
|
|
156
215
|
},
|
|
157
216
|
"required": [
|
package/schema/semantic-lint.ts
CHANGED
|
@@ -5,6 +5,23 @@ import { listFiles, readManifest } from "../drift/index.js";
|
|
|
5
5
|
|
|
6
6
|
type UnknownRecord = Record<string, unknown>;
|
|
7
7
|
|
|
8
|
+
/** Collect all locale keys from a JSON object, supporting both flat dotted keys and nested objects. */
|
|
9
|
+
function collectLocaleKeys(data: unknown, prefix = ""): string[] {
|
|
10
|
+
if (!data || typeof data !== "object" || Array.isArray(data)) return [];
|
|
11
|
+
const keys: string[] = [];
|
|
12
|
+
for (const [key, value] of Object.entries(data as UnknownRecord)) {
|
|
13
|
+
if (key.startsWith("$")) continue; // skip $locale, $direction
|
|
14
|
+
const fullKey = prefix ? `${prefix}.${key}` : key;
|
|
15
|
+
if (typeof value === "string") {
|
|
16
|
+
keys.push(fullKey);
|
|
17
|
+
} else if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
|
18
|
+
// Nested object — recurse to flatten
|
|
19
|
+
keys.push(...collectLocaleKeys(value, fullKey));
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return keys;
|
|
23
|
+
}
|
|
24
|
+
|
|
8
25
|
export interface Includes {
|
|
9
26
|
tokens: string;
|
|
10
27
|
contracts: string;
|
|
@@ -212,7 +229,14 @@ function buildContext(projectDir: string, includes: Includes, manifest: UnknownR
|
|
|
212
229
|
for (const filePath of listFiles(localeDir, ".json")) {
|
|
213
230
|
const localeName = basename(filePath, ".json");
|
|
214
231
|
const data = loadJson(filePath);
|
|
215
|
-
|
|
232
|
+
// Support both flat dotted keys ("nav.home": "Home") and nested objects ({ nav: { home: "Home" } })
|
|
233
|
+
const flatKeys = Object.keys(data as object).filter(k => !k.startsWith("$"));
|
|
234
|
+
const hasNestedObjects = flatKeys.some(k => {
|
|
235
|
+
const v = (data as UnknownRecord)[k];
|
|
236
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
237
|
+
});
|
|
238
|
+
const allKeys = hasNestedObjects ? collectLocaleKeys(data) : flatKeys;
|
|
239
|
+
localeFiles.set(localeName, new Set(allKeys));
|
|
216
240
|
}
|
|
217
241
|
|
|
218
242
|
const formatterNames = new Set<string>([
|