@shohojdhara/atomix 0.4.8 → 0.5.0
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/atomix.config.ts +58 -1
- package/dist/atomix.css +148 -120
- package/dist/atomix.css.map +1 -1
- package/dist/atomix.min.css +1 -1
- package/dist/atomix.min.css.map +1 -1
- package/dist/charts.d.ts +33 -0
- package/dist/charts.js +1227 -122
- package/dist/charts.js.map +1 -1
- package/dist/core.d.ts +33 -10
- package/dist/core.js +1052 -41
- package/dist/core.js.map +1 -1
- package/dist/forms.d.ts +33 -0
- package/dist/forms.js +2086 -1035
- package/dist/forms.js.map +1 -1
- package/dist/heavy.d.ts +42 -1
- package/dist/heavy.js +1620 -600
- package/dist/heavy.js.map +1 -1
- package/dist/index.d.ts +441 -270
- package/dist/index.esm.js +1900 -638
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +1935 -670
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/package.json +6 -3
- package/scripts/atomix-cli.js +148 -4
- package/scripts/cli/__tests__/basic.test.js +3 -2
- package/scripts/cli/__tests__/clean.test.js +278 -0
- package/scripts/cli/__tests__/component-validator.test.js +433 -0
- package/scripts/cli/__tests__/generator.test.js +613 -0
- package/scripts/cli/__tests__/glass-motion.test.js +256 -0
- package/scripts/cli/__tests__/integration.test.js +719 -108
- package/scripts/cli/__tests__/migrate.test.js +74 -0
- package/scripts/cli/__tests__/security.test.js +206 -0
- package/scripts/cli/__tests__/test-setup.js +3 -1
- package/scripts/cli/__tests__/theme-bridge.test.js +507 -0
- package/scripts/cli/__tests__/token-provider.test.js +361 -0
- package/scripts/cli/__tests__/utils.test.js +5 -5
- package/scripts/cli/commands/benchmark.js +105 -0
- package/scripts/cli/commands/build-theme.js +4 -1
- package/scripts/cli/commands/clean.js +109 -0
- package/scripts/cli/commands/doctor.js +88 -0
- package/scripts/cli/commands/generate.js +135 -14
- package/scripts/cli/commands/init.js +45 -18
- package/scripts/cli/commands/migrate.js +106 -0
- package/scripts/cli/commands/sync-tokens.js +206 -0
- package/scripts/cli/commands/theme-bridge.js +248 -0
- package/scripts/cli/commands/tokens.js +157 -0
- package/scripts/cli/commands/validate.js +194 -0
- package/scripts/cli/internal/ai-engine.js +156 -0
- package/scripts/cli/internal/component-validator.js +443 -0
- package/scripts/cli/internal/config-loader.js +162 -0
- package/scripts/cli/internal/filesystem.js +102 -2
- package/scripts/cli/internal/generator.js +359 -39
- package/scripts/cli/internal/glass-generator.js +398 -0
- package/scripts/cli/internal/hook-generator.js +369 -0
- package/scripts/cli/internal/hooks.js +61 -0
- package/scripts/cli/internal/itcss-generator.js +565 -0
- package/scripts/cli/internal/motion-generator.js +679 -0
- package/scripts/cli/internal/template-engine.js +301 -0
- package/scripts/cli/internal/theme-bridge.js +664 -0
- package/scripts/cli/internal/tokens/engine.js +122 -0
- package/scripts/cli/internal/tokens/provider.js +34 -0
- package/scripts/cli/internal/tokens/providers/figma.js +50 -0
- package/scripts/cli/internal/tokens/providers/style-dictionary.js +48 -0
- package/scripts/cli/internal/tokens/providers/w3c.js +48 -0
- package/scripts/cli/internal/tokens/token-provider.js +443 -0
- package/scripts/cli/internal/tokens/token-validator.js +513 -0
- package/scripts/cli/internal/validator.js +276 -0
- package/scripts/cli/internal/wizard.js +60 -6
- package/scripts/cli/mappings.js +23 -0
- package/scripts/cli/migration-tools.js +164 -94
- package/scripts/cli/plugins/style-dictionary.js +46 -0
- package/scripts/cli/templates/README.md +525 -95
- package/scripts/cli/templates/common-templates.js +40 -14
- package/scripts/cli/templates/components/react-component.ts +282 -0
- package/scripts/cli/templates/config/project-config.ts +112 -0
- package/scripts/cli/templates/hooks/use-component.ts +477 -0
- package/scripts/cli/templates/index.js +19 -4
- package/scripts/cli/templates/index.ts +171 -0
- package/scripts/cli/templates/next-templates.js +72 -0
- package/scripts/cli/templates/react-templates.js +70 -126
- package/scripts/cli/templates/scss-templates.js +35 -35
- package/scripts/cli/templates/stories/storybook-story.ts +241 -0
- package/scripts/cli/templates/styles/scss-component.ts +255 -0
- package/scripts/cli/templates/tests/vitest-test.ts +229 -0
- package/scripts/cli/templates/token-templates.js +337 -1
- package/scripts/cli/templates/tokens/token-generators.ts +1088 -0
- package/scripts/cli/templates/types/component-types.ts +145 -0
- package/scripts/cli/templates/utils/testing-utils.ts +144 -0
- package/scripts/cli/templates/vanilla-templates.js +39 -0
- package/scripts/cli/token-manager.js +8 -2
- package/scripts/cli/utils/cache-manager.js +240 -0
- package/scripts/cli/utils/detector.js +46 -0
- package/scripts/cli/utils/diagnostics.js +289 -0
- package/scripts/cli/utils/error.js +45 -3
- package/scripts/cli/utils/helpers.js +24 -0
- package/scripts/cli/utils/logger.js +1 -1
- package/scripts/cli/utils/security.js +302 -0
- package/scripts/cli/utils/telemetry.js +115 -0
- package/scripts/cli/utils/validation.js +4 -38
- package/scripts/cli/utils.js +46 -0
- package/src/components/Accordion/Accordion.stories.tsx +0 -18
- package/src/components/Accordion/Accordion.test.tsx +0 -17
- package/src/components/Accordion/Accordion.tsx +0 -4
- package/src/components/AtomixGlass/AtomixGlass.tsx +102 -2
- package/src/components/AtomixGlass/AtomixGlassContainer.tsx +125 -12
- package/src/components/AtomixGlass/PerformanceDashboard.tsx +219 -0
- package/src/components/AtomixGlass/README.md +25 -10
- package/src/components/AtomixGlass/animation-system.ts +578 -0
- package/src/components/AtomixGlass/shader-utils.ts +3 -0
- package/src/components/AtomixGlass/stories/AnimationFeatures.stories.tsx +653 -0
- package/src/components/AtomixGlass/stories/AnimationTests.stories.tsx +95 -0
- package/src/components/AtomixGlass/stories/CardExamples.stories.tsx +212 -0
- package/src/components/AtomixGlass/stories/DashboardExamples.stories.tsx +348 -0
- package/src/components/AtomixGlass/stories/EcommerceExamples.stories.tsx +410 -0
- package/src/components/AtomixGlass/stories/FormExamples.stories.tsx +436 -0
- package/src/components/AtomixGlass/stories/HeroExamples.stories.tsx +264 -0
- package/src/components/AtomixGlass/stories/InteractivePlayground.stories.tsx +247 -0
- package/src/components/AtomixGlass/stories/MobileUIExamples.stories.tsx +418 -0
- package/src/components/AtomixGlass/stories/ModalExamples.stories.tsx +402 -0
- package/src/components/AtomixGlass/stories/Overview.stories.tsx +157 -6
- package/src/components/AtomixGlass/stories/Playground.stories.tsx +658 -93
- package/src/components/AtomixGlass/stories/PresetGallery.stories.tsx +335 -0
- package/src/components/AtomixGlass/stories/WidgetExamples.stories.tsx +441 -0
- package/src/components/AtomixGlass/stories/argTypes.ts +384 -0
- package/src/components/AtomixGlass/stories/shared-components.tsx +91 -1
- package/src/components/AtomixGlass/stories/types.ts +127 -0
- package/src/components/Avatar/Avatar.tsx +1 -1
- package/src/components/Button/Button.stories.disabled-link.tsx +10 -0
- package/src/components/Button/Button.stories.tsx +10 -0
- package/src/components/Button/Button.test.tsx +16 -11
- package/src/components/Button/Button.tsx +4 -4
- package/src/components/Card/Card.tsx +1 -1
- package/src/components/Dropdown/Dropdown.tsx +12 -12
- package/src/components/Form/Select.tsx +62 -3
- package/src/components/Modal/Modal.tsx +14 -3
- package/src/components/Navigation/Navbar/Navbar.tsx +44 -0
- package/src/components/Slider/Slider.stories.tsx +3 -3
- package/src/components/Slider/Slider.tsx +38 -0
- package/src/components/Steps/Steps.tsx +3 -3
- package/src/components/Tabs/Tabs.tsx +77 -8
- package/src/components/Testimonial/Testimonial.tsx +1 -1
- package/src/components/TypedButton/TypedButton.stories.tsx +59 -0
- package/src/components/TypedButton/TypedButton.tsx +39 -0
- package/src/components/TypedButton/index.ts +2 -0
- package/src/components/VideoPlayer/VideoPlayer.tsx +11 -4
- package/src/lib/composables/index.ts +4 -7
- package/src/lib/composables/types.ts +45 -0
- package/src/lib/composables/useAccordion.ts +0 -7
- package/src/lib/composables/useAtomixGlass.ts +144 -5
- package/src/lib/composables/useChartExport.ts +3 -13
- package/src/lib/composables/useDropdown.ts +66 -0
- package/src/lib/composables/useFocusTrap.ts +80 -0
- package/src/lib/composables/usePerformanceMonitor.ts +448 -0
- package/src/lib/composables/useResponsiveGlass.presets.ts +192 -0
- package/src/lib/composables/useResponsiveGlass.ts +441 -0
- package/src/lib/composables/useTooltip.ts +16 -0
- package/src/lib/composables/useTypedButton.ts +66 -0
- package/src/lib/config/index.ts +62 -5
- package/src/lib/constants/components.ts +55 -0
- package/src/lib/theme/devtools/__tests__/useHistory.test.tsx +150 -0
- package/src/lib/theme/tokens/centralized-tokens.ts +120 -0
- package/src/lib/theme/utils/__tests__/domUtils.test.ts +101 -0
- package/src/lib/types/components.ts +37 -11
- package/src/lib/types/glass.ts +35 -0
- package/src/lib/types/index.ts +1 -0
- package/src/lib/utils/displacement-generator.ts +1 -1
- package/src/styles/01-settings/_settings.testtypecheck.scss +53 -0
- package/src/styles/01-settings/_settings.typedbutton.scss +53 -0
- package/src/styles/06-components/_components.testbutton.scss +212 -0
- package/src/styles/06-components/_components.testtypecheck.scss +212 -0
- package/src/styles/06-components/_components.typedbutton.scss +212 -0
- package/src/styles/99-utilities/_index.scss +1 -0
- package/src/styles/99-utilities/_utilities.text.scss +1 -1
- package/src/styles/99-utilities/_utilities.touch-target.scss +36 -0
- package/src/styles/06-components/old.chart.styles.scss +0 -2788
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Atomix CLI Validate Command
|
|
3
|
+
* Standalone audit tool for code and configuration quality
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { logger } from '../utils/logger.js';
|
|
7
|
+
import { validateA11y, validateTokens, validatePerformance, validateComponent } from '../internal/validator.js';
|
|
8
|
+
import { validateComponentName } from '../utils/validation.js';
|
|
9
|
+
import { hookManager } from '../internal/hooks.js';
|
|
10
|
+
import { telemetry } from '../utils/telemetry.js';
|
|
11
|
+
import { AtomixCLIError, ErrorCategory } from '../utils/error.js';
|
|
12
|
+
import chalk from 'chalk';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Action for the `atomix validate` command
|
|
16
|
+
* @param {object} options - Command options
|
|
17
|
+
* @param {string} [subcommand] - When 'component', run component-scoped validation
|
|
18
|
+
* @param {string} [name] - Component name for validate component <name>
|
|
19
|
+
*/
|
|
20
|
+
export async function validateAction(options = {}, subcommand, name) {
|
|
21
|
+
if (subcommand === 'component' && name) {
|
|
22
|
+
return runComponentValidation(name);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const spinner = logger.spinner('Starting validation audit...').start();
|
|
26
|
+
|
|
27
|
+
try {
|
|
28
|
+
const a11yResults = await validateA11y();
|
|
29
|
+
const tokenResults = await validateTokens();
|
|
30
|
+
const performanceResults = await validatePerformance();
|
|
31
|
+
|
|
32
|
+
// Phase 4: CLI Performance Budget check
|
|
33
|
+
const telemetryLogs = await telemetry.getLogs();
|
|
34
|
+
const cliPerformanceIssues = validateCLIPerformance(telemetryLogs);
|
|
35
|
+
|
|
36
|
+
spinner.stop();
|
|
37
|
+
|
|
38
|
+
// Collect all results into a unified report
|
|
39
|
+
let report = {
|
|
40
|
+
valid: true,
|
|
41
|
+
issues: [],
|
|
42
|
+
rawResults: {
|
|
43
|
+
a11y: a11yResults,
|
|
44
|
+
tokens: tokenResults,
|
|
45
|
+
performance: performanceResults,
|
|
46
|
+
cli: cliPerformanceIssues
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
// Populate initial issues from standard validators
|
|
51
|
+
const allResults = [...a11yResults, ...tokenResults, ...performanceResults, ...cliPerformanceIssues];
|
|
52
|
+
for (const res of allResults) {
|
|
53
|
+
report.issues.push({
|
|
54
|
+
type: res.type,
|
|
55
|
+
severity: res.severity,
|
|
56
|
+
file: res.file,
|
|
57
|
+
message: res.message
|
|
58
|
+
});
|
|
59
|
+
if (res.severity === 'error') report.valid = false;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Trigger plugin hooks for custom validation
|
|
63
|
+
report = await hookManager.trigger('onValidate', report);
|
|
64
|
+
|
|
65
|
+
logger.box('Atomix Quality Audit', {
|
|
66
|
+
borderColor: 'magenta',
|
|
67
|
+
padding: 1,
|
|
68
|
+
margin: 1
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
if (report.issues.length === 0 && report.valid) {
|
|
72
|
+
console.log(chalk.bold.green('✨ No issues found! Your project meets all quality criteria.'));
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
let errors = 0;
|
|
77
|
+
let warnings = 0;
|
|
78
|
+
|
|
79
|
+
for (const result of report.issues) {
|
|
80
|
+
// Handle both object-based issues (standard) and string-based issues (simple plugin hooks)
|
|
81
|
+
const isObject = typeof result === 'object';
|
|
82
|
+
const severity = isObject ? (result.severity || 'error') : 'error';
|
|
83
|
+
const type = isObject ? (result.type || 'PLUGIN') : 'PLUGIN';
|
|
84
|
+
const file = isObject ? (result.file || 'N/A') : 'N/A';
|
|
85
|
+
const message = isObject ? result.message : result;
|
|
86
|
+
|
|
87
|
+
const icon = severity === 'error' ? chalk.red('❌') : chalk.yellow('⚠️');
|
|
88
|
+
if (severity === 'error') errors++;
|
|
89
|
+
else warnings++;
|
|
90
|
+
|
|
91
|
+
console.log(`${icon} [${type.toUpperCase()}] ${chalk.bold(file)}: ${message}`);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
console.log(chalk.bold(`\nSummary: ${errors} errors, ${warnings} warnings.`));
|
|
95
|
+
|
|
96
|
+
if (errors > 0) {
|
|
97
|
+
throw new AtomixCLIError(
|
|
98
|
+
`Validation failed with ${errors} error(s) and ${warnings} warning(s).`,
|
|
99
|
+
ErrorCategory.VALIDATION,
|
|
100
|
+
['Fix the reported issues and run atomix validate again.']
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
} catch (error) {
|
|
104
|
+
spinner.fail('Validation failed');
|
|
105
|
+
throw error;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Validate CLI performance against a budget
|
|
111
|
+
*/
|
|
112
|
+
function validateCLIPerformance(logs) {
|
|
113
|
+
if (logs.length === 0) return [];
|
|
114
|
+
|
|
115
|
+
const issues = [];
|
|
116
|
+
const BUDGET_MS = 2000;
|
|
117
|
+
const byCommand = {};
|
|
118
|
+
|
|
119
|
+
logs.forEach(log => {
|
|
120
|
+
if (!byCommand[log.command]) {
|
|
121
|
+
byCommand[log.command] = { durations: [] };
|
|
122
|
+
}
|
|
123
|
+
byCommand[log.command].durations.push(log.duration);
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
for (const [name, data] of Object.entries(byCommand)) {
|
|
127
|
+
data.durations.sort((a, b) => a - b);
|
|
128
|
+
const p95Index = Math.floor(data.durations.length * 0.95);
|
|
129
|
+
const p95 = data.durations[p95Index];
|
|
130
|
+
|
|
131
|
+
if (p95 > BUDGET_MS) {
|
|
132
|
+
issues.push({
|
|
133
|
+
type: 'performance',
|
|
134
|
+
severity: 'warning',
|
|
135
|
+
file: `cli:${name}`,
|
|
136
|
+
message: `CLI Performance budget exceeded (P95: ${p95}ms, Budget: ${BUDGET_MS}ms)`
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return issues;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Run validation for a single component and print component-scoped report
|
|
146
|
+
* @param {string} name - Component name (PascalCase)
|
|
147
|
+
*/
|
|
148
|
+
async function runComponentValidation(name) {
|
|
149
|
+
const nameValidation = await validateComponentName(name);
|
|
150
|
+
if (!nameValidation.isValid) {
|
|
151
|
+
throw new AtomixCLIError(
|
|
152
|
+
nameValidation.error || `Invalid component name: ${name}`,
|
|
153
|
+
ErrorCategory.VALIDATION,
|
|
154
|
+
['Use PascalCase (e.g. Button, Card). See atomix validate --help.']
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const spinner = logger.spinner(`Validating component ${name}...`).start();
|
|
159
|
+
try {
|
|
160
|
+
const report = await validateComponent(name);
|
|
161
|
+
spinner.stop();
|
|
162
|
+
|
|
163
|
+
logger.box(`Component: ${report.component}`, {
|
|
164
|
+
borderColor: 'magenta',
|
|
165
|
+
padding: 1,
|
|
166
|
+
margin: 1
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
if (report.issues.length === 0) {
|
|
170
|
+
console.log(chalk.bold.green(`✨ No issues found for ${report.component}.`));
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
let errors = 0;
|
|
175
|
+
let warnings = 0;
|
|
176
|
+
for (const r of report.issues) {
|
|
177
|
+
const icon = r.severity === 'error' ? chalk.red('❌') : chalk.yellow('⚠️');
|
|
178
|
+
if (r.severity === 'error') errors++;
|
|
179
|
+
else warnings++;
|
|
180
|
+
console.log(`${icon} [${r.type}] ${chalk.bold(r.file)}: ${r.message}`);
|
|
181
|
+
}
|
|
182
|
+
console.log(chalk.bold(`\nSummary: ${errors} errors, ${warnings} warnings.`));
|
|
183
|
+
if (!report.valid) {
|
|
184
|
+
throw new AtomixCLIError(
|
|
185
|
+
`Component validation failed with ${errors} error(s) and ${warnings} warning(s).`,
|
|
186
|
+
ErrorCategory.VALIDATION,
|
|
187
|
+
['Fix the reported issues and run atomix validate component <Name> again.']
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
} catch (error) {
|
|
191
|
+
spinner.fail('Validation failed');
|
|
192
|
+
throw error;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Atomix CLI - AI Engine
|
|
3
|
+
* Handles integration with LLMs for component generation
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import chalk from 'chalk';
|
|
7
|
+
import { logger } from '../utils/logger.js';
|
|
8
|
+
import { configLoader } from './config-loader.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* AI Scaffolding Engine
|
|
12
|
+
*/
|
|
13
|
+
export class AIEngine {
|
|
14
|
+
constructor() {
|
|
15
|
+
this.config = configLoader.get('ai') || {};
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Generate component code based on prompt
|
|
20
|
+
*/
|
|
21
|
+
async generateComponent(name, prompt) {
|
|
22
|
+
const provider = this.config.provider || 'openai';
|
|
23
|
+
const apiKey = this.config.apiKey || process.env.ATOMIX_AI_API_KEY;
|
|
24
|
+
|
|
25
|
+
if (!apiKey) {
|
|
26
|
+
throw new Error(`AI API Key missing. Please configure it in atomix.config.ts or set ATOMIX_AI_API_KEY environment variable.`);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
logger.info(chalk.blue(`🤖 AI Engine: Generating component "${name}" using ${provider}...`));
|
|
30
|
+
|
|
31
|
+
try {
|
|
32
|
+
let response;
|
|
33
|
+
if (provider === 'openai') {
|
|
34
|
+
response = await this.callOpenAI(name, prompt, apiKey);
|
|
35
|
+
} else if (provider === 'anthropic') {
|
|
36
|
+
response = await this.callAnthropic(name, prompt, apiKey);
|
|
37
|
+
} else {
|
|
38
|
+
throw new Error(`Unsupported AI provider: ${provider}`);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return this.parseAIResponse(response);
|
|
42
|
+
} catch (error) {
|
|
43
|
+
logger.error(`AI Generation failed: ${error.message}`);
|
|
44
|
+
throw error;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Call OpenAI API
|
|
50
|
+
*/
|
|
51
|
+
async callOpenAI(name, prompt, apiKey) {
|
|
52
|
+
const model = this.config.model || 'gpt-4';
|
|
53
|
+
const systemPrompt = this.getSystemPrompt(name);
|
|
54
|
+
|
|
55
|
+
const response = await fetch('https://api.openai.com/v1/chat/completions', {
|
|
56
|
+
method: 'POST',
|
|
57
|
+
headers: {
|
|
58
|
+
'Content-Type': 'application/json',
|
|
59
|
+
'Authorization': `Bearer ${apiKey}`
|
|
60
|
+
},
|
|
61
|
+
body: JSON.stringify({
|
|
62
|
+
model: model,
|
|
63
|
+
messages: [
|
|
64
|
+
{ role: 'system', content: systemPrompt },
|
|
65
|
+
{ role: 'user', content: prompt }
|
|
66
|
+
],
|
|
67
|
+
temperature: 0.7
|
|
68
|
+
})
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
if (!response.ok) {
|
|
72
|
+
const errorData = await response.json();
|
|
73
|
+
throw new Error(`OpenAI API error: ${errorData.error?.message || response.statusText}`);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const data = await response.json();
|
|
77
|
+
return data.choices[0].message.content;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Call Anthropic API
|
|
82
|
+
*/
|
|
83
|
+
async callAnthropic(name, prompt, apiKey) {
|
|
84
|
+
const model = this.config.model || 'claude-3-sonnet-20240229';
|
|
85
|
+
const systemPrompt = this.getSystemPrompt(name);
|
|
86
|
+
|
|
87
|
+
const response = await fetch('https://api.anthropic.com/v1/messages', {
|
|
88
|
+
method: 'POST',
|
|
89
|
+
headers: {
|
|
90
|
+
'Content-Type': 'application/json',
|
|
91
|
+
'x-api-key': apiKey,
|
|
92
|
+
'anthropic-version': '2023-06-01'
|
|
93
|
+
},
|
|
94
|
+
body: JSON.stringify({
|
|
95
|
+
model: model,
|
|
96
|
+
max_tokens: 4000,
|
|
97
|
+
system: systemPrompt,
|
|
98
|
+
messages: [
|
|
99
|
+
{ role: 'user', content: prompt }
|
|
100
|
+
]
|
|
101
|
+
})
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
if (!response.ok) {
|
|
105
|
+
const errorData = await response.json();
|
|
106
|
+
throw new Error(`Anthropic API error: ${errorData.error?.message || response.statusText}`);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const data = await response.json();
|
|
110
|
+
return data.content[0].text;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Get system prompt for the AI
|
|
115
|
+
*/
|
|
116
|
+
getSystemPrompt(name) {
|
|
117
|
+
return `You are an expert design system engineer specializing in the Atomix design system.
|
|
118
|
+
Your task is to generate a high-quality React component named "${name}" based on the user's prompt.
|
|
119
|
+
|
|
120
|
+
The component should follow these rules:
|
|
121
|
+
1. Use React and TypeScript.
|
|
122
|
+
2. Use Atomix utility classes (u-*) and component classes (c-*).
|
|
123
|
+
3. Follow the Atomix component structure (Props interface, functional component, exports).
|
|
124
|
+
4. Include JSDoc comments for all props.
|
|
125
|
+
5. Ensure the component is accessible (aria labels, roles).
|
|
126
|
+
6. Return only a JSON object with the following structure:
|
|
127
|
+
{
|
|
128
|
+
"component": "Full component code as a string",
|
|
129
|
+
"styles": "Any custom CSS/SCSS if needed (optional)",
|
|
130
|
+
"tests": "Unit test code using Vitest and React Testing Library",
|
|
131
|
+
"stories": "Storybook story file code",
|
|
132
|
+
"readme": "Usage documentation in Markdown"
|
|
133
|
+
}
|
|
134
|
+
Ensure the output is a valid JSON object. Do not include any other text or explanation.`;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Parse AI response to extract files
|
|
139
|
+
*/
|
|
140
|
+
parseAIResponse(content) {
|
|
141
|
+
try {
|
|
142
|
+
// Try to find JSON in the response if the AI included other text
|
|
143
|
+
const jsonMatch = content.match(/\{[\s\S]*\}/);
|
|
144
|
+
if (jsonMatch) {
|
|
145
|
+
return JSON.parse(jsonMatch[0]);
|
|
146
|
+
}
|
|
147
|
+
return JSON.parse(content);
|
|
148
|
+
} catch (error) {
|
|
149
|
+
logger.error('Failed to parse AI response as JSON. Raw content:');
|
|
150
|
+
console.log(content);
|
|
151
|
+
throw new Error('AI returned invalid JSON format. See console for raw output.');
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export const aiEngine = new AIEngine();
|