@famgia/omnify-cli 2.0.14 → 2.0.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +67 -15
- package/dist/cli.js +193 -12
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +85 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +43 -2
- package/dist/index.d.ts +43 -2
- package/dist/index.js +88 -12
- package/dist/index.js.map +1 -1
- package/package.json +9 -6
package/README.md
CHANGED
|
@@ -122,6 +122,58 @@ omnify generate --force
|
|
|
122
122
|
omnify generate -v
|
|
123
123
|
```
|
|
124
124
|
|
|
125
|
+
### `omnify ai-guides`
|
|
126
|
+
|
|
127
|
+
Generate AI assistant guides (Cursor rules, Claude guides/rules, Antigravity rules).
|
|
128
|
+
|
|
129
|
+
> This command loads `@famgia/omnify-ai-guides`. If it’s not installed, install it first:
|
|
130
|
+
>
|
|
131
|
+
> ```bash
|
|
132
|
+
> pnpm add -D @famgia/omnify-ai-guides
|
|
133
|
+
> ```
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
omnify ai-guides [options]
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
This command reads from `omnify.config.ts` (if present). Add `aiGuides` section:
|
|
140
|
+
|
|
141
|
+
```typescript
|
|
142
|
+
export default defineConfig({
|
|
143
|
+
// ... other config
|
|
144
|
+
aiGuides: {
|
|
145
|
+
typescriptBase: 'resources/ts', // or 'resources/js', 'src', etc.
|
|
146
|
+
laravelBase: 'app',
|
|
147
|
+
categories: ['omnify', 'laravel', 'react'], // optional
|
|
148
|
+
adapters: ['cursor', 'claude', 'antigravity'], // optional
|
|
149
|
+
},
|
|
150
|
+
});
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Options (override config):
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
-v, --verbose Enable verbose output
|
|
157
|
+
-c, --categories <categories> Categories to generate (comma-separated: omnify,laravel,react)
|
|
158
|
+
-a, --adapters <adapters> Adapters to use (comma-separated: cursor,claude,antigravity)
|
|
159
|
+
--laravel-base <path> Laravel base path for placeholders
|
|
160
|
+
--typescript-base <path> TypeScript base path for placeholders
|
|
161
|
+
--dry-run Show what would be generated without writing files
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Common examples:
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
# API-only project (skip React)
|
|
168
|
+
omnify ai-guides --categories omnify,laravel
|
|
169
|
+
|
|
170
|
+
# Frontend-only (skip Laravel)
|
|
171
|
+
omnify ai-guides --categories omnify,react
|
|
172
|
+
|
|
173
|
+
# Only Cursor rules
|
|
174
|
+
omnify ai-guides --adapters cursor
|
|
175
|
+
```
|
|
176
|
+
|
|
125
177
|
### `omnify create-laravel-project`
|
|
126
178
|
|
|
127
179
|
Create a new Laravel project from the boilerplate template.
|
|
@@ -187,13 +239,13 @@ export default defineConfig({
|
|
|
187
239
|
|
|
188
240
|
### Configuration Options
|
|
189
241
|
|
|
190
|
-
| Option
|
|
191
|
-
|
|
192
|
-
| `schemasDir`
|
|
193
|
-
| `lockFilePath`
|
|
194
|
-
| `database.driver` | `string`
|
|
195
|
-
| `database.devUrl` | `string`
|
|
196
|
-
| `plugins`
|
|
242
|
+
| Option | Type | Required | Description |
|
|
243
|
+
| ----------------- | ---------- | -------- | ----------------------------------------------------------- |
|
|
244
|
+
| `schemasDir` | `string` | Yes | Directory containing schema files |
|
|
245
|
+
| `lockFilePath` | `string` | Yes | Path to lock file for change tracking |
|
|
246
|
+
| `database.driver` | `string` | Yes | Database driver: `mysql`, `postgres`, `sqlite` |
|
|
247
|
+
| `database.devUrl` | `string` | Yes* | Development database URL for Atlas (*required for generate) |
|
|
248
|
+
| `plugins` | `Plugin[]` | No | Array of generator plugins |
|
|
197
249
|
|
|
198
250
|
### Database URL Format
|
|
199
251
|
|
|
@@ -301,18 +353,18 @@ values:
|
|
|
301
353
|
|
|
302
354
|
## Exit Codes
|
|
303
355
|
|
|
304
|
-
| Code | Meaning
|
|
305
|
-
|
|
306
|
-
| 0
|
|
307
|
-
| 1
|
|
308
|
-
| 2
|
|
356
|
+
| Code | Meaning |
|
|
357
|
+
| ---- | ---------------- |
|
|
358
|
+
| 0 | Success |
|
|
359
|
+
| 1 | General error |
|
|
360
|
+
| 2 | Validation error |
|
|
309
361
|
|
|
310
362
|
## Environment Variables
|
|
311
363
|
|
|
312
|
-
| Variable
|
|
313
|
-
|
|
364
|
+
| Variable | Description |
|
|
365
|
+
| ---------------- | ------------------------------------ |
|
|
314
366
|
| `OMNIFY_DEV_URL` | Override database.devUrl from config |
|
|
315
|
-
| `DEBUG`
|
|
367
|
+
| `DEBUG` | Set to `omnify:*` for debug output |
|
|
316
368
|
|
|
317
369
|
## Troubleshooting
|
|
318
370
|
|
package/dist/cli.js
CHANGED
|
@@ -839,7 +839,8 @@ async function resolveConfig(userConfig, configPath2) {
|
|
|
839
839
|
lockFilePath: userConfig.lockFilePath ?? ".omnify.lock",
|
|
840
840
|
discovery,
|
|
841
841
|
...userConfig.locale && { locale: userConfig.locale },
|
|
842
|
-
...allSchemaPaths.length > 0 && { additionalSchemaPaths: allSchemaPaths }
|
|
842
|
+
...allSchemaPaths.length > 0 && { additionalSchemaPaths: allSchemaPaths },
|
|
843
|
+
...userConfig.aiGuides && { aiGuides: userConfig.aiGuides }
|
|
843
844
|
};
|
|
844
845
|
return result;
|
|
845
846
|
}
|
|
@@ -1127,6 +1128,9 @@ import {
|
|
|
1127
1128
|
isLockFileV2,
|
|
1128
1129
|
validateMigrations,
|
|
1129
1130
|
getMigrationsToRegenerate,
|
|
1131
|
+
addEnhancedMigrationRecord,
|
|
1132
|
+
extractTimestampFromFilename,
|
|
1133
|
+
extractTableNameFromFilename,
|
|
1130
1134
|
VERSION_CHAIN_FILE,
|
|
1131
1135
|
readVersionChain,
|
|
1132
1136
|
checkBulkLockViolation
|
|
@@ -1590,6 +1594,7 @@ function schemaChangeToVersionChange(change) {
|
|
|
1590
1594
|
}
|
|
1591
1595
|
function writeGeneratorOutputs(outputs, rootDir) {
|
|
1592
1596
|
const counts = { migrations: 0, types: 0, models: 0, factories: 0, other: 0 };
|
|
1597
|
+
const migrationRecords = [];
|
|
1593
1598
|
for (const output of outputs) {
|
|
1594
1599
|
const filePath = resolve9(rootDir, output.path);
|
|
1595
1600
|
const dir = dirname6(filePath);
|
|
@@ -1603,13 +1608,34 @@ function writeGeneratorOutputs(outputs, rootDir) {
|
|
|
1603
1608
|
}
|
|
1604
1609
|
writeFileSync5(filePath, output.content);
|
|
1605
1610
|
logger.debug(`Created: ${output.path}`);
|
|
1606
|
-
if (output.type === "migration")
|
|
1607
|
-
|
|
1611
|
+
if (output.type === "migration") {
|
|
1612
|
+
counts.migrations++;
|
|
1613
|
+
const fileName = output.path.split("/").pop() ?? output.path;
|
|
1614
|
+
const timestamp = extractTimestampFromFilename(fileName);
|
|
1615
|
+
const metaTableName = output.metadata?.tableName;
|
|
1616
|
+
const tableName = metaTableName ?? extractTableNameFromFilename(fileName);
|
|
1617
|
+
const migrationType = output.metadata?.migrationType;
|
|
1618
|
+
const schemaName = output.metadata?.schemaName;
|
|
1619
|
+
const pathParts = output.path.split("/");
|
|
1620
|
+
pathParts.pop();
|
|
1621
|
+
const outputPath = pathParts.join("/");
|
|
1622
|
+
if (timestamp && tableName) {
|
|
1623
|
+
migrationRecords.push({
|
|
1624
|
+
fileName,
|
|
1625
|
+
timestamp,
|
|
1626
|
+
tableName,
|
|
1627
|
+
type: migrationType ?? "create",
|
|
1628
|
+
schemas: schemaName ? [schemaName] : [],
|
|
1629
|
+
content: output.content,
|
|
1630
|
+
outputPath
|
|
1631
|
+
});
|
|
1632
|
+
}
|
|
1633
|
+
} else if (output.type === "type") counts.types++;
|
|
1608
1634
|
else if (output.type === "model") counts.models++;
|
|
1609
1635
|
else if (output.type === "factory") counts.factories++;
|
|
1610
1636
|
else counts.other++;
|
|
1611
1637
|
}
|
|
1612
|
-
return counts;
|
|
1638
|
+
return { ...counts, migrationRecords };
|
|
1613
1639
|
}
|
|
1614
1640
|
async function runPluginGeneration(plugins, schemas, rootDir, verbose, changes, localeConfig) {
|
|
1615
1641
|
const pluginManager = new PluginManager({
|
|
@@ -1640,6 +1666,7 @@ function runDirectGeneration(schemas, config, rootDir, options, changes) {
|
|
|
1640
1666
|
let typesGenerated = 0;
|
|
1641
1667
|
let modelsGenerated = 0;
|
|
1642
1668
|
let factoriesGenerated = 0;
|
|
1669
|
+
const migrationRecords = [];
|
|
1643
1670
|
const customTypesMap = /* @__PURE__ */ new Map();
|
|
1644
1671
|
for (const plugin of config.plugins) {
|
|
1645
1672
|
if (plugin.types) {
|
|
@@ -1685,6 +1712,17 @@ function runDirectGeneration(schemas, config, rootDir, options, changes) {
|
|
|
1685
1712
|
writeFileSync5(filePath, migration.content);
|
|
1686
1713
|
logger.debug(`Created: ${migration.fileName}`);
|
|
1687
1714
|
migrationsGenerated++;
|
|
1715
|
+
const timestamp = extractTimestampFromFilename(migration.fileName);
|
|
1716
|
+
if (timestamp && tableName) {
|
|
1717
|
+
migrationRecords.push({
|
|
1718
|
+
fileName: migration.fileName,
|
|
1719
|
+
timestamp,
|
|
1720
|
+
tableName,
|
|
1721
|
+
type: "create",
|
|
1722
|
+
schemas: migration.schemaName ? [migration.schemaName] : [],
|
|
1723
|
+
content: migration.content
|
|
1724
|
+
});
|
|
1725
|
+
}
|
|
1688
1726
|
}
|
|
1689
1727
|
}
|
|
1690
1728
|
if (alterChanges.length > 0) {
|
|
@@ -1694,6 +1732,18 @@ function runDirectGeneration(schemas, config, rootDir, options, changes) {
|
|
|
1694
1732
|
writeFileSync5(filePath, migration.content);
|
|
1695
1733
|
logger.debug(`Created: ${migration.fileName}`);
|
|
1696
1734
|
migrationsGenerated++;
|
|
1735
|
+
const timestamp = extractTimestampFromFilename(migration.fileName);
|
|
1736
|
+
const tableName = migration.tables[0];
|
|
1737
|
+
if (timestamp && tableName) {
|
|
1738
|
+
migrationRecords.push({
|
|
1739
|
+
fileName: migration.fileName,
|
|
1740
|
+
timestamp,
|
|
1741
|
+
tableName,
|
|
1742
|
+
type: migration.type,
|
|
1743
|
+
schemas: [],
|
|
1744
|
+
content: migration.content
|
|
1745
|
+
});
|
|
1746
|
+
}
|
|
1697
1747
|
}
|
|
1698
1748
|
}
|
|
1699
1749
|
logger.success(`Generated ${migrationsGenerated} migration(s)`);
|
|
@@ -1854,7 +1904,7 @@ function runDirectGeneration(schemas, config, rootDir, options, changes) {
|
|
|
1854
1904
|
logger.success("Auto-configured @omnify-base/* path in tsconfig.json");
|
|
1855
1905
|
}
|
|
1856
1906
|
}
|
|
1857
|
-
return { migrations: migrationsGenerated, types: typesGenerated, models: modelsGenerated, factories: factoriesGenerated };
|
|
1907
|
+
return { migrations: migrationsGenerated, types: typesGenerated, models: modelsGenerated, factories: factoriesGenerated, migrationRecords };
|
|
1858
1908
|
}
|
|
1859
1909
|
async function runGenerate(options) {
|
|
1860
1910
|
logger.setVerbose(options.verbose ?? false);
|
|
@@ -2014,7 +2064,7 @@ async function runGenerate(options) {
|
|
|
2014
2064
|
}
|
|
2015
2065
|
if (existingLock && config.output.laravel?.migrationsPath) {
|
|
2016
2066
|
const migrationsDir = resolve9(rootDir, config.output.laravel.migrationsPath);
|
|
2017
|
-
const migrationValidation = await validateMigrations(existingLock, migrationsDir);
|
|
2067
|
+
const migrationValidation = await validateMigrations(existingLock, migrationsDir, rootDir);
|
|
2018
2068
|
if (!migrationValidation.valid) {
|
|
2019
2069
|
logger.newline();
|
|
2020
2070
|
logger.warn("Migration file issues detected:");
|
|
@@ -2073,7 +2123,7 @@ async function runGenerate(options) {
|
|
|
2073
2123
|
const alterMigrations = toRegenerate.filter((m) => m.type === "alter" || m.type === "drop");
|
|
2074
2124
|
if (createMigrations.length > 0) {
|
|
2075
2125
|
logger.info(`Regenerating ${createMigrations.length} missing CREATE migration(s) with original timestamps...`);
|
|
2076
|
-
const
|
|
2126
|
+
const defaultMigrationsDir = resolve9(rootDir, config.output.laravel.migrationsPath);
|
|
2077
2127
|
const customTypesMap2 = /* @__PURE__ */ new Map();
|
|
2078
2128
|
for (const plugin of config.plugins) {
|
|
2079
2129
|
if (plugin.types) {
|
|
@@ -2094,11 +2144,20 @@ async function runGenerate(options) {
|
|
|
2094
2144
|
timestamp: migData.timestamp,
|
|
2095
2145
|
customTypes: customTypesMap2
|
|
2096
2146
|
});
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2147
|
+
const matchingMig = regenerated.find((mig) => {
|
|
2148
|
+
return mig.tables.includes(migData.tableName);
|
|
2149
|
+
});
|
|
2150
|
+
if (!matchingMig) {
|
|
2151
|
+
logger.warn(` Cannot regenerate ${migData.fileName}: migration for table '${migData.tableName}' not found`);
|
|
2152
|
+
continue;
|
|
2101
2153
|
}
|
|
2154
|
+
const targetDir = migData.outputPath ? resolve9(rootDir, migData.outputPath) : defaultMigrationsDir;
|
|
2155
|
+
if (!existsSync9(targetDir)) {
|
|
2156
|
+
mkdirSync3(targetDir, { recursive: true });
|
|
2157
|
+
}
|
|
2158
|
+
const filePath = resolve9(targetDir, migData.fileName);
|
|
2159
|
+
writeFileSync5(filePath, matchingMig.content);
|
|
2160
|
+
logger.success(` Regenerated: ${migData.fileName}`);
|
|
2102
2161
|
}
|
|
2103
2162
|
}
|
|
2104
2163
|
if (alterMigrations.length > 0) {
|
|
@@ -2128,6 +2187,7 @@ async function runGenerate(options) {
|
|
|
2128
2187
|
let typesGenerated = 0;
|
|
2129
2188
|
let modelsGenerated = 0;
|
|
2130
2189
|
let factoriesGenerated = 0;
|
|
2190
|
+
let allMigrationRecords = [];
|
|
2131
2191
|
const usePlugins = hasPluginGenerators(config.plugins);
|
|
2132
2192
|
const customTypesMap = /* @__PURE__ */ new Map();
|
|
2133
2193
|
for (const plugin of config.plugins) {
|
|
@@ -2157,6 +2217,7 @@ async function runGenerate(options) {
|
|
|
2157
2217
|
);
|
|
2158
2218
|
migrationsGenerated = counts.migrations;
|
|
2159
2219
|
typesGenerated = counts.types;
|
|
2220
|
+
allMigrationRecords = counts.migrationRecords;
|
|
2160
2221
|
if (counts.migrations > 0) {
|
|
2161
2222
|
logger.success(`Generated ${counts.migrations} migration(s)`);
|
|
2162
2223
|
}
|
|
@@ -2282,9 +2343,24 @@ async function runGenerate(options) {
|
|
|
2282
2343
|
typesGenerated = counts.types;
|
|
2283
2344
|
modelsGenerated = counts.models;
|
|
2284
2345
|
factoriesGenerated = counts.factories;
|
|
2346
|
+
allMigrationRecords = counts.migrationRecords;
|
|
2285
2347
|
}
|
|
2286
2348
|
logger.step("Updating lock file...");
|
|
2287
|
-
|
|
2349
|
+
let newLockFile = updateLockFile(existingLock, currentSnapshots, config.database.driver);
|
|
2350
|
+
if (allMigrationRecords.length > 0) {
|
|
2351
|
+
logger.debug(`Adding ${allMigrationRecords.length} migration(s) to lock file...`);
|
|
2352
|
+
for (const record of allMigrationRecords) {
|
|
2353
|
+
newLockFile = addEnhancedMigrationRecord(newLockFile, {
|
|
2354
|
+
fileName: record.fileName,
|
|
2355
|
+
timestamp: record.timestamp,
|
|
2356
|
+
tableName: record.tableName,
|
|
2357
|
+
type: record.type,
|
|
2358
|
+
schemas: record.schemas,
|
|
2359
|
+
content: record.content,
|
|
2360
|
+
outputPath: record.outputPath
|
|
2361
|
+
});
|
|
2362
|
+
}
|
|
2363
|
+
}
|
|
2288
2364
|
await writeLockFile(lockPath, newLockFile);
|
|
2289
2365
|
logger.debug(`Updated: ${config.lockFilePath}`);
|
|
2290
2366
|
if (comparison.hasChanges) {
|
|
@@ -3252,6 +3328,110 @@ function registerVerifyCommand(program2) {
|
|
|
3252
3328
|
});
|
|
3253
3329
|
}
|
|
3254
3330
|
|
|
3331
|
+
// src/commands/ai-guides.ts
|
|
3332
|
+
async function runAIGuides(options) {
|
|
3333
|
+
logger.setVerbose(options.verbose ?? false);
|
|
3334
|
+
logger.header("Generating AI Guides");
|
|
3335
|
+
let generateAIGuides2;
|
|
3336
|
+
let getAvailableCategories;
|
|
3337
|
+
try {
|
|
3338
|
+
const aiGuidesModule = await import("@famgia/omnify-ai-guides");
|
|
3339
|
+
generateAIGuides2 = aiGuidesModule.generateAIGuides;
|
|
3340
|
+
getAvailableCategories = aiGuidesModule.getAvailableCategories;
|
|
3341
|
+
} catch (error) {
|
|
3342
|
+
logger.error("Failed to load @famgia/omnify-ai-guides package");
|
|
3343
|
+
logger.error("Please install it: pnpm add @famgia/omnify-ai-guides");
|
|
3344
|
+
throw error;
|
|
3345
|
+
}
|
|
3346
|
+
const rootDir = process.cwd();
|
|
3347
|
+
let configAiGuides;
|
|
3348
|
+
try {
|
|
3349
|
+
const { config } = await loadConfig();
|
|
3350
|
+
configAiGuides = config.aiGuides;
|
|
3351
|
+
if (configAiGuides) {
|
|
3352
|
+
logger.debug("Loaded aiGuides config from omnify.config.ts");
|
|
3353
|
+
}
|
|
3354
|
+
} catch {
|
|
3355
|
+
logger.debug("No omnify.config.ts found, using defaults");
|
|
3356
|
+
}
|
|
3357
|
+
let categories = getAvailableCategories();
|
|
3358
|
+
if (options.categories) {
|
|
3359
|
+
categories = options.categories.split(",").map((c) => c.trim());
|
|
3360
|
+
logger.debug(`Categories (from CLI): ${categories.join(", ")}`);
|
|
3361
|
+
} else if (configAiGuides?.categories) {
|
|
3362
|
+
categories = [...configAiGuides.categories];
|
|
3363
|
+
logger.debug(`Categories (from config): ${categories.join(", ")}`);
|
|
3364
|
+
}
|
|
3365
|
+
let adapters;
|
|
3366
|
+
if (options.adapters) {
|
|
3367
|
+
adapters = options.adapters.split(",").map((a) => a.trim());
|
|
3368
|
+
logger.debug(`Adapters (from CLI): ${adapters.join(", ")}`);
|
|
3369
|
+
} else if (configAiGuides?.adapters) {
|
|
3370
|
+
adapters = [...configAiGuides.adapters];
|
|
3371
|
+
logger.debug(`Adapters (from config): ${adapters.join(", ")}`);
|
|
3372
|
+
}
|
|
3373
|
+
const placeholders = {
|
|
3374
|
+
LARAVEL_BASE: options.laravelBase ?? configAiGuides?.laravelBase ?? "app",
|
|
3375
|
+
LARAVEL_ROOT: "",
|
|
3376
|
+
TYPESCRIPT_BASE: options.typescriptBase ?? configAiGuides?.typescriptBase ?? "resources/ts"
|
|
3377
|
+
};
|
|
3378
|
+
logger.step("Generating guides...");
|
|
3379
|
+
logger.debug(`Root directory: ${rootDir}`);
|
|
3380
|
+
logger.debug(`Laravel base: ${placeholders.LARAVEL_BASE}`);
|
|
3381
|
+
logger.debug(`TypeScript base: ${placeholders.TYPESCRIPT_BASE}`);
|
|
3382
|
+
logger.debug(`Categories: ${JSON.stringify(categories)}`);
|
|
3383
|
+
logger.debug(`Adapters: ${JSON.stringify(adapters)}`);
|
|
3384
|
+
const result = generateAIGuides2(rootDir, {
|
|
3385
|
+
categories,
|
|
3386
|
+
adapters,
|
|
3387
|
+
placeholders,
|
|
3388
|
+
dryRun: options.dryRun
|
|
3389
|
+
});
|
|
3390
|
+
const claudeCount = result.counts["claude"] || 0;
|
|
3391
|
+
const cursorCount = result.counts["cursor"] || 0;
|
|
3392
|
+
const antigravityCount = result.counts["antigravity"] || 0;
|
|
3393
|
+
const totalCount = claudeCount + cursorCount + antigravityCount;
|
|
3394
|
+
if (options.dryRun) {
|
|
3395
|
+
logger.info("[DRY RUN] Would generate:");
|
|
3396
|
+
}
|
|
3397
|
+
if (claudeCount > 0) {
|
|
3398
|
+
logger.success(` ${claudeCount} Claude files (.claude/)`);
|
|
3399
|
+
}
|
|
3400
|
+
if (cursorCount > 0) {
|
|
3401
|
+
logger.success(` ${cursorCount} Cursor rules (.cursor/rules/)`);
|
|
3402
|
+
}
|
|
3403
|
+
if (antigravityCount > 0) {
|
|
3404
|
+
logger.success(` ${antigravityCount} Antigravity rules (.agent/rules/)`);
|
|
3405
|
+
}
|
|
3406
|
+
if (result.errors?.length) {
|
|
3407
|
+
logger.newline();
|
|
3408
|
+
logger.warn("Warnings:");
|
|
3409
|
+
for (const error of result.errors) {
|
|
3410
|
+
logger.warn(` ${error}`);
|
|
3411
|
+
}
|
|
3412
|
+
}
|
|
3413
|
+
logger.newline();
|
|
3414
|
+
logger.success(`Generated ${totalCount} AI guide files!`);
|
|
3415
|
+
}
|
|
3416
|
+
function registerAIGuidesCommand(program2) {
|
|
3417
|
+
program2.command("ai-guides").description("Generate AI assistant guides (Cursor, Claude, Antigravity). Reads from omnify.config.ts").option("-v, --verbose", "Enable verbose output").option(
|
|
3418
|
+
"-c, --categories <categories>",
|
|
3419
|
+
"Categories to generate (comma-separated: omnify,laravel,react). Overrides config"
|
|
3420
|
+
).option(
|
|
3421
|
+
"-a, --adapters <adapters>",
|
|
3422
|
+
"Adapters to use (comma-separated: cursor,claude,antigravity). Overrides config"
|
|
3423
|
+
).option("--laravel-base <path>", "Laravel base path for placeholders. Overrides config").option("--typescript-base <path>", "TypeScript base path for placeholders. Overrides config").option("--dry-run", "Show what would be generated without writing files").action(async (opts) => {
|
|
3424
|
+
try {
|
|
3425
|
+
await runAIGuides(opts);
|
|
3426
|
+
} catch (error) {
|
|
3427
|
+
if (error instanceof Error) {
|
|
3428
|
+
logger.error(error.message);
|
|
3429
|
+
}
|
|
3430
|
+
process.exit(1);
|
|
3431
|
+
}
|
|
3432
|
+
});
|
|
3433
|
+
}
|
|
3434
|
+
|
|
3255
3435
|
// src/cli.ts
|
|
3256
3436
|
var VERSION = "0.0.5";
|
|
3257
3437
|
var program = new Command();
|
|
@@ -3264,6 +3444,7 @@ registerResetCommand(program);
|
|
|
3264
3444
|
registerCreateProjectCommand(program);
|
|
3265
3445
|
registerDeployCommand(program);
|
|
3266
3446
|
registerVerifyCommand(program);
|
|
3447
|
+
registerAIGuidesCommand(program);
|
|
3267
3448
|
process.on("uncaughtException", (error) => {
|
|
3268
3449
|
if (error instanceof OmnifyError7) {
|
|
3269
3450
|
logger.formatError(error);
|