openuispec 0.1.21 → 0.1.23
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/cli/index.ts +33 -1
- package/cli/init.ts +114 -3
- package/examples/todo-orbit/AGENTS.md +39 -86
- package/examples/todo-orbit/CLAUDE.md +7 -2
- package/examples/todo-orbit/openuispec/screens/home.yaml +1 -1
- package/examples/todo-orbit/openuispec/screens/settings.yaml +2 -0
- package/package.json +1 -1
package/cli/index.ts
CHANGED
|
@@ -9,7 +9,33 @@
|
|
|
9
9
|
* openuispec validate [group...] Validate spec files against schemas
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import { init } from "./init.js";
|
|
12
|
+
import { init, updateRules, extractRulesVersion, getPackageVersion } from "./init.js";
|
|
13
|
+
import { join } from "node:path";
|
|
14
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
15
|
+
|
|
16
|
+
function checkRulesVersion(): void {
|
|
17
|
+
const cwd = process.cwd();
|
|
18
|
+
const installed = getPackageVersion();
|
|
19
|
+
for (const file of ["CLAUDE.md", "AGENTS.md"]) {
|
|
20
|
+
const filePath = join(cwd, file);
|
|
21
|
+
if (!existsSync(filePath)) continue;
|
|
22
|
+
const rulesVersion = extractRulesVersion(filePath);
|
|
23
|
+
if (rulesVersion && rulesVersion !== installed) {
|
|
24
|
+
console.log(
|
|
25
|
+
`\n⚠ ${file} rules were generated by v${rulesVersion} but v${installed} is installed.` +
|
|
26
|
+
`\n Run: openuispec update-rules\n`
|
|
27
|
+
);
|
|
28
|
+
} else if (!rulesVersion) {
|
|
29
|
+
const content = readFileSync(filePath, "utf-8");
|
|
30
|
+
if (content.includes("OpenUISpec")) {
|
|
31
|
+
console.log(
|
|
32
|
+
`\n⚠ ${file} has OpenUISpec rules without a version marker.` +
|
|
33
|
+
`\n Run: openuispec update-rules\n`
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
13
39
|
|
|
14
40
|
async function main(): Promise<void> {
|
|
15
41
|
const [command, ...rest] = process.argv.slice(2);
|
|
@@ -19,6 +45,10 @@ async function main(): Promise<void> {
|
|
|
19
45
|
await init();
|
|
20
46
|
break;
|
|
21
47
|
|
|
48
|
+
case "update-rules":
|
|
49
|
+
updateRules();
|
|
50
|
+
break;
|
|
51
|
+
|
|
22
52
|
case "drift": {
|
|
23
53
|
const { runDrift } = await import("../drift/index.js");
|
|
24
54
|
runDrift(rest);
|
|
@@ -28,6 +58,7 @@ async function main(): Promise<void> {
|
|
|
28
58
|
case "validate": {
|
|
29
59
|
const { runValidate } = await import("../schema/validate.js");
|
|
30
60
|
runValidate(rest);
|
|
61
|
+
checkRulesVersion();
|
|
31
62
|
break;
|
|
32
63
|
}
|
|
33
64
|
|
|
@@ -39,6 +70,7 @@ OpenUISpec CLI v0.1
|
|
|
39
70
|
|
|
40
71
|
Usage:
|
|
41
72
|
openuispec init Create a new spec project
|
|
73
|
+
openuispec update-rules Update AI rules to match installed version
|
|
42
74
|
openuispec drift [--target <t>] Check for spec drift
|
|
43
75
|
openuispec drift --snapshot --target <t> Snapshot current state
|
|
44
76
|
openuispec validate [group...] Validate spec files
|
package/cli/init.ts
CHANGED
|
@@ -15,7 +15,8 @@ import {
|
|
|
15
15
|
existsSync,
|
|
16
16
|
appendFileSync,
|
|
17
17
|
} from "node:fs";
|
|
18
|
-
import { join, relative } from "node:path";
|
|
18
|
+
import { join, relative, dirname } from "node:path";
|
|
19
|
+
import { fileURLToPath } from "node:url";
|
|
19
20
|
|
|
20
21
|
// ── prompts ──────────────────────────────────────────────────────────
|
|
21
22
|
|
|
@@ -64,6 +65,21 @@ function writeIfMissing(path: string, content: string): boolean {
|
|
|
64
65
|
return true;
|
|
65
66
|
}
|
|
66
67
|
|
|
68
|
+
// ── version ─────────────────────────────────────────────────────────
|
|
69
|
+
|
|
70
|
+
const RULES_START_MARKER = "<!-- openuispec-rules-start -->";
|
|
71
|
+
const RULES_END_MARKER = "<!-- openuispec-rules-end -->";
|
|
72
|
+
|
|
73
|
+
function getPackageVersion(): string {
|
|
74
|
+
const pkgPath = join(
|
|
75
|
+
dirname(fileURLToPath(import.meta.url)),
|
|
76
|
+
"..",
|
|
77
|
+
"package.json"
|
|
78
|
+
);
|
|
79
|
+
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
80
|
+
return pkg.version;
|
|
81
|
+
}
|
|
82
|
+
|
|
67
83
|
// ── templates ────────────────────────────────────────────────────────
|
|
68
84
|
|
|
69
85
|
function manifestTemplate(
|
|
@@ -175,7 +191,10 @@ Docs: https://openuispec.rsteam.uz
|
|
|
175
191
|
|
|
176
192
|
function aiRulesBlock(specDir: string, targets: string[]): string {
|
|
177
193
|
const targetList = targets.map((t) => `"${t}"`).join(", ");
|
|
194
|
+
const version = getPackageVersion();
|
|
178
195
|
return `
|
|
196
|
+
${RULES_START_MARKER}
|
|
197
|
+
<!-- openuispec-rules-version: ${version} -->
|
|
179
198
|
# OpenUISpec — AI Assistant Rules
|
|
180
199
|
# ================================
|
|
181
200
|
# This project uses OpenUISpec to define UI as a semantic spec.
|
|
@@ -242,18 +261,110 @@ This means the project has existing UI code but hasn't been specced yet. Your jo
|
|
|
242
261
|
|
|
243
262
|
## After modifying spec files
|
|
244
263
|
1. Run \`openuispec validate\` to check specs against the schema.
|
|
245
|
-
2.
|
|
246
|
-
3. Run \`openuispec drift
|
|
264
|
+
2. **Update the generated code** for each affected platform to match the new spec.
|
|
265
|
+
3. Run \`openuispec drift --snapshot --target <target>\` to baseline the updated state.
|
|
266
|
+
4. Run \`openuispec drift\` to verify no untracked drift remains.
|
|
247
267
|
|
|
248
268
|
## CLI commands
|
|
249
269
|
- \`openuispec init\` — scaffold a new spec project
|
|
250
270
|
- \`openuispec validate [group...]\` — validate spec files against schemas
|
|
251
271
|
- \`openuispec drift --target <t>\` — check for spec drift
|
|
252
272
|
- \`openuispec drift --snapshot --target <t>\` — snapshot current state
|
|
273
|
+
- \`openuispec update-rules\` — update AI rules to match installed package version
|
|
253
274
|
- \`openuispec drift --all\` — include stubs in drift check
|
|
275
|
+
${RULES_END_MARKER}
|
|
254
276
|
`;
|
|
255
277
|
}
|
|
256
278
|
|
|
279
|
+
// ── update-rules ────────────────────────────────────────────────────
|
|
280
|
+
|
|
281
|
+
export function updateRules(): void {
|
|
282
|
+
const cwd = process.cwd();
|
|
283
|
+
const version = getPackageVersion();
|
|
284
|
+
|
|
285
|
+
// Detect spec dir from existing openuispec.yaml
|
|
286
|
+
let specDir = "openuispec";
|
|
287
|
+
for (const candidate of ["openuispec", "spec", "."]) {
|
|
288
|
+
if (existsSync(join(cwd, candidate, "openuispec.yaml"))) {
|
|
289
|
+
specDir = candidate;
|
|
290
|
+
break;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// Detect targets from manifest
|
|
295
|
+
let targets = ["ios", "android", "web"];
|
|
296
|
+
try {
|
|
297
|
+
const manifest = readFileSync(
|
|
298
|
+
join(cwd, specDir, "openuispec.yaml"),
|
|
299
|
+
"utf-8"
|
|
300
|
+
);
|
|
301
|
+
const match = manifest.match(/targets:\s*\[([^\]]+)\]/);
|
|
302
|
+
if (match) {
|
|
303
|
+
targets = match[1].split(",").map((t) => t.trim().replace(/['"]/g, ""));
|
|
304
|
+
}
|
|
305
|
+
} catch {}
|
|
306
|
+
|
|
307
|
+
const rules = aiRulesBlock(specDir, targets);
|
|
308
|
+
let updated = 0;
|
|
309
|
+
|
|
310
|
+
for (const file of ["CLAUDE.md", "AGENTS.md"]) {
|
|
311
|
+
const filePath = join(cwd, file);
|
|
312
|
+
if (!existsSync(filePath)) continue;
|
|
313
|
+
|
|
314
|
+
const content = readFileSync(filePath, "utf-8");
|
|
315
|
+
|
|
316
|
+
// Try marker-based replacement first
|
|
317
|
+
const startIdx = content.indexOf(RULES_START_MARKER);
|
|
318
|
+
const endIdx = content.indexOf(RULES_END_MARKER);
|
|
319
|
+
|
|
320
|
+
if (startIdx !== -1 && endIdx !== -1) {
|
|
321
|
+
const before = content.slice(0, startIdx);
|
|
322
|
+
const after = content.slice(endIdx + RULES_END_MARKER.length);
|
|
323
|
+
writeFileSync(filePath, before + rules.trimStart().trimEnd() + after);
|
|
324
|
+
console.log(` updated ${file} (v${version})`);
|
|
325
|
+
updated++;
|
|
326
|
+
continue;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// Fallback: find the OpenUISpec rules block by header pattern
|
|
330
|
+
// The block runs from the header to EOF (it's always the last content)
|
|
331
|
+
const headerIdx = content.indexOf("# OpenUISpec — AI Assistant Rules");
|
|
332
|
+
if (headerIdx !== -1) {
|
|
333
|
+
const before = content.slice(0, headerIdx);
|
|
334
|
+
const newContent = before + rules.trimStart().trimEnd() + "\n";
|
|
335
|
+
writeFileSync(filePath, newContent);
|
|
336
|
+
console.log(` updated ${file} (v${version}, migrated to markers)`);
|
|
337
|
+
updated++;
|
|
338
|
+
continue;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
console.log(` skip ${file} (no OpenUISpec rules block found)`);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
if (updated === 0) {
|
|
345
|
+
console.log(
|
|
346
|
+
"No CLAUDE.md or AGENTS.md with OpenUISpec rules found.\nRun `openuispec init` first."
|
|
347
|
+
);
|
|
348
|
+
} else {
|
|
349
|
+
console.log(`\nAI rules updated to v${version}`);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Extract the rules version from a CLAUDE.md / AGENTS.md file.
|
|
355
|
+
* Returns null if no version marker is found.
|
|
356
|
+
*/
|
|
357
|
+
export function extractRulesVersion(filePath: string): string | null {
|
|
358
|
+
if (!existsSync(filePath)) return null;
|
|
359
|
+
const content = readFileSync(filePath, "utf-8");
|
|
360
|
+
const match = content.match(
|
|
361
|
+
/<!-- openuispec-rules-version:\s*([^\s]+)\s*-->/
|
|
362
|
+
);
|
|
363
|
+
return match ? match[1] : null;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
export { getPackageVersion };
|
|
367
|
+
|
|
257
368
|
// ── main ─────────────────────────────────────────────────────────────
|
|
258
369
|
|
|
259
370
|
export async function init(): Promise<void> {
|
|
@@ -1,29 +1,52 @@
|
|
|
1
|
+
<!-- openuispec-rules-start -->
|
|
2
|
+
<!-- openuispec-rules-version: 0.1.22 -->
|
|
1
3
|
# OpenUISpec — AI Assistant Rules
|
|
2
4
|
# ================================
|
|
3
5
|
# This project uses OpenUISpec to define UI as a semantic spec.
|
|
4
6
|
# Spec files are the single source of truth for all UI across platforms.
|
|
5
7
|
# Targets: "ios", "android", "web"
|
|
6
8
|
|
|
9
|
+
## IMPORTANT — Read the specification before working with spec files
|
|
10
|
+
|
|
11
|
+
The spec format, file schemas, and generation rules are defined in the installed `openuispec` package.
|
|
12
|
+
You MUST read the reference files listed below before creating, editing, or generating from any spec file.
|
|
13
|
+
Do NOT guess the file format — skipping this step will produce invalid YAML that fails validation.
|
|
14
|
+
|
|
15
|
+
**Find the package in this order:**
|
|
16
|
+
1. `node_modules/openuispec/` (project dependency)
|
|
17
|
+
2. Run `npm root -g` → `<prefix>/openuispec/` (global install)
|
|
18
|
+
3. Online: `https://openuispec.rsteam.uz/llms-full.txt` (if not installed)
|
|
19
|
+
|
|
20
|
+
**Reference files inside the package (read in this order):**
|
|
21
|
+
1. `README.md` — schema tables, file format reference, root wrapper keys
|
|
22
|
+
2. `spec/openuispec-v0.1.md` — full specification (contracts, layout, expressions, adaptive, etc.)
|
|
23
|
+
3. `examples/taskflow/` — complete working example with all file types
|
|
24
|
+
4. `schema/` — JSON Schemas for every file type
|
|
25
|
+
|
|
26
|
+
These files are updated with each package version. Always read from the installed package,
|
|
27
|
+
not from cached or memorized content, to ensure you use the latest spec.
|
|
28
|
+
|
|
7
29
|
## What is OpenUISpec
|
|
8
30
|
OpenUISpec is a YAML-based spec format that describes an app's UI semantically — tokens, screens, flows, and platform overrides. AI reads the spec and generates native code (SwiftUI, Compose, React). AI reads native code and updates the spec. The spec is the sync layer between platforms.
|
|
9
31
|
|
|
10
32
|
## Spec location
|
|
11
33
|
- Spec root: `openuispec/`
|
|
12
34
|
- Manifest: `openuispec/openuispec.yaml` — always read this first.
|
|
13
|
-
- Tokens: `openuispec/tokens/`
|
|
14
|
-
- Screens: `openuispec/screens/`
|
|
15
|
-
- Flows: `openuispec/flows/`
|
|
16
|
-
- Contracts: `openuispec/contracts/`
|
|
17
|
-
- Platform: `openuispec/platform/`
|
|
18
|
-
- Locales: `openuispec/locales/`
|
|
35
|
+
- Tokens: `openuispec/tokens/`
|
|
36
|
+
- Screens: `openuispec/screens/`
|
|
37
|
+
- Flows: `openuispec/flows/`
|
|
38
|
+
- Contracts: `openuispec/contracts/`
|
|
39
|
+
- Platform: `openuispec/platform/`
|
|
40
|
+
- Locales: `openuispec/locales/`
|
|
19
41
|
|
|
20
|
-
**Note:** These are the default paths. Actual paths are in `includes:` in `openuispec.yaml` and may use relative paths
|
|
42
|
+
**Note:** These are the default paths. Actual paths are in `includes:` in `openuispec.yaml` and may use relative paths. Always read `openuispec.yaml` to find the real directories.
|
|
21
43
|
|
|
22
44
|
## If spec directories are empty (first-time setup)
|
|
23
45
|
This means the project has existing UI code but hasn't been specced yet. Your job:
|
|
24
46
|
|
|
25
|
-
1. **
|
|
26
|
-
2. **
|
|
47
|
+
1. **Read the spec first** — find and read `spec/openuispec-v0.1.md` from the installed package.
|
|
48
|
+
2. **Find existing screens** — scan the codebase for UI screen files.
|
|
49
|
+
3. **Create stubs** — for each screen, create `openuispec/screens/<name>.yaml` with:
|
|
27
50
|
```yaml
|
|
28
51
|
screen_name:
|
|
29
52
|
semantic: "Brief description of what this screen does"
|
|
@@ -31,14 +54,8 @@ This means the project has existing UI code but hasn't been specced yet. Your jo
|
|
|
31
54
|
layout:
|
|
32
55
|
type: scroll_vertical
|
|
33
56
|
```
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
5. **Spec screens on demand** — when the user asks to spec a screen, read the native code, create a full spec, and change `status: draft` → `ready`.
|
|
37
|
-
|
|
38
|
-
## Screen and flow status
|
|
39
|
-
- `stub` — placeholder, not yet specced. Drift detection skips these.
|
|
40
|
-
- `draft` — actively being specced. Tracked by drift.
|
|
41
|
-
- `ready` — fully specified (default if omitted). Tracked by drift.
|
|
57
|
+
4. **Extract tokens** — scan for colors, fonts, spacing and create files in `openuispec/tokens/`.
|
|
58
|
+
5. **Update the manifest** — fill in `data_model` and `api.endpoints` in `openuispec/openuispec.yaml`.
|
|
42
59
|
|
|
43
60
|
## Making UI changes
|
|
44
61
|
1. Read the relevant spec files before modifying any UI code.
|
|
@@ -49,79 +66,15 @@ This means the project has existing UI code but hasn't been specced yet. Your jo
|
|
|
49
66
|
|
|
50
67
|
## After modifying spec files
|
|
51
68
|
1. Run `openuispec validate` to check specs against the schema.
|
|
52
|
-
2.
|
|
53
|
-
3. Run `openuispec drift
|
|
54
|
-
|
|
55
|
-
## Learning OpenUISpec — where to find the docs
|
|
56
|
-
All documentation is in the installed `openuispec` package. Search in this order:
|
|
57
|
-
1. **Local:** `node_modules/openuispec/` (project dependency)
|
|
58
|
-
2. **Global:** run `npm root -g` to get the global prefix, then look in `<prefix>/openuispec/`
|
|
59
|
-
3. **Online fallback:** if not installed, fetch from:
|
|
60
|
-
- `https://openuispec.rsteam.uz/llms-full.txt` — complete spec + all JSON schemas
|
|
61
|
-
- `https://openuispec.rsteam.uz/llms.txt` — concise summary with links
|
|
62
|
-
|
|
63
|
-
Inside the package:
|
|
64
|
-
1. **Full specification:** `spec/openuispec-v0.1.md` — the complete spec (read this to understand the format)
|
|
65
|
-
2. **Example app:** `examples/taskflow/` — a complete working app with all file types
|
|
66
|
-
3. **JSON Schemas:** `schema/` — validation schemas that define the exact structure of every file type
|
|
67
|
-
|
|
68
|
-
## Token file structure — root wrapper key required
|
|
69
|
-
Every token file must have a single root key matching the token type. Do NOT put properties at the top level.
|
|
70
|
-
- `tokens/color.yaml` → root key: `color`
|
|
71
|
-
- `tokens/typography.yaml` → root key: `typography`
|
|
72
|
-
- `tokens/spacing.yaml` → root key: `spacing`
|
|
73
|
-
- `tokens/elevation.yaml` → root key: `elevation`
|
|
74
|
-
- `tokens/motion.yaml` → root key: `motion`
|
|
75
|
-
- `tokens/layout.yaml` → root key: `layout`
|
|
76
|
-
- `tokens/themes.yaml` → root key: `themes`
|
|
77
|
-
- `tokens/icons.yaml` → root key: `icons`
|
|
78
|
-
|
|
79
|
-
## File formats and schemas — read before creating spec files
|
|
80
|
-
Before creating or editing any spec file, read the corresponding JSON Schema. Do not guess the file format.
|
|
81
|
-
|
|
82
|
-
| File | Schema (in `schema/` inside the installed package) | Root key |
|
|
83
|
-
|------|--------|----------|
|
|
84
|
-
| `openuispec.yaml` | `openuispec.schema.json` | `spec_version` |
|
|
85
|
-
| `screens/*.yaml` | `screen.schema.json` | `<screen_id>` |
|
|
86
|
-
| `flows/*.yaml` | `flow.schema.json` | `<flow_id>` |
|
|
87
|
-
| `platform/*.yaml` | `platform.schema.json` | `platform` |
|
|
88
|
-
| `locales/*.json` | `locale.schema.json` | (object) |
|
|
89
|
-
| `contracts/x_*.yaml` | `custom-contract.schema.json` | `contract` |
|
|
90
|
-
| `tokens/color.yaml` | `tokens/color.schema.json` | `color` |
|
|
91
|
-
| `tokens/typography.yaml` | `tokens/typography.schema.json` | `typography` |
|
|
92
|
-
| `tokens/spacing.yaml` | `tokens/spacing.schema.json` | `spacing` |
|
|
93
|
-
| `tokens/elevation.yaml` | `tokens/elevation.schema.json` | `elevation` |
|
|
94
|
-
| `tokens/motion.yaml` | `tokens/motion.schema.json` | `motion` |
|
|
95
|
-
| `tokens/layout.yaml` | `tokens/layout.schema.json` | `layout` |
|
|
96
|
-
| `tokens/themes.yaml` | `tokens/themes.schema.json` | `themes` |
|
|
97
|
-
| `tokens/icons.yaml` | `tokens/icons.schema.json` | `icons` |
|
|
98
|
-
|
|
99
|
-
Shared type definitions (actions, data-binding, adaptive, validation, common) are in `schema/defs/`.
|
|
100
|
-
|
|
101
|
-
Workflow: read the schema → read an example from `examples/taskflow/` → create the YAML → run `openuispec validate`.
|
|
102
|
-
|
|
103
|
-
## Spec format reference
|
|
104
|
-
- 7 contract families: nav_container, surface, action_trigger, input_field, data_display, collection, feedback
|
|
105
|
-
- Custom contracts: prefixed with `x_` (e.g., `x_media_player`)
|
|
106
|
-
- Data binding: `$data:`, `$state:`, `$param:`, `$t:` prefixes
|
|
107
|
-
- Actions: typed objects (navigate, api_call, set_state, confirm, sequence, feedback, etc.)
|
|
108
|
-
- Adaptive layout: size classes (compact, regular, expanded) with per-section overrides
|
|
109
|
-
|
|
110
|
-
## Output directories
|
|
111
|
-
Drift tracks spec changes per target. By default state is stored in `generated/<target>/<project>/`.
|
|
112
|
-
To map targets to actual code directories, set `generation.output_dir` in `openuispec.yaml`:
|
|
113
|
-
```yaml
|
|
114
|
-
generation:
|
|
115
|
-
output_dir:
|
|
116
|
-
web: "../web-ui/"
|
|
117
|
-
android: "../kmp-ui/"
|
|
118
|
-
ios: "../kmp-ui/iosApp/"
|
|
119
|
-
```
|
|
120
|
-
Paths are relative to `openuispec.yaml`. The `.openuispec-state.json` file is stored inside each output directory.
|
|
69
|
+
2. **Update the generated code** for each affected platform to match the new spec.
|
|
70
|
+
3. Run `openuispec drift --snapshot --target <target>` to baseline the updated state.
|
|
71
|
+
4. Run `openuispec drift` to verify no untracked drift remains.
|
|
121
72
|
|
|
122
73
|
## CLI commands
|
|
123
74
|
- `openuispec init` — scaffold a new spec project
|
|
124
75
|
- `openuispec validate [group...]` — validate spec files against schemas
|
|
125
76
|
- `openuispec drift --target <t>` — check for spec drift
|
|
126
77
|
- `openuispec drift --snapshot --target <t>` — snapshot current state
|
|
78
|
+
- `openuispec update-rules` — update AI rules to match installed package version
|
|
127
79
|
- `openuispec drift --all` — include stubs in drift check
|
|
80
|
+
<!-- openuispec-rules-end -->
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
<!-- openuispec-rules-start -->
|
|
2
|
+
<!-- openuispec-rules-version: 0.1.22 -->
|
|
1
3
|
# OpenUISpec — AI Assistant Rules
|
|
2
4
|
# ================================
|
|
3
5
|
# This project uses OpenUISpec to define UI as a semantic spec.
|
|
@@ -64,12 +66,15 @@ This means the project has existing UI code but hasn't been specced yet. Your jo
|
|
|
64
66
|
|
|
65
67
|
## After modifying spec files
|
|
66
68
|
1. Run `openuispec validate` to check specs against the schema.
|
|
67
|
-
2.
|
|
68
|
-
3. Run `openuispec drift
|
|
69
|
+
2. **Update the generated code** for each affected platform to match the new spec.
|
|
70
|
+
3. Run `openuispec drift --snapshot --target <target>` to baseline the updated state.
|
|
71
|
+
4. Run `openuispec drift` to verify no untracked drift remains.
|
|
69
72
|
|
|
70
73
|
## CLI commands
|
|
71
74
|
- `openuispec init` — scaffold a new spec project
|
|
72
75
|
- `openuispec validate [group...]` — validate spec files against schemas
|
|
73
76
|
- `openuispec drift --target <t>` — check for spec drift
|
|
74
77
|
- `openuispec drift --snapshot --target <t>` — snapshot current state
|
|
78
|
+
- `openuispec update-rules` — update AI rules to match installed package version
|
|
75
79
|
- `openuispec drift --all` — include stubs in drift check
|
|
80
|
+
<!-- openuispec-rules-end -->
|
|
@@ -122,7 +122,7 @@ home:
|
|
|
122
122
|
item_variant: compact
|
|
123
123
|
item_props_map:
|
|
124
124
|
title: "item.title"
|
|
125
|
-
subtitle: "{item.due_date | format:date_relative}"
|
|
125
|
+
subtitle: "{item.due_date | format:date_relative.abbreviated}"
|
|
126
126
|
leading:
|
|
127
127
|
contract: input_field
|
|
128
128
|
input_type: checkbox
|
|
@@ -61,6 +61,7 @@ settings:
|
|
|
61
61
|
children:
|
|
62
62
|
- contract: input_field
|
|
63
63
|
input_type: select
|
|
64
|
+
render_hint: segmented
|
|
64
65
|
props:
|
|
65
66
|
label: "$t:settings.language"
|
|
66
67
|
icon: { ref: "globe", position: leading }
|
|
@@ -71,6 +72,7 @@ settings:
|
|
|
71
72
|
|
|
72
73
|
- contract: input_field
|
|
73
74
|
input_type: select
|
|
75
|
+
render_hint: segmented
|
|
74
76
|
props:
|
|
75
77
|
label: "$t:settings.theme"
|
|
76
78
|
options:
|