@famgia/omnify 1.0.15 → 1.0.19

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 (2) hide show
  1. package/package.json +8 -8
  2. package/scripts/postinstall.js +144 -292
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@famgia/omnify",
3
- "version": "1.0.15",
3
+ "version": "1.0.19",
4
4
  "description": "Schema-driven database migration system with TypeScript types and Laravel migrations",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -24,13 +24,13 @@
24
24
  "README.md"
25
25
  ],
26
26
  "dependencies": {
27
- "@famgia/omnify-cli": "0.0.14",
28
- "@famgia/omnify-core": "0.0.14",
29
- "@famgia/omnify-types": "0.0.10",
30
- "@famgia/omnify-laravel": "0.0.19",
31
- "@famgia/omnify-typescript": "0.0.1",
32
- "@famgia/omnify-atlas": "0.0.10",
33
- "@famgia/omnify-mcp": "0.0.2"
27
+ "@famgia/omnify-cli": "0.0.18",
28
+ "@famgia/omnify-core": "0.0.18",
29
+ "@famgia/omnify-types": "0.0.14",
30
+ "@famgia/omnify-laravel": "0.0.24",
31
+ "@famgia/omnify-typescript": "0.0.6",
32
+ "@famgia/omnify-atlas": "0.0.14",
33
+ "@famgia/omnify-mcp": "0.0.6"
34
34
  },
35
35
  "keywords": [
36
36
  "omnify",
@@ -4,63 +4,42 @@ import fs from 'fs';
4
4
  import path from 'path';
5
5
  import os from 'os';
6
6
 
7
- // Main CLAUDE.md content (used when creating new file)
8
- const CLAUDE_MD_CONTENT = `# Omnify Schema Rules
7
+ // Content for CLAUDE.md
8
+ const CLAUDE_MD_SECTION = `## Omnify
9
9
 
10
- This project uses **Omnify** for schema-driven code generation. When creating or modifying schemas, follow these rules.
10
+ This project uses Omnify for schema-driven code generation.
11
11
 
12
- ## Quick Reference
13
-
14
- For detailed documentation, see:
15
- - \`.claude/omnify/schema-guide.md\` - Complete schema format guide
16
- - \`.claude/omnify/examples.md\` - Example schemas
17
-
18
- ## Schema Location
19
-
20
- Schemas are stored in \`schemas/\` directory with \`.yaml\` extension.
21
-
22
- ## Basic Schema Format
23
-
24
- \`\`\`yaml
25
- # yaml-language-server: $schema=https://raw.githubusercontent.com/ecsol/omnify-ts/main/packages/types/schemas/omnify-schema.json
26
- name: ModelName
27
- displayName:
28
- ja: 日本語名
29
- en: English Name
30
- options:
31
- softDelete: true
32
- timestamps: true
33
- properties:
34
- propertyName:
35
- type: String
36
- displayName:
37
- ja: プロパティ名
38
- en: Property Name
39
- \`\`\`
40
-
41
- ## Commands
12
+ **Documentation**: \`.claude/omnify/\`
13
+ - \`schema-guide.md\` - Schema format and property types
14
+ - \`config-guide.md\` - Configuration (omnify.config.ts)
15
+ - \`laravel-guide.md\` - Laravel generator (if installed)
16
+ - \`typescript-guide.md\` - TypeScript generator (if installed)
42
17
 
18
+ **Commands**:
43
19
  - \`npx omnify generate\` - Generate code from schemas
44
- - \`npx omnify validate\` - Validate all schemas
20
+ - \`npx omnify validate\` - Validate schemas
45
21
  `;
46
22
 
47
- // Content to append when CLAUDE.md already exists
48
- const CLAUDE_MD_APPEND = `
49
- ---
23
+ // Cursor rules content
24
+ const CURSORRULES_CONTENT = `# Omnify Schema Rules
50
25
 
51
- ## Omnify Schema Integration
26
+ This project uses Omnify for schema-driven code generation.
27
+ Schemas are in \`schemas/\` directory with \`.yaml\` extension.
52
28
 
53
- This project uses **Omnify** for schema-driven code generation.
29
+ For detailed documentation, read these files:
30
+ - .claude/omnify/schema-guide.md - Base schema format
31
+ - .claude/omnify/config-guide.md - Configuration (omnify.config.ts)
32
+ - .claude/omnify/laravel-guide.md - Laravel generator (if exists)
33
+ - .claude/omnify/typescript-guide.md - TypeScript generator (if exists)
54
34
 
55
- For detailed Omnify documentation, see:
56
- - \`.claude/omnify/schema-guide.md\` - Complete schema format guide
57
- - \`.claude/omnify/examples.md\` - Example schemas
58
-
59
- ### Quick Commands
60
- - \`npx omnify generate\` - Generate code from schemas
61
- - \`npx omnify validate\` - Validate all schemas
35
+ Commands:
36
+ - npx omnify generate - Generate code from schemas
37
+ - npx omnify validate - Validate all schemas
62
38
  `;
63
39
 
40
+ // Marker to check if Omnify section exists
41
+ const OMNIFY_MARKER = '.claude/omnify/';
42
+
64
43
  // Schema guide skill file
65
44
  const SCHEMA_GUIDE_CONTENT = `# Omnify Schema Format Guide
66
45
 
@@ -71,7 +50,7 @@ All schemas are stored in \`schemas/\` directory with \`.yaml\` extension.
71
50
  ## Object Schema Structure
72
51
 
73
52
  \`\`\`yaml
74
- # yaml-language-server: $schema=https://raw.githubusercontent.com/ecsol/omnify-ts/main/packages/types/schemas/omnify-schema.json
53
+ # yaml-language-server: $schema=https://unpkg.com/@famgia/omnify-types/schemas/omnify-schema.json
75
54
  name: ModelName # Required: PascalCase
76
55
  kind: object # Optional: 'object' (default) or 'enum'
77
56
  displayName: # Optional: i18n display name
@@ -208,242 +187,95 @@ If Omnify MCP is configured, these tools are available:
208
187
  - \`omnify_get_examples\` - Example schemas
209
188
  `;
210
189
 
211
- // Examples skill file
212
- const EXAMPLES_CONTENT = `# Omnify Schema Examples
190
+ // Config guide skill file
191
+ const CONFIG_GUIDE_CONTENT = `# Omnify Configuration Guide
213
192
 
214
- ## User Schema
193
+ ## Configuration File
215
194
 
216
- \`\`\`yaml
217
- name: User
218
- displayName:
219
- ja: ユーザー
220
- en: User
221
- options:
222
- softDelete: true
223
- timestamps: true
224
- properties:
225
- name:
226
- type: String
227
- displayName:
228
- ja: 名前
229
- en: Name
230
- required: true
231
- maxLength: 255
232
- email:
233
- type: String
234
- displayName:
235
- ja: メールアドレス
236
- en: Email
237
- required: true
238
- unique: true
239
- password:
240
- type: String
241
- displayName:
242
- ja: パスワード
243
- en: Password
244
- required: true
245
- role:
246
- type: EnumRef
247
- enum: UserRole
248
- default: user
249
- posts:
250
- type: Association
251
- relation: OneToMany
252
- target: Post
253
- mappedBy: author
254
- \`\`\`
255
-
256
- ## Post Schema
257
-
258
- \`\`\`yaml
259
- name: Post
260
- displayName:
261
- ja: 投稿
262
- en: Post
263
- group: blog
264
- options:
265
- softDelete: true
266
- timestamps: true
267
- properties:
268
- title:
269
- type: String
270
- displayName:
271
- ja: タイトル
272
- en: Title
273
- required: true
274
- maxLength: 255
275
- content:
276
- type: LongText
277
- displayName:
278
- ja: 内容
279
- en: Content
280
- status:
281
- type: EnumRef
282
- enum: PostStatus
283
- default: draft
284
- publishedAt:
285
- type: DateTime
286
- displayName:
287
- ja: 公開日時
288
- en: Published At
289
- author:
290
- type: Association
291
- relation: ManyToOne
292
- target: User
293
- onDelete: CASCADE
294
- category:
295
- type: Association
296
- relation: ManyToOne
297
- target: Category
298
- onDelete: SET_NULL
299
- tags:
300
- type: Association
301
- relation: ManyToMany
302
- target: Tag
303
- \`\`\`
195
+ Create \`omnify.config.ts\` in project root:
304
196
 
305
- ## Category Schema
197
+ \`\`\`typescript
198
+ import { defineConfig } from '@famgia/omnify';
306
199
 
307
- \`\`\`yaml
308
- name: Category
309
- displayName:
310
- ja: カテゴリー
311
- en: Category
312
- group: blog
313
- options:
314
- timestamps: true
315
- properties:
316
- name:
317
- type: String
318
- displayName:
319
- ja: カテゴリー名
320
- en: Category Name
321
- required: true
322
- maxLength: 100
323
- slug:
324
- type: String
325
- displayName:
326
- ja: スラッグ
327
- en: Slug
328
- required: true
329
- unique: true
330
- description:
331
- type: LongText
332
- displayName:
333
- ja: 説明
334
- en: Description
335
- posts:
336
- type: Association
337
- relation: OneToMany
338
- target: Post
339
- mappedBy: category
340
- \`\`\`
200
+ export default defineConfig({
201
+ schemasDir: './schemas',
341
202
 
342
- ## Enum Examples
203
+ database: {
204
+ driver: 'mysql', // 'mysql' | 'pgsql' | 'sqlite' | 'sqlsrv' | 'mariadb'
205
+ },
343
206
 
344
- ### UserRole Enum
345
- \`\`\`yaml
346
- name: UserRole
347
- kind: enum
348
- displayName:
349
- ja: ユーザーロール
350
- en: User Role
351
- values:
352
- admin: 管理者
353
- editor: 編集者
354
- user: 一般ユーザー
355
- \`\`\`
207
+ output: {
208
+ laravel: {
209
+ migrationsPath: './database/migrations/omnify',
210
+ modelsPath: './app/Models',
211
+ enumsPath: './app/Enums',
212
+ },
213
+ typescript: {
214
+ path: './src/types/model',
215
+ singleFile: false,
216
+ },
217
+ },
356
218
 
357
- ### PostStatus Enum
358
- \`\`\`yaml
359
- name: PostStatus
360
- kind: enum
361
- displayName:
362
- ja: 投稿ステータス
363
- en: Post Status
364
- values:
365
- draft: 下書き
366
- review: レビュー中
367
- published: 公開済み
368
- archived: アーカイブ
219
+ // Multi-language support (optional)
220
+ locale: {
221
+ locales: ['en', 'ja', 'vi'],
222
+ defaultLocale: 'en',
223
+ fallbackLocale: 'en',
224
+ },
225
+ });
369
226
  \`\`\`
370
227
 
371
- ## E-commerce Example
372
-
373
- ### Product Schema
374
- \`\`\`yaml
375
- name: Product
376
- displayName:
377
- ja: 商品
378
- en: Product
379
- group: shop
380
- options:
381
- softDelete: true
382
- timestamps: true
383
- properties:
384
- name:
385
- type: String
386
- required: true
387
- maxLength: 255
388
- description:
389
- type: LongText
390
- price:
391
- type: Float
392
- precision: 10
393
- scale: 2
394
- required: true
395
- stock:
396
- type: Int
397
- default: 0
398
- unsigned: true
399
- sku:
400
- type: String
401
- unique: true
402
- maxLength: 50
403
- isActive:
404
- type: Boolean
405
- default: true
406
- category:
407
- type: Association
408
- relation: ManyToOne
409
- target: ProductCategory
410
- onDelete: SET_NULL
228
+ ## Configuration Options
229
+
230
+ ### database (required)
231
+ | Option | Type | Description |
232
+ |--------|------|-------------|
233
+ | \`driver\` | string | Database driver: mysql, pgsql, sqlite, sqlsrv, mariadb |
234
+ | \`devUrl\` | string | Development database URL for Atlas diff |
235
+ | \`enableFieldComments\` | boolean | Enable field comments in migrations (MySQL) |
236
+
237
+ ### output.laravel
238
+ | Option | Type | Description |
239
+ |--------|------|-------------|
240
+ | \`migrationsPath\` | string | Directory for generated migrations |
241
+ | \`modelsPath\` | string | Directory for generated models |
242
+ | \`modelsNamespace\` | string | PHP namespace for models |
243
+ | \`factoriesPath\` | string | Directory for generated factories |
244
+ | \`enumsPath\` | string | Directory for generated enums |
245
+ | \`enumsNamespace\` | string | PHP namespace for enums |
246
+
247
+ ### output.typescript
248
+ | Option | Type | Description |
249
+ |--------|------|-------------|
250
+ | \`path\` | string | Output directory for TypeScript types |
251
+ | \`singleFile\` | boolean | Generate single file vs multiple files |
252
+ | \`generateEnums\` | boolean | Generate enum types |
253
+ | \`generateRelationships\` | boolean | Generate relationship types |
254
+
255
+ ### locale (optional)
256
+ | Option | Type | Description |
257
+ |--------|------|-------------|
258
+ | \`locales\` | string[] | Supported locale codes: ['en', 'ja', 'vi'] |
259
+ | \`defaultLocale\` | string | Default locale for simple strings |
260
+ | \`fallbackLocale\` | string | Fallback when requested locale not found |
261
+
262
+ ## Common Mistakes
263
+
264
+ ❌ **Wrong** - \`locales\` at root level:
265
+ \`\`\`typescript
266
+ {
267
+ locales: ['en', 'ja'], // ERROR: locales not in OmnifyConfig
268
+ }
411
269
  \`\`\`
412
270
 
413
- ### Order Schema
414
- \`\`\`yaml
415
- name: Order
416
- displayName:
417
- ja: 注文
418
- en: Order
419
- group: shop
420
- options:
421
- timestamps: true
422
- properties:
423
- orderNumber:
424
- type: String
425
- required: true
426
- unique: true
427
- status:
428
- type: EnumRef
429
- enum: OrderStatus
430
- default: pending
431
- totalAmount:
432
- type: Float
433
- precision: 12
434
- scale: 2
435
- customer:
436
- type: Association
437
- relation: ManyToOne
438
- target: User
439
- onDelete: RESTRICT
440
- items:
441
- type: Association
442
- relation: OneToMany
443
- target: OrderItem
444
- mappedBy: order
445
- shippingAddress:
446
- type: Json
271
+ **Correct** - \`locales\` inside \`locale\` object:
272
+ \`\`\`typescript
273
+ {
274
+ locale: {
275
+ locales: ['en', 'ja'],
276
+ defaultLocale: 'en',
277
+ },
278
+ }
447
279
  \`\`\`
448
280
  `;
449
281
 
@@ -455,8 +287,9 @@ const MCP_CONFIG = {
455
287
  };
456
288
 
457
289
  function findProjectRoot() {
458
- // Start from the current working directory or script location
459
- let dir = process.cwd();
290
+ // npm/pnpm set INIT_CWD to the directory where the install was run
291
+ // This is more reliable than process.cwd() during postinstall
292
+ let dir = process.env.INIT_CWD || process.cwd();
460
293
 
461
294
  // If we're in node_modules, go up to find the actual project
462
295
  const nodeModulesIndex = dir.indexOf('node_modules');
@@ -482,15 +315,16 @@ function createOmnifySkillFiles(projectRoot) {
482
315
  fs.mkdirSync(omnifyDir, { recursive: true });
483
316
  }
484
317
 
485
- // Write schema guide
318
+ // Write base schema guide (plugin-specific guides are created by each plugin)
486
319
  const schemaGuidePath = path.join(omnifyDir, 'schema-guide.md');
487
320
  fs.writeFileSync(schemaGuidePath, SCHEMA_GUIDE_CONTENT, 'utf-8');
488
321
 
489
- // Write examples
490
- const examplesPath = path.join(omnifyDir, 'examples.md');
491
- fs.writeFileSync(examplesPath, EXAMPLES_CONTENT, 'utf-8');
322
+ // Write config guide
323
+ const configGuidePath = path.join(omnifyDir, 'config-guide.md');
324
+ fs.writeFileSync(configGuidePath, CONFIG_GUIDE_CONTENT, 'utf-8');
492
325
 
493
- console.log(' Created .claude/omnify/ skill files');
326
+ console.log(' Created .claude/omnify/schema-guide.md');
327
+ console.log(' Created .claude/omnify/config-guide.md');
494
328
  return true;
495
329
  } catch (error) {
496
330
  console.log(' Note: Could not create .claude/omnify/ skill files');
@@ -500,33 +334,49 @@ function createOmnifySkillFiles(projectRoot) {
500
334
 
501
335
  function createClaudeMd(projectRoot) {
502
336
  const claudeMdPath = path.join(projectRoot, 'CLAUDE.md');
503
- // Check for both variants of the Omnify marker
504
- const omnifyMarkers = ['# Omnify Schema', '## Omnify Schema', 'omnify/schema-guide.md'];
505
337
 
506
338
  // Check if CLAUDE.md exists
507
339
  if (fs.existsSync(claudeMdPath)) {
508
- // Read existing content
509
340
  const existingContent = fs.readFileSync(claudeMdPath, 'utf-8');
510
341
 
511
342
  // Check if Omnify section already exists
512
- if (omnifyMarkers.some((marker) => existingContent.includes(marker))) {
343
+ if (existingContent.includes(OMNIFY_MARKER)) {
513
344
  console.log(' CLAUDE.md already has Omnify section, skipping...');
514
345
  return false;
515
346
  }
516
347
 
517
348
  // Append Omnify section to existing CLAUDE.md
518
- const newContent = existingContent.trimEnd() + '\n' + CLAUDE_MD_APPEND;
349
+ const newContent = existingContent.trimEnd() + '\n\n' + CLAUDE_MD_SECTION;
519
350
  fs.writeFileSync(claudeMdPath, newContent, 'utf-8');
520
- console.log(' Appended Omnify section to existing CLAUDE.md');
351
+ console.log(' Appended Omnify section to CLAUDE.md');
521
352
  return true;
522
353
  }
523
354
 
524
- // Create new CLAUDE.md
525
- fs.writeFileSync(claudeMdPath, CLAUDE_MD_CONTENT, 'utf-8');
526
- console.log(' Created CLAUDE.md with Omnify schema rules');
355
+ // Create new CLAUDE.md with just the Omnify section
356
+ fs.writeFileSync(claudeMdPath, CLAUDE_MD_SECTION, 'utf-8');
357
+ console.log(' Created CLAUDE.md');
527
358
  return true;
528
359
  }
529
360
 
361
+ function createCursorRules(projectRoot) {
362
+ const cursorDir = path.join(projectRoot, '.cursor', 'rules');
363
+ const cursorRulesPath = path.join(cursorDir, 'omnify.md');
364
+
365
+ try {
366
+ // Create .cursor/rules directory
367
+ if (!fs.existsSync(cursorDir)) {
368
+ fs.mkdirSync(cursorDir, { recursive: true });
369
+ }
370
+
371
+ // Always overwrite - this file is fully managed by Omnify
372
+ fs.writeFileSync(cursorRulesPath, CURSORRULES_CONTENT, 'utf-8');
373
+ console.log(' Updated .cursor/rules/omnify.md');
374
+ return true;
375
+ } catch {
376
+ return false;
377
+ }
378
+ }
379
+
530
380
  function configureClaudeMcp() {
531
381
  const homeDir = os.homedir();
532
382
  const claudeDir = path.join(homeDir, '.claude');
@@ -580,9 +430,9 @@ function main() {
580
430
  return;
581
431
  }
582
432
 
583
- // Skip if this is a dev install (in the omnify-ts monorepo itself)
584
- const cwd = process.cwd();
585
- if (cwd.includes('omnify-ts') && !cwd.includes('node_modules')) {
433
+ // Skip if in omnify-ts monorepo (source code), but allow examples/
434
+ const projectDir = process.env.INIT_CWD || process.cwd();
435
+ if (projectDir.includes('omnify-ts') && !projectDir.includes('omnify-ts/examples')) {
586
436
  return;
587
437
  }
588
438
 
@@ -596,13 +446,15 @@ function main() {
596
446
 
597
447
  // Create or update CLAUDE.md in project root
598
448
  createClaudeMd(projectRoot);
449
+
450
+ // Create Cursor rules
451
+ createCursorRules(projectRoot);
599
452
  }
600
453
 
601
454
  // Configure MCP server in user's home directory
602
455
  configureClaudeMcp();
603
456
 
604
457
  console.log('\n✅ Omnify setup complete!\n');
605
- console.log(' Restart Claude Code/Desktop to enable MCP tools.\n');
606
458
  }
607
459
 
608
460
  main();