openuispec 0.1.2 → 0.1.4

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 CHANGED
@@ -17,11 +17,11 @@ The result: each platform feels native, but every app stays consistent because i
17
17
 
18
18
  ## How it works
19
19
 
20
- ![How OpenUISpec works](docs/images/how-it-works.jpg)
20
+ ![How OpenUISpec works](https://raw.githubusercontent.com/rsktash/openuispec/main/docs/images/how-it-works.jpg)
21
21
 
22
22
  ## Workflows
23
23
 
24
- ![OpenUISpec workflows](docs/images/workflows.png)
24
+ ![OpenUISpec workflows](https://raw.githubusercontent.com/rsktash/openuispec/main/docs/images/workflows.png)
25
25
 
26
26
  ## Key concepts
27
27
 
package/cli/init.ts CHANGED
@@ -35,13 +35,9 @@ async function askList(
35
35
  options: string[],
36
36
  defaults: string[]
37
37
  ): Promise<string[]> {
38
- console.log(`${question}`);
39
- for (const opt of options) {
40
- const mark = defaults.includes(opt) ? "[x]" : "[ ]";
41
- console.log(` ${mark} ${opt}`);
42
- }
38
+ const defaultStr = defaults.join(", ");
43
39
  const raw = (
44
- await rl.question(`Enter choices (comma-separated, enter for defaults): `)
40
+ await rl.question(`${question} [${options.join(", ")}] (${defaultStr}): `)
45
41
  ).trim();
46
42
  if (!raw) return defaults;
47
43
  return raw
@@ -122,84 +118,6 @@ api:
122
118
  `;
123
119
  }
124
120
 
125
- function starterColorTokens(): string {
126
- return `# Design tokens: Color palette
127
- brand:
128
- primary:
129
- "50": "#EEF2FF"
130
- "100": "#E0E7FF"
131
- "500": "#6366F1"
132
- "600": "#4F46E5"
133
- "900": "#312E81"
134
-
135
- surface:
136
- background: "#FFFFFF"
137
- card: "#F9FAFB"
138
- elevated: "#FFFFFF"
139
-
140
- text:
141
- primary: "#111827"
142
- secondary: "#6B7280"
143
- disabled: "#D1D5DB"
144
-
145
- semantic:
146
- success: "#10B981"
147
- warning: "#F59E0B"
148
- error: "#EF4444"
149
- info: "#3B82F6"
150
- `;
151
- }
152
-
153
- function starterTypographyTokens(): string {
154
- return `# Design tokens: Typography
155
- font_families:
156
- sans: { default: "System" }
157
-
158
- type_scale:
159
- title_lg: { size: 28, weight: bold, tracking: 0, line_height: 1.2 }
160
- title_md: { size: 22, weight: semibold, tracking: 0, line_height: 1.3 }
161
- title_sm: { size: 17, weight: semibold, tracking: 0, line_height: 1.3 }
162
- body_lg: { size: 17, weight: regular, tracking: 0, line_height: 1.5 }
163
- body_md: { size: 15, weight: regular, tracking: 0, line_height: 1.5 }
164
- body_sm: { size: 13, weight: regular, tracking: 0, line_height: 1.4 }
165
- label_lg: { size: 15, weight: medium, tracking: 0.02, line_height: 1.3 }
166
- label_md: { size: 13, weight: medium, tracking: 0.02, line_height: 1.3 }
167
- caption: { size: 11, weight: regular, tracking: 0.02, line_height: 1.3 }
168
- `;
169
- }
170
-
171
- function starterSpacingTokens(): string {
172
- return `# Design tokens: Spacing
173
- base_unit: 4
174
- platform_flex: "10%"
175
-
176
- scale:
177
- "0": 0
178
- "1": 4
179
- "2": 8
180
- "3": 12
181
- "4": 16
182
- "5": 20
183
- "6": 24
184
- "8": 32
185
- "10": 40
186
- "12": 48
187
- "16": 64
188
- `;
189
- }
190
-
191
- function starterLocale(): string {
192
- return JSON.stringify(
193
- {
194
- app: {
195
- name: "My App",
196
- },
197
- },
198
- null,
199
- 2
200
- );
201
- }
202
-
203
121
  function aiRulesBlock(specDir: string, targets: string[]): string {
204
122
  const targetList = targets.map((t) => `"${t}"`).join(", ");
205
123
  return `
@@ -261,10 +179,9 @@ export async function init(): Promise<void> {
261
179
  console.log("\nOpenUISpec — Project Setup\n");
262
180
 
263
181
  try {
264
- // 1. Project name
182
+ // 1. Project name (display name in manifest, derived from current folder)
265
183
  const cwd = process.cwd();
266
- const defaultName =
267
- cwd.split("/").pop()?.replace(/[^a-zA-Z0-9]/g, "") || "MyApp";
184
+ const defaultName = cwd.split("/").pop() || "MyApp";
268
185
  const name = await ask(rl, "Project name", defaultName);
269
186
 
270
187
  // 2. Spec directory
@@ -276,7 +193,7 @@ export async function init(): Promise<void> {
276
193
  rl,
277
194
  "\nWhich platforms?",
278
195
  allTargets,
279
- ["ios", "android"]
196
+ allTargets
280
197
  );
281
198
 
282
199
  if (targets.length === 0) {
@@ -284,16 +201,6 @@ export async function init(): Promise<void> {
284
201
  process.exit(1);
285
202
  }
286
203
 
287
- // 4. Starter tokens?
288
- const wantTokens = await ask(rl, "Include starter tokens? (y/n)", "y");
289
-
290
- // 5. AI rules?
291
- const wantRules = await ask(
292
- rl,
293
- "Add rules to CLAUDE.md and AGENTS.md? (y/n)",
294
- "y"
295
- );
296
-
297
204
  rl.close();
298
205
 
299
206
  // ── create folders ─────────────────────────────────────────────
@@ -322,27 +229,6 @@ export async function init(): Promise<void> {
322
229
  manifestTemplate(name, targets, specDir)
323
230
  );
324
231
 
325
- // ── starter tokens ─────────────────────────────────────────────
326
-
327
- if (wantTokens.toLowerCase().startsWith("y")) {
328
- writeIfMissing(join(root, "tokens", "color.yaml"), starterColorTokens());
329
- writeIfMissing(
330
- join(root, "tokens", "typography.yaml"),
331
- starterTypographyTokens()
332
- );
333
- writeIfMissing(
334
- join(root, "tokens", "spacing.yaml"),
335
- starterSpacingTokens()
336
- );
337
- }
338
-
339
- // ── starter locale ─────────────────────────────────────────────
340
-
341
- writeIfMissing(
342
- join(root, "locales", "en.json"),
343
- starterLocale() + "\n"
344
- );
345
-
346
232
  // ── .gitkeep for empty dirs ────────────────────────────────────
347
233
 
348
234
  for (const d of dirs) {
@@ -361,23 +247,21 @@ export async function init(): Promise<void> {
361
247
 
362
248
  // ── AI assistant rules ─────────────────────────────────────────
363
249
 
364
- if (wantRules.toLowerCase().startsWith("y")) {
365
- const rules = aiRulesBlock(specDir, targets);
366
-
367
- for (const file of ["CLAUDE.md", "AGENTS.md"]) {
368
- const filePath = join(cwd, file);
369
- if (existsSync(filePath)) {
370
- const existing = readFileSync(filePath, "utf-8");
371
- if (existing.includes("OpenUISpec")) {
372
- console.log(` skip ${file} (already has OpenUISpec rules)`);
373
- continue;
374
- }
375
- appendFileSync(filePath, "\n" + rules);
376
- console.log(` update ${file} (appended rules)`);
377
- } else {
378
- writeFileSync(filePath, rules.trimStart());
379
- console.log(` create ${file}`);
250
+ const rules = aiRulesBlock(specDir, targets);
251
+
252
+ for (const file of ["CLAUDE.md", "AGENTS.md"]) {
253
+ const filePath = join(cwd, file);
254
+ if (existsSync(filePath)) {
255
+ const existing = readFileSync(filePath, "utf-8");
256
+ if (existing.includes("OpenUISpec")) {
257
+ console.log(` skip ${file} (already has OpenUISpec rules)`);
258
+ continue;
380
259
  }
260
+ appendFileSync(filePath, "\n" + rules);
261
+ console.log(` update ${file} (appended rules)`);
262
+ } else {
263
+ writeFileSync(filePath, rules.trimStart());
264
+ console.log(` create ${file}`);
381
265
  }
382
266
  }
383
267
 
@@ -386,14 +270,28 @@ export async function init(): Promise<void> {
386
270
  console.log(`
387
271
  Done! Your spec project is ready at ./${specDir}/
388
272
 
389
- Next steps:
390
- 1. Edit ${specDir}/openuispec.yaml to define your data model and API
391
- 2. Add screens in ${specDir}/screens/
392
- 3. Add flows in ${specDir}/flows/
393
- 4. Generate code for your target platform
273
+ Getting started (new project):
274
+ 1. Edit ${specDir}/openuispec.yaml define your data model and API
275
+ 2. Create screens in ${specDir}/screens/ (one YAML per screen)
276
+ 3. Create flows in ${specDir}/flows/ (multi-step navigation)
277
+ 4. Ask AI to generate native code from the spec
394
278
  5. Run \`openuispec drift --snapshot --target ${targets[0]}\` to baseline
395
279
 
396
- Learn more: https://github.com/anthropics/openuispec
280
+ Getting started (existing project):
281
+ 1. Ask AI to read your existing UI code and generate spec files:
282
+ "Read src/screens/HomeScreen.swift and create ${specDir}/screens/home.yaml as status: stub"
283
+ 2. Spec screens incrementally: stub → draft → ready
284
+ 3. Only ready/draft screens are tracked by drift detection
285
+ 4. Run \`openuispec validate\` to check specs against the schema
286
+
287
+ Commands:
288
+ openuispec validate Validate spec files
289
+ openuispec drift --target ios Check for spec changes
290
+ openuispec drift --snapshot --target ios Save current state
291
+
292
+ AI rules have been added to CLAUDE.md and AGENTS.md.
293
+
294
+ Learn more: https://github.com/rsktash/openuispec
397
295
  `);
398
296
  } catch (err) {
399
297
  rl.close();
Binary file
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openuispec",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "description": "A semantic UI specification format for AI-native, platform-native app development",
@@ -13,6 +13,7 @@
13
13
  "drift/",
14
14
  "schema/",
15
15
  "spec/",
16
+ "docs/",
16
17
  "examples/",
17
18
  "README.md",
18
19
  "LICENSE"