@famgia/omnify-ai-guides 2.0.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/README.md +105 -0
  2. package/dist/chunk-RCTEXK7C.js +549 -0
  3. package/dist/chunk-RCTEXK7C.js.map +1 -0
  4. package/dist/config/rules.yaml +524 -0
  5. package/dist/index.cjs +587 -0
  6. package/dist/index.cjs.map +1 -0
  7. package/dist/index.d.cts +55 -0
  8. package/dist/index.d.ts +55 -0
  9. package/dist/index.js +26 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/knowledge/agents/architect.md.stub +150 -0
  12. package/dist/knowledge/agents/developer.md.stub +190 -0
  13. package/dist/knowledge/agents/reviewer.md.stub +134 -0
  14. package/dist/knowledge/agents/tester.md.stub +196 -0
  15. package/dist/knowledge/checklists/backend.md.stub +112 -0
  16. package/dist/knowledge/checklists/react.md.stub +108 -0
  17. package/dist/knowledge/claude-rules/laravel-controllers.md.stub +57 -0
  18. package/dist/knowledge/claude-rules/laravel-migrations.md.stub +47 -0
  19. package/dist/knowledge/claude-rules/laravel-tests.md.stub +52 -0
  20. package/dist/knowledge/claude-rules/naming.md.stub +369 -0
  21. package/dist/knowledge/claude-rules/performance.md.stub +256 -0
  22. package/dist/knowledge/claude-rules/php-standards.md.stub +305 -0
  23. package/dist/knowledge/claude-rules/react-components.md.stub +67 -0
  24. package/dist/knowledge/claude-rules/schema-yaml.md.stub +83 -0
  25. package/dist/knowledge/claude-rules/security.md.stub +164 -0
  26. package/dist/knowledge/cursor-rules/antd-deprecations.mdc.stub +62 -0
  27. package/dist/knowledge/cursor-rules/basemodel-readonly.mdc.stub +66 -0
  28. package/dist/knowledge/cursor-rules/baserequest-readonly.mdc.stub +74 -0
  29. package/dist/knowledge/cursor-rules/baseresource-readonly.mdc.stub +78 -0
  30. package/dist/knowledge/cursor-rules/laravel-controller.mdc.stub +421 -0
  31. package/dist/knowledge/cursor-rules/laravel-request.mdc.stub +112 -0
  32. package/dist/knowledge/cursor-rules/laravel-resource.mdc.stub +73 -0
  33. package/dist/knowledge/cursor-rules/laravel-review.mdc.stub +69 -0
  34. package/dist/knowledge/cursor-rules/laravel-testing.mdc.stub +138 -0
  35. package/dist/knowledge/cursor-rules/laravel.mdc.stub +138 -0
  36. package/dist/knowledge/cursor-rules/migrations-workflow.mdc.stub +224 -0
  37. package/dist/knowledge/cursor-rules/model-editable.mdc.stub +120 -0
  38. package/dist/knowledge/cursor-rules/omnify-migrations.mdc.stub +109 -0
  39. package/dist/knowledge/cursor-rules/omnify-schema.mdc.stub +358 -0
  40. package/dist/knowledge/cursor-rules/omnify.mdc.stub +58 -0
  41. package/dist/knowledge/cursor-rules/react-design.mdc.stub +693 -0
  42. package/dist/knowledge/cursor-rules/react-form.mdc.stub +292 -0
  43. package/dist/knowledge/cursor-rules/react-services.mdc.stub +304 -0
  44. package/dist/knowledge/cursor-rules/react.mdc.stub +336 -0
  45. package/dist/knowledge/cursor-rules/request-editable.mdc.stub +111 -0
  46. package/dist/knowledge/cursor-rules/resource-editable.mdc.stub +125 -0
  47. package/dist/knowledge/cursor-rules/schema-create.mdc.stub +440 -0
  48. package/dist/knowledge/cursor-rules/validation-rules.mdc.stub +181 -0
  49. package/dist/knowledge/laravel/README.md.stub +59 -0
  50. package/dist/knowledge/laravel/architecture.md.stub +424 -0
  51. package/dist/knowledge/laravel/authentication.md.stub +588 -0
  52. package/dist/knowledge/laravel/controller.md.stub +484 -0
  53. package/dist/knowledge/laravel/datetime.md.stub +334 -0
  54. package/dist/knowledge/laravel/migrations-team.md.stub +376 -0
  55. package/dist/knowledge/laravel/openapi.md.stub +449 -0
  56. package/dist/knowledge/laravel/request.md.stub +450 -0
  57. package/dist/knowledge/laravel/resource.md.stub +516 -0
  58. package/dist/knowledge/laravel/service.md.stub +503 -0
  59. package/dist/knowledge/laravel/testing.md.stub +1504 -0
  60. package/dist/knowledge/omnify/antdesign-guide.md.stub +401 -0
  61. package/dist/knowledge/omnify/config-guide.md.stub +405 -0
  62. package/dist/knowledge/omnify/japan-guide.md.stub +186 -0
  63. package/dist/knowledge/omnify/laravel-guide.md.stub +61 -0
  64. package/dist/knowledge/omnify/partial-schema-guide.md.stub +353 -0
  65. package/dist/knowledge/omnify/react-form-guide.md.stub +225 -0
  66. package/dist/knowledge/omnify/schema-guide.md.stub +144 -0
  67. package/dist/knowledge/omnify/typescript-guide.md.stub +337 -0
  68. package/dist/knowledge/react/README.md.stub +221 -0
  69. package/dist/knowledge/react/antd-guide.md +528 -0
  70. package/dist/knowledge/react/antd-guide.md.stub +528 -0
  71. package/dist/knowledge/react/checklist.md.stub +108 -0
  72. package/dist/knowledge/react/datetime-guide.md.stub +137 -0
  73. package/dist/knowledge/react/design-philosophy.md.stub +363 -0
  74. package/dist/knowledge/react/i18n-guide.md.stub +211 -0
  75. package/dist/knowledge/react/laravel-integration.md.stub +181 -0
  76. package/dist/knowledge/react/service-pattern.md.stub +180 -0
  77. package/dist/knowledge/react/tanstack-query.md.stub +339 -0
  78. package/dist/knowledge/react/types-guide.md +669 -0
  79. package/dist/knowledge/react/types-guide.md.stub +669 -0
  80. package/dist/knowledge/workflows/bug-fix.md.stub +201 -0
  81. package/dist/knowledge/workflows/code-review.md.stub +164 -0
  82. package/dist/knowledge/workflows/new-feature.md.stub +327 -0
  83. package/dist/plugin-M95GyBll.d.cts +191 -0
  84. package/dist/plugin-M95GyBll.d.ts +191 -0
  85. package/dist/plugin.cjs +573 -0
  86. package/dist/plugin.cjs.map +1 -0
  87. package/dist/plugin.d.cts +2 -0
  88. package/dist/plugin.d.ts +2 -0
  89. package/dist/plugin.js +15 -0
  90. package/dist/plugin.js.map +1 -0
  91. package/package.json +53 -0
package/README.md ADDED
@@ -0,0 +1,105 @@
1
+ # @famgia/omnify-ai-guides
2
+
3
+ Generate **AI Guides** for your Omnify project:
4
+
5
+ - **Cursor rules** → `.cursor/rules/omnify/*.mdc`
6
+ - **Claude guides** → `.claude/omnify/guides/**`
7
+ - **Claude rules** → `.claude/rules/omnify/*.md`
8
+ - **Antigravity rules** → `.agent/rules/omnify/*.md`
9
+
10
+ This package is intentionally **separated** from Laravel/TypeScript generators to avoid mixing concerns.
11
+
12
+ ## Install
13
+
14
+ ```bash
15
+ pnpm add -D @famgia/omnify-ai-guides
16
+ ```
17
+
18
+ ## CLI usage (recommended)
19
+
20
+ The CLI command is provided by `@famgia/omnify-cli` and loads this package dynamically.
21
+
22
+ ```bash
23
+ # Generate all categories (omnify, laravel, react)
24
+ npx omnify ai-guides
25
+ ```
26
+
27
+ ### Configuration via `omnify.config.ts`
28
+
29
+ Add `aiGuides` to your `omnify.config.ts`:
30
+
31
+ ```typescript
32
+ import { defineConfig } from '@famgia/omnify';
33
+
34
+ export default defineConfig({
35
+ // ... other config
36
+
37
+ aiGuides: {
38
+ typescriptBase: 'resources/ts', // or 'resources/js', 'src', etc.
39
+ laravelBase: 'app',
40
+ categories: ['omnify', 'laravel', 'react'], // optional
41
+ adapters: ['cursor', 'claude', 'antigravity'], // optional
42
+ },
43
+ });
44
+ ```
45
+
46
+ CLI options override config values.
47
+
48
+ ### Filter by category
49
+
50
+ ```bash
51
+ # API-only Laravel project (skip React rules)
52
+ npx omnify ai-guides --categories omnify,laravel
53
+
54
+ # Frontend-only (skip Laravel rules)
55
+ npx omnify ai-guides --categories omnify,react
56
+ ```
57
+
58
+ ### Customize base paths (globs placeholders)
59
+
60
+ ```bash
61
+ # Change TypeScript base path used in Cursor/Antigravity globs
62
+ npx omnify ai-guides --typescript-base resources/js
63
+
64
+ # Change Laravel base path used in globs
65
+ npx omnify ai-guides --laravel-base app
66
+ ```
67
+
68
+ ### Filter by adapter
69
+
70
+ ```bash
71
+ # Only Cursor rules
72
+ npx omnify ai-guides --adapters cursor
73
+ ```
74
+
75
+ ### Dry run
76
+
77
+ ```bash
78
+ npx omnify ai-guides --dry-run
79
+ ```
80
+
81
+ ## Plugin usage (optional)
82
+
83
+ You can also run it as an Omnify plugin generator (if you want it in `omnify generate`):
84
+
85
+ ```ts
86
+ import { defineConfig } from '@famgia/omnify';
87
+ import aiGuides from '@famgia/omnify-ai-guides/plugin';
88
+
89
+ export default defineConfig({
90
+ plugins: [
91
+ aiGuides({
92
+ categories: ['omnify', 'laravel'], // for example
93
+ typescriptBasePath: 'resources/ts',
94
+ laravelBasePath: 'app',
95
+ adapters: ['cursor', 'claude', 'antigravity'],
96
+ }),
97
+ ],
98
+ });
99
+ ```
100
+
101
+ ## Notes
102
+
103
+ - This package writes files directly under `.cursor/`, `.claude/`, `.agent/`.
104
+ - If you don’t install `@famgia/omnify-ai-guides`, the CLI will prompt you to install it when you run `omnify ai-guides`.
105
+
@@ -0,0 +1,549 @@
1
+ // src/plugin.ts
2
+ import { readFileSync as readFileSync2 } from "fs";
3
+
4
+ // src/generator.ts
5
+ import { existsSync, mkdirSync, readFileSync, writeFileSync, readdirSync } from "fs";
6
+ import { resolve, dirname, join, basename } from "path";
7
+ import { fileURLToPath } from "url";
8
+ import { parse as parseYaml } from "yaml";
9
+
10
+ // src/adapters/cursor.ts
11
+ function replacePlaceholders(content, placeholders) {
12
+ let result = content;
13
+ for (const [key, value] of Object.entries(placeholders)) {
14
+ result = result.replace(new RegExp(`\\{\\{${key}\\}\\}`, "g"), value);
15
+ }
16
+ return result;
17
+ }
18
+ var cursorAdapter = {
19
+ name: "cursor",
20
+ outputDir: ".cursor/rules/omnify",
21
+ transform(content, rule, placeholders) {
22
+ const target = rule.targets.cursor;
23
+ let transformedContent = replacePlaceholders(content, placeholders);
24
+ if (transformedContent.startsWith("---")) {
25
+ return transformedContent;
26
+ }
27
+ const description = target?.description || "";
28
+ const globs = target?.globs || [];
29
+ const alwaysApply = target?.alwaysApply ?? false;
30
+ const frontmatter = `---
31
+ description: "${description}"
32
+ globs: ${JSON.stringify(globs)}
33
+ alwaysApply: ${alwaysApply}
34
+ ---
35
+
36
+ `;
37
+ return frontmatter + transformedContent;
38
+ },
39
+ getFilename(rule) {
40
+ const target = rule.targets.cursor;
41
+ if (target?.filename) {
42
+ return target.filename;
43
+ }
44
+ return `${rule.id}.mdc`;
45
+ },
46
+ isEnabled(rule) {
47
+ const target = rule.targets.cursor;
48
+ return target?.enabled ?? false;
49
+ },
50
+ getOutputPath(rule) {
51
+ const filename = this.getFilename(rule);
52
+ return filename;
53
+ }
54
+ };
55
+
56
+ // src/adapters/claude.ts
57
+ function replacePlaceholders2(content, placeholders) {
58
+ let result = content;
59
+ for (const [key, value] of Object.entries(placeholders)) {
60
+ result = result.replace(new RegExp(`\\{\\{${key}\\}\\}`, "g"), value);
61
+ }
62
+ return result;
63
+ }
64
+ var claudeAdapter = {
65
+ name: "claude",
66
+ outputDir: ".claude/omnify",
67
+ transform(content, _rule, placeholders) {
68
+ return replacePlaceholders2(content, placeholders);
69
+ },
70
+ getFilename(rule) {
71
+ const target = rule.targets.claude;
72
+ if (target?.filename) {
73
+ return target.filename;
74
+ }
75
+ return `${rule.id}.md`;
76
+ },
77
+ isEnabled(rule) {
78
+ const target = rule.targets.claude;
79
+ return target?.enabled ?? false;
80
+ },
81
+ getOutputPath(rule) {
82
+ const target = rule.targets.claude;
83
+ const filename = this.getFilename(rule);
84
+ const subdir = target?.subdir || rule.category;
85
+ if (subdir) {
86
+ return `${subdir}/${filename}`;
87
+ }
88
+ return filename;
89
+ }
90
+ };
91
+
92
+ // src/adapters/antigravity.ts
93
+ function replacePlaceholders3(content, placeholders) {
94
+ let result = content;
95
+ for (const [key, value] of Object.entries(placeholders)) {
96
+ result = result.replace(new RegExp(`\\{\\{${key}\\}\\}`, "g"), value);
97
+ }
98
+ return result;
99
+ }
100
+ var antigravityAdapter = {
101
+ name: "antigravity",
102
+ outputDir: ".agent/rules/omnify",
103
+ transform(content, rule, placeholders) {
104
+ const target = rule.targets.antigravity;
105
+ let transformedContent = replacePlaceholders3(content, placeholders);
106
+ if (transformedContent.startsWith("---")) {
107
+ const endIndex = transformedContent.indexOf("---", 3);
108
+ if (endIndex !== -1) {
109
+ const existingFrontmatter = transformedContent.substring(3, endIndex).trim();
110
+ const bodyContent = transformedContent.substring(endIndex + 3).trim();
111
+ const antigravityFrontmatter = buildAntigravityFrontmatter(rule, target, existingFrontmatter);
112
+ return `---
113
+ ${antigravityFrontmatter}---
114
+
115
+ ${bodyContent}`;
116
+ }
117
+ }
118
+ const frontmatter = buildAntigravityFrontmatter(rule, target);
119
+ return `---
120
+ ${frontmatter}---
121
+
122
+ ${transformedContent}`;
123
+ },
124
+ getFilename(rule) {
125
+ const target = rule.targets.antigravity;
126
+ if (target?.filename) {
127
+ return target.filename;
128
+ }
129
+ return `${rule.id}.md`;
130
+ },
131
+ isEnabled(rule) {
132
+ const target = rule.targets.antigravity;
133
+ return target?.enabled ?? false;
134
+ },
135
+ getOutputPath(rule) {
136
+ const filename = this.getFilename(rule);
137
+ return filename;
138
+ }
139
+ };
140
+ function buildAntigravityFrontmatter(rule, target, existingFrontmatter) {
141
+ const lines = [];
142
+ lines.push(`id: ${rule.id}`);
143
+ const description = target?.description || extractDescription(existingFrontmatter) || rule.id;
144
+ lines.push(`description: "${description}"`);
145
+ const priority = target?.priority || "medium";
146
+ lines.push(`priority: ${priority}`);
147
+ const globs = target?.globs || extractGlobs(existingFrontmatter) || [];
148
+ if (globs.length > 0) {
149
+ lines.push(`globs:`);
150
+ for (const glob of globs) {
151
+ lines.push(` - "${glob}"`);
152
+ }
153
+ }
154
+ const tags = target?.tags || inferTags(rule);
155
+ if (tags.length > 0) {
156
+ lines.push(`tags:`);
157
+ for (const tag of tags) {
158
+ lines.push(` - ${tag}`);
159
+ }
160
+ }
161
+ return lines.join("\n") + "\n";
162
+ }
163
+ function extractDescription(frontmatter) {
164
+ if (!frontmatter) return void 0;
165
+ const match = frontmatter.match(/description:\s*["']?([^"'\n]+)["']?/);
166
+ return match?.[1];
167
+ }
168
+ function extractGlobs(frontmatter) {
169
+ if (!frontmatter) return [];
170
+ const match = frontmatter.match(/globs:\s*\[([^\]]+)\]/);
171
+ if (match?.[1]) {
172
+ return match[1].split(",").map((g) => g.trim().replace(/["']/g, ""));
173
+ }
174
+ return [];
175
+ }
176
+ function inferTags(rule) {
177
+ const tags = [];
178
+ if (rule.category) {
179
+ const parts = rule.category.split("/");
180
+ tags.push(...parts.filter((p) => p !== "guides"));
181
+ }
182
+ if (rule.id.includes("laravel")) tags.push("laravel");
183
+ if (rule.id.includes("react")) tags.push("react");
184
+ if (rule.id.includes("schema")) tags.push("schema");
185
+ if (rule.id.includes("omnify")) tags.push("omnify");
186
+ return [...new Set(tags)];
187
+ }
188
+
189
+ // src/adapters/index.ts
190
+ var allAdapters = [cursorAdapter, claudeAdapter, antigravityAdapter];
191
+ function getAdapters(names) {
192
+ if (!names || names.length === 0) {
193
+ return allAdapters;
194
+ }
195
+ return allAdapters.filter((a) => names.includes(a.name));
196
+ }
197
+
198
+ // src/generator.ts
199
+ var __filename = fileURLToPath(import.meta.url);
200
+ var __dirname = dirname(__filename);
201
+ function getKnowledgeDir() {
202
+ const possiblePaths = [
203
+ // Dev: running in src
204
+ resolve(__dirname, "knowledge"),
205
+ // Dist: running from dist/
206
+ resolve(__dirname, "../knowledge"),
207
+ // Installed package: in node_modules
208
+ resolve(__dirname, "../../knowledge")
209
+ ];
210
+ for (const path of possiblePaths) {
211
+ if (existsSync(path)) {
212
+ return path;
213
+ }
214
+ }
215
+ throw new Error(`AI guides knowledge directory not found. Tried: ${possiblePaths.join(", ")}`);
216
+ }
217
+ function getConfigDir() {
218
+ const possiblePaths = [
219
+ // Dev: running in src
220
+ resolve(__dirname, "config"),
221
+ // Dist: running from dist/
222
+ resolve(__dirname, "../config"),
223
+ // Installed package: in node_modules
224
+ resolve(__dirname, "../../config")
225
+ ];
226
+ for (const path of possiblePaths) {
227
+ if (existsSync(path)) {
228
+ return path;
229
+ }
230
+ }
231
+ throw new Error(`AI guides config directory not found. Tried: ${possiblePaths.join(", ")}`);
232
+ }
233
+ function loadRulesConfig() {
234
+ const configDir = getConfigDir();
235
+ const rulesPath = join(configDir, "rules.yaml");
236
+ if (!existsSync(rulesPath)) {
237
+ throw new Error(`Rules config not found: ${rulesPath}`);
238
+ }
239
+ const content = readFileSync(rulesPath, "utf-8");
240
+ return parseYaml(content);
241
+ }
242
+ function loadKnowledgeFile(source) {
243
+ const knowledgeDir = getKnowledgeDir();
244
+ const filePath = join(knowledgeDir, source);
245
+ if (!existsSync(filePath)) {
246
+ throw new Error(`Knowledge file not found: ${filePath}`);
247
+ }
248
+ return readFileSync(filePath, "utf-8");
249
+ }
250
+ function replacePlaceholders4(content, placeholders) {
251
+ let result = content;
252
+ for (const [key, value] of Object.entries(placeholders)) {
253
+ result = result.replace(new RegExp(`\\{\\{${key}\\}\\}`, "g"), value);
254
+ }
255
+ return result;
256
+ }
257
+ function writeOutputFile(filePath, content, dryRun) {
258
+ if (dryRun) {
259
+ console.log(`[DRY RUN] Would write: ${filePath}`);
260
+ return;
261
+ }
262
+ const dir = dirname(filePath);
263
+ if (!existsSync(dir)) {
264
+ mkdirSync(dir, { recursive: true });
265
+ }
266
+ writeFileSync(filePath, content);
267
+ }
268
+ function matchesCategory(ruleCategory, categories) {
269
+ if (!categories || categories.length === 0) {
270
+ return true;
271
+ }
272
+ const parts = ruleCategory.split("/");
273
+ const category = parts[parts.length - 1];
274
+ return categories.includes(category);
275
+ }
276
+ function sourceMatchesCategory(source, categories) {
277
+ if (!categories || categories.length === 0) {
278
+ return true;
279
+ }
280
+ const filename = basename(source).toLowerCase();
281
+ for (const category of categories) {
282
+ if (filename.startsWith(category)) {
283
+ return true;
284
+ }
285
+ if (source.includes(`/${category}/`) || source.startsWith(`${category}/`)) {
286
+ return true;
287
+ }
288
+ }
289
+ if (categories.includes("react")) {
290
+ if (filename.startsWith("react") || filename.includes("antd")) {
291
+ return true;
292
+ }
293
+ }
294
+ if (categories.includes("omnify")) {
295
+ if (filename.startsWith("omnify") || filename.startsWith("schema") || filename.startsWith("validation") || filename.includes("migration")) {
296
+ return true;
297
+ }
298
+ }
299
+ return false;
300
+ }
301
+ function generateAIGuides(rootDir, options = {}) {
302
+ const config = loadRulesConfig();
303
+ const adapters = getAdapters(options.adapters);
304
+ const dryRun = options.dryRun ?? false;
305
+ const categories = options.categories;
306
+ const placeholders = {
307
+ ...config.placeholders,
308
+ ...options.placeholders
309
+ };
310
+ const result = {
311
+ counts: {},
312
+ files: []
313
+ };
314
+ for (const adapter of adapters) {
315
+ result.counts[adapter.name] = 0;
316
+ }
317
+ for (const rule of config.guides) {
318
+ if (!matchesCategory(rule.category, categories)) {
319
+ continue;
320
+ }
321
+ try {
322
+ const content = loadKnowledgeFile(rule.source);
323
+ for (const adapter of adapters) {
324
+ if (!adapter.isEnabled(rule)) {
325
+ continue;
326
+ }
327
+ const transformed = adapter.transform(content, rule, placeholders);
328
+ const outputPath = adapter.getOutputPath(rule);
329
+ const fullPath = resolve(rootDir, adapter.outputDir, outputPath);
330
+ writeOutputFile(fullPath, transformed, dryRun);
331
+ result.files.push(fullPath);
332
+ result.counts[adapter.name] = (result.counts[adapter.name] ?? 0) + 1;
333
+ }
334
+ } catch (error) {
335
+ const message = error instanceof Error ? error.message : String(error);
336
+ result.errors = result.errors ?? [];
337
+ result.errors.push(`Error processing ${rule.id}: ${message}`);
338
+ }
339
+ }
340
+ const cursorAdapter2 = adapters.find((a) => a.name === "cursor");
341
+ if (cursorAdapter2 && config.cursorRules) {
342
+ for (const rule of config.cursorRules) {
343
+ if (!sourceMatchesCategory(rule.source, categories)) {
344
+ continue;
345
+ }
346
+ try {
347
+ const content = loadKnowledgeFile(rule.source);
348
+ const transformed = replacePlaceholders4(content, placeholders);
349
+ const filename = basename(rule.source).replace(".mdc.stub", ".mdc").replace(".md.stub", ".md");
350
+ const fullPath = resolve(rootDir, cursorAdapter2.outputDir, filename);
351
+ writeOutputFile(fullPath, transformed, dryRun);
352
+ result.files.push(fullPath);
353
+ result.counts[cursorAdapter2.name] = (result.counts[cursorAdapter2.name] ?? 0) + 1;
354
+ } catch (error) {
355
+ const message = error instanceof Error ? error.message : String(error);
356
+ result.errors = result.errors ?? [];
357
+ result.errors.push(`Error processing cursor rule ${rule.source}: ${message}`);
358
+ }
359
+ }
360
+ }
361
+ const claudeAdapter2 = adapters.find((a) => a.name === "claude");
362
+ if (claudeAdapter2 && config.claudeRules) {
363
+ for (const rule of config.claudeRules) {
364
+ if (!sourceMatchesCategory(rule.source, categories)) {
365
+ continue;
366
+ }
367
+ try {
368
+ const content = loadKnowledgeFile(rule.source);
369
+ const strippedContent = stripFrontmatter(content);
370
+ const transformed = replacePlaceholders4(strippedContent, placeholders);
371
+ const filename = basename(rule.source).replace(".mdc.stub", ".mdc").replace(".md.stub", ".md").replace(".mdc", ".md");
372
+ const fullPath = resolve(rootDir, ".claude/rules/omnify", filename);
373
+ writeOutputFile(fullPath, transformed, dryRun);
374
+ result.files.push(fullPath);
375
+ result.counts[claudeAdapter2.name] = (result.counts[claudeAdapter2.name] ?? 0) + 1;
376
+ } catch (error) {
377
+ const message = error instanceof Error ? error.message : String(error);
378
+ result.errors = result.errors ?? [];
379
+ result.errors.push(`Error processing claude rule ${rule.source}: ${message}`);
380
+ }
381
+ }
382
+ }
383
+ const antigravityAdapterInstance = adapters.find((a) => a.name === "antigravity");
384
+ if (antigravityAdapterInstance && config.antigravityRules) {
385
+ for (const rule of config.antigravityRules) {
386
+ if (!sourceMatchesCategory(rule.source, categories)) {
387
+ continue;
388
+ }
389
+ try {
390
+ const content = loadKnowledgeFile(rule.source);
391
+ const transformed = transformForAntigravity(content, rule, placeholders);
392
+ const filename = basename(rule.source).replace(".mdc.stub", ".mdc").replace(".md.stub", ".md").replace(".mdc", ".md");
393
+ const fullPath = resolve(rootDir, antigravityAdapterInstance.outputDir, filename);
394
+ writeOutputFile(fullPath, transformed, dryRun);
395
+ result.files.push(fullPath);
396
+ result.counts[antigravityAdapterInstance.name] = (result.counts[antigravityAdapterInstance.name] ?? 0) + 1;
397
+ } catch (error) {
398
+ const message = error instanceof Error ? error.message : String(error);
399
+ result.errors = result.errors ?? [];
400
+ result.errors.push(`Error processing antigravity rule ${rule.source}: ${message}`);
401
+ }
402
+ }
403
+ }
404
+ return result;
405
+ }
406
+ function transformForAntigravity(content, rule, placeholders) {
407
+ let transformed = replacePlaceholders4(content, placeholders);
408
+ if (transformed.startsWith("---")) {
409
+ const endIndex = transformed.indexOf("---", 3);
410
+ if (endIndex !== -1) {
411
+ const existingFrontmatter = transformed.substring(3, endIndex).trim();
412
+ const bodyContent = transformed.substring(endIndex + 3).trim();
413
+ const id = basename(rule.source).replace(".mdc.stub", "").replace(".md.stub", "").replace(".mdc", "").replace(".md", "");
414
+ const description = extractYamlValue(existingFrontmatter, "description") || id;
415
+ const globs = extractYamlArray(existingFrontmatter, "globs");
416
+ const priority = rule.priority || "medium";
417
+ const tags = rule.tags || [];
418
+ const lines = [`id: ${id}`, `description: "${description}"`, `priority: ${priority}`];
419
+ if (globs.length > 0) {
420
+ lines.push("globs:");
421
+ for (const glob of globs) {
422
+ lines.push(` - "${glob}"`);
423
+ }
424
+ }
425
+ if (tags.length > 0) {
426
+ lines.push("tags:");
427
+ for (const tag of tags) {
428
+ lines.push(` - ${tag}`);
429
+ }
430
+ }
431
+ return `---
432
+ ${lines.join("\n")}
433
+ ---
434
+
435
+ ${bodyContent}`;
436
+ }
437
+ }
438
+ return transformed;
439
+ }
440
+ function extractYamlValue(yaml, key) {
441
+ const match = yaml.match(new RegExp(`${key}:\\s*["']?([^"'\\n]+)["']?`));
442
+ return match?.[1]?.trim();
443
+ }
444
+ function extractYamlArray(yaml, key) {
445
+ const match = yaml.match(new RegExp(`${key}:\\s*\\[([^\\]]+)\\]`));
446
+ if (match?.[1]) {
447
+ return match[1].split(",").map((g) => g.trim().replace(/["']/g, ""));
448
+ }
449
+ return [];
450
+ }
451
+ function stripFrontmatter(content) {
452
+ if (!content.startsWith("---")) {
453
+ return content;
454
+ }
455
+ const endIndex = content.indexOf("---", 3);
456
+ if (endIndex === -1) {
457
+ return content;
458
+ }
459
+ return content.substring(endIndex + 3).trim();
460
+ }
461
+ function shouldGenerateAIGuides(rootDir) {
462
+ const claudeDir = resolve(rootDir, ".claude/omnify/guides");
463
+ const cursorDir = resolve(rootDir, ".cursor/rules/omnify");
464
+ if (!existsSync(claudeDir) || !existsSync(cursorDir)) {
465
+ return true;
466
+ }
467
+ try {
468
+ const claudeFiles = readdirSync(claudeDir, { recursive: true });
469
+ const cursorFiles = readdirSync(cursorDir);
470
+ return claudeFiles.length === 0 || cursorFiles.length === 0;
471
+ } catch {
472
+ return true;
473
+ }
474
+ }
475
+ function getAvailableAdapters() {
476
+ return getAdapters().map((a) => a.name);
477
+ }
478
+ function getAvailableCategories() {
479
+ return ["omnify", "laravel", "react"];
480
+ }
481
+
482
+ // src/plugin.ts
483
+ function getPluginVersion() {
484
+ try {
485
+ const pkgPath = new URL("../package.json", import.meta.url);
486
+ const pkgContent = readFileSync2(pkgPath, "utf-8");
487
+ const pkg = JSON.parse(pkgContent);
488
+ return pkg.version;
489
+ } catch {
490
+ return "0.0.0";
491
+ }
492
+ }
493
+ function aiGuidesPlugin(options = {}) {
494
+ const resolvedOptions = {
495
+ categories: options.categories ?? getAvailableCategories(),
496
+ laravelBasePath: options.laravelBasePath ?? "app",
497
+ typescriptBasePath: options.typescriptBasePath ?? "resources/ts",
498
+ adapters: options.adapters
499
+ };
500
+ return {
501
+ name: "@famgia/omnify-ai-guides",
502
+ version: getPluginVersion(),
503
+ generators: [
504
+ {
505
+ name: "ai-guides",
506
+ description: "Generate AI assistant guides (Cursor, Claude, Antigravity)",
507
+ generate: async (ctx) => {
508
+ const result = generateAIGuides(ctx.cwd, {
509
+ categories: resolvedOptions.categories,
510
+ adapters: resolvedOptions.adapters,
511
+ placeholders: {
512
+ LARAVEL_BASE: resolvedOptions.laravelBasePath,
513
+ LARAVEL_ROOT: "",
514
+ TYPESCRIPT_BASE: resolvedOptions.typescriptBasePath
515
+ }
516
+ });
517
+ const claudeCount = result.counts["claude"] || 0;
518
+ const cursorCount = result.counts["cursor"] || 0;
519
+ const antigravityCount = result.counts["antigravity"] || 0;
520
+ const parts = [];
521
+ if (claudeCount > 0) parts.push(`${claudeCount} Claude`);
522
+ if (cursorCount > 0) parts.push(`${cursorCount} Cursor`);
523
+ if (antigravityCount > 0) parts.push(`${antigravityCount} Antigravity`);
524
+ ctx.logger.info(`Generated ${parts.join(", ")} files`);
525
+ if (result.errors?.length) {
526
+ for (const error of result.errors) {
527
+ ctx.logger.warn(error);
528
+ }
529
+ }
530
+ return [];
531
+ }
532
+ }
533
+ ]
534
+ };
535
+ }
536
+
537
+ export {
538
+ cursorAdapter,
539
+ claudeAdapter,
540
+ antigravityAdapter,
541
+ allAdapters,
542
+ getAdapters,
543
+ generateAIGuides,
544
+ shouldGenerateAIGuides,
545
+ getAvailableAdapters,
546
+ getAvailableCategories,
547
+ aiGuidesPlugin
548
+ };
549
+ //# sourceMappingURL=chunk-RCTEXK7C.js.map