@famgia/omnify 1.0.44 → 1.0.45

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.
@@ -0,0 +1,122 @@
1
+ # Omnify Configuration Guide
2
+
3
+ ## Configuration File
4
+
5
+ Create `omnify.config.ts` in project root:
6
+
7
+ ```typescript
8
+ import { defineConfig } from '@famgia/omnify';
9
+
10
+ export default defineConfig({
11
+ schemasDir: './schemas',
12
+
13
+ database: {
14
+ driver: 'mysql', // 'mysql' | 'pgsql' | 'sqlite' | 'sqlsrv' | 'mariadb'
15
+ },
16
+
17
+ output: {
18
+ laravel: {
19
+ migrationsPath: './database/migrations/omnify',
20
+ modelsPath: './app/Models',
21
+ enumsPath: './app/Enums',
22
+ },
23
+ typescript: {
24
+ path: './src/types/model',
25
+ singleFile: false,
26
+ },
27
+ },
28
+
29
+ // Multi-language support (optional)
30
+ locale: {
31
+ locales: ['en', 'ja', 'vi'],
32
+ defaultLocale: 'en',
33
+ fallbackLocale: 'en',
34
+ },
35
+ });
36
+ ```
37
+
38
+ ## Configuration Options
39
+
40
+ ### database (required)
41
+ | Option | Type | Description |
42
+ |--------|------|-------------|
43
+ | `driver` | string | Database driver: mysql, pgsql, sqlite, sqlsrv, mariadb |
44
+ | `devUrl` | string | Development database URL for Atlas diff |
45
+ | `enableFieldComments` | boolean | Enable field comments in migrations (MySQL) |
46
+
47
+ ### output.laravel
48
+ | Option | Type | Description |
49
+ |--------|------|-------------|
50
+ | `migrationsPath` | string | Directory for generated migrations |
51
+ | `modelsPath` | string | Directory for generated models |
52
+ | `modelsNamespace` | string | PHP namespace for models |
53
+ | `factoriesPath` | string | Directory for generated factories |
54
+ | `enumsPath` | string | Directory for generated enums |
55
+ | `enumsNamespace` | string | PHP namespace for enums |
56
+
57
+ ### output.typescript
58
+ | Option | Type | Description |
59
+ |--------|------|-------------|
60
+ | `path` | string | Output directory for TypeScript types |
61
+ | `singleFile` | boolean | Generate single file vs multiple files |
62
+ | `generateEnums` | boolean | Generate enum types |
63
+ | `generateRelationships` | boolean | Generate relationship types |
64
+ | `generateRules` | boolean | Generate Ant Design validation rules (default: true) |
65
+ | `validationTemplates` | object | Custom validation message templates |
66
+
67
+ #### Validation Templates
68
+
69
+ Customize validation messages for your locales:
70
+
71
+ ```typescript
72
+ {
73
+ output: {
74
+ typescript: {
75
+ validationTemplates: {
76
+ required: {
77
+ ja: '${displayName}を入力してください',
78
+ en: '${displayName} is required',
79
+ },
80
+ maxLength: {
81
+ ja: '${displayName}は${max}文字以内です',
82
+ en: '${displayName} must be at most ${max} characters',
83
+ },
84
+ minLength: { /* ... */ },
85
+ min: { /* ... */ },
86
+ max: { /* ... */ },
87
+ email: { /* ... */ },
88
+ url: { /* ... */ },
89
+ pattern: { /* ... */ },
90
+ },
91
+ },
92
+ },
93
+ }
94
+ ```
95
+
96
+ Built-in templates are available for: ja, en, vi, ko, zh
97
+
98
+ ### locale (optional)
99
+ | Option | Type | Description |
100
+ |--------|------|-------------|
101
+ | `locales` | string[] | Supported locale codes: ['en', 'ja', 'vi'] |
102
+ | `defaultLocale` | string | Default locale for simple strings |
103
+ | `fallbackLocale` | string | Fallback when requested locale not found |
104
+
105
+ ## Common Mistakes
106
+
107
+ **Wrong** - `locales` at root level:
108
+ ```typescript
109
+ {
110
+ locales: ['en', 'ja'], // ERROR: locales not in OmnifyConfig
111
+ }
112
+ ```
113
+
114
+ **Correct** - `locales` inside `locale` object:
115
+ ```typescript
116
+ {
117
+ locale: {
118
+ locales: ['en', 'ja'],
119
+ defaultLocale: 'en',
120
+ },
121
+ }
122
+ ```
@@ -0,0 +1,144 @@
1
+ # Omnify Schema Format Guide
2
+
3
+ ## Schema Location
4
+
5
+ All schemas are stored in `schemas/` directory with `.yaml` extension.
6
+
7
+ ## Object Schema Structure
8
+
9
+ ```yaml
10
+ # yaml-language-server: $schema=./node_modules/.omnify/combined-schema.json
11
+ name: ModelName # Required: PascalCase
12
+ kind: object # Optional: 'object' (default) or 'enum'
13
+ displayName: # Optional: i18n display name
14
+ ja: 日本語名
15
+ en: English Name
16
+ description: # Optional: i18n description
17
+ ja: 説明文
18
+ en: Description
19
+ group: group-name # Optional: for organizing schemas
20
+ options:
21
+ softDelete: true # Enable soft delete (deleted_at column)
22
+ timestamps: true # Enable created_at, updated_at
23
+ table: custom_table # Custom table name
24
+ properties:
25
+ # Property definitions here
26
+ ```
27
+
28
+ ## Property Types
29
+
30
+ ### String Types
31
+ | Type | Description | Options |
32
+ |------|-------------|---------|
33
+ | `String` | Short text (varchar) | `maxLength`, `minLength`, `default` |
34
+ | `LongText` | Long text (text) | `default` |
35
+
36
+ ### Numeric Types
37
+ | Type | Description | Options |
38
+ |------|-------------|---------|
39
+ | `Int` | Integer | `min`, `max`, `default`, `unsigned` |
40
+ | `BigInt` | Big integer | `min`, `max`, `default`, `unsigned` |
41
+ | `Float` | Decimal | `precision`, `scale`, `default` |
42
+
43
+ ### Other Types
44
+ | Type | Description | Options |
45
+ |------|-------------|---------|
46
+ | `Boolean` | True/false | `default` |
47
+ | `Date` | Date only | `default` |
48
+ | `DateTime` | Date and time | `default` |
49
+ | `Json` | JSON object | `default` |
50
+ | `EnumRef` | Reference to enum | `enum` (required), `default` |
51
+
52
+ ### Association Type
53
+ | Type | Description | Options |
54
+ |------|-------------|---------|
55
+ | `Association` | Relation | `relation`, `target`, `onDelete`, `mappedBy` |
56
+
57
+ ## Property Options
58
+
59
+ ```yaml
60
+ properties:
61
+ name:
62
+ type: String
63
+ displayName:
64
+ ja: 名前
65
+ en: Name
66
+ required: true # Not nullable
67
+ unique: true # Unique constraint
68
+ index: true # Create index
69
+ maxLength: 255 # For String
70
+ default: 'default' # Default value
71
+ ```
72
+
73
+ ## Association Relations
74
+
75
+ ### ManyToOne (N:1)
76
+ ```yaml
77
+ author:
78
+ type: Association
79
+ relation: ManyToOne
80
+ target: User
81
+ onDelete: CASCADE # CASCADE, SET_NULL, RESTRICT
82
+ ```
83
+
84
+ ### OneToMany (1:N)
85
+ ```yaml
86
+ posts:
87
+ type: Association
88
+ relation: OneToMany
89
+ target: Post
90
+ mappedBy: author # Property name in Post that references this
91
+ ```
92
+
93
+ ### ManyToMany (N:M)
94
+ ```yaml
95
+ tags:
96
+ type: Association
97
+ relation: ManyToMany
98
+ target: Tag
99
+ pivotTable: post_tags # Optional: custom pivot table name
100
+ pivotFields: # Optional: extra pivot fields
101
+ - name: order
102
+ type: Int
103
+ default: 0
104
+ ```
105
+
106
+ ### OneToOne (1:1)
107
+ ```yaml
108
+ profile:
109
+ type: Association
110
+ relation: OneToOne
111
+ target: Profile
112
+ onDelete: CASCADE
113
+ ```
114
+
115
+ ## Enum Schema
116
+
117
+ ```yaml
118
+ name: PostStatus
119
+ kind: enum
120
+ displayName:
121
+ ja: 投稿ステータス
122
+ en: Post Status
123
+ values:
124
+ draft: ドラフト # value: displayName format
125
+ published: 公開済み
126
+ archived: アーカイブ
127
+ ```
128
+
129
+ Use enum in object schema:
130
+ ```yaml
131
+ status:
132
+ type: EnumRef
133
+ enum: PostStatus # Reference enum name
134
+ default: draft # Default value from enum
135
+ ```
136
+
137
+ ## MCP Tools
138
+
139
+ If Omnify MCP is configured, these tools are available:
140
+ - `omnify_create_schema` - Generate schema YAML
141
+ - `omnify_validate_schema` - Validate YAML content
142
+ - `omnify_get_types` - Property types documentation
143
+ - `omnify_get_relationships` - Relationship guide
144
+ - `omnify_get_examples` - Example schemas
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@famgia/omnify",
3
- "version": "1.0.44",
3
+ "version": "1.0.45",
4
4
  "description": "Schema-driven database migration system with TypeScript types and Laravel migrations",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -21,17 +21,18 @@
21
21
  "bin",
22
22
  "docs",
23
23
  "scripts",
24
+ "ai-guides",
24
25
  "README.md"
25
26
  ],
26
27
  "dependencies": {
27
- "@famgia/omnify-cli": "0.0.43",
28
- "@famgia/omnify-core": "0.0.39",
29
- "@famgia/omnify-laravel": "0.0.45",
30
- "@famgia/omnify-types": "0.0.36",
31
- "@famgia/omnify-atlas": "0.0.35",
32
- "@famgia/omnify-typescript": "0.0.28",
33
- "@famgia/omnify-mcp": "0.0.27",
34
- "@famgia/omnify-japan": "0.0.34"
28
+ "@famgia/omnify-cli": "0.0.44",
29
+ "@famgia/omnify-core": "0.0.40",
30
+ "@famgia/omnify-types": "0.0.37",
31
+ "@famgia/omnify-laravel": "0.0.46",
32
+ "@famgia/omnify-typescript": "0.0.29",
33
+ "@famgia/omnify-atlas": "0.0.36",
34
+ "@famgia/omnify-mcp": "0.0.28",
35
+ "@famgia/omnify-japan": "0.0.35"
35
36
  },
36
37
  "keywords": [
37
38
  "omnify",
@@ -3,6 +3,10 @@
3
3
  import fs from 'fs';
4
4
  import path from 'path';
5
5
  import os from 'os';
6
+ import { fileURLToPath } from 'url';
7
+
8
+ const __filename = fileURLToPath(import.meta.url);
9
+ const __dirname = path.dirname(__filename);
6
10
 
7
11
  // Content for CLAUDE.md
8
12
  const CLAUDE_MD_SECTION = `## Omnify
@@ -14,6 +18,7 @@ This project uses Omnify for schema-driven code generation.
14
18
  - \`config-guide.md\` - Configuration (omnify.config.ts)
15
19
  - \`laravel-guide.md\` - Laravel generator (if installed)
16
20
  - \`typescript-guide.md\` - TypeScript generator (if installed)
21
+ - \`antdesign-guide.md\` - Ant Design Form integration (if installed)
17
22
 
18
23
  **Commands**:
19
24
  - \`npx omnify generate\` - Generate code from schemas
@@ -31,6 +36,7 @@ For detailed documentation, read these files:
31
36
  - .claude/omnify/config-guide.md - Configuration (omnify.config.ts)
32
37
  - .claude/omnify/laravel-guide.md - Laravel generator (if exists)
33
38
  - .claude/omnify/typescript-guide.md - TypeScript generator (if exists)
39
+ - .claude/omnify/antdesign-guide.md - Ant Design Form integration (if exists)
34
40
 
35
41
  Commands:
36
42
  - npx omnify generate - Generate code from schemas
@@ -40,278 +46,6 @@ Commands:
40
46
  // Marker to check if Omnify section exists
41
47
  const OMNIFY_MARKER = '.claude/omnify/';
42
48
 
43
- // Schema guide skill file
44
- const SCHEMA_GUIDE_CONTENT = `# Omnify Schema Format Guide
45
-
46
- ## Schema Location
47
-
48
- All schemas are stored in \`schemas/\` directory with \`.yaml\` extension.
49
-
50
- ## Object Schema Structure
51
-
52
- \`\`\`yaml
53
- # yaml-language-server: $schema=./node_modules/.omnify/combined-schema.json
54
- name: ModelName # Required: PascalCase
55
- kind: object # Optional: 'object' (default) or 'enum'
56
- displayName: # Optional: i18n display name
57
- ja: 日本語名
58
- en: English Name
59
- description: # Optional: i18n description
60
- ja: 説明文
61
- en: Description
62
- group: group-name # Optional: for organizing schemas
63
- options:
64
- softDelete: true # Enable soft delete (deleted_at column)
65
- timestamps: true # Enable created_at, updated_at
66
- table: custom_table # Custom table name
67
- properties:
68
- # Property definitions here
69
- \`\`\`
70
-
71
- ## Property Types
72
-
73
- ### String Types
74
- | Type | Description | Options |
75
- |------|-------------|---------|
76
- | \`String\` | Short text (varchar) | \`maxLength\`, \`minLength\`, \`default\` |
77
- | \`LongText\` | Long text (text) | \`default\` |
78
-
79
- ### Numeric Types
80
- | Type | Description | Options |
81
- |------|-------------|---------|
82
- | \`Int\` | Integer | \`min\`, \`max\`, \`default\`, \`unsigned\` |
83
- | \`BigInt\` | Big integer | \`min\`, \`max\`, \`default\`, \`unsigned\` |
84
- | \`Float\` | Decimal | \`precision\`, \`scale\`, \`default\` |
85
-
86
- ### Other Types
87
- | Type | Description | Options |
88
- |------|-------------|---------|
89
- | \`Boolean\` | True/false | \`default\` |
90
- | \`Date\` | Date only | \`default\` |
91
- | \`DateTime\` | Date and time | \`default\` |
92
- | \`Json\` | JSON object | \`default\` |
93
- | \`EnumRef\` | Reference to enum | \`enum\` (required), \`default\` |
94
-
95
- ### Association Type
96
- | Type | Description | Options |
97
- |------|-------------|---------|
98
- | \`Association\` | Relation | \`relation\`, \`target\`, \`onDelete\`, \`mappedBy\` |
99
-
100
- ## Property Options
101
-
102
- \`\`\`yaml
103
- properties:
104
- name:
105
- type: String
106
- displayName:
107
- ja: 名前
108
- en: Name
109
- required: true # Not nullable
110
- unique: true # Unique constraint
111
- index: true # Create index
112
- maxLength: 255 # For String
113
- default: 'default' # Default value
114
- \`\`\`
115
-
116
- ## Association Relations
117
-
118
- ### ManyToOne (N:1)
119
- \`\`\`yaml
120
- author:
121
- type: Association
122
- relation: ManyToOne
123
- target: User
124
- onDelete: CASCADE # CASCADE, SET_NULL, RESTRICT
125
- \`\`\`
126
-
127
- ### OneToMany (1:N)
128
- \`\`\`yaml
129
- posts:
130
- type: Association
131
- relation: OneToMany
132
- target: Post
133
- mappedBy: author # Property name in Post that references this
134
- \`\`\`
135
-
136
- ### ManyToMany (N:M)
137
- \`\`\`yaml
138
- tags:
139
- type: Association
140
- relation: ManyToMany
141
- target: Tag
142
- pivotTable: post_tags # Optional: custom pivot table name
143
- pivotFields: # Optional: extra pivot fields
144
- - name: order
145
- type: Int
146
- default: 0
147
- \`\`\`
148
-
149
- ### OneToOne (1:1)
150
- \`\`\`yaml
151
- profile:
152
- type: Association
153
- relation: OneToOne
154
- target: Profile
155
- onDelete: CASCADE
156
- \`\`\`
157
-
158
- ## Enum Schema
159
-
160
- \`\`\`yaml
161
- name: PostStatus
162
- kind: enum
163
- displayName:
164
- ja: 投稿ステータス
165
- en: Post Status
166
- values:
167
- draft: ドラフト # value: displayName format
168
- published: 公開済み
169
- archived: アーカイブ
170
- \`\`\`
171
-
172
- Use enum in object schema:
173
- \`\`\`yaml
174
- status:
175
- type: EnumRef
176
- enum: PostStatus # Reference enum name
177
- default: draft # Default value from enum
178
- \`\`\`
179
-
180
- ## MCP Tools
181
-
182
- If Omnify MCP is configured, these tools are available:
183
- - \`omnify_create_schema\` - Generate schema YAML
184
- - \`omnify_validate_schema\` - Validate YAML content
185
- - \`omnify_get_types\` - Property types documentation
186
- - \`omnify_get_relationships\` - Relationship guide
187
- - \`omnify_get_examples\` - Example schemas
188
- `;
189
-
190
- // Config guide skill file
191
- const CONFIG_GUIDE_CONTENT = `# Omnify Configuration Guide
192
-
193
- ## Configuration File
194
-
195
- Create \`omnify.config.ts\` in project root:
196
-
197
- \`\`\`typescript
198
- import { defineConfig } from '@famgia/omnify';
199
-
200
- export default defineConfig({
201
- schemasDir: './schemas',
202
-
203
- database: {
204
- driver: 'mysql', // 'mysql' | 'pgsql' | 'sqlite' | 'sqlsrv' | 'mariadb'
205
- },
206
-
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
- },
218
-
219
- // Multi-language support (optional)
220
- locale: {
221
- locales: ['en', 'ja', 'vi'],
222
- defaultLocale: 'en',
223
- fallbackLocale: 'en',
224
- },
225
- });
226
- \`\`\`
227
-
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
- | \`generateRules\` | boolean | Generate Ant Design validation rules (default: true) |
255
- | \`validationTemplates\` | object | Custom validation message templates |
256
-
257
- #### Validation Templates
258
-
259
- Customize validation messages for your locales:
260
-
261
- \`\`\`typescript
262
- {
263
- output: {
264
- typescript: {
265
- validationTemplates: {
266
- required: {
267
- ja: '\${displayName}を入力してください',
268
- en: '\${displayName} is required',
269
- },
270
- maxLength: {
271
- ja: '\${displayName}は\${max}文字以内です',
272
- en: '\${displayName} must be at most \${max} characters',
273
- },
274
- minLength: { /* ... */ },
275
- min: { /* ... */ },
276
- max: { /* ... */ },
277
- email: { /* ... */ },
278
- url: { /* ... */ },
279
- pattern: { /* ... */ },
280
- },
281
- },
282
- },
283
- }
284
- \`\`\`
285
-
286
- Built-in templates are available for: ja, en, vi, ko, zh
287
-
288
- ### locale (optional)
289
- | Option | Type | Description |
290
- |--------|------|-------------|
291
- | \`locales\` | string[] | Supported locale codes: ['en', 'ja', 'vi'] |
292
- | \`defaultLocale\` | string | Default locale for simple strings |
293
- | \`fallbackLocale\` | string | Fallback when requested locale not found |
294
-
295
- ## Common Mistakes
296
-
297
- ❌ **Wrong** - \`locales\` at root level:
298
- \`\`\`typescript
299
- {
300
- locales: ['en', 'ja'], // ERROR: locales not in OmnifyConfig
301
- }
302
- \`\`\`
303
-
304
- ✅ **Correct** - \`locales\` inside \`locale\` object:
305
- \`\`\`typescript
306
- {
307
- locale: {
308
- locales: ['en', 'ja'],
309
- defaultLocale: 'en',
310
- },
311
- }
312
- \`\`\`
313
- `;
314
-
315
49
  const MCP_CONFIG = {
316
50
  omnify: {
317
51
  command: 'npx',
@@ -319,9 +53,6 @@ const MCP_CONFIG = {
319
53
  },
320
54
  };
321
55
 
322
- // Combined schema path (relative from project root)
323
- const COMBINED_SCHEMA_PATH = 'node_modules/.omnify/combined-schema.json';
324
-
325
56
  /**
326
57
  * Generate combined JSON Schema from base schema + all plugin contributions
327
58
  */
@@ -332,34 +63,33 @@ function generateCombinedSchema(projectRoot) {
332
63
 
333
64
  try {
334
65
  // Read base schema from @famgia/omnify-types
335
- // Check multiple possible locations (direct, nested via omnify, pnpm hoisted)
336
66
  const possiblePaths = [
337
67
  path.join(nodeModulesDir, '@famgia/omnify-types/schemas/omnify-schema.json'),
338
68
  path.join(nodeModulesDir, '@famgia/omnify/node_modules/@famgia/omnify-types/schemas/omnify-schema.json'),
339
- path.join(nodeModulesDir, '.pnpm/@famgia+omnify-types@*/node_modules/@famgia/omnify-types/schemas/omnify-schema.json'),
340
69
  ];
341
70
 
342
71
  let baseSchemaPath = null;
343
72
  for (const p of possiblePaths) {
344
- // Handle glob pattern for pnpm
345
- if (p.includes('*')) {
346
- const dir = path.dirname(path.dirname(p));
347
- if (fs.existsSync(path.dirname(dir))) {
348
- const matches = fs.readdirSync(path.dirname(dir)).filter(f => f.startsWith('@famgia+omnify-types@'));
349
- if (matches.length > 0) {
350
- const matchPath = path.join(path.dirname(dir), matches[0], 'node_modules/@famgia/omnify-types/schemas/omnify-schema.json');
351
- if (fs.existsSync(matchPath)) {
352
- baseSchemaPath = matchPath;
353
- break;
354
- }
355
- }
356
- }
357
- } else if (fs.existsSync(p)) {
73
+ if (fs.existsSync(p)) {
358
74
  baseSchemaPath = p;
359
75
  break;
360
76
  }
361
77
  }
362
78
 
79
+ // Try pnpm hoisted location
80
+ if (!baseSchemaPath) {
81
+ const pnpmDir = path.join(nodeModulesDir, '.pnpm');
82
+ if (fs.existsSync(pnpmDir)) {
83
+ const matches = fs.readdirSync(pnpmDir).filter(f => f.startsWith('@famgia+omnify-types@'));
84
+ if (matches.length > 0) {
85
+ const matchPath = path.join(pnpmDir, matches[0], 'node_modules/@famgia/omnify-types/schemas/omnify-schema.json');
86
+ if (fs.existsSync(matchPath)) {
87
+ baseSchemaPath = matchPath;
88
+ }
89
+ }
90
+ }
91
+ }
92
+
363
93
  if (!baseSchemaPath) {
364
94
  console.log(' Note: Base schema not found, skipping combined schema generation');
365
95
  return false;
@@ -368,7 +98,6 @@ function generateCombinedSchema(projectRoot) {
368
98
  const baseSchema = JSON.parse(fs.readFileSync(baseSchemaPath, 'utf-8'));
369
99
 
370
100
  // Find all @famgia/omnify-* plugins with schema contributions
371
- // Check multiple possible locations (direct, nested via omnify)
372
101
  const famgiaDirs = [
373
102
  path.join(nodeModulesDir, '@famgia'),
374
103
  path.join(nodeModulesDir, '@famgia/omnify/node_modules/@famgia'),
@@ -381,7 +110,6 @@ function generateCombinedSchema(projectRoot) {
381
110
 
382
111
  const packages = fs.readdirSync(famgiaDir);
383
112
  for (const pkg of packages) {
384
- // Skip non-plugin packages and already processed
385
113
  if (!pkg.startsWith('omnify-') || pkg === 'omnify-types' || pkg === 'omnify-mcp') {
386
114
  continue;
387
115
  }
@@ -402,14 +130,12 @@ function generateCombinedSchema(projectRoot) {
402
130
 
403
131
  // Merge contributions into base schema
404
132
  for (const { name, contribution } of pluginContributions) {
405
- // Add definitions
406
133
  if (contribution.definitions) {
407
134
  for (const [defName, defValue] of Object.entries(contribution.definitions)) {
408
135
  baseSchema.definitions[defName] = defValue;
409
136
  }
410
137
  }
411
138
 
412
- // Add to PropertyDefinition oneOf
413
139
  if (contribution.propertyTypes && baseSchema.definitions.PropertyDefinition) {
414
140
  for (const typeName of contribution.propertyTypes) {
415
141
  baseSchema.definitions.PropertyDefinition.oneOf.push({
@@ -421,16 +147,13 @@ function generateCombinedSchema(projectRoot) {
421
147
  console.log(` Added schema contributions from @famgia/${name}`);
422
148
  }
423
149
 
424
- // Update schema $id to indicate it's combined
425
150
  baseSchema.$id = 'omnify://combined-schema.json';
426
151
  baseSchema.description = baseSchema.description + ' (Combined with plugin contributions)';
427
152
 
428
- // Create output directory
429
153
  if (!fs.existsSync(outputDir)) {
430
154
  fs.mkdirSync(outputDir, { recursive: true });
431
155
  }
432
156
 
433
- // Write combined schema
434
157
  fs.writeFileSync(outputPath, JSON.stringify(baseSchema, null, 2), 'utf-8');
435
158
  console.log(' Generated combined JSON schema at node_modules/.omnify/combined-schema.json');
436
159
 
@@ -442,47 +165,42 @@ function generateCombinedSchema(projectRoot) {
442
165
  }
443
166
 
444
167
  function findProjectRoot() {
445
- // npm/pnpm set INIT_CWD to the directory where the install was run
446
- // This is more reliable than process.cwd() during postinstall
447
168
  let dir = process.env.INIT_CWD || process.cwd();
448
-
449
- // If we're in node_modules, go up to find the actual project
450
169
  const nodeModulesIndex = dir.indexOf('node_modules');
451
170
  if (nodeModulesIndex !== -1) {
452
171
  dir = dir.substring(0, nodeModulesIndex - 1);
453
172
  }
454
-
455
- // Verify it's a project root by checking for package.json
456
173
  const packageJsonPath = path.join(dir, 'package.json');
457
174
  if (fs.existsSync(packageJsonPath)) {
458
175
  return dir;
459
176
  }
460
-
461
177
  return null;
462
178
  }
463
179
 
464
- function createOmnifySkillFiles(projectRoot) {
180
+ function copyAiGuidesToProject(projectRoot) {
465
181
  const omnifyDir = path.join(projectRoot, '.claude', 'omnify');
182
+ const aiGuidesDir = path.join(__dirname, '..', 'ai-guides');
466
183
 
467
184
  try {
468
- // Create .claude/omnify directory
469
185
  if (!fs.existsSync(omnifyDir)) {
470
186
  fs.mkdirSync(omnifyDir, { recursive: true });
471
187
  }
472
188
 
473
- // Write base schema guide (plugin-specific guides are created by each plugin)
474
- const schemaGuidePath = path.join(omnifyDir, 'schema-guide.md');
475
- fs.writeFileSync(schemaGuidePath, SCHEMA_GUIDE_CONTENT, 'utf-8');
189
+ if (fs.existsSync(aiGuidesDir)) {
190
+ const files = fs.readdirSync(aiGuidesDir);
191
+ for (const file of files) {
192
+ const srcPath = path.join(aiGuidesDir, file);
193
+ const destPath = path.join(omnifyDir, file);
476
194
 
477
- // Write config guide
478
- const configGuidePath = path.join(omnifyDir, 'config-guide.md');
479
- fs.writeFileSync(configGuidePath, CONFIG_GUIDE_CONTENT, 'utf-8');
195
+ if (fs.statSync(srcPath).isFile()) {
196
+ fs.copyFileSync(srcPath, destPath);
197
+ console.log(` Created .claude/omnify/${file}`);
198
+ }
199
+ }
200
+ }
480
201
 
481
- console.log(' Created .claude/omnify/schema-guide.md');
482
- console.log(' Created .claude/omnify/config-guide.md');
483
202
  return true;
484
- } catch (error) {
485
- console.log(' Note: Could not create .claude/omnify/ skill files');
203
+ } catch {
486
204
  return false;
487
205
  }
488
206
  }
@@ -490,24 +208,20 @@ function createOmnifySkillFiles(projectRoot) {
490
208
  function createClaudeMd(projectRoot) {
491
209
  const claudeMdPath = path.join(projectRoot, 'CLAUDE.md');
492
210
 
493
- // Check if CLAUDE.md exists
494
211
  if (fs.existsSync(claudeMdPath)) {
495
212
  const existingContent = fs.readFileSync(claudeMdPath, 'utf-8');
496
213
 
497
- // Check if Omnify section already exists
498
214
  if (existingContent.includes(OMNIFY_MARKER)) {
499
215
  console.log(' CLAUDE.md already has Omnify section, skipping...');
500
216
  return false;
501
217
  }
502
218
 
503
- // Append Omnify section to existing CLAUDE.md
504
219
  const newContent = existingContent.trimEnd() + '\n\n' + CLAUDE_MD_SECTION;
505
220
  fs.writeFileSync(claudeMdPath, newContent, 'utf-8');
506
221
  console.log(' Appended Omnify section to CLAUDE.md');
507
222
  return true;
508
223
  }
509
224
 
510
- // Create new CLAUDE.md with just the Omnify section
511
225
  fs.writeFileSync(claudeMdPath, CLAUDE_MD_SECTION, 'utf-8');
512
226
  console.log(' Created CLAUDE.md');
513
227
  return true;
@@ -518,12 +232,10 @@ function createCursorRules(projectRoot) {
518
232
  const cursorRulesPath = path.join(cursorDir, 'omnify.md');
519
233
 
520
234
  try {
521
- // Create .cursor/rules directory
522
235
  if (!fs.existsSync(cursorDir)) {
523
236
  fs.mkdirSync(cursorDir, { recursive: true });
524
237
  }
525
238
 
526
- // Always overwrite - this file is fully managed by Omnify
527
239
  fs.writeFileSync(cursorRulesPath, CURSORRULES_CONTENT, 'utf-8');
528
240
  console.log(' Updated .cursor/rules/omnify.md');
529
241
  return true;
@@ -538,14 +250,12 @@ function configureClaudeMcp() {
538
250
  const configPath = path.join(claudeDir, 'claude_desktop_config.json');
539
251
 
540
252
  try {
541
- // Create .claude directory if not exists
542
253
  if (!fs.existsSync(claudeDir)) {
543
254
  fs.mkdirSync(claudeDir, { recursive: true });
544
255
  }
545
256
 
546
257
  let config = { mcpServers: {} };
547
258
 
548
- // Read existing config if exists
549
259
  if (fs.existsSync(configPath)) {
550
260
  try {
551
261
  const content = fs.readFileSync(configPath, 'utf-8');
@@ -554,38 +264,30 @@ function configureClaudeMcp() {
554
264
  config.mcpServers = {};
555
265
  }
556
266
  } catch {
557
- // Invalid JSON, start fresh
558
267
  config = { mcpServers: {} };
559
268
  }
560
269
  }
561
270
 
562
- // Check if omnify is already configured
563
271
  if (config.mcpServers.omnify) {
564
272
  console.log(' Omnify MCP already configured');
565
273
  return false;
566
274
  }
567
275
 
568
- // Add omnify MCP server
569
276
  config.mcpServers.omnify = MCP_CONFIG.omnify;
570
-
571
- // Write config
572
277
  fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8');
573
278
  console.log(' Configured Omnify MCP server in ~/.claude/claude_desktop_config.json');
574
279
  return true;
575
280
  } catch (error) {
576
- // Silently fail - MCP config is optional
577
281
  console.log(' Note: Could not auto-configure MCP (optional)');
578
282
  return false;
579
283
  }
580
284
  }
581
285
 
582
286
  function main() {
583
- // Skip in CI environments
584
287
  if (process.env.CI || process.env.CONTINUOUS_INTEGRATION) {
585
288
  return;
586
289
  }
587
290
 
588
- // Skip if in omnify-ts monorepo (source code), but allow examples/
589
291
  const projectDir = process.env.INIT_CWD || process.cwd();
590
292
  if (projectDir.includes('omnify-ts') && !projectDir.includes('omnify-ts/examples')) {
591
293
  return;
@@ -596,20 +298,12 @@ function main() {
596
298
  const projectRoot = findProjectRoot();
597
299
 
598
300
  if (projectRoot) {
599
- // Generate combined JSON schema with plugin contributions
600
301
  generateCombinedSchema(projectRoot);
601
-
602
- // Create .claude/omnify/ skill files
603
- createOmnifySkillFiles(projectRoot);
604
-
605
- // Create or update CLAUDE.md in project root
302
+ copyAiGuidesToProject(projectRoot);
606
303
  createClaudeMd(projectRoot);
607
-
608
- // Create Cursor rules
609
304
  createCursorRules(projectRoot);
610
305
  }
611
306
 
612
- // Configure MCP server in user's home directory
613
307
  configureClaudeMcp();
614
308
 
615
309
  console.log('\n✅ Omnify setup complete!\n');