openuispec 0.1.44 → 0.1.46

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.
Files changed (134) hide show
  1. package/README.md +79 -55
  2. package/cli/init.ts +14 -3
  3. package/examples/social-app/.mcp.json +10 -0
  4. package/examples/social-app/AGENTS.md +105 -0
  5. package/examples/social-app/CLAUDE.md +105 -0
  6. package/examples/social-app/README.md +19 -0
  7. package/examples/social-app/backend/.gitkeep +1 -0
  8. package/examples/social-app/generated/android/social-app/app/build.gradle.kts +92 -0
  9. package/examples/social-app/generated/android/social-app/app/src/main/AndroidManifest.xml +26 -0
  10. package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/AppContainer.kt +20 -0
  11. package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/MainActivity.kt +35 -0
  12. package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/SocialAppApplication.kt +13 -0
  13. package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/data/MockData.kt +98 -0
  14. package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/data/preferences/AppPreferences.kt +19 -0
  15. package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/data/preferences/DataStorePreferencesRepository.kt +68 -0
  16. package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/data/preferences/PreferencesRepository.kt +15 -0
  17. package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/model/Models.kt +34 -0
  18. package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/MainShell.kt +390 -0
  19. package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/components/Components.kt +234 -0
  20. package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/components/ContractPrimitives.kt +641 -0
  21. package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/navigation/RootComponent.kt +113 -0
  22. package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/screens/ChatDetailScreen.kt +212 -0
  23. package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/screens/CreatePostScreen.kt +113 -0
  24. package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/screens/DiscoverScreen.kt +137 -0
  25. package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/screens/EditProfileScreen.kt +180 -0
  26. package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/screens/HomeFeedScreen.kt +157 -0
  27. package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/screens/MessagesInboxScreen.kt +85 -0
  28. package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/screens/NotificationsScreen.kt +74 -0
  29. package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/screens/PostDetailScreen.kt +293 -0
  30. package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/screens/ProfileSelfScreen.kt +116 -0
  31. package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/screens/SearchResultsScreen.kt +161 -0
  32. package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/screens/SettingsScreen.kt +162 -0
  33. package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/screens/SettingsStore.kt +95 -0
  34. package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/screens/UserProfileScreen.kt +123 -0
  35. package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/theme/Color.kt +33 -0
  36. package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/theme/Shape.kt +41 -0
  37. package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/theme/Spacing.kt +20 -0
  38. package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/theme/Theme.kt +82 -0
  39. package/examples/social-app/generated/android/social-app/app/src/main/java/com/social/app/ui/theme/Type.kt +60 -0
  40. package/examples/social-app/generated/android/social-app/app/src/main/res/drawable/ic_launcher_foreground.xml +9 -0
  41. package/examples/social-app/generated/android/social-app/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +5 -0
  42. package/examples/social-app/generated/android/social-app/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +5 -0
  43. package/examples/social-app/generated/android/social-app/app/src/main/res/values/strings.xml +91 -0
  44. package/examples/social-app/generated/android/social-app/app/src/main/res/values/themes.xml +10 -0
  45. package/examples/social-app/generated/android/social-app/app/src/main/res/values-ru/strings.xml +79 -0
  46. package/examples/social-app/generated/android/social-app/app/src/main/res/values-uz/strings.xml +79 -0
  47. package/examples/social-app/generated/android/social-app/app/src/main/xml/AndroidManifest.xml +23 -0
  48. package/examples/social-app/generated/android/social-app/build.gradle.kts +6 -0
  49. package/examples/social-app/generated/android/social-app/gradle/libs.versions.toml +48 -0
  50. package/examples/social-app/generated/android/social-app/gradle/wrapper/gradle-wrapper.properties +8 -0
  51. package/examples/social-app/generated/android/social-app/gradle.properties +11 -0
  52. package/examples/social-app/generated/android/social-app/gradlew +25 -0
  53. package/examples/social-app/generated/android/social-app/settings.gradle.kts +23 -0
  54. package/examples/social-app/generated/web/social-app/index.html +12 -0
  55. package/examples/social-app/generated/web/social-app/package-lock.json +2517 -0
  56. package/examples/social-app/generated/web/social-app/package.json +27 -0
  57. package/examples/social-app/generated/web/social-app/src/app/App.tsx +58 -0
  58. package/examples/social-app/generated/web/social-app/src/components/Shell.tsx +247 -0
  59. package/examples/social-app/generated/web/social-app/src/components/cards.tsx +317 -0
  60. package/examples/social-app/generated/web/social-app/src/components/ui.tsx +328 -0
  61. package/examples/social-app/generated/web/social-app/src/flows/CreatePostFlow.tsx +86 -0
  62. package/examples/social-app/generated/web/social-app/src/i18n.tsx +59 -0
  63. package/examples/social-app/generated/web/social-app/src/lib/icons.tsx +85 -0
  64. package/examples/social-app/generated/web/social-app/src/lib/tokens.ts +70 -0
  65. package/examples/social-app/generated/web/social-app/src/lib/utils.ts +97 -0
  66. package/examples/social-app/generated/web/social-app/src/locales/en.json +67 -0
  67. package/examples/social-app/generated/web/social-app/src/locales/ru.json +67 -0
  68. package/examples/social-app/generated/web/social-app/src/locales/uz.json +67 -0
  69. package/examples/social-app/generated/web/social-app/src/main.tsx +16 -0
  70. package/examples/social-app/generated/web/social-app/src/screens/ChatDetailScreen.tsx +90 -0
  71. package/examples/social-app/generated/web/social-app/src/screens/DiscoverScreen.tsx +86 -0
  72. package/examples/social-app/generated/web/social-app/src/screens/EditProfileScreen.tsx +57 -0
  73. package/examples/social-app/generated/web/social-app/src/screens/HomeFeedScreen.tsx +113 -0
  74. package/examples/social-app/generated/web/social-app/src/screens/MessagesInboxScreen.tsx +52 -0
  75. package/examples/social-app/generated/web/social-app/src/screens/NotificationsScreen.tsx +41 -0
  76. package/examples/social-app/generated/web/social-app/src/screens/PostDetailScreen.tsx +115 -0
  77. package/examples/social-app/generated/web/social-app/src/screens/ProfileSelfScreen.tsx +57 -0
  78. package/examples/social-app/generated/web/social-app/src/screens/ProfileUserScreen.tsx +76 -0
  79. package/examples/social-app/generated/web/social-app/src/screens/SearchResultsScreen.tsx +96 -0
  80. package/examples/social-app/generated/web/social-app/src/screens/SettingsScreen.tsx +77 -0
  81. package/examples/social-app/generated/web/social-app/src/state/store.ts +592 -0
  82. package/examples/social-app/generated/web/social-app/src/styles.css +124 -0
  83. package/examples/social-app/generated/web/social-app/src/vite-env.d.ts +1 -0
  84. package/examples/social-app/generated/web/social-app/tsconfig.json +22 -0
  85. package/examples/social-app/generated/web/social-app/tsconfig.node.json +13 -0
  86. package/examples/social-app/generated/web/social-app/tsconfig.node.tsbuildinfo +1 -0
  87. package/examples/social-app/generated/web/social-app/tsconfig.tsbuildinfo +1 -0
  88. package/examples/social-app/generated/web/social-app/vite.config.d.ts +2 -0
  89. package/examples/social-app/generated/web/social-app/vite.config.js +6 -0
  90. package/examples/social-app/generated/web/social-app/vite.config.ts +7 -0
  91. package/examples/social-app/openuispec/README.md +56 -0
  92. package/examples/social-app/openuispec/contracts/.gitkeep +0 -0
  93. package/examples/social-app/openuispec/contracts/action_trigger.yaml +73 -0
  94. package/examples/social-app/openuispec/contracts/collection.yaml +43 -0
  95. package/examples/social-app/openuispec/contracts/data_display.yaml +47 -0
  96. package/examples/social-app/openuispec/contracts/feedback.yaml +49 -0
  97. package/examples/social-app/openuispec/contracts/input_field.yaml +41 -0
  98. package/examples/social-app/openuispec/contracts/nav_container.yaml +34 -0
  99. package/examples/social-app/openuispec/contracts/surface.yaml +41 -0
  100. package/examples/social-app/openuispec/flows/.gitkeep +0 -0
  101. package/examples/social-app/openuispec/flows/create_post.yaml +66 -0
  102. package/examples/social-app/openuispec/locales/.gitkeep +0 -0
  103. package/examples/social-app/openuispec/locales/en.json +67 -0
  104. package/examples/social-app/openuispec/locales/ru.json +67 -0
  105. package/examples/social-app/openuispec/locales/uz.json +67 -0
  106. package/examples/social-app/openuispec/openuispec.yaml +214 -0
  107. package/examples/social-app/openuispec/platform/.gitkeep +0 -0
  108. package/examples/social-app/openuispec/platform/android.yaml +30 -0
  109. package/examples/social-app/openuispec/platform/ios.yaml +19 -0
  110. package/examples/social-app/openuispec/platform/web.yaml +23 -0
  111. package/examples/social-app/openuispec/screens/.gitkeep +0 -0
  112. package/examples/social-app/openuispec/screens/chat_detail.yaml +53 -0
  113. package/examples/social-app/openuispec/screens/discover.yaml +78 -0
  114. package/examples/social-app/openuispec/screens/edit_profile.yaml +78 -0
  115. package/examples/social-app/openuispec/screens/home_feed.yaml +123 -0
  116. package/examples/social-app/openuispec/screens/messages_inbox.yaml +43 -0
  117. package/examples/social-app/openuispec/screens/notifications.yaml +29 -0
  118. package/examples/social-app/openuispec/screens/post_detail.yaml +86 -0
  119. package/examples/social-app/openuispec/screens/profile_self.yaml +53 -0
  120. package/examples/social-app/openuispec/screens/profile_user.yaml +60 -0
  121. package/examples/social-app/openuispec/screens/search_results.yaml +62 -0
  122. package/examples/social-app/openuispec/screens/settings.yaml +94 -0
  123. package/examples/social-app/openuispec/tokens/.gitkeep +0 -0
  124. package/examples/social-app/openuispec/tokens/color.yaml +76 -0
  125. package/examples/social-app/openuispec/tokens/elevation.yaml +31 -0
  126. package/examples/social-app/openuispec/tokens/icons.yaml +147 -0
  127. package/examples/social-app/openuispec/tokens/layout.yaml +37 -0
  128. package/examples/social-app/openuispec/tokens/motion.yaml +28 -0
  129. package/examples/social-app/openuispec/tokens/spacing.yaml +19 -0
  130. package/examples/social-app/openuispec/tokens/themes.yaml +31 -0
  131. package/examples/social-app/openuispec/tokens/typography.yaml +50 -0
  132. package/examples/social-app/package.json +12 -0
  133. package/mcp-server/index.ts +69 -0
  134. package/package.json +1 -1
package/README.md CHANGED
@@ -52,25 +52,92 @@ cd your-project
52
52
  openuispec init
53
53
  ```
54
54
 
55
- This scaffolds a spec directory, starter tokens, adds rules to `CLAUDE.md` / `AGENTS.md`, and configures the MCP server so AI assistants track spec changes automatically.
56
- Use `openuispec init --no-configure-targets` if you want to scaffold first and choose target stacks later.
55
+ This scaffolds a spec directory, starter tokens, and **configures the MCP server** for your AI coding agent (Claude Code, VS Code/Copilot, Codex). Use `openuispec init --no-configure-targets` to scaffold first and choose target stacks later.
57
56
 
58
- Then hand your spec to any AI code generator:
57
+ ## AI integration (MCP)
59
58
 
60
- > Generate a native iOS app from this OpenUISpec. Follow all contract state machines, apply token ranges for iOS, and implement navigation flows as defined. Use `platform/ios.yaml` for SwiftUI-specific overrides.
59
+ OpenUISpec is designed to be used by AI coding agents. The package includes an **MCP server** that exposes tools AI assistants call automatically during UI work no manual prompting needed.
60
+
61
+ ### How it works
62
+
63
+ ```
64
+ openuispec init → configures MCP for your agent → AI calls tools automatically
65
+ ```
66
+
67
+ When you ask your AI to "add a settings page" or "update the home feed," the MCP server:
68
+
69
+ 1. **Schema reference** — `openuispec_spec_types` and `openuispec_spec_schema` give the AI the exact format for any spec file it needs to create or edit
70
+ 2. **Before generation** — `openuispec_prepare` gives the AI your spec context, platform config, and constraints
71
+ 3. **During generation** — `openuispec_read_specs` feeds the AI the actual spec file contents as the authoritative source
72
+ 4. **After generation** — `openuispec_check` returns a concrete audit checklist derived from your spec (every contract `must_handle` item, every screen section, every locale key) and the AI verifies its code matches
73
+
74
+ This replaces the old approach of writing instructions in CLAUDE.md and hoping the AI follows them. MCP tools are called reliably because they're part of the AI's tool-calling loop, not a text instruction it can skip.
75
+
76
+ ### Setup
77
+
78
+ `openuispec init` and `openuispec update-rules` automatically configure MCP for all supported agents:
79
+
80
+ | Agent | Config file | Created automatically |
81
+ |-------|------------|----------------------|
82
+ | **Claude Code** | `.mcp.json` | Always |
83
+ | **Codex** | `.codex/config.toml` | Always |
84
+ | **VS Code / Copilot** | `.vscode/mcp.json` | If `.vscode/` exists |
85
+ | **Gemini CLI** | `.gemini/settings.json` | If `.gemini/` exists |
86
+
87
+ Manual setup (if needed):
88
+
89
+ **Claude Code** (`.mcp.json`), **VS Code / Copilot** (`.vscode/mcp.json`), **Gemini CLI** (`.gemini/settings.json`):
90
+ ```json
91
+ {
92
+ "mcpServers": {
93
+ "openuispec": {
94
+ "command": "openuispec",
95
+ "args": ["mcp"]
96
+ }
97
+ }
98
+ }
99
+ ```
100
+
101
+ **Codex** (`.codex/config.toml`):
102
+ ```toml
103
+ [mcp_servers.openuispec]
104
+ command = "openuispec"
105
+ args = ["mcp"]
106
+ ```
107
+
108
+ Or run directly: `openuispec mcp`
109
+
110
+ ### Tools
61
111
 
62
- Before platform code generation, the AI should refresh its understanding of the current target toolchain and platform conventions instead of relying on stale memory. This matters most for project formats, resource wiring, navigation APIs, packaging rules, and other implementation details that change across toolchain versions.
112
+ | Tool | When | What it does |
113
+ |------|------|-------------|
114
+ | `openuispec_spec_types` | Before creating spec files | Lists all available spec types with descriptions — discover what kinds of spec files exist |
115
+ | `openuispec_spec_schema` | Before creating/editing spec files | Returns the full JSON schema for a specific spec type — exact structure, required fields, allowed values |
116
+ | `openuispec_prepare` | Before UI code generation | Returns spec context, platform config, generation constraints |
117
+ | `openuispec_read_specs` | Before and after generation | Loads spec file contents — the authoritative source for tokens, screens, contracts |
118
+ | `openuispec_check` | After generation | Schema validation + concrete audit checklist from your spec |
119
+ | `openuispec_validate` | After spec edits | Schema-only validation, optionally filtered by group |
120
+ | `openuispec_drift` | Before updates | Detect spec drift since last snapshot, with semantic explanation |
121
+ | `openuispec_status` | Anytime | Cross-target summary: baselines, drift, next steps |
122
+
123
+ The server includes **protocol-level instructions** that trigger on UI-related requests independently of CLAUDE.md rules — so even if CLAUDE.md is buried under other project rules, the MCP enforcement still works.
124
+
125
+ ## Using without MCP
126
+
127
+ You can also use OpenUISpec with any AI by providing context manually:
128
+
129
+ > Generate a native iOS app from this OpenUISpec. Follow all contract state machines, apply token ranges for iOS, and implement navigation flows as defined. Use `platform/ios.yaml` for SwiftUI-specific overrides.
63
130
 
64
131
  For platform generation, treat these as hard output constraints:
65
132
 
66
- - Generate a valid native project or target that actually bundles every required runtime resource. Converting spec inputs into platform-native resource files is insufficient unless those files are attached to the final app target and resolve at runtime.
67
- - Do not ship unresolved resource identifiers in the UI. Raw localization keys, token references, asset names, or placeholder paths mean the generated output is incomplete.
68
- - Do not use a container or navigation primitive without defining its behavior for every supported size class and form factor. Master-detail patterns must provide a non-empty compact fallback instead of assuming large-screen behavior.
133
+ - Generate a valid native project that bundles every required runtime resource
134
+ - Do not ship unresolved resource identifiers (raw locale keys, token refs, placeholder paths)
135
+ - Define behavior for every supported size class and form factor
69
136
 
70
- See the examples for concrete reference projects:
137
+ See the examples for reference:
71
138
 
72
- - [TaskFlow](./examples/taskflow/openuispec/) for a compact reference spec covering all 7 contract families, with generated iOS, Android, and web targets under `examples/taskflow/generated/`
73
- - [Todo Orbit](./examples/todo-orbit/openuispec/) for a bilingual task app with generated iOS, Android, and web targets under `examples/todo-orbit/generated/`
139
+ - [TaskFlow](./examples/taskflow/openuispec/) compact reference spec covering all 7 contract families
140
+ - [Todo Orbit](./examples/todo-orbit/openuispec/) bilingual task app with localization, custom contracts, and generated native/web targets
74
141
 
75
142
  ## Repository structure
76
143
 
@@ -117,7 +184,7 @@ openuispec/
117
184
  │ ├── index.ts # Entry point
118
185
  │ └── init.ts # Project scaffolding + AI rules
119
186
  ├── mcp-server/ # MCP server (openuispec-mcp)
120
- │ └── index.ts # Stdio transport, 5 tools
187
+ │ └── index.ts # Stdio transport, 8 tools
121
188
  ├── check/ # Composite validation command
122
189
  │ └── index.ts # Schema + semantic + readiness
123
190
  ├── drift/ # Drift detection (spec change tracking)
@@ -245,49 +312,6 @@ to see which targets are already up to date and which ones still need to catch u
245
312
 
246
313
  `drift --snapshot` is bookkeeping. It does not prove that the target code matches the spec, and it will not create a missing target output directory for you.
247
314
 
248
- ## MCP server
249
-
250
- OpenUISpec includes an MCP (Model Context Protocol) server that exposes CLI commands as tools for AI assistants. This is the recommended way to integrate with Claude Code and other MCP-compatible clients — tools are called more reliably than CLAUDE.md instructions.
251
-
252
- ### Setup
253
-
254
- `openuispec init` automatically configures the MCP server for your coding agent. For existing projects, run `openuispec update-rules` or add the config manually:
255
-
256
- **Claude Code** (`.mcp.json`), **VS Code / Copilot** (`.vscode/mcp.json`):
257
- ```json
258
- {
259
- "mcpServers": {
260
- "openuispec": {
261
- "command": "openuispec",
262
- "args": ["mcp"]
263
- }
264
- }
265
- }
266
- ```
267
-
268
- **Codex** (`.codex/config.toml`):
269
- ```toml
270
- [mcp_servers.openuispec]
271
- command = "openuispec"
272
- args = ["mcp"]
273
- ```
274
-
275
- Or run directly: `openuispec mcp`
276
-
277
- Set `OPENUISPEC_PROJECT_DIR` to override the working directory.
278
-
279
- ### Tools
280
-
281
- | Tool | Description |
282
- |------|-------------|
283
- | `openuispec_prepare` | Build AI-ready work bundle for a target. **Call before any UI code generation.** |
284
- | `openuispec_check` | Schema validation + semantic lint + prepare readiness. Call after spec edits. |
285
- | `openuispec_status` | Cross-target summary: baselines, drift, next steps. |
286
- | `openuispec_validate` | Schema-only validation, optionally filtered by group. |
287
- | `openuispec_drift` | Detect spec drift since last snapshot, with optional semantic explanation. |
288
-
289
- All tools return structured JSON. The server includes protocol-level instructions that tell AI assistants to call `openuispec_prepare` before any UI work — this works independently of CLAUDE.md rules.
290
-
291
315
  ## Spec at a glance
292
316
 
293
317
  | Section | What it defines |
package/cli/init.ts CHANGED
@@ -268,11 +268,14 @@ When the openuispec MCP server is configured, AI assistants should use these too
268
268
 
269
269
  | Tool | When to use |
270
270
  |------|-------------|
271
+ | \`openuispec_spec_types\` | Discover available spec types and their descriptions. |
272
+ | \`openuispec_spec_schema\` | Get the full JSON schema for a specific spec type — exact structure, required fields, allowed values. |
271
273
  | \`openuispec_prepare\` | **Before any UI code generation.** Returns spec context, platform config, and constraints. |
274
+ | \`openuispec_read_specs\` | Load spec file contents — the authoritative source for tokens, screens, contracts. |
272
275
  | \`openuispec_check\` | After editing spec files. Validates schema + semantics + readiness. |
273
- | \`openuispec_status\` | To understand cross-target state (baselines, drift, next steps). |
274
276
  | \`openuispec_validate\` | Schema-only validation, optionally by group. |
275
277
  | \`openuispec_drift\` | Detect spec changes since last snapshot. |
278
+ | \`openuispec_status\` | To understand cross-target state (baselines, drift, next steps). |
276
279
 
277
280
  ## CLI commands
278
281
 
@@ -337,6 +340,11 @@ Call these MCP tools directly. They return structured JSON with everything you n
337
340
  - Navigation targets match flow definitions
338
341
  8. Report any real gaps found and fix them before finishing.
339
342
 
343
+ **Creating new spec files:**
344
+ - Call \`openuispec_spec_types\` to discover available spec types.
345
+ - Call \`openuispec_spec_schema\` with the specific type to get the full JSON schema.
346
+ - Write the spec file following the schema exactly.
347
+
340
348
  **Other tools:**
341
349
  - \`openuispec_status\` — cross-target summary, good starting point
342
350
  - \`openuispec_drift\` with \`explain: true\` — property-level spec changes
@@ -493,12 +501,14 @@ const EXPECTED_MCP_CONFIG = {
493
501
  * MCP config files by agent:
494
502
  * .mcp.json — Claude Code (project scope)
495
503
  * .vscode/mcp.json — VS Code / Copilot Chat
504
+ * .gemini/settings.json — Gemini CLI (if .gemini/ exists)
496
505
  *
497
506
  * All use the same { mcpServers: { openuispec: { command, args } } } shape.
498
507
  */
499
508
  const JSON_MCP_PATHS = [
500
509
  ".mcp.json",
501
510
  join(".vscode", "mcp.json"),
511
+ join(".gemini", "settings.json"),
502
512
  ];
503
513
 
504
514
  /** Codex uses TOML: .codex/config.toml */
@@ -534,8 +544,9 @@ function configureMcp(cwd: string, showRestart: boolean, quiet: boolean = false)
534
544
  for (const relPath of JSON_MCP_PATHS) {
535
545
  const configPath = join(cwd, relPath);
536
546
 
537
- // .vscode/mcp.json: only write if .vscode/ already exists
538
- if (relPath.startsWith(".vscode") && !existsSync(join(cwd, ".vscode"))) continue;
547
+ // Optional dirs: only write config if the parent directory already exists
548
+ const optionalParent = [".vscode", ".gemini"].find((d) => relPath.startsWith(d));
549
+ if (optionalParent && !existsSync(join(cwd, optionalParent))) continue;
539
550
 
540
551
  try {
541
552
  let config: Record<string, any> = {};
@@ -0,0 +1,10 @@
1
+ {
2
+ "mcpServers": {
3
+ "openuispec": {
4
+ "command": "openuispec",
5
+ "args": [
6
+ "mcp"
7
+ ]
8
+ }
9
+ }
10
+ }
@@ -0,0 +1,105 @@
1
+ <!-- openuispec-rules-start -->
2
+ <!-- openuispec-rules-version: 0.1.45 -->
3
+ # OpenUISpec — AI Assistant Rules
4
+ # ================================
5
+ # This project uses OpenUISpec to define UI as a semantic spec.
6
+ # Spec files are the single source of truth for all UI across platforms.
7
+ # Targets: "ios", "android", "web"
8
+
9
+ ## MANDATORY — UI work requires OpenUISpec tools
10
+
11
+ When the user's request involves UI — screens, navigation, layout, tokens, flows, localization,
12
+ or any visual/structural change — you MUST use the OpenUISpec tools before writing any code.
13
+
14
+ ### MCP Tools (use these when available)
15
+
16
+ Call these MCP tools directly. They return structured JSON with everything you need.
17
+
18
+ **Pre-generation:**
19
+ 1. Call `openuispec_prepare` with the target platform — returns spec context, platform config, constraints.
20
+ 2. Call `openuispec_read_specs` to load spec file contents. Use these as the AUTHORITATIVE source.
21
+ 3. If spec changes are needed, update spec files FIRST, then call `openuispec_check`.
22
+ 4. Generate or update the platform UI code based on the spec contents.
23
+
24
+ **Post-generation (EVERY TIME after writing UI code):**
25
+ 5. Call `openuispec_check` to validate spec integrity.
26
+ 6. Call `openuispec_read_specs` for the screens/contracts you just generated code for.
27
+ 7. Audit your generated code against the spec. For each screen, verify:
28
+ - Every field/action in the spec has a corresponding UI element
29
+ - Token values (colors, spacing, radii) match exactly — no approximations
30
+ - Contract `must_handle` states are all implemented (loading, error, empty, etc.)
31
+ - Adaptive breakpoints match the spec's `size_classes`
32
+ - Locale keys match `$t:` references
33
+ - Navigation targets match flow definitions
34
+ 8. Report any real gaps found and fix them before finishing.
35
+
36
+ **Creating new spec files:**
37
+ - Call `openuispec_spec_types` to discover available spec types.
38
+ - Call `openuispec_spec_schema` with the specific type to get the full JSON schema.
39
+ - Write the spec file following the schema exactly.
40
+
41
+ **Other tools:**
42
+ - `openuispec_status` — cross-target summary, good starting point
43
+ - `openuispec_drift` with `explain: true` — property-level spec changes
44
+ - `openuispec_validate` — schema-only validation by group
45
+
46
+ ### CLI fallback (when MCP is not available)
47
+
48
+ If MCP tools are not available, use these CLI commands with `--json` flag:
49
+ - `openuispec prepare --target <t> --json` — build AI-ready work bundle
50
+ - `openuispec check --target <t> --json` — composite validation
51
+ - `openuispec status --json` — cross-target status
52
+ - `openuispec drift --target <t> --explain --json` — semantic drift
53
+ - `openuispec validate [group...] --json` — schema validation
54
+
55
+ ### Other CLI commands
56
+ - `openuispec init` — scaffold a new spec project
57
+ - `openuispec drift --snapshot --target <t>` — snapshot current state (only after UI code is updated)
58
+ - `openuispec configure-target <t>` — configure target platform stack
59
+ - `openuispec update-rules` — update AI rules to match installed package version
60
+
61
+ ## Spec format reference
62
+
63
+ The spec format, schemas, and generation rules are in the installed `openuispec` package.
64
+ You MUST read the reference files before creating or editing spec files — do NOT guess the format.
65
+
66
+ **Find the package:** `node_modules/openuispec/` or run `npm root -g` → `<prefix>/openuispec/`.
67
+ **Online fallback:** `https://openuispec.rsteam.uz/llms-full.txt`
68
+
69
+ **Reference files (read in order):**
70
+ 1. `README.md` — schema tables, file format, root wrapper keys
71
+ 2. `spec/openuispec-v0.1.md` — full specification
72
+ 3. `examples/taskflow/openuispec/` — complete working example
73
+ 4. `schema/` — JSON Schemas for every file type
74
+
75
+ ## Spec location
76
+ - Spec root: `openuispec/` — read `openuispec/openuispec.yaml` first for actual paths.
77
+ - Default dirs: tokens/, screens/, flows/, contracts/, platform/, locales/
78
+
79
+ ## When to start from spec vs platform code
80
+
81
+ **Spec-first** (use `openuispec_prepare` or `openuispec prepare`):
82
+ - Screen structure, navigation, fields, actions, validation, data binding changes
83
+ - Token, variant, contract, flow, or localization changes
84
+ - Changes affecting multiple platforms
85
+ - Requests in product/UI terms
86
+
87
+ **Platform-first** (skip spec tools):
88
+ - Platform-specific polish (iOS-only, Android-only, web-only)
89
+ - Local bug fixes that don't alter shared semantic behavior
90
+
91
+ ## If spec directories are empty (first-time setup)
92
+
93
+ Read `spec/openuispec-v0.1.md` from the package first, then:
94
+ 1. Scan codebase for UI screens → create `openuispec/screens/<name>.yaml` as `status: stub`
95
+ 2. Extract tokens (colors, fonts, spacing) → `openuispec/tokens/`
96
+ 3. Create contract extensions → `openuispec/contracts/`
97
+ 4. Create locale files → `openuispec/locales/<locale>.json`
98
+ 5. Fill in `data_model`, `api.endpoints` in `openuispec/openuispec.yaml`
99
+
100
+ ## Rules
101
+ - Do not snapshot drift unless the UI code has also been updated.
102
+ - Do not modify generated UI without checking whether the spec must change first.
103
+ - Do not use `configure-target --defaults` as silent approval — ask the user to confirm.
104
+ - Always read spec format from the installed package, not from cached/memorized content.
105
+ <!-- openuispec-rules-end -->
@@ -0,0 +1,105 @@
1
+ <!-- openuispec-rules-start -->
2
+ <!-- openuispec-rules-version: 0.1.45 -->
3
+ # OpenUISpec — AI Assistant Rules
4
+ # ================================
5
+ # This project uses OpenUISpec to define UI as a semantic spec.
6
+ # Spec files are the single source of truth for all UI across platforms.
7
+ # Targets: "ios", "android", "web"
8
+
9
+ ## MANDATORY — UI work requires OpenUISpec tools
10
+
11
+ When the user's request involves UI — screens, navigation, layout, tokens, flows, localization,
12
+ or any visual/structural change — you MUST use the OpenUISpec tools before writing any code.
13
+
14
+ ### MCP Tools (use these when available)
15
+
16
+ Call these MCP tools directly. They return structured JSON with everything you need.
17
+
18
+ **Pre-generation:**
19
+ 1. Call `openuispec_prepare` with the target platform — returns spec context, platform config, constraints.
20
+ 2. Call `openuispec_read_specs` to load spec file contents. Use these as the AUTHORITATIVE source.
21
+ 3. If spec changes are needed, update spec files FIRST, then call `openuispec_check`.
22
+ 4. Generate or update the platform UI code based on the spec contents.
23
+
24
+ **Post-generation (EVERY TIME after writing UI code):**
25
+ 5. Call `openuispec_check` to validate spec integrity.
26
+ 6. Call `openuispec_read_specs` for the screens/contracts you just generated code for.
27
+ 7. Audit your generated code against the spec. For each screen, verify:
28
+ - Every field/action in the spec has a corresponding UI element
29
+ - Token values (colors, spacing, radii) match exactly — no approximations
30
+ - Contract `must_handle` states are all implemented (loading, error, empty, etc.)
31
+ - Adaptive breakpoints match the spec's `size_classes`
32
+ - Locale keys match `$t:` references
33
+ - Navigation targets match flow definitions
34
+ 8. Report any real gaps found and fix them before finishing.
35
+
36
+ **Creating new spec files:**
37
+ - Call `openuispec_spec_types` to discover available spec types.
38
+ - Call `openuispec_spec_schema` with the specific type to get the full JSON schema.
39
+ - Write the spec file following the schema exactly.
40
+
41
+ **Other tools:**
42
+ - `openuispec_status` — cross-target summary, good starting point
43
+ - `openuispec_drift` with `explain: true` — property-level spec changes
44
+ - `openuispec_validate` — schema-only validation by group
45
+
46
+ ### CLI fallback (when MCP is not available)
47
+
48
+ If MCP tools are not available, use these CLI commands with `--json` flag:
49
+ - `openuispec prepare --target <t> --json` — build AI-ready work bundle
50
+ - `openuispec check --target <t> --json` — composite validation
51
+ - `openuispec status --json` — cross-target status
52
+ - `openuispec drift --target <t> --explain --json` — semantic drift
53
+ - `openuispec validate [group...] --json` — schema validation
54
+
55
+ ### Other CLI commands
56
+ - `openuispec init` — scaffold a new spec project
57
+ - `openuispec drift --snapshot --target <t>` — snapshot current state (only after UI code is updated)
58
+ - `openuispec configure-target <t>` — configure target platform stack
59
+ - `openuispec update-rules` — update AI rules to match installed package version
60
+
61
+ ## Spec format reference
62
+
63
+ The spec format, schemas, and generation rules are in the installed `openuispec` package.
64
+ You MUST read the reference files before creating or editing spec files — do NOT guess the format.
65
+
66
+ **Find the package:** `node_modules/openuispec/` or run `npm root -g` → `<prefix>/openuispec/`.
67
+ **Online fallback:** `https://openuispec.rsteam.uz/llms-full.txt`
68
+
69
+ **Reference files (read in order):**
70
+ 1. `README.md` — schema tables, file format, root wrapper keys
71
+ 2. `spec/openuispec-v0.1.md` — full specification
72
+ 3. `examples/taskflow/openuispec/` — complete working example
73
+ 4. `schema/` — JSON Schemas for every file type
74
+
75
+ ## Spec location
76
+ - Spec root: `openuispec/` — read `openuispec/openuispec.yaml` first for actual paths.
77
+ - Default dirs: tokens/, screens/, flows/, contracts/, platform/, locales/
78
+
79
+ ## When to start from spec vs platform code
80
+
81
+ **Spec-first** (use `openuispec_prepare` or `openuispec prepare`):
82
+ - Screen structure, navigation, fields, actions, validation, data binding changes
83
+ - Token, variant, contract, flow, or localization changes
84
+ - Changes affecting multiple platforms
85
+ - Requests in product/UI terms
86
+
87
+ **Platform-first** (skip spec tools):
88
+ - Platform-specific polish (iOS-only, Android-only, web-only)
89
+ - Local bug fixes that don't alter shared semantic behavior
90
+
91
+ ## If spec directories are empty (first-time setup)
92
+
93
+ Read `spec/openuispec-v0.1.md` from the package first, then:
94
+ 1. Scan codebase for UI screens → create `openuispec/screens/<name>.yaml` as `status: stub`
95
+ 2. Extract tokens (colors, fonts, spacing) → `openuispec/tokens/`
96
+ 3. Create contract extensions → `openuispec/contracts/`
97
+ 4. Create locale files → `openuispec/locales/<locale>.json`
98
+ 5. Fill in `data_model`, `api.endpoints` in `openuispec/openuispec.yaml`
99
+
100
+ ## Rules
101
+ - Do not snapshot drift unless the UI code has also been updated.
102
+ - Do not modify generated UI without checking whether the spec must change first.
103
+ - Do not use `configure-target --defaults` as silent approval — ask the user to confirm.
104
+ - Always read spec format from the installed package, not from cached/memorized content.
105
+ <!-- openuispec-rules-end -->
@@ -0,0 +1,19 @@
1
+ # social-app
2
+
3
+ Test project for exercising the local [`openuispec`](../openuispec) checkout.
4
+
5
+ ## Structure
6
+
7
+ - `openuispec/` contains the spec scaffold.
8
+ - `AGENTS.md` and `CLAUDE.md` include the OpenUISpec assistant rules generated by the local CLI.
9
+
10
+ ## Commands
11
+
12
+ ```bash
13
+ npm run validate
14
+ npm run validate:semantic
15
+ npm run status
16
+ npm run openuispec -- init
17
+ ```
18
+
19
+ The scripts call the local `../openuispec` repo directly, so this project can be used without installing `openuispec` globally.
@@ -0,0 +1,92 @@
1
+ plugins {
2
+ alias(libs.plugins.android.application)
3
+ alias(libs.plugins.compose.compiler)
4
+ kotlin("plugin.serialization")
5
+ }
6
+
7
+ android {
8
+ namespace = "com.social.app"
9
+ compileSdk = 36
10
+
11
+ defaultConfig {
12
+ applicationId = "com.social.app"
13
+ minSdk = 26
14
+ targetSdk = 36
15
+ versionCode = 1
16
+ versionName = "1.0"
17
+
18
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
19
+ vectorDrawables {
20
+ useSupportLibrary = true
21
+ }
22
+ }
23
+
24
+ buildTypes {
25
+ release {
26
+ isMinifyEnabled = false
27
+ proguardFiles(
28
+ getDefaultProguardFile("proguard-android-optimize.txt"),
29
+ "proguard-rules.pro"
30
+ )
31
+ }
32
+ }
33
+ compileOptions {
34
+ sourceCompatibility = JavaVersion.VERSION_11
35
+ targetCompatibility = JavaVersion.VERSION_11
36
+ }
37
+ kotlin {
38
+ compilerOptions {
39
+ jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_11)
40
+ }
41
+ }
42
+ buildFeatures {
43
+ compose = true
44
+ }
45
+ packaging {
46
+ resources {
47
+ excludes += "/META-INF/{AL2.0,LGPL2.1}"
48
+ }
49
+ }
50
+ }
51
+
52
+ dependencies {
53
+ implementation(libs.androidx.core.ktx)
54
+ implementation(libs.androidx.lifecycle.runtime.ktx)
55
+ implementation(libs.androidx.activity.compose)
56
+ implementation(platform(libs.androidx.compose.bom))
57
+ implementation(libs.androidx.ui)
58
+ implementation(libs.androidx.ui.graphics)
59
+ implementation(libs.androidx.ui.tooling.preview)
60
+ implementation(libs.androidx.material3)
61
+ implementation(libs.androidx.material.icons.extended)
62
+ implementation(libs.google.material)
63
+ implementation(libs.coil.compose)
64
+ implementation(libs.coil.network)
65
+
66
+ // Decompose
67
+ implementation(libs.decompose)
68
+ implementation(libs.decompose.extensions.compose)
69
+ implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3")
70
+
71
+ // MVIKotlin
72
+ implementation(libs.mvikotlin)
73
+ implementation(libs.mvikotlin.main)
74
+ implementation(libs.mvikotlin.logging)
75
+ implementation("com.arkivanov.mvikotlin:mvikotlin-extensions-coroutines:4.3.0")
76
+
77
+ // Essenty
78
+ implementation(libs.essenty.lifecycle)
79
+ implementation(libs.essenty.instancekeeper)
80
+
81
+ // DataStore
82
+ implementation(libs.androidx.datastore.preferences)
83
+ implementation(libs.androidx.datastore.core)
84
+
85
+ testImplementation("junit:junit:4.13.2")
86
+ androidTestImplementation("androidx.test.ext:junit:1.2.1")
87
+ androidTestImplementation("androidx.test.espresso:espresso-core:3.6.1")
88
+ androidTestImplementation(platform(libs.androidx.compose.bom))
89
+ androidTestImplementation("androidx.compose.ui:ui-test-junit4")
90
+ debugImplementation(libs.androidx.ui.tooling)
91
+ debugImplementation("androidx.compose.ui:ui-test-manifest")
92
+ }
@@ -0,0 +1,26 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android">
3
+
4
+ <uses-permission android:name="android.permission.INTERNET" />
5
+
6
+ <application
7
+ android:name=".SocialAppApplication"
8
+ android:allowBackup="true"
9
+ android:icon="@mipmap/ic_launcher"
10
+ android:label="@string/nav_home"
11
+ android:roundIcon="@mipmap/ic_launcher_round"
12
+ android:supportsRtl="true"
13
+ android:theme="@style/Theme.SocialApp">
14
+ <activity
15
+ android:name=".MainActivity"
16
+ android:exported="true"
17
+ android:label="@string/nav_home"
18
+ android:theme="@style/Theme.SocialApp">
19
+ <intent-filter>
20
+ <action android:name="android.intent.action.MAIN" />
21
+ <category android:name="android.intent.category.LAUNCHER" />
22
+ </intent-filter>
23
+ </activity>
24
+ </application>
25
+
26
+ </manifest>
@@ -0,0 +1,20 @@
1
+ package com.social.app
2
+
3
+ import android.content.Context
4
+ import com.arkivanov.decompose.ComponentContext
5
+ import com.arkivanov.mvikotlin.core.store.StoreFactory
6
+ import com.social.app.data.preferences.DataStorePreferencesRepository
7
+ import com.social.app.data.preferences.PreferencesRepository
8
+ import com.social.app.ui.navigation.DefaultRootComponent
9
+ import com.social.app.ui.navigation.RootComponent
10
+ import com.arkivanov.mvikotlin.main.store.DefaultStoreFactory
11
+ import com.arkivanov.mvikotlin.logging.store.LoggingStoreFactory
12
+
13
+ class AppContainer(
14
+ context: Context,
15
+ ) {
16
+ val preferencesRepository: PreferencesRepository = DataStorePreferencesRepository(context.applicationContext)
17
+ val storeFactory: StoreFactory = LoggingStoreFactory(DefaultStoreFactory())
18
+
19
+ fun createRootComponent(componentContext: ComponentContext): RootComponent = DefaultRootComponent(componentContext)
20
+ }
@@ -0,0 +1,35 @@
1
+ package com.social.app
2
+
3
+ import android.os.Bundle
4
+ import androidx.activity.ComponentActivity
5
+ import androidx.activity.compose.setContent
6
+ import androidx.activity.enableEdgeToEdge
7
+ import androidx.compose.runtime.collectAsState
8
+ import androidx.compose.runtime.getValue
9
+ import com.arkivanov.decompose.defaultComponentContext
10
+ import com.social.app.data.preferences.AppPreferences
11
+ import com.social.app.ui.MainShell
12
+ import com.social.app.ui.theme.SocialAppTheme
13
+
14
+ class MainActivity : ComponentActivity() {
15
+ override fun onCreate(savedInstanceState: Bundle?) {
16
+ super.onCreate(savedInstanceState)
17
+ val appContainer = (application as SocialAppApplication).appContainer
18
+ val root = appContainer.createRootComponent(defaultComponentContext())
19
+
20
+ enableEdgeToEdge()
21
+ setContent {
22
+ val preferences by appContainer.preferencesRepository.preferences.collectAsState(initial = AppPreferences())
23
+
24
+ SocialAppTheme(
25
+ themeMode = preferences.themeMode,
26
+ ) {
27
+ MainShell(
28
+ root = root,
29
+ preferencesRepository = appContainer.preferencesRepository,
30
+ storeFactory = appContainer.storeFactory,
31
+ )
32
+ }
33
+ }
34
+ }
35
+ }
@@ -0,0 +1,13 @@
1
+ package com.social.app
2
+
3
+ import android.app.Application
4
+
5
+ class SocialAppApplication : Application() {
6
+ lateinit var appContainer: AppContainer
7
+ private set
8
+
9
+ override fun onCreate() {
10
+ super.onCreate()
11
+ appContainer = AppContainer(this)
12
+ }
13
+ }