@famgia/omnify 1.0.43 → 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.43",
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.42",
28
- "@famgia/omnify-types": "0.0.35",
29
- "@famgia/omnify-core": "0.0.38",
30
- "@famgia/omnify-laravel": "0.0.44",
31
- "@famgia/omnify-typescript": "0.0.27",
32
- "@famgia/omnify-japan": "0.0.33",
33
- "@famgia/omnify-atlas": "0.0.34",
34
- "@famgia/omnify-mcp": "0.0.26"
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,245 +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
-
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
- }
269
- \`\`\`
270
-
271
- ✅ **Correct** - \`locales\` inside \`locale\` object:
272
- \`\`\`typescript
273
- {
274
- locale: {
275
- locales: ['en', 'ja'],
276
- defaultLocale: 'en',
277
- },
278
- }
279
- \`\`\`
280
- `;
281
-
282
49
  const MCP_CONFIG = {
283
50
  omnify: {
284
51
  command: 'npx',
@@ -286,9 +53,6 @@ const MCP_CONFIG = {
286
53
  },
287
54
  };
288
55
 
289
- // Combined schema path (relative from project root)
290
- const COMBINED_SCHEMA_PATH = 'node_modules/.omnify/combined-schema.json';
291
-
292
56
  /**
293
57
  * Generate combined JSON Schema from base schema + all plugin contributions
294
58
  */
@@ -299,34 +63,33 @@ function generateCombinedSchema(projectRoot) {
299
63
 
300
64
  try {
301
65
  // Read base schema from @famgia/omnify-types
302
- // Check multiple possible locations (direct, nested via omnify, pnpm hoisted)
303
66
  const possiblePaths = [
304
67
  path.join(nodeModulesDir, '@famgia/omnify-types/schemas/omnify-schema.json'),
305
68
  path.join(nodeModulesDir, '@famgia/omnify/node_modules/@famgia/omnify-types/schemas/omnify-schema.json'),
306
- path.join(nodeModulesDir, '.pnpm/@famgia+omnify-types@*/node_modules/@famgia/omnify-types/schemas/omnify-schema.json'),
307
69
  ];
308
70
 
309
71
  let baseSchemaPath = null;
310
72
  for (const p of possiblePaths) {
311
- // Handle glob pattern for pnpm
312
- if (p.includes('*')) {
313
- const dir = path.dirname(path.dirname(p));
314
- if (fs.existsSync(path.dirname(dir))) {
315
- const matches = fs.readdirSync(path.dirname(dir)).filter(f => f.startsWith('@famgia+omnify-types@'));
316
- if (matches.length > 0) {
317
- const matchPath = path.join(path.dirname(dir), matches[0], 'node_modules/@famgia/omnify-types/schemas/omnify-schema.json');
318
- if (fs.existsSync(matchPath)) {
319
- baseSchemaPath = matchPath;
320
- break;
321
- }
322
- }
323
- }
324
- } else if (fs.existsSync(p)) {
73
+ if (fs.existsSync(p)) {
325
74
  baseSchemaPath = p;
326
75
  break;
327
76
  }
328
77
  }
329
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
+
330
93
  if (!baseSchemaPath) {
331
94
  console.log(' Note: Base schema not found, skipping combined schema generation');
332
95
  return false;
@@ -335,7 +98,6 @@ function generateCombinedSchema(projectRoot) {
335
98
  const baseSchema = JSON.parse(fs.readFileSync(baseSchemaPath, 'utf-8'));
336
99
 
337
100
  // Find all @famgia/omnify-* plugins with schema contributions
338
- // Check multiple possible locations (direct, nested via omnify)
339
101
  const famgiaDirs = [
340
102
  path.join(nodeModulesDir, '@famgia'),
341
103
  path.join(nodeModulesDir, '@famgia/omnify/node_modules/@famgia'),
@@ -348,7 +110,6 @@ function generateCombinedSchema(projectRoot) {
348
110
 
349
111
  const packages = fs.readdirSync(famgiaDir);
350
112
  for (const pkg of packages) {
351
- // Skip non-plugin packages and already processed
352
113
  if (!pkg.startsWith('omnify-') || pkg === 'omnify-types' || pkg === 'omnify-mcp') {
353
114
  continue;
354
115
  }
@@ -369,14 +130,12 @@ function generateCombinedSchema(projectRoot) {
369
130
 
370
131
  // Merge contributions into base schema
371
132
  for (const { name, contribution } of pluginContributions) {
372
- // Add definitions
373
133
  if (contribution.definitions) {
374
134
  for (const [defName, defValue] of Object.entries(contribution.definitions)) {
375
135
  baseSchema.definitions[defName] = defValue;
376
136
  }
377
137
  }
378
138
 
379
- // Add to PropertyDefinition oneOf
380
139
  if (contribution.propertyTypes && baseSchema.definitions.PropertyDefinition) {
381
140
  for (const typeName of contribution.propertyTypes) {
382
141
  baseSchema.definitions.PropertyDefinition.oneOf.push({
@@ -388,16 +147,13 @@ function generateCombinedSchema(projectRoot) {
388
147
  console.log(` Added schema contributions from @famgia/${name}`);
389
148
  }
390
149
 
391
- // Update schema $id to indicate it's combined
392
150
  baseSchema.$id = 'omnify://combined-schema.json';
393
151
  baseSchema.description = baseSchema.description + ' (Combined with plugin contributions)';
394
152
 
395
- // Create output directory
396
153
  if (!fs.existsSync(outputDir)) {
397
154
  fs.mkdirSync(outputDir, { recursive: true });
398
155
  }
399
156
 
400
- // Write combined schema
401
157
  fs.writeFileSync(outputPath, JSON.stringify(baseSchema, null, 2), 'utf-8');
402
158
  console.log(' Generated combined JSON schema at node_modules/.omnify/combined-schema.json');
403
159
 
@@ -409,47 +165,42 @@ function generateCombinedSchema(projectRoot) {
409
165
  }
410
166
 
411
167
  function findProjectRoot() {
412
- // npm/pnpm set INIT_CWD to the directory where the install was run
413
- // This is more reliable than process.cwd() during postinstall
414
168
  let dir = process.env.INIT_CWD || process.cwd();
415
-
416
- // If we're in node_modules, go up to find the actual project
417
169
  const nodeModulesIndex = dir.indexOf('node_modules');
418
170
  if (nodeModulesIndex !== -1) {
419
171
  dir = dir.substring(0, nodeModulesIndex - 1);
420
172
  }
421
-
422
- // Verify it's a project root by checking for package.json
423
173
  const packageJsonPath = path.join(dir, 'package.json');
424
174
  if (fs.existsSync(packageJsonPath)) {
425
175
  return dir;
426
176
  }
427
-
428
177
  return null;
429
178
  }
430
179
 
431
- function createOmnifySkillFiles(projectRoot) {
180
+ function copyAiGuidesToProject(projectRoot) {
432
181
  const omnifyDir = path.join(projectRoot, '.claude', 'omnify');
182
+ const aiGuidesDir = path.join(__dirname, '..', 'ai-guides');
433
183
 
434
184
  try {
435
- // Create .claude/omnify directory
436
185
  if (!fs.existsSync(omnifyDir)) {
437
186
  fs.mkdirSync(omnifyDir, { recursive: true });
438
187
  }
439
188
 
440
- // Write base schema guide (plugin-specific guides are created by each plugin)
441
- const schemaGuidePath = path.join(omnifyDir, 'schema-guide.md');
442
- 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);
443
194
 
444
- // Write config guide
445
- const configGuidePath = path.join(omnifyDir, 'config-guide.md');
446
- 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
+ }
447
201
 
448
- console.log(' Created .claude/omnify/schema-guide.md');
449
- console.log(' Created .claude/omnify/config-guide.md');
450
202
  return true;
451
- } catch (error) {
452
- console.log(' Note: Could not create .claude/omnify/ skill files');
203
+ } catch {
453
204
  return false;
454
205
  }
455
206
  }
@@ -457,24 +208,20 @@ function createOmnifySkillFiles(projectRoot) {
457
208
  function createClaudeMd(projectRoot) {
458
209
  const claudeMdPath = path.join(projectRoot, 'CLAUDE.md');
459
210
 
460
- // Check if CLAUDE.md exists
461
211
  if (fs.existsSync(claudeMdPath)) {
462
212
  const existingContent = fs.readFileSync(claudeMdPath, 'utf-8');
463
213
 
464
- // Check if Omnify section already exists
465
214
  if (existingContent.includes(OMNIFY_MARKER)) {
466
215
  console.log(' CLAUDE.md already has Omnify section, skipping...');
467
216
  return false;
468
217
  }
469
218
 
470
- // Append Omnify section to existing CLAUDE.md
471
219
  const newContent = existingContent.trimEnd() + '\n\n' + CLAUDE_MD_SECTION;
472
220
  fs.writeFileSync(claudeMdPath, newContent, 'utf-8');
473
221
  console.log(' Appended Omnify section to CLAUDE.md');
474
222
  return true;
475
223
  }
476
224
 
477
- // Create new CLAUDE.md with just the Omnify section
478
225
  fs.writeFileSync(claudeMdPath, CLAUDE_MD_SECTION, 'utf-8');
479
226
  console.log(' Created CLAUDE.md');
480
227
  return true;
@@ -485,12 +232,10 @@ function createCursorRules(projectRoot) {
485
232
  const cursorRulesPath = path.join(cursorDir, 'omnify.md');
486
233
 
487
234
  try {
488
- // Create .cursor/rules directory
489
235
  if (!fs.existsSync(cursorDir)) {
490
236
  fs.mkdirSync(cursorDir, { recursive: true });
491
237
  }
492
238
 
493
- // Always overwrite - this file is fully managed by Omnify
494
239
  fs.writeFileSync(cursorRulesPath, CURSORRULES_CONTENT, 'utf-8');
495
240
  console.log(' Updated .cursor/rules/omnify.md');
496
241
  return true;
@@ -505,14 +250,12 @@ function configureClaudeMcp() {
505
250
  const configPath = path.join(claudeDir, 'claude_desktop_config.json');
506
251
 
507
252
  try {
508
- // Create .claude directory if not exists
509
253
  if (!fs.existsSync(claudeDir)) {
510
254
  fs.mkdirSync(claudeDir, { recursive: true });
511
255
  }
512
256
 
513
257
  let config = { mcpServers: {} };
514
258
 
515
- // Read existing config if exists
516
259
  if (fs.existsSync(configPath)) {
517
260
  try {
518
261
  const content = fs.readFileSync(configPath, 'utf-8');
@@ -521,38 +264,30 @@ function configureClaudeMcp() {
521
264
  config.mcpServers = {};
522
265
  }
523
266
  } catch {
524
- // Invalid JSON, start fresh
525
267
  config = { mcpServers: {} };
526
268
  }
527
269
  }
528
270
 
529
- // Check if omnify is already configured
530
271
  if (config.mcpServers.omnify) {
531
272
  console.log(' Omnify MCP already configured');
532
273
  return false;
533
274
  }
534
275
 
535
- // Add omnify MCP server
536
276
  config.mcpServers.omnify = MCP_CONFIG.omnify;
537
-
538
- // Write config
539
277
  fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8');
540
278
  console.log(' Configured Omnify MCP server in ~/.claude/claude_desktop_config.json');
541
279
  return true;
542
280
  } catch (error) {
543
- // Silently fail - MCP config is optional
544
281
  console.log(' Note: Could not auto-configure MCP (optional)');
545
282
  return false;
546
283
  }
547
284
  }
548
285
 
549
286
  function main() {
550
- // Skip in CI environments
551
287
  if (process.env.CI || process.env.CONTINUOUS_INTEGRATION) {
552
288
  return;
553
289
  }
554
290
 
555
- // Skip if in omnify-ts monorepo (source code), but allow examples/
556
291
  const projectDir = process.env.INIT_CWD || process.cwd();
557
292
  if (projectDir.includes('omnify-ts') && !projectDir.includes('omnify-ts/examples')) {
558
293
  return;
@@ -563,20 +298,12 @@ function main() {
563
298
  const projectRoot = findProjectRoot();
564
299
 
565
300
  if (projectRoot) {
566
- // Generate combined JSON schema with plugin contributions
567
301
  generateCombinedSchema(projectRoot);
568
-
569
- // Create .claude/omnify/ skill files
570
- createOmnifySkillFiles(projectRoot);
571
-
572
- // Create or update CLAUDE.md in project root
302
+ copyAiGuidesToProject(projectRoot);
573
303
  createClaudeMd(projectRoot);
574
-
575
- // Create Cursor rules
576
304
  createCursorRules(projectRoot);
577
305
  }
578
306
 
579
- // Configure MCP server in user's home directory
580
307
  configureClaudeMcp();
581
308
 
582
309
  console.log('\n✅ Omnify setup complete!\n');