openuispec 0.2.9 → 0.2.11
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/cli/index.ts +80 -2
- package/cli/init.ts +23 -8
- package/docs/cli.md +42 -7
- package/drift/index.ts +41 -15
- package/mcp-server/index.ts +247 -117
- package/mcp-server/screenshot-android.ts +185 -44
- package/mcp-server/screenshot-ios.ts +242 -30
- package/mcp-server/screenshot.ts +96 -1
- package/package.json +5 -2
- package/prepare/index.ts +16 -0
- package/scripts/take-all-screenshots.ts +507 -0
- package/status/index.ts +2 -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 -26
- 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 -400
- package/examples/todo-orbit/generated/ios/Todo Orbit/TodoOrbit.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -7
- package/examples/todo-orbit/generated/ios/Todo Orbit/project.yml +0 -25
- 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/README.md
CHANGED
|
@@ -74,7 +74,7 @@ OpenUISpec includes an **MCP server** that AI assistants call automatically duri
|
|
|
74
74
|
openuispec init → configures MCP for your agent → AI calls tools automatically
|
|
75
75
|
```
|
|
76
76
|
|
|
77
|
-
When you ask your AI to "add a settings page" or "update the home feed," the MCP server provides spec context before generation, feeds authoritative spec contents during generation, and returns a
|
|
77
|
+
When you ask your AI to "add a settings page" or "update the home feed," the MCP server provides spec context before generation, feeds authoritative spec contents during generation, validates spec integrity after edits, and returns a spec-derived checklist for the AI to review the generated code against.
|
|
78
78
|
|
|
79
79
|
15 tools are available as both MCP tools and CLI commands — see the [full reference](./docs/cli.md).
|
|
80
80
|
|
|
@@ -90,6 +90,8 @@ When you ask your AI to "add a settings page" or "update the home feed," the MCP
|
|
|
90
90
|
| [Todo Orbit](./examples/todo-orbit/openuispec/) | iOS, Android, Web | Bilingual task app with localization, custom contracts |
|
|
91
91
|
| [Social App](./examples/social-app/openuispec/) | Android, Web | Trilingual social app with feeds, messaging, profiles |
|
|
92
92
|
|
|
93
|
+
Screenshots of the generated apps are in the [artifacts](./artifacts/) directory.
|
|
94
|
+
|
|
93
95
|
## Documentation
|
|
94
96
|
|
|
95
97
|
| Doc | What's in it |
|
package/cli/index.ts
CHANGED
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
* openuispec spec-schema <type> Get JSON schema for a spec type
|
|
25
25
|
* openuispec screenshot [--route /path] Screenshot the web app
|
|
26
26
|
* openuispec screenshot-android [opts] Screenshot Android app on emulator
|
|
27
|
+
* openuispec screenshot-android-batch [opts] Batch screenshot Android app on emulator
|
|
27
28
|
* openuispec screenshot-ios [opts] Screenshot iOS app on simulator
|
|
28
29
|
*/
|
|
29
30
|
|
|
@@ -47,6 +48,25 @@ function getPositional(argv: string[], startIdx = 0): string[] {
|
|
|
47
48
|
return argv.slice(startIdx).filter((a) => !a.startsWith("--"));
|
|
48
49
|
}
|
|
49
50
|
|
|
51
|
+
function readJsonFile(filePath: string): any {
|
|
52
|
+
return JSON.parse(readFileSync(resolve(filePath), "utf-8"));
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function parseBatchConfig(rest: string[], usage: string): { config: any; captures: any[] } {
|
|
56
|
+
const configPath = getOption(rest, "--config");
|
|
57
|
+
if (!configPath) {
|
|
58
|
+
console.error(usage);
|
|
59
|
+
process.exit(1);
|
|
60
|
+
}
|
|
61
|
+
const config = readJsonFile(configPath);
|
|
62
|
+
const captures = Array.isArray(config) ? config : config.captures;
|
|
63
|
+
if (!Array.isArray(captures) || captures.length === 0) {
|
|
64
|
+
console.error("Batch config must be an array of captures or an object with a non-empty 'captures' array.");
|
|
65
|
+
process.exit(1);
|
|
66
|
+
}
|
|
67
|
+
return { config, captures };
|
|
68
|
+
}
|
|
69
|
+
|
|
50
70
|
// ── rules version check ─────────────────────────────────────────────
|
|
51
71
|
|
|
52
72
|
function checkRulesVersion(): void {
|
|
@@ -312,6 +332,7 @@ async function main(): Promise<void> {
|
|
|
312
332
|
width: parseInt(getOption(rest, "--width") ?? "1280"),
|
|
313
333
|
height: parseInt(getOption(rest, "--height") ?? "800"),
|
|
314
334
|
},
|
|
335
|
+
scale: parseFloat(getOption(rest, "--scale") ?? "2"),
|
|
315
336
|
theme: getOption(rest, "--theme") as "light" | "dark" | undefined,
|
|
316
337
|
wait_for: parseInt(getOption(rest, "--wait-for") ?? "1000"),
|
|
317
338
|
full_page: getFlag(rest, "--full-page"),
|
|
@@ -338,6 +359,38 @@ async function main(): Promise<void> {
|
|
|
338
359
|
break;
|
|
339
360
|
}
|
|
340
361
|
|
|
362
|
+
case "screenshot-android-batch": {
|
|
363
|
+
const { takeAndroidScreenshotBatch } = await import("../mcp-server/screenshot-android.js");
|
|
364
|
+
const { config, captures } = parseBatchConfig(rest,
|
|
365
|
+
"Usage: openuispec screenshot-android-batch --config <captures.json> [--project-dir path] [--module name] [--theme light|dark] [--output-dir dir]");
|
|
366
|
+
|
|
367
|
+
const result = await takeAndroidScreenshotBatch(cwd, {
|
|
368
|
+
captures,
|
|
369
|
+
theme: (getOption(rest, "--theme") ?? config.theme) as "light" | "dark" | undefined,
|
|
370
|
+
output_dir: getOption(rest, "--output-dir") ?? config.output_dir ?? undefined,
|
|
371
|
+
project_dir: getOption(rest, "--project-dir") ?? config.project_dir ?? undefined,
|
|
372
|
+
module: getOption(rest, "--module") ?? config.module ?? undefined,
|
|
373
|
+
});
|
|
374
|
+
printScreenshotResult(result);
|
|
375
|
+
break;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
case "screenshot-web-batch": {
|
|
379
|
+
const { takeScreenshotBatch } = await import("../mcp-server/screenshot.js");
|
|
380
|
+
const { config, captures } = parseBatchConfig(rest,
|
|
381
|
+
"Usage: openuispec screenshot-web-batch --config <captures.json> [--theme light|dark] [--output-dir dir]");
|
|
382
|
+
|
|
383
|
+
const result = await takeScreenshotBatch(cwd, {
|
|
384
|
+
captures,
|
|
385
|
+
viewport: config.viewport,
|
|
386
|
+
scale: parseFloat(getOption(rest, "--scale") ?? config.scale ?? "2"),
|
|
387
|
+
theme: (getOption(rest, "--theme") ?? config.theme) as "light" | "dark" | undefined,
|
|
388
|
+
output_dir: getOption(rest, "--output-dir") ?? config.output_dir ?? undefined,
|
|
389
|
+
});
|
|
390
|
+
printScreenshotResult(result);
|
|
391
|
+
break;
|
|
392
|
+
}
|
|
393
|
+
|
|
341
394
|
case "screenshot-ios": {
|
|
342
395
|
const { takeIOSScreenshot } = await import("../mcp-server/screenshot-ios.js");
|
|
343
396
|
const result = await takeIOSScreenshot(cwd, {
|
|
@@ -355,6 +408,24 @@ async function main(): Promise<void> {
|
|
|
355
408
|
break;
|
|
356
409
|
}
|
|
357
410
|
|
|
411
|
+
case "screenshot-ios-batch": {
|
|
412
|
+
const { takeIOSScreenshotBatch } = await import("../mcp-server/screenshot-ios.js");
|
|
413
|
+
const { config, captures } = parseBatchConfig(rest,
|
|
414
|
+
"Usage: openuispec screenshot-ios-batch --config <captures.json> [--project-dir path] [--scheme name] [--bundle-id id] [--device name] [--theme light|dark] [--output-dir dir]");
|
|
415
|
+
|
|
416
|
+
const result = await takeIOSScreenshotBatch(cwd, {
|
|
417
|
+
captures,
|
|
418
|
+
device: getOption(rest, "--device") ?? config.device ?? undefined,
|
|
419
|
+
theme: (getOption(rest, "--theme") ?? config.theme) as "light" | "dark" | undefined,
|
|
420
|
+
output_dir: getOption(rest, "--output-dir") ?? config.output_dir ?? undefined,
|
|
421
|
+
project_dir: getOption(rest, "--project-dir") ?? config.project_dir ?? undefined,
|
|
422
|
+
scheme: getOption(rest, "--scheme") ?? config.scheme ?? undefined,
|
|
423
|
+
bundle_id: getOption(rest, "--bundle-id") ?? config.bundle_id ?? undefined,
|
|
424
|
+
});
|
|
425
|
+
printScreenshotResult(result);
|
|
426
|
+
break;
|
|
427
|
+
}
|
|
428
|
+
|
|
358
429
|
// ── help ────────────────────────────────────────────────────────
|
|
359
430
|
|
|
360
431
|
case undefined:
|
|
@@ -389,13 +460,20 @@ Spec access:
|
|
|
389
460
|
openuispec spec-types List available spec types
|
|
390
461
|
openuispec spec-schema <type> Get full JSON schema for a spec type
|
|
391
462
|
|
|
392
|
-
Screenshots:
|
|
393
|
-
openuispec screenshot [--route /path] [--theme light|dark] [--output-dir dir]
|
|
463
|
+
Screenshots (single):
|
|
464
|
+
openuispec screenshot [--route /path] [--width px] [--height px] [--scale n] [--theme light|dark] [--output-dir dir]
|
|
394
465
|
openuispec screenshot-android [--screen name] [--project-dir path] [--module name]
|
|
395
466
|
[--route deeplink] [--nav Step1,Step2] [--theme light|dark] [--output-dir dir]
|
|
396
467
|
openuispec screenshot-ios [--screen name] [--project-dir path] [--scheme name]
|
|
397
468
|
[--bundle-id id] [--device name] [--nav Step1,Step2] [--theme light|dark]
|
|
398
469
|
|
|
470
|
+
Screenshots (batch — build once, capture many):
|
|
471
|
+
openuispec screenshot-web-batch --config captures.json [--scale n] [--theme light|dark] [--output-dir dir]
|
|
472
|
+
openuispec screenshot-android-batch --config captures.json [--project-dir path]
|
|
473
|
+
[--module name] [--theme light|dark] [--output-dir dir]
|
|
474
|
+
openuispec screenshot-ios-batch --config captures.json [--project-dir path]
|
|
475
|
+
[--scheme name] [--bundle-id id] [--device name] [--theme light|dark] [--output-dir dir]
|
|
476
|
+
|
|
399
477
|
Server:
|
|
400
478
|
openuispec mcp Start MCP server (stdio transport)
|
|
401
479
|
|
package/cli/init.ts
CHANGED
|
@@ -348,21 +348,35 @@ Call these MCP tools directly. They return structured JSON with everything you n
|
|
|
348
348
|
|
|
349
349
|
**Pre-generation:**
|
|
350
350
|
1. Call \`openuispec_prepare\` with the target platform — returns spec context, platform config, constraints.
|
|
351
|
-
|
|
351
|
+
Use \`include_specs: true\` to embed all spec contents in one call (saves a separate read_specs).
|
|
352
|
+
2. Call \`openuispec_read_specs\` to load spec file contents if not using include_specs.
|
|
353
|
+
Without paths: returns file listing. With paths: returns contents. Use these as the AUTHORITATIVE source.
|
|
352
354
|
3. If spec changes are needed, update spec files FIRST, then call \`openuispec_check\`.
|
|
353
355
|
4. Generate or update the platform UI code based on the spec contents.
|
|
354
356
|
|
|
355
357
|
**Post-generation (EVERY TIME after writing UI code):**
|
|
356
|
-
5. Call \`openuispec_check\` to validate spec
|
|
357
|
-
|
|
358
|
-
|
|
358
|
+
5. Call \`openuispec_check\` to validate spec files (schema + semantics) and confirm prepare readiness.
|
|
359
|
+
Note: this validates the SPEC, not the generated code.
|
|
360
|
+
6. Call \`openuispec_check\` with \`audit: true\` to get a spec-derived checklist, then manually review
|
|
361
|
+
the generated code against it. For each screen, verify:
|
|
359
362
|
- Every field/action in the spec has a corresponding UI element
|
|
360
363
|
- Token values (colors, spacing, radii) match exactly — no approximations
|
|
361
364
|
- Contract \`must_handle\` states are all implemented (loading, error, empty, etc.)
|
|
362
365
|
- Adaptive breakpoints match the spec's \`size_classes\`
|
|
363
366
|
- Locale keys match \`$t:\` references
|
|
364
367
|
- Navigation targets match flow definitions
|
|
365
|
-
|
|
368
|
+
7. Report any real gaps found and fix them before finishing.
|
|
369
|
+
|
|
370
|
+
**Iterating before baseline:**
|
|
371
|
+
Generated code rarely needs just one pass. Read the spec, audit the generated code against it,
|
|
372
|
+
take screenshots to verify visuals, then fix gaps and repeat.
|
|
373
|
+
Multiple generate → review → fix cycles are expected before the user accepts the result.
|
|
374
|
+
|
|
375
|
+
**Baseline reminder:**
|
|
376
|
+
After generation, remind the user to review the output and run the baseline when satisfied:
|
|
377
|
+
> When you're happy with the generated output, run: \`openuispec drift --snapshot --target <t>\`
|
|
378
|
+
> This records the spec state so future changes are tracked as incremental drift.
|
|
379
|
+
Do not baseline on your own initiative — only run the snapshot when the user asks.
|
|
366
380
|
|
|
367
381
|
**Creating new spec files:**
|
|
368
382
|
- Call \`openuispec_spec_types\` to discover available spec types.
|
|
@@ -374,7 +388,7 @@ Call these MCP tools directly. They return structured JSON with everything you n
|
|
|
374
388
|
- \`openuispec_get_contract(name, variant?)\` — single contract, optionally one variant
|
|
375
389
|
- \`openuispec_get_tokens(category)\` — single token category (color, typography, spacing, etc.)
|
|
376
390
|
- \`openuispec_get_locale(locale, keys?)\` — single locale file, optionally filtered keys
|
|
377
|
-
- \`openuispec_check(target, screens?, contracts?)\` — scoped audit
|
|
391
|
+
- \`openuispec_check(target, audit?, screens?, contracts?)\` — validation + optional scoped audit checklist
|
|
378
392
|
|
|
379
393
|
Use \`read_specs\` for full-project generation; use focused getters when editing one screen or contract.
|
|
380
394
|
|
|
@@ -404,7 +418,7 @@ If MCP tools are not available, use these CLI commands with \`--json\` flag:
|
|
|
404
418
|
|
|
405
419
|
### Other CLI commands
|
|
406
420
|
- \`openuispec init\` — scaffold a new spec project
|
|
407
|
-
- \`openuispec drift --snapshot --target <t>\` — snapshot current state (
|
|
421
|
+
- \`openuispec drift --snapshot --target <t>\` — snapshot current state (user-initiated, after reviewing generated output)
|
|
408
422
|
- \`openuispec configure-target <t>\` — configure target platform stack
|
|
409
423
|
- \`openuispec update-rules\` — update AI rules to match installed package version
|
|
410
424
|
|
|
@@ -448,7 +462,8 @@ Read \`spec/openuispec-v0.1.md\` from the package first, then:
|
|
|
448
462
|
5. Fill in \`data_model\`, \`api.endpoints\` in \`${specDir}/openuispec.yaml\`
|
|
449
463
|
|
|
450
464
|
## Rules
|
|
451
|
-
- Do not
|
|
465
|
+
- Do not baseline on your own initiative — the user decides when generated output is accepted.
|
|
466
|
+
- After generation, always remind the user to review and baseline: \`openuispec drift --snapshot --target <t>\`.
|
|
452
467
|
- Do not modify generated UI without checking whether the spec must change first.
|
|
453
468
|
- Do not use \`configure-target --defaults\` as silent approval — ask the user to confirm.
|
|
454
469
|
- Always read spec format from the installed package, not from cached/memorized content.
|
package/docs/cli.md
CHANGED
|
@@ -41,12 +41,12 @@ Or run directly: `openuispec mcp`
|
|
|
41
41
|
| Tool | When | What it does |
|
|
42
42
|
|------|------|-------------|
|
|
43
43
|
| `openuispec_spec_types` | Before creating spec files | Lists all available spec types with descriptions |
|
|
44
|
-
| `openuispec_spec_schema` | Before creating/editing spec files | Returns
|
|
45
|
-
| `openuispec_prepare` | Before UI code generation | Returns spec context, platform config,
|
|
46
|
-
| `openuispec_read_specs` | Before and after generation |
|
|
47
|
-
| `openuispec_check` | After generation |
|
|
44
|
+
| `openuispec_spec_schema` | Before creating/editing spec files | Returns JSON schema for a spec type. Optional `summary` for top-level overview |
|
|
45
|
+
| `openuispec_prepare` | Before UI code generation | Returns spec context, platform config, constraints. Optional `include_specs` embeds all spec contents |
|
|
46
|
+
| `openuispec_read_specs` | Before and after generation | Without `paths`: returns file listing. With `paths`: loads spec contents |
|
|
47
|
+
| `openuispec_check` | After spec edits or generation | Spec validation (schema + semantic) + prepare readiness. `audit=true` returns a spec-derived checklist for manual code review |
|
|
48
48
|
| `openuispec_validate` | After spec edits | Schema-only validation, optionally filtered by group |
|
|
49
|
-
| `openuispec_drift` | Before updates | Detect
|
|
49
|
+
| `openuispec_drift` | Before updates / after generation | Detect drift, or `snapshot=true` to create/update baseline |
|
|
50
50
|
| `openuispec_status` | Anytime | Cross-target summary: baselines, drift, next steps |
|
|
51
51
|
| `openuispec_get_screen` | Incremental edits | Get a single screen spec by name |
|
|
52
52
|
| `openuispec_get_contract` | Incremental edits | Get a single contract spec, optionally filtered to one variant |
|
|
@@ -55,6 +55,9 @@ Or run directly: `openuispec mcp`
|
|
|
55
55
|
| `openuispec_screenshot` | Visual verification | Screenshot the web app at a route via headless browser |
|
|
56
56
|
| `openuispec_screenshot_android` | Visual verification | Screenshot Android app on emulator. Works with any project via `project_dir` |
|
|
57
57
|
| `openuispec_screenshot_ios` | Visual verification | Screenshot iOS app on Simulator via XCUITest. Works with any project via `project_dir` |
|
|
58
|
+
| `openuispec_screenshot_web_batch` | Visual verification | Multiple web screenshots in one server session |
|
|
59
|
+
| `openuispec_screenshot_android_batch` | Visual verification | Multiple Android screenshots in one build+install cycle |
|
|
60
|
+
| `openuispec_screenshot_ios_batch` | Visual verification | Multiple iOS screenshots in one build+install cycle |
|
|
58
61
|
|
|
59
62
|
The server includes **protocol-level instructions** that trigger on UI-related requests independently of CLAUDE.md rules.
|
|
60
63
|
|
|
@@ -92,9 +95,15 @@ openuispec spec-schema <type> # Get JSON schema for a spec type
|
|
|
92
95
|
### Screenshots
|
|
93
96
|
|
|
94
97
|
```bash
|
|
95
|
-
|
|
98
|
+
# Single captures
|
|
99
|
+
openuispec screenshot --route /home [--width 1280] [--height 800] [--scale 2] [--theme dark] [--output-dir dir]
|
|
96
100
|
openuispec screenshot-android [--project-dir path] [--screen name] [--module name] [--route deeplink]
|
|
97
101
|
openuispec screenshot-ios [--project-dir path] [--screen name] [--scheme name] [--bundle-id id]
|
|
102
|
+
|
|
103
|
+
# Batch — build once, capture many
|
|
104
|
+
openuispec screenshot-web-batch --config captures.json [--scale 2] [--theme dark] [--output-dir dir]
|
|
105
|
+
openuispec screenshot-android-batch --config captures.json [--project-dir path] [--module name]
|
|
106
|
+
openuispec screenshot-ios-batch --config captures.json [--project-dir path] [--scheme name] [--bundle-id id]
|
|
98
107
|
```
|
|
99
108
|
|
|
100
109
|
Screenshot tools work with **any** project — use `--project-dir` to skip manifest lookup.
|
|
@@ -107,10 +116,36 @@ Screenshot tools work with **any** project — use `--project-dir` to skip manif
|
|
|
107
116
|
| `--bundle-id` | -- | yes | Override bundle ID (default: auto-detect) |
|
|
108
117
|
| `--route` | yes | -- | Deep link URI for navigation |
|
|
109
118
|
| `--nav` | yes | yes | UI tap steps, comma-separated |
|
|
119
|
+
| `--scale` | web | -- | Device pixel ratio for sharper screenshots (default: 2) |
|
|
110
120
|
| `--theme` | yes | yes | Force light or dark mode |
|
|
111
121
|
| `--device` | -- | yes | Simulator device name |
|
|
112
122
|
| `--output-dir` | yes | yes | Save screenshot to directory |
|
|
113
123
|
|
|
124
|
+
### Batch config
|
|
125
|
+
|
|
126
|
+
All batch commands accept `--config captures.json`. The JSON file has the same structure for all platforms:
|
|
127
|
+
|
|
128
|
+
```json
|
|
129
|
+
{
|
|
130
|
+
"project_dir": "path/to/project",
|
|
131
|
+
"output_dir": "screenshots",
|
|
132
|
+
"scale": 2,
|
|
133
|
+
"theme": "light",
|
|
134
|
+
"captures": [
|
|
135
|
+
{ "screen": "home", "route": "/home", "wait_for": 3000 },
|
|
136
|
+
{ "screen": "settings", "nav": ["Settings"], "wait_for": 5000 }
|
|
137
|
+
]
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Each capture supports:
|
|
142
|
+
- `screen`: output filename stem (required)
|
|
143
|
+
- `route`: deep link URI (Android) or URL path (web)
|
|
144
|
+
- `nav`: array of visible-text tap steps after launch (Android, iOS)
|
|
145
|
+
- `wait_for`: per-capture wait time in ms
|
|
146
|
+
- `selector`: CSS selector to screenshot a specific element (web only)
|
|
147
|
+
- `full_page`: capture full scrollable page (web only)
|
|
148
|
+
|
|
114
149
|
## Target Update Workflow
|
|
115
150
|
|
|
116
151
|
When a shared spec change needs to be applied to a target:
|
|
@@ -126,5 +161,5 @@ openuispec drift --snapshot --target ios
|
|
|
126
161
|
```
|
|
127
162
|
|
|
128
163
|
- `prepare` runs in `bootstrap` mode for first-time generation and `update` mode after a snapshot exists
|
|
129
|
-
- `drift --snapshot` is bookkeeping — it does not prove code matches the spec, and requires the output directory to exist
|
|
164
|
+
- `drift --snapshot` is bookkeeping — it does not prove code matches the spec, and requires the output directory to exist. Only run it after reviewing the generated output.
|
|
130
165
|
- Run `openuispec status` between targets to see what still needs updating
|
package/drift/index.ts
CHANGED
|
@@ -538,19 +538,28 @@ function normalizeEntry(value: string | FileEntry): FileEntry {
|
|
|
538
538
|
|
|
539
539
|
// ── snapshot ──────────────────────────────────────────────────────────
|
|
540
540
|
|
|
541
|
-
|
|
541
|
+
export interface SnapshotResult {
|
|
542
|
+
target: string;
|
|
543
|
+
snapshot_at: string;
|
|
544
|
+
files_hashed: number;
|
|
545
|
+
stubs: number;
|
|
546
|
+
state_path: string;
|
|
547
|
+
baseline: string | null;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
export function createSnapshot(cwd: string, target: string): SnapshotResult {
|
|
551
|
+
const projectDir = findProjectDir(cwd);
|
|
542
552
|
const projectName = readProjectName(projectDir);
|
|
543
553
|
const outDir = resolveOutputDir(projectDir, projectName, target);
|
|
544
554
|
if (!existsSync(outDir)) {
|
|
545
|
-
|
|
546
|
-
`
|
|
555
|
+
throw new Error(
|
|
556
|
+
`Output directory not found: ${relative(cwd, outDir)}\n` +
|
|
547
557
|
`Run code generation for "${target}" first.`
|
|
548
558
|
);
|
|
549
|
-
process.exit(1);
|
|
550
559
|
}
|
|
551
560
|
|
|
561
|
+
const manifest = readManifest(projectDir);
|
|
552
562
|
const files = discoverSpecFiles(projectDir);
|
|
553
|
-
const doc = YAML.parse(readFileSync(join(projectDir, "openuispec.yaml"), "utf-8"));
|
|
554
563
|
const baseline = captureBaseline(projectDir, files);
|
|
555
564
|
|
|
556
565
|
const entries: Record<string, FileEntry> = {};
|
|
@@ -564,7 +573,7 @@ function snapshot(cwd: string, projectDir: string, target: string): void {
|
|
|
564
573
|
}
|
|
565
574
|
|
|
566
575
|
const state: StateFile = {
|
|
567
|
-
spec_version:
|
|
576
|
+
spec_version: manifest.spec_version ?? "0.1",
|
|
568
577
|
snapshot_at: new Date().toISOString(),
|
|
569
578
|
target,
|
|
570
579
|
baseline,
|
|
@@ -573,15 +582,32 @@ function snapshot(cwd: string, projectDir: string, target: string): void {
|
|
|
573
582
|
|
|
574
583
|
const outPath = stateFilePath(projectDir, projectName, target);
|
|
575
584
|
writeFileSync(outPath, JSON.stringify(state, null, 2) + "\n");
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
+
|
|
586
|
+
return {
|
|
587
|
+
target,
|
|
588
|
+
snapshot_at: state.snapshot_at,
|
|
589
|
+
files_hashed: Object.keys(entries).length,
|
|
590
|
+
stubs: stubCount,
|
|
591
|
+
state_path: relative(cwd, outPath),
|
|
592
|
+
baseline: formatBaseline(baseline),
|
|
593
|
+
};
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
function snapshot(cwd: string, projectDir: string, target: string): void {
|
|
597
|
+
try {
|
|
598
|
+
const result = createSnapshot(cwd, target);
|
|
599
|
+
console.log(`Snapshot saved: ${result.state_path}`);
|
|
600
|
+
console.log(` ${result.files_hashed} files hashed`);
|
|
601
|
+
if (result.stubs > 0) {
|
|
602
|
+
console.log(` ${result.stubs} stubs (not tracked for drift)`);
|
|
603
|
+
}
|
|
604
|
+
console.log(` target: ${result.target}`);
|
|
605
|
+
if (result.baseline) {
|
|
606
|
+
console.log(` baseline: ${result.baseline}`);
|
|
607
|
+
}
|
|
608
|
+
} catch (err) {
|
|
609
|
+
console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
610
|
+
process.exit(1);
|
|
585
611
|
}
|
|
586
612
|
}
|
|
587
613
|
|