@famgia/omnify 1.0.89 → 1.0.91

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.
@@ -75,6 +75,10 @@ properties:
75
75
  displayName:
76
76
  ja: 名前
77
77
  en: Name
78
+ placeholder: # Placeholder for form inputs (multi-language)
79
+ ja: 名前を入力
80
+ en: Enter name
81
+ vi: Nhập tên
78
82
  nullable: false # Nullable (default: false)
79
83
  unique: true # Unique constraint
80
84
  primary: true # Primary key (use with options.id: false)
@@ -84,6 +88,40 @@ properties:
84
88
  maxLength: 255
85
89
  ```
86
90
 
91
+ ## Placeholder for Compound Types
92
+
93
+ For compound types (like JapaneseName, JapaneseAddress), you can customize placeholders per field:
94
+
95
+ ```yaml
96
+ properties:
97
+ name:
98
+ type: JapaneseName
99
+ displayName:
100
+ ja: 氏名
101
+ en: Full Name
102
+ fields: # Per-field overrides for compound types
103
+ Lastname:
104
+ placeholder: # Override default placeholder
105
+ ja: 姓を入力
106
+ en: Enter last name
107
+ Firstname:
108
+ placeholder:
109
+ ja: 名を入力
110
+ en: Enter first name
111
+ KanaLastname:
112
+ nullable: true
113
+ placeholder:
114
+ ja: セイ(カナ)
115
+ en: Last name (Kana)
116
+ KanaFirstname:
117
+ nullable: true
118
+ placeholder:
119
+ ja: メイ(カナ)
120
+ en: First name (Kana)
121
+ ```
122
+
123
+ **Note**: Compound types from plugins (like `@famgia/omnify-japan`) come with default placeholders for common locales (en, ja, vi). You can override them in your schema as shown above.
124
+
87
125
  ## Association Relations
88
126
 
89
127
  ### ManyToOne (N:1)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@famgia/omnify",
3
- "version": "1.0.89",
3
+ "version": "1.0.91",
4
4
  "description": "Schema-driven database migration system with TypeScript types and Laravel migrations",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -25,14 +25,14 @@
25
25
  "README.md"
26
26
  ],
27
27
  "dependencies": {
28
- "@famgia/omnify-typescript": "0.0.67",
29
- "@famgia/omnify-laravel": "0.0.88",
30
- "@famgia/omnify-atlas": "0.0.73",
31
- "@famgia/omnify-core": "0.0.79",
32
- "@famgia/omnify-cli": "0.0.85",
33
- "@famgia/omnify-types": "0.0.77",
34
- "@famgia/omnify-mcp": "0.0.65",
35
- "@famgia/omnify-japan": "0.0.72"
28
+ "@famgia/omnify-cli": "0.0.87",
29
+ "@famgia/omnify-core": "0.0.81",
30
+ "@famgia/omnify-types": "0.0.79",
31
+ "@famgia/omnify-laravel": "0.0.90",
32
+ "@famgia/omnify-typescript": "0.0.69",
33
+ "@famgia/omnify-mcp": "0.0.67",
34
+ "@famgia/omnify-atlas": "0.0.75",
35
+ "@famgia/omnify-japan": "0.0.74"
36
36
  },
37
37
  "keywords": [
38
38
  "omnify",
@@ -1,5 +1,16 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ /**
4
+ * @famgia/omnify postinstall
5
+ *
6
+ * Sets up AI assistant integration:
7
+ * 1. Generate combined JSON Schema (for YAML validation in editors)
8
+ * 2. Copy AI guides to .claude/omnify/
9
+ * 3. Create/update CLAUDE.md
10
+ * 4. Create .cursor/rules/omnify.md
11
+ * 5. Configure Claude MCP server
12
+ */
13
+
3
14
  import fs from 'fs';
4
15
  import path from 'path';
5
16
  import os from 'os';
@@ -8,7 +19,10 @@ import { fileURLToPath } from 'url';
8
19
  const __filename = fileURLToPath(import.meta.url);
9
20
  const __dirname = path.dirname(__filename);
10
21
 
11
- // Content for CLAUDE.md
22
+ // ============================================================================
23
+ // Content Templates
24
+ // ============================================================================
25
+
12
26
  const CLAUDE_MD_SECTION = `## Omnify
13
27
 
14
28
  This project uses Omnify for schema-driven code generation.
@@ -18,15 +32,13 @@ This project uses Omnify for schema-driven code generation.
18
32
  - \`config-guide.md\` - Configuration (omnify.config.ts)
19
33
  - \`laravel-guide.md\` - Laravel generator (if installed)
20
34
  - \`typescript-guide.md\` - TypeScript generator (if installed)
21
- - \`antdesign-guide.md\` - Ant Design Form integration (if installed)
22
35
 
23
36
  **Commands**:
24
37
  - \`npx omnify generate\` - Generate code from schemas
25
38
  - \`npx omnify validate\` - Validate schemas
26
39
  `;
27
40
 
28
- // Cursor rules content
29
- const CURSORRULES_CONTENT = `# Omnify Schema Rules
41
+ const CURSOR_RULES = `# Omnify Schema Rules
30
42
 
31
43
  This project uses Omnify for schema-driven code generation.
32
44
  Schemas are in \`schemas/\` directory with \`.yaml\` extension.
@@ -36,358 +48,213 @@ For detailed documentation, read these files:
36
48
  - .claude/omnify/config-guide.md - Configuration (omnify.config.ts)
37
49
  - .claude/omnify/laravel-guide.md - Laravel generator (if exists)
38
50
  - .claude/omnify/typescript-guide.md - TypeScript generator (if exists)
39
- - .claude/omnify/antdesign-guide.md - Ant Design Form integration (if exists)
40
51
 
41
52
  Commands:
42
53
  - npx omnify generate - Generate code from schemas
43
54
  - npx omnify validate - Validate all schemas
44
55
  `;
45
56
 
46
- const MCP_CONFIG = {
47
- omnify: {
48
- command: 'npx',
49
- args: ['@famgia/omnify-mcp'],
50
- },
51
- };
57
+ // ============================================================================
58
+ // Helper Functions
59
+ // ============================================================================
60
+
61
+ function findProjectRoot() {
62
+ let dir = process.env.INIT_CWD || process.cwd();
63
+ const idx = dir.indexOf('node_modules');
64
+ if (idx !== -1) dir = dir.substring(0, idx - 1);
65
+ return fs.existsSync(path.join(dir, 'package.json')) ? dir : null;
66
+ }
67
+
68
+ function copyFiles(srcDir, destDir) {
69
+ if (!fs.existsSync(srcDir)) return [];
70
+ if (!fs.existsSync(destDir)) fs.mkdirSync(destDir, { recursive: true });
71
+
72
+ const copied = [];
73
+ for (const file of fs.readdirSync(srcDir)) {
74
+ const src = path.join(srcDir, file);
75
+ if (fs.statSync(src).isFile()) {
76
+ fs.copyFileSync(src, path.join(destDir, file));
77
+ copied.push(file);
78
+ }
79
+ }
80
+ return copied;
81
+ }
82
+
83
+ // ============================================================================
84
+ // Setup Functions
85
+ // ============================================================================
52
86
 
53
- /**
54
- * Generate combined JSON Schema from base schema + all plugin contributions
55
- */
56
87
  function generateCombinedSchema(projectRoot) {
57
- const nodeModulesDir = path.join(projectRoot, 'node_modules');
58
- const outputDir = path.join(nodeModulesDir, '.omnify');
88
+ const nodeModules = path.join(projectRoot, 'node_modules');
89
+ const outputDir = path.join(nodeModules, '.omnify');
59
90
  const outputPath = path.join(outputDir, 'combined-schema.json');
60
91
 
61
- try {
62
- // Read base schema from @famgia/omnify-types
63
- const possiblePaths = [
64
- path.join(nodeModulesDir, '@famgia/omnify-types/schemas/omnify-schema.json'),
65
- path.join(nodeModulesDir, '@famgia/omnify/node_modules/@famgia/omnify-types/schemas/omnify-schema.json'),
66
- ];
67
-
68
- let baseSchemaPath = null;
69
- for (const p of possiblePaths) {
70
- if (fs.existsSync(p)) {
71
- baseSchemaPath = p;
72
- break;
73
- }
74
- }
92
+ // Find base schema
93
+ const searchPaths = [
94
+ path.join(nodeModules, '@famgia/omnify-types/schemas/omnify-schema.json'),
95
+ path.join(nodeModules, '@famgia/omnify/node_modules/@famgia/omnify-types/schemas/omnify-schema.json'),
96
+ ];
75
97
 
76
- // Try pnpm hoisted location
77
- if (!baseSchemaPath) {
78
- const pnpmDir = path.join(nodeModulesDir, '.pnpm');
79
- if (fs.existsSync(pnpmDir)) {
80
- const matches = fs.readdirSync(pnpmDir).filter(f => f.startsWith('@famgia+omnify-types@'));
81
- if (matches.length > 0) {
82
- const matchPath = path.join(pnpmDir, matches[0], 'node_modules/@famgia/omnify-types/schemas/omnify-schema.json');
83
- if (fs.existsSync(matchPath)) {
84
- baseSchemaPath = matchPath;
85
- }
86
- }
87
- }
98
+ // Also check pnpm hoisted location
99
+ const pnpmDir = path.join(nodeModules, '.pnpm');
100
+ if (fs.existsSync(pnpmDir)) {
101
+ const match = fs.readdirSync(pnpmDir).find(f => f.startsWith('@famgia+omnify-types@'));
102
+ if (match) {
103
+ searchPaths.push(path.join(pnpmDir, match, 'node_modules/@famgia/omnify-types/schemas/omnify-schema.json'));
88
104
  }
105
+ }
89
106
 
90
- if (!baseSchemaPath) {
91
- console.log(' Note: Base schema not found, skipping combined schema generation');
92
- return false;
93
- }
107
+ const baseSchemaPath = searchPaths.find(p => fs.existsSync(p));
108
+ if (!baseSchemaPath) return false;
94
109
 
110
+ try {
95
111
  const baseSchema = JSON.parse(fs.readFileSync(baseSchemaPath, 'utf-8'));
96
112
 
97
- // Find all @famgia/omnify-* plugins with schema contributions
98
- const famgiaDirs = [
99
- path.join(nodeModulesDir, '@famgia'),
100
- path.join(nodeModulesDir, '@famgia/omnify/node_modules/@famgia'),
101
- ];
102
- const pluginContributions = [];
103
- const processedPlugins = new Set();
104
-
105
- for (const famgiaDir of famgiaDirs) {
106
- if (!fs.existsSync(famgiaDir)) continue;
107
-
108
- const packages = fs.readdirSync(famgiaDir);
109
- for (const pkg of packages) {
110
- if (!pkg.startsWith('omnify-') || pkg === 'omnify-types' || pkg === 'omnify-mcp') {
111
- continue;
112
- }
113
- if (processedPlugins.has(pkg)) continue;
113
+ // Find plugin schema contributions
114
+ const famgiaDir = path.join(nodeModules, '@famgia');
115
+ if (fs.existsSync(famgiaDir)) {
116
+ for (const pkg of fs.readdirSync(famgiaDir)) {
117
+ if (!pkg.startsWith('omnify-') || pkg === 'omnify-types' || pkg === 'omnify-mcp') continue;
114
118
 
115
119
  const contributionPath = path.join(famgiaDir, pkg, 'schemas/schema-contribution.json');
116
120
  if (fs.existsSync(contributionPath)) {
117
121
  try {
118
122
  const contribution = JSON.parse(fs.readFileSync(contributionPath, 'utf-8'));
119
- pluginContributions.push({ name: pkg, contribution });
120
- processedPlugins.add(pkg);
121
- } catch {
122
- // Invalid JSON, skip
123
- }
124
- }
125
- }
126
- }
127
123
 
128
- // Merge contributions into base schema
129
- for (const { name, contribution } of pluginContributions) {
130
- if (contribution.definitions) {
131
- for (const [defName, defValue] of Object.entries(contribution.definitions)) {
132
- baseSchema.definitions[defName] = defValue;
133
- }
134
- }
124
+ // Merge definitions
125
+ if (contribution.definitions) {
126
+ Object.assign(baseSchema.definitions, contribution.definitions);
127
+ }
135
128
 
136
- if (contribution.propertyTypes && baseSchema.definitions.PropertyDefinition) {
137
- for (const typeName of contribution.propertyTypes) {
138
- baseSchema.definitions.PropertyDefinition.oneOf.push({
139
- "$ref": `#/definitions/${typeName}`
140
- });
129
+ // Add property types
130
+ if (contribution.propertyTypes && baseSchema.definitions.PropertyDefinition) {
131
+ for (const typeName of contribution.propertyTypes) {
132
+ baseSchema.definitions.PropertyDefinition.oneOf.push({
133
+ "$ref": `#/definitions/${typeName}`
134
+ });
135
+ }
136
+ }
137
+ } catch { /* skip invalid */ }
141
138
  }
142
139
  }
143
-
144
- console.log(` Added schema contributions from @famgia/${name}`);
145
140
  }
146
141
 
147
142
  baseSchema.$id = 'omnify://combined-schema.json';
148
- baseSchema.description = baseSchema.description + ' (Combined with plugin contributions)';
149
-
150
- if (!fs.existsSync(outputDir)) {
151
- fs.mkdirSync(outputDir, { recursive: true });
152
- }
153
-
154
- fs.writeFileSync(outputPath, JSON.stringify(baseSchema, null, 2), 'utf-8');
155
- console.log(' Generated combined JSON schema at node_modules/.omnify/combined-schema.json');
156
-
143
+ if (!fs.existsSync(outputDir)) fs.mkdirSync(outputDir, { recursive: true });
144
+ fs.writeFileSync(outputPath, JSON.stringify(baseSchema, null, 2));
157
145
  return true;
158
- } catch (error) {
159
- console.log(' Note: Could not generate combined schema');
146
+ } catch {
160
147
  return false;
161
148
  }
162
149
  }
163
150
 
164
- function findProjectRoot() {
165
- let dir = process.env.INIT_CWD || process.cwd();
166
- const nodeModulesIndex = dir.indexOf('node_modules');
167
- if (nodeModulesIndex !== -1) {
168
- dir = dir.substring(0, nodeModulesIndex - 1);
169
- }
170
- const packageJsonPath = path.join(dir, 'package.json');
171
- if (fs.existsSync(packageJsonPath)) {
172
- return dir;
173
- }
174
- return null;
151
+ function copyAiGuides(projectRoot) {
152
+ const src = path.join(__dirname, '..', 'ai-guides');
153
+ const dest = path.join(projectRoot, '.claude', 'omnify');
154
+ return copyFiles(src, dest);
175
155
  }
176
156
 
177
- /**
178
- * Find all @famgia/omnify-* packages with ai-guides directories
179
- */
180
- function findPluginAiGuides(projectRoot) {
181
- const nodeModulesDir = path.join(projectRoot, 'node_modules');
182
- const aiGuidesDirs = [];
183
-
184
- // Check @famgia directory
185
- const famgiaDir = path.join(nodeModulesDir, '@famgia');
186
- if (fs.existsSync(famgiaDir)) {
187
- const packages = fs.readdirSync(famgiaDir);
188
- for (const pkg of packages) {
189
- if (pkg.startsWith('omnify')) {
190
- const aiGuidesPath = path.join(famgiaDir, pkg, 'ai-guides');
191
- if (fs.existsSync(aiGuidesPath)) {
192
- aiGuidesDirs.push(aiGuidesPath);
193
- }
194
- }
195
- }
196
- }
157
+ function setupClaudeMd(projectRoot) {
158
+ const filePath = path.join(projectRoot, 'CLAUDE.md');
197
159
 
198
- // Also check pnpm hoisted location (.pnpm/@famgia+omnify-xxx@version/node_modules/@famgia/omnify-xxx)
199
- const pnpmDir = path.join(nodeModulesDir, '.pnpm');
200
- if (fs.existsSync(pnpmDir)) {
201
- try {
202
- const pnpmPackages = fs.readdirSync(pnpmDir);
203
- for (const pkg of pnpmPackages) {
204
- if (pkg.startsWith('@famgia+omnify')) {
205
- // Extract package name from pnpm folder name (e.g., @famgia+omnify-laravel@0.0.70 -> omnify-laravel)
206
- const match = pkg.match(/@famgia\+([^@]+)@/);
207
- if (match) {
208
- const pkgName = match[1]; // e.g., omnify-laravel
209
- const aiGuidesPath = path.join(pnpmDir, pkg, 'node_modules/@famgia', pkgName, 'ai-guides');
210
- if (fs.existsSync(aiGuidesPath)) {
211
- aiGuidesDirs.push(aiGuidesPath);
212
- }
213
- }
214
- }
215
- }
216
- } catch {
217
- // Ignore errors reading pnpm directory
218
- }
219
- }
220
-
221
- return aiGuidesDirs;
222
- }
223
-
224
- function copyAiGuidesToProject(projectRoot) {
225
- const omnifyDir = path.join(projectRoot, '.claude', 'omnify');
226
-
227
- try {
228
- // Create .claude/omnify directory
229
- if (!fs.existsSync(omnifyDir)) {
230
- fs.mkdirSync(omnifyDir, { recursive: true });
231
- }
232
-
233
- // Track copied files to avoid duplicates
234
- const copiedFiles = new Set();
235
-
236
- // Helper to copy files without duplicates
237
- const copyWithoutDuplicates = (srcDir) => {
238
- if (!fs.existsSync(srcDir)) return;
239
- const files = fs.readdirSync(srcDir);
240
- for (const file of files) {
241
- if (copiedFiles.has(file)) continue;
242
- const srcPath = path.join(srcDir, file);
243
- const destPath = path.join(omnifyDir, file);
244
- if (fs.statSync(srcPath).isFile()) {
245
- fs.copyFileSync(srcPath, destPath);
246
- copiedFiles.add(file);
247
- console.log(` Created .claude/omnify/${file}`);
248
- }
249
- }
250
- };
251
-
252
- // Copy from main omnify package first
253
- const mainAiGuidesDir = path.join(__dirname, '..', 'ai-guides');
254
- copyWithoutDuplicates(mainAiGuidesDir);
255
-
256
- // Copy from all @famgia/omnify-* plugin packages
257
- const pluginDirs = findPluginAiGuides(projectRoot);
258
- for (const pluginDir of pluginDirs) {
259
- copyWithoutDuplicates(pluginDir);
260
- }
261
-
262
- return true;
263
- } catch {
264
- return false;
265
- }
266
- }
160
+ if (fs.existsSync(filePath)) {
161
+ let content = fs.readFileSync(filePath, 'utf-8');
162
+ const match = content.match(/## Omnify[^\n]*/);
267
163
 
268
- function createClaudeMd(projectRoot) {
269
- const claudeMdPath = path.join(projectRoot, 'CLAUDE.md');
270
- const SECTION_START = '## Omnify';
271
- const SECTION_END_MARKERS = ['## ', '---', '# ']; // Next section indicators
272
-
273
- if (fs.existsSync(claudeMdPath)) {
274
- let content = fs.readFileSync(claudeMdPath, 'utf-8');
275
-
276
- // Find existing Omnify section (## Omnify or ## Omnify Schema Integration, etc.)
277
- const omnifyMatch = content.match(/## Omnify[^\n]*/);
278
- if (omnifyMatch) {
279
- const startIdx = content.indexOf(omnifyMatch[0]);
280
- // Find the end of the section (next ## heading or --- or end of file)
164
+ if (match) {
165
+ // Replace existing section
166
+ const startIdx = content.indexOf(match[0]);
281
167
  let endIdx = content.length;
282
- const afterStart = content.substring(startIdx + omnifyMatch[0].length);
168
+ const after = content.substring(startIdx + match[0].length);
283
169
 
284
- for (const marker of SECTION_END_MARKERS) {
285
- const markerIdx = afterStart.indexOf('\n' + marker);
286
- if (markerIdx !== -1 && markerIdx < endIdx - startIdx - omnifyMatch[0].length) {
287
- endIdx = startIdx + omnifyMatch[0].length + markerIdx + 1;
170
+ for (const marker of ['## ', '---', '# ']) {
171
+ const idx = after.indexOf('\n' + marker);
172
+ if (idx !== -1 && idx < endIdx - startIdx - match[0].length) {
173
+ endIdx = startIdx + match[0].length + idx + 1;
288
174
  }
289
175
  }
290
176
 
291
- // Replace the old section with new content
292
- const before = content.substring(0, startIdx);
293
- const after = content.substring(endIdx);
294
- content = before + CLAUDE_MD_SECTION + after;
295
- fs.writeFileSync(claudeMdPath, content, 'utf-8');
296
- console.log(' Updated Omnify section in CLAUDE.md');
297
- return true;
177
+ content = content.substring(0, startIdx) + CLAUDE_MD_SECTION + content.substring(endIdx);
178
+ } else {
179
+ // Append section
180
+ content = content.trimEnd() + '\n\n' + CLAUDE_MD_SECTION;
298
181
  }
299
182
 
300
- // No Omnify section found, append
301
- const newContent = content.trimEnd() + '\n\n' + CLAUDE_MD_SECTION;
302
- fs.writeFileSync(claudeMdPath, newContent, 'utf-8');
303
- console.log(' Appended Omnify section to CLAUDE.md');
304
- return true;
183
+ fs.writeFileSync(filePath, content);
184
+ } else {
185
+ fs.writeFileSync(filePath, CLAUDE_MD_SECTION);
305
186
  }
306
-
307
- fs.writeFileSync(claudeMdPath, CLAUDE_MD_SECTION, 'utf-8');
308
- console.log(' Created CLAUDE.md');
309
- return true;
310
187
  }
311
188
 
312
- function createCursorRules(projectRoot) {
313
- const cursorDir = path.join(projectRoot, '.cursor', 'rules');
314
- const cursorRulesPath = path.join(cursorDir, 'omnify.md');
315
-
316
- try {
317
- if (!fs.existsSync(cursorDir)) {
318
- fs.mkdirSync(cursorDir, { recursive: true });
319
- }
320
-
321
- fs.writeFileSync(cursorRulesPath, CURSORRULES_CONTENT, 'utf-8');
322
- console.log(' Updated .cursor/rules/omnify.md');
323
- return true;
324
- } catch {
325
- return false;
326
- }
189
+ function setupCursorRules(projectRoot) {
190
+ const dir = path.join(projectRoot, '.cursor', 'rules');
191
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
192
+ fs.writeFileSync(path.join(dir, 'omnify.md'), CURSOR_RULES);
327
193
  }
328
194
 
329
- function configureClaudeMcp() {
330
- const homeDir = os.homedir();
331
- const claudeDir = path.join(homeDir, '.claude');
332
- const configPath = path.join(claudeDir, 'claude_desktop_config.json');
195
+ function setupClaudeMcp() {
196
+ const configPath = path.join(os.homedir(), '.claude', 'claude_desktop_config.json');
333
197
 
334
198
  try {
335
- if (!fs.existsSync(claudeDir)) {
336
- fs.mkdirSync(claudeDir, { recursive: true });
337
- }
199
+ const dir = path.dirname(configPath);
200
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
338
201
 
339
202
  let config = { mcpServers: {} };
340
-
341
203
  if (fs.existsSync(configPath)) {
342
204
  try {
343
- const content = fs.readFileSync(configPath, 'utf-8');
344
- config = JSON.parse(content);
345
- if (!config.mcpServers) {
346
- config.mcpServers = {};
347
- }
348
- } catch {
349
- config = { mcpServers: {} };
350
- }
205
+ config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
206
+ config.mcpServers = config.mcpServers || {};
207
+ } catch { /* use default */ }
351
208
  }
352
209
 
353
- if (config.mcpServers.omnify) {
354
- console.log(' Omnify MCP already configured');
355
- return false;
210
+ if (!config.mcpServers.omnify) {
211
+ config.mcpServers.omnify = { command: 'npx', args: ['@famgia/omnify-mcp'] };
212
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
356
213
  }
357
-
358
- config.mcpServers.omnify = MCP_CONFIG.omnify;
359
- fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8');
360
- console.log(' Configured Omnify MCP server in ~/.claude/claude_desktop_config.json');
361
- return true;
362
- } catch (error) {
363
- console.log(' Note: Could not auto-configure MCP (optional)');
364
- return false;
365
- }
214
+ } catch { /* optional, ignore errors */ }
366
215
  }
367
216
 
217
+ // ============================================================================
218
+ // Main
219
+ // ============================================================================
220
+
368
221
  function main() {
369
- if (process.env.CI || process.env.CONTINUOUS_INTEGRATION) {
370
- return;
371
- }
222
+ // Skip in CI
223
+ if (process.env.CI || process.env.CONTINUOUS_INTEGRATION) return;
372
224
 
225
+ // Skip in monorepo source (but allow examples/)
373
226
  const projectDir = process.env.INIT_CWD || process.cwd();
374
- if (projectDir.includes('omnify-ts') && !projectDir.includes('omnify-ts/examples')) {
375
- return;
376
- }
377
-
378
- console.log('\n🔧 Omnify: Setting up Claude Code integration...\n');
227
+ if (projectDir.includes('omnify-ts') && !projectDir.includes('omnify-ts/examples')) return;
379
228
 
380
229
  const projectRoot = findProjectRoot();
230
+ if (!projectRoot) return;
231
+
232
+ console.log('\n🔧 Omnify: Setting up AI integration...\n');
233
+
234
+ const results = [];
381
235
 
382
- if (projectRoot) {
383
- generateCombinedSchema(projectRoot);
384
- copyAiGuidesToProject(projectRoot);
385
- createClaudeMd(projectRoot);
386
- createCursorRules(projectRoot);
236
+ if (generateCombinedSchema(projectRoot)) {
237
+ results.push('✓ Generated combined JSON schema');
387
238
  }
388
239
 
389
- configureClaudeMcp();
240
+ const guides = copyAiGuides(projectRoot);
241
+ if (guides.length > 0) {
242
+ results.push(`✓ Copied ${guides.length} AI guides to .claude/omnify/`);
243
+ }
244
+
245
+ try {
246
+ setupClaudeMd(projectRoot);
247
+ results.push('✓ Updated CLAUDE.md');
248
+ } catch { /* ignore */ }
249
+
250
+ try {
251
+ setupCursorRules(projectRoot);
252
+ results.push('✓ Updated .cursor/rules/omnify.md');
253
+ } catch { /* ignore */ }
254
+
255
+ setupClaudeMcp();
390
256
 
257
+ for (const r of results) console.log(` ${r}`);
391
258
  console.log('\n✅ Omnify setup complete!\n');
392
259
  }
393
260