@calibrate-ds/cli 0.1.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/dist/__tests__/component-slug.test.d.ts +2 -0
- package/dist/__tests__/component-slug.test.d.ts.map +1 -0
- package/dist/__tests__/component-slug.test.js +54 -0
- package/dist/__tests__/component-slug.test.js.map +1 -0
- package/dist/__tests__/lock-changes.test.d.ts +2 -0
- package/dist/__tests__/lock-changes.test.d.ts.map +1 -0
- package/dist/__tests__/lock-changes.test.js +81 -0
- package/dist/__tests__/lock-changes.test.js.map +1 -0
- package/dist/__tests__/permissions.test.d.ts +2 -0
- package/dist/__tests__/permissions.test.d.ts.map +1 -0
- package/dist/__tests__/permissions.test.js +67 -0
- package/dist/__tests__/permissions.test.js.map +1 -0
- package/dist/__tests__/stamp-in-lock.test.d.ts +2 -0
- package/dist/__tests__/stamp-in-lock.test.d.ts.map +1 -0
- package/dist/__tests__/stamp-in-lock.test.js +102 -0
- package/dist/__tests__/stamp-in-lock.test.js.map +1 -0
- package/dist/__tests__/status-logic.test.d.ts +2 -0
- package/dist/__tests__/status-logic.test.d.ts.map +1 -0
- package/dist/__tests__/status-logic.test.js +74 -0
- package/dist/__tests__/status-logic.test.js.map +1 -0
- package/dist/__tests__/team-roster.test.d.ts +2 -0
- package/dist/__tests__/team-roster.test.d.ts.map +1 -0
- package/dist/__tests__/team-roster.test.js +97 -0
- package/dist/__tests__/team-roster.test.js.map +1 -0
- package/dist/ai/claude-provider.d.ts +13 -0
- package/dist/ai/claude-provider.d.ts.map +1 -0
- package/dist/ai/claude-provider.js +335 -0
- package/dist/ai/claude-provider.js.map +1 -0
- package/dist/ai/enhance-doc.d.ts +24 -0
- package/dist/ai/enhance-doc.d.ts.map +1 -0
- package/dist/ai/enhance-doc.js +272 -0
- package/dist/ai/enhance-doc.js.map +1 -0
- package/dist/ai/openai-provider.d.ts +13 -0
- package/dist/ai/openai-provider.d.ts.map +1 -0
- package/dist/ai/openai-provider.js +345 -0
- package/dist/ai/openai-provider.js.map +1 -0
- package/dist/ai/prompt-utils.d.ts +23 -0
- package/dist/ai/prompt-utils.d.ts.map +1 -0
- package/dist/ai/prompt-utils.js +67 -0
- package/dist/ai/prompt-utils.js.map +1 -0
- package/dist/commands/ai.d.ts +8 -0
- package/dist/commands/ai.d.ts.map +1 -0
- package/dist/commands/ai.js +576 -0
- package/dist/commands/ai.js.map +1 -0
- package/dist/commands/apply.d.ts +4 -0
- package/dist/commands/apply.d.ts.map +1 -0
- package/dist/commands/apply.js +98 -0
- package/dist/commands/apply.js.map +1 -0
- package/dist/commands/assign.d.ts +5 -0
- package/dist/commands/assign.d.ts.map +1 -0
- package/dist/commands/assign.js +180 -0
- package/dist/commands/assign.js.map +1 -0
- package/dist/commands/ci.d.ts +4 -0
- package/dist/commands/ci.d.ts.map +1 -0
- package/dist/commands/ci.js +84 -0
- package/dist/commands/ci.js.map +1 -0
- package/dist/commands/context.d.ts +19 -0
- package/dist/commands/context.d.ts.map +1 -0
- package/dist/commands/context.js +297 -0
- package/dist/commands/context.js.map +1 -0
- package/dist/commands/diff.d.ts +2 -0
- package/dist/commands/diff.d.ts.map +1 -0
- package/dist/commands/diff.js +119 -0
- package/dist/commands/diff.js.map +1 -0
- package/dist/commands/doctor.d.ts +5 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +348 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/document-system.d.ts +5 -0
- package/dist/commands/document-system.d.ts.map +1 -0
- package/dist/commands/document-system.js +84 -0
- package/dist/commands/document-system.js.map +1 -0
- package/dist/commands/document.d.ts +6 -0
- package/dist/commands/document.d.ts.map +1 -0
- package/dist/commands/document.js +276 -0
- package/dist/commands/document.js.map +1 -0
- package/dist/commands/export.d.ts +11 -0
- package/dist/commands/export.d.ts.map +1 -0
- package/dist/commands/export.js +74 -0
- package/dist/commands/export.js.map +1 -0
- package/dist/commands/generate-components.d.ts +4 -0
- package/dist/commands/generate-components.d.ts.map +1 -0
- package/dist/commands/generate-components.js +62 -0
- package/dist/commands/generate-components.js.map +1 -0
- package/dist/commands/generate-composites.d.ts +2 -0
- package/dist/commands/generate-composites.d.ts.map +1 -0
- package/dist/commands/generate-composites.js +31 -0
- package/dist/commands/generate-composites.js.map +1 -0
- package/dist/commands/generate-tokens.d.ts +2 -0
- package/dist/commands/generate-tokens.d.ts.map +1 -0
- package/dist/commands/generate-tokens.js +48 -0
- package/dist/commands/generate-tokens.js.map +1 -0
- package/dist/commands/help-topics.d.ts +2 -0
- package/dist/commands/help-topics.d.ts.map +1 -0
- package/dist/commands/help-topics.js +324 -0
- package/dist/commands/help-topics.js.map +1 -0
- package/dist/commands/implement.d.ts +5 -0
- package/dist/commands/implement.d.ts.map +1 -0
- package/dist/commands/implement.js +595 -0
- package/dist/commands/implement.js.map +1 -0
- package/dist/commands/import-tokens.d.ts +2 -0
- package/dist/commands/import-tokens.d.ts.map +1 -0
- package/dist/commands/import-tokens.js +42 -0
- package/dist/commands/import-tokens.js.map +1 -0
- package/dist/commands/init.d.ts +6 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +410 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/inspect-component.d.ts +2 -0
- package/dist/commands/inspect-component.d.ts.map +1 -0
- package/dist/commands/inspect-component.js +146 -0
- package/dist/commands/inspect-component.js.map +1 -0
- package/dist/commands/log.d.ts +4 -0
- package/dist/commands/log.d.ts.map +1 -0
- package/dist/commands/log.js +109 -0
- package/dist/commands/log.js.map +1 -0
- package/dist/commands/onboarding.d.ts +9 -0
- package/dist/commands/onboarding.d.ts.map +1 -0
- package/dist/commands/onboarding.js +63 -0
- package/dist/commands/onboarding.js.map +1 -0
- package/dist/commands/plan.d.ts +3 -0
- package/dist/commands/plan.d.ts.map +1 -0
- package/dist/commands/plan.js +108 -0
- package/dist/commands/plan.js.map +1 -0
- package/dist/commands/prompt.d.ts +5 -0
- package/dist/commands/prompt.d.ts.map +1 -0
- package/dist/commands/prompt.js +77 -0
- package/dist/commands/prompt.js.map +1 -0
- package/dist/commands/prune.d.ts +2 -0
- package/dist/commands/prune.d.ts.map +1 -0
- package/dist/commands/prune.js +95 -0
- package/dist/commands/prune.js.map +1 -0
- package/dist/commands/remove.d.ts +2 -0
- package/dist/commands/remove.d.ts.map +1 -0
- package/dist/commands/remove.js +76 -0
- package/dist/commands/remove.js.map +1 -0
- package/dist/commands/scaffold.d.ts +2 -0
- package/dist/commands/scaffold.d.ts.map +1 -0
- package/dist/commands/scaffold.js +47 -0
- package/dist/commands/scaffold.js.map +1 -0
- package/dist/commands/scan.d.ts +2 -0
- package/dist/commands/scan.d.ts.map +1 -0
- package/dist/commands/scan.js +91 -0
- package/dist/commands/scan.js.map +1 -0
- package/dist/commands/stamp.d.ts +11 -0
- package/dist/commands/stamp.d.ts.map +1 -0
- package/dist/commands/stamp.js +147 -0
- package/dist/commands/stamp.js.map +1 -0
- package/dist/commands/status.d.ts +7 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +219 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/team.d.ts +7 -0
- package/dist/commands/team.d.ts.map +1 -0
- package/dist/commands/team.js +173 -0
- package/dist/commands/team.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +303 -0
- package/dist/index.js.map +1 -0
- package/dist/onboarding/content.d.ts +39 -0
- package/dist/onboarding/content.d.ts.map +1 -0
- package/dist/onboarding/content.js +82 -0
- package/dist/onboarding/content.js.map +1 -0
- package/dist/utils/component-slug.d.ts +10 -0
- package/dist/utils/component-slug.d.ts.map +1 -0
- package/dist/utils/component-slug.js +13 -0
- package/dist/utils/component-slug.js.map +1 -0
- package/dist/utils/framework-registry.d.ts +41 -0
- package/dist/utils/framework-registry.d.ts.map +1 -0
- package/dist/utils/framework-registry.js +82 -0
- package/dist/utils/framework-registry.js.map +1 -0
- package/dist/utils/gitignore.d.ts +4 -0
- package/dist/utils/gitignore.d.ts.map +1 -0
- package/dist/utils/gitignore.js +67 -0
- package/dist/utils/gitignore.js.map +1 -0
- package/dist/utils/lock-changes.d.ts +14 -0
- package/dist/utils/lock-changes.d.ts.map +1 -0
- package/dist/utils/lock-changes.js +26 -0
- package/dist/utils/lock-changes.js.map +1 -0
- package/dist/utils/logger.d.ts +9 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +32 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/permissions.d.ts +17 -0
- package/dist/utils/permissions.d.ts.map +1 -0
- package/dist/utils/permissions.js +37 -0
- package/dist/utils/permissions.js.map +1 -0
- package/dist/utils/status-logic.d.ts +16 -0
- package/dist/utils/status-logic.d.ts.map +1 -0
- package/dist/utils/status-logic.js +32 -0
- package/dist/utils/status-logic.js.map +1 -0
- package/dist/utils/storybook-setup.d.ts +5 -0
- package/dist/utils/storybook-setup.d.ts.map +1 -0
- package/dist/utils/storybook-setup.js +104 -0
- package/dist/utils/storybook-setup.js.map +1 -0
- package/dist/utils/team-roster.d.ts +35 -0
- package/dist/utils/team-roster.d.ts.map +1 -0
- package/dist/utils/team-roster.js +99 -0
- package/dist/utils/team-roster.js.map +1 -0
- package/package.json +44 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ImplementationProvider, ComponentImplementationResult, ComponentPromptPackage } from "@calibrate-ds/shared-types";
|
|
2
|
+
export declare class OpenAIProvider implements ImplementationProvider {
|
|
3
|
+
name: string;
|
|
4
|
+
private client;
|
|
5
|
+
private model;
|
|
6
|
+
constructor(apiKey: string, model?: string);
|
|
7
|
+
implementComponent(params: {
|
|
8
|
+
componentName: string;
|
|
9
|
+
framework: string | null;
|
|
10
|
+
promptPackage: ComponentPromptPackage;
|
|
11
|
+
}): Promise<ComponentImplementationResult>;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=openai-provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai-provider.d.ts","sourceRoot":"","sources":["../../src/ai/openai-provider.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,sBAAsB,EAAE,6BAA6B,EAAE,sBAAsB,EAAiB,MAAM,4BAA4B,CAAC;AA+S/I,qBAAa,cAAe,YAAW,sBAAsB;IACzD,IAAI,SAAY;IAChB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,KAAK,CAAS;gBAEV,MAAM,EAAE,MAAM,EAAE,KAAK,SAAW;IAKtC,kBAAkB,CAAC,MAAM,EAAE;QAC7B,aAAa,EAAE,MAAM,CAAC;QACtB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;QACzB,aAAa,EAAE,sBAAsB,CAAC;KACzC,GAAG,OAAO,CAAC,6BAA6B,CAAC;CAgD7C"}
|
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
import OpenAI from "openai";
|
|
2
|
+
import { calcMaxTokens, buildUserMessage, formatTokenUsage } from "./prompt-utils.js";
|
|
3
|
+
const SYSTEM_PROMPT = `You are a design system component implementation assistant working inside PTB (Calibrate).
|
|
4
|
+
|
|
5
|
+
You receive a structured design context document describing a component extracted directly from Figma. Your job is to implement the component files that bring this design to life in code.
|
|
6
|
+
|
|
7
|
+
The examples below use React/JSX syntax. If the context specifies a different framework, apply the same principles using that framework's equivalent patterns.
|
|
8
|
+
|
|
9
|
+
## Rules
|
|
10
|
+
|
|
11
|
+
1. Call the write_file function for EVERY file you generate. Do not output prose or fenced code blocks — function calls only.
|
|
12
|
+
2. You MUST generate ALL FOUR of these files, no exceptions:
|
|
13
|
+
- <ComponentName>.<ext> — the component implementation
|
|
14
|
+
- <ComponentName>.types.ts — TypeScript prop types
|
|
15
|
+
- <ComponentName>.module.css — CSS module styles (generate an empty file if the component truly has no styles)
|
|
16
|
+
- index.ts — barrel export (always required, even if it is a single re-export line)
|
|
17
|
+
Before writing the last file, verify:
|
|
18
|
+
- [ ] The component file imports the Props type: \`import type { ComponentNameProps } from './ComponentName.types';\`
|
|
19
|
+
- [ ] Every \`[Class: X]\` annotation in the render structure is applied as a plain utility string (never a CSS module key)
|
|
20
|
+
- [ ] No \`display: none\` in CSS for elements already handled by a JS conditional in the template
|
|
21
|
+
- [ ] No fixed \`height: Npx\` on any element that wraps text content
|
|
22
|
+
- [ ] Dependency props match the \`Accepted props\` list in the context — no invented prop names, defaults match \`/* default: X */\` annotations
|
|
23
|
+
- [ ] Conditional rendering wraps ONLY the node at the specified path, not all instances of that component type
|
|
24
|
+
- [ ] Every prop in the Props Interface Skeleton is destructured in the function signature — no props silently dropped
|
|
25
|
+
3. Implement ONLY what the design context specifies:
|
|
26
|
+
- Variant axes → prop union types (these are PROPS, not useState)
|
|
27
|
+
- Token bindings → CSS custom properties (use the resolved variable names from the context)
|
|
28
|
+
- State contract → conditional class logic driven by a prop or controlled state
|
|
29
|
+
- Interaction contract → event handler stubs
|
|
30
|
+
- Layout → flex/grid CSS matching direction, gap, padding from context
|
|
31
|
+
- Size → CSS classes, never inline style={{ width, height }}
|
|
32
|
+
4. Do NOT invent business logic, API calls, or application state.
|
|
33
|
+
5. Do NOT add features absent from the design context.
|
|
34
|
+
6. Follow the framework and naming conventions specified in the prompt.
|
|
35
|
+
7. Never reference hardcoded colour values — always use the CSS custom properties from the token bindings.
|
|
36
|
+
|
|
37
|
+
## Anti-patterns — never do these
|
|
38
|
+
|
|
39
|
+
**1. Variant axes are props, not state:**
|
|
40
|
+
\`\`\`tsx
|
|
41
|
+
// WRONG — variant axes from the design context are never local state
|
|
42
|
+
const [variant, setVariant] = useState<'primary' | 'secondary'>('primary');
|
|
43
|
+
// RIGHT — receive as a prop with the Figma default as the default value
|
|
44
|
+
function Component({ variant = 'primary' }: ComponentProps) { ... }
|
|
45
|
+
\`\`\`
|
|
46
|
+
|
|
47
|
+
**2. CSS modules must be imported as an object, not as a side-effect:**
|
|
48
|
+
\`\`\`tsx
|
|
49
|
+
// WRONG — side-effect import; className string has no scoping
|
|
50
|
+
import './Component.module.css';
|
|
51
|
+
className="root"
|
|
52
|
+
// RIGHT — named import gives you the scoped class map
|
|
53
|
+
import styles from './Component.module.css';
|
|
54
|
+
className={styles.root}
|
|
55
|
+
\`\`\`
|
|
56
|
+
|
|
57
|
+
**3. Import every component you render — never use an undeclared identifier:**
|
|
58
|
+
\`\`\`tsx
|
|
59
|
+
// WRONG — renders <SubComponent /> without importing it; runtime error
|
|
60
|
+
// RIGHT
|
|
61
|
+
import { SubComponent } from '../sub-component/index.js';
|
|
62
|
+
\`\`\`
|
|
63
|
+
|
|
64
|
+
**4. Never inline pixel dimensions from the context — put them in CSS:**
|
|
65
|
+
\`\`\`tsx
|
|
66
|
+
// WRONG — inline styles bypass the CSS module and are hard to override
|
|
67
|
+
<div style={{ width: 320, height: 48 }}>
|
|
68
|
+
// RIGHT — dimensions belong in the CSS module
|
|
69
|
+
.root { width: 320px; height: 48px; }
|
|
70
|
+
\`\`\`
|
|
71
|
+
|
|
72
|
+
**5. Never pass a Figma metadata object as a prop:**
|
|
73
|
+
\`\`\`tsx
|
|
74
|
+
// WRONG — slot values in the context are design descriptions, not runtime values
|
|
75
|
+
<Component iconSlot={{ kind: 'unknown', componentId: '123:456' }} />
|
|
76
|
+
// RIGHT — render the actual resolved component in JSX
|
|
77
|
+
<IconComponent />
|
|
78
|
+
\`\`\`
|
|
79
|
+
|
|
80
|
+
**6. Pass sub-component dependencies as named slot props, not as children:**
|
|
81
|
+
\`\`\`tsx
|
|
82
|
+
// WRONG — passing as children only works if the component explicitly renders {children}
|
|
83
|
+
<ParentComponent><IconComponent /></ParentComponent>
|
|
84
|
+
// RIGHT — use the named slot prop defined in the Slot Contract
|
|
85
|
+
<ParentComponent icon={<IconComponent />} />
|
|
86
|
+
\`\`\`
|
|
87
|
+
|
|
88
|
+
**7. Never use heading tags (h1–h6) for non-heading content:**
|
|
89
|
+
\`\`\`tsx
|
|
90
|
+
// WRONG — labels, captions, and timestamps are not document headings
|
|
91
|
+
<h1>{label}</h1>
|
|
92
|
+
// RIGHT — use the semantically appropriate inline or block element
|
|
93
|
+
<span className={styles.label}>{label}</span>
|
|
94
|
+
<time className={styles.timestamp}>{timestamp}</time>
|
|
95
|
+
\`\`\`
|
|
96
|
+
|
|
97
|
+
**8. All props that have a Figma default must have a default value in code:**
|
|
98
|
+
\`\`\`tsx
|
|
99
|
+
// WRONG — prop with no default silently breaks the component when omitted
|
|
100
|
+
function Component({ label, value }: ComponentProps) { ... }
|
|
101
|
+
// RIGHT — mirror the Figma default so the component renders correctly in isolation
|
|
102
|
+
function Component({ label = 'Default label', value = '' }: ComponentProps) { ... }
|
|
103
|
+
\`\`\`
|
|
104
|
+
|
|
105
|
+
**9. Never use local state for anything driven by the design context:**
|
|
106
|
+
\`\`\`tsx
|
|
107
|
+
// WRONG — design-system variant axes are never local state
|
|
108
|
+
const [variant, setVariant] = useState('primary');
|
|
109
|
+
// WRONG — inventing a boolean flag for a slot that should be a ReactNode
|
|
110
|
+
function Component({ showIcon = false }: ComponentProps) { ... }
|
|
111
|
+
// RIGHT — receive variant axes and slot props directly; derive everything from props
|
|
112
|
+
function Component({ variant = 'primary', icon }: ComponentProps) { ... }
|
|
113
|
+
\`\`\`
|
|
114
|
+
Slot props (icons, sub-components) are ALWAYS \`ReactNode\` — never \`boolean\`.
|
|
115
|
+
|
|
116
|
+
**10. Never set a fixed height on a text or content container:**
|
|
117
|
+
\`\`\`css
|
|
118
|
+
/* WRONG — clips content when text reflows on the web */
|
|
119
|
+
.content { height: 80px; }
|
|
120
|
+
/* RIGHT — let the container grow with its content */
|
|
121
|
+
.content { min-height: 1.5em; } /* or omit height entirely */
|
|
122
|
+
\`\`\`
|
|
123
|
+
Figma fixes containers to their current content height. On the web, text reflows freely.
|
|
124
|
+
Use \`min-height\` or no height for any element that wraps text. Only apply a fixed \`height\`
|
|
125
|
+
to elements with a truly fixed visual footprint (icons, avatars, dividers, separators).
|
|
126
|
+
|
|
127
|
+
**11. A slot prop IS the element to render — never use its presence to select a hardcoded fallback:**
|
|
128
|
+
\`\`\`tsx
|
|
129
|
+
// WRONG — prop holds a ReactNode; treating it as a boolean selects a hardcoded component
|
|
130
|
+
const rendered = icon ? <DefaultIcon /> : null;
|
|
131
|
+
// RIGHT — render whatever was passed in
|
|
132
|
+
{icon}
|
|
133
|
+
// RIGHT — use the design default only as a fallback when nothing is passed
|
|
134
|
+
{icon ?? <DefaultIcon />}
|
|
135
|
+
\`\`\`
|
|
136
|
+
A slot prop named \`icon?: React.ReactNode\` is the element itself. The named component in the
|
|
137
|
+
context is the design tool's placeholder — use it as the \`??\` fallback, not the primary render.
|
|
138
|
+
|
|
139
|
+
**12. Never concatenate className with template literals — use a filtered join:**
|
|
140
|
+
\`\`\`tsx
|
|
141
|
+
// WRONG — produces "root undefined" when the optional className prop is not passed
|
|
142
|
+
className={\`\${styles.root} \${className}\`}
|
|
143
|
+
// RIGHT — filter removes falsy values before joining
|
|
144
|
+
className={[styles.root, className].filter(Boolean).join(' ')}
|
|
145
|
+
\`\`\`
|
|
146
|
+
|
|
147
|
+
**13. Never build dynamic class names from variant values — use data attributes:**
|
|
148
|
+
\`\`\`tsx
|
|
149
|
+
// WRONG — generates class names like "size-sm-status-active" that don't exist in the CSS module
|
|
150
|
+
const cls = \`size-\${size}-status-\${status}\`;
|
|
151
|
+
<div className={styles[cls]}>
|
|
152
|
+
// RIGHT — the CSS skeleton uses [data-*] attribute selectors; wire props to data attributes
|
|
153
|
+
<div
|
|
154
|
+
className={styles.root}
|
|
155
|
+
data-size={size}
|
|
156
|
+
data-status={status}
|
|
157
|
+
>
|
|
158
|
+
\`\`\`
|
|
159
|
+
The CSS skeleton already has \`.root[data-size="sm"] { ... }\` — connect props via \`data-*\`, never via dynamic class names.
|
|
160
|
+
|
|
161
|
+
**14. Always import the component's Props type from its .types file:**
|
|
162
|
+
\`\`\`tsx
|
|
163
|
+
// WRONG — type identifier is used but not imported → TypeScript error
|
|
164
|
+
const MyComponent: React.FC<MyComponentProps> = ...
|
|
165
|
+
// RIGHT
|
|
166
|
+
import type { MyComponentProps } from './MyComponent.types';
|
|
167
|
+
const MyComponent: React.FC<MyComponentProps> = ...
|
|
168
|
+
\`\`\`
|
|
169
|
+
Every component has a \`<ComponentName>.types.ts\` file. Always import the Props type from it.
|
|
170
|
+
|
|
171
|
+
**15. A CSS module key lookup must contain exactly one key — never two class names in one string:**
|
|
172
|
+
\`\`\`tsx
|
|
173
|
+
// WRONG — looks up a single key with a space in it; always resolves to undefined
|
|
174
|
+
className={styles['element-name utility-class']}
|
|
175
|
+
// RIGHT — look up the module key, then join utility classes separately as plain strings
|
|
176
|
+
className={[styles['element-name'], 'utility-class'].filter(Boolean).join(' ')}
|
|
177
|
+
\`\`\`
|
|
178
|
+
\`styles[key]\` is a single object property lookup. A space-separated string is one key, not two classes.
|
|
179
|
+
|
|
180
|
+
**16. CSS module keys containing a hyphen MUST use bracket notation — dot notation is a syntax error:**
|
|
181
|
+
\`\`\`tsx
|
|
182
|
+
// WRONG — "list-item" parses as "styles.list" minus "item" — JavaScript subtraction syntax error
|
|
183
|
+
className={styles.list-item}
|
|
184
|
+
// RIGHT — any key that is not a valid JS identifier requires bracket notation
|
|
185
|
+
className={styles['list-item']}
|
|
186
|
+
\`\`\`
|
|
187
|
+
Any CSS module key with a \`-\`, digit start, or reserved word must use \`styles['key']\`.
|
|
188
|
+
|
|
189
|
+
**17. A ReactNode slot prop is already an element — render it directly, never invoke it as a component:**
|
|
190
|
+
\`\`\`tsx
|
|
191
|
+
// WRONG — variable name in lowercase JSX is treated as a DOM element tag, not a component
|
|
192
|
+
{icon && <icon />}
|
|
193
|
+
// WRONG — the variable holds a ReactNode, not a constructor; calling it as a component is an error
|
|
194
|
+
{icon && <Icon />}
|
|
195
|
+
// RIGHT — a ReactNode renders as-is; undefined or null renders nothing
|
|
196
|
+
{icon}
|
|
197
|
+
\`\`\`
|
|
198
|
+
If the slot is optional, \`{prop}\` is the complete render expression — no boolean guard, no JSX invocation.
|
|
199
|
+
Never invent a paired \`showX: boolean\` alongside \`x: ReactNode\`. The presence or absence of the node IS the visibility control.
|
|
200
|
+
|
|
201
|
+
**18. Render structure \`[Class: X]\` tags are global utility classes — apply them as plain strings alongside the module class:**
|
|
202
|
+
\`\`\`tsx
|
|
203
|
+
// Context render structure: "Label node [Class: type-body-sm]"
|
|
204
|
+
// WRONG — drops the typography utility class entirely
|
|
205
|
+
<span className={styles['label']}>{text}</span>
|
|
206
|
+
// WRONG — tries to look up the utility class as a module key; always undefined
|
|
207
|
+
<span className={styles['label type-body-sm']}>{text}</span>
|
|
208
|
+
// RIGHT — module class handles component-specific styles; utility class handles typography
|
|
209
|
+
<span className={[styles['label'], 'type-body-sm'].filter(Boolean).join(' ')}>{text}</span>
|
|
210
|
+
\`\`\`
|
|
211
|
+
\`[Class: X]\` in the render structure is a global utility class (e.g. from \`typography.css\`). It is NOT a CSS module key. Always apply it as a plain string entry in the class array.
|
|
212
|
+
|
|
213
|
+
**19. Nodes marked \`visible: false\` in a variant diff must be conditionally removed from the DOM:**
|
|
214
|
+
\`\`\`tsx
|
|
215
|
+
// Context variant diff: "sidebar node — visible: true → false in state=collapsed"
|
|
216
|
+
// WRONG — CSS display:none hides visually but the node is still in the DOM and still runs
|
|
217
|
+
<div className={styles.layout}>
|
|
218
|
+
<Sidebar />
|
|
219
|
+
</div>
|
|
220
|
+
// RIGHT — use a JS conditional so the node does not render at all in that state
|
|
221
|
+
<div className={styles.layout}>
|
|
222
|
+
{status !== 'collapsed' && <Sidebar />}
|
|
223
|
+
</div>
|
|
224
|
+
\`\`\`
|
|
225
|
+
When the variant diff shows \`visible: true → false\` for a node in a given state, use \`&&\` or a ternary to remove it entirely — do not rely only on CSS.
|
|
226
|
+
|
|
227
|
+
**20. When one of several instances of the same dependency is conditionally hidden, wrap ONLY that instance:**
|
|
228
|
+
\`\`\`tsx
|
|
229
|
+
// Context: two SubComponent instances — one always visible, one hidden in state=secondary
|
|
230
|
+
// WRONG — wraps both; nothing renders in 'secondary' state
|
|
231
|
+
{variant !== 'secondary' && <SubComponent type="icon" />}
|
|
232
|
+
{variant !== 'secondary' && <SubComponent label="Open" />}
|
|
233
|
+
// RIGHT — the Conditional Rendering Guide names the hidden SLOT (e.g. "cta");
|
|
234
|
+
// cross-reference the Slot Render Guide to find which specific instance it maps to
|
|
235
|
+
<SubComponent type="icon" /> {/* always rendered */}
|
|
236
|
+
{variant !== 'secondary' && <SubComponent label="Open" />} {/* 'cta' slot — hidden in secondary */}
|
|
237
|
+
\`\`\`
|
|
238
|
+
The Conditional Rendering Guide names SLOTS (e.g. \`/* hide slot: cta */\`), not component types.
|
|
239
|
+
Look up that slot in the Slot Render Guide to identify exactly which instance to wrap.
|
|
240
|
+
All other instances of the same component that are NOT named remain always-rendered.
|
|
241
|
+
|
|
242
|
+
**21. Always use named exports — never default exports:**
|
|
243
|
+
\`\`\`tsx
|
|
244
|
+
// WRONG — default exports break named imports used by every consumer of this component
|
|
245
|
+
export default function Component({ ... }: ComponentProps) { ... }
|
|
246
|
+
export default Component;
|
|
247
|
+
|
|
248
|
+
// RIGHT — named export so every import can use { Component }
|
|
249
|
+
export function Component({ ... }: ComponentProps) { ... }
|
|
250
|
+
// OR
|
|
251
|
+
export const Component: React.FC<ComponentProps> = ({ ... }) => { ... };
|
|
252
|
+
\`\`\`
|
|
253
|
+
The \`index.ts\` barrel must also re-export named:
|
|
254
|
+
\`\`\`ts
|
|
255
|
+
// WRONG
|
|
256
|
+
export { default } from './Component.js';
|
|
257
|
+
// RIGHT
|
|
258
|
+
export { Component } from './Component.js';
|
|
259
|
+
\`\`\`
|
|
260
|
+
|
|
261
|
+
**22. \`data-state\` only exists on the root container — child overrides must use descendant selectors:**
|
|
262
|
+
\`\`\`css
|
|
263
|
+
/* WRONG — data-state is not on .sidebar; this selector never matches */
|
|
264
|
+
.sidebar[data-state="collapsed"] { width: 0; }
|
|
265
|
+
|
|
266
|
+
/* RIGHT — data-state lives on .container; use descendant selector */
|
|
267
|
+
.container[data-state="collapsed"] .sidebar { width: 0; }
|
|
268
|
+
\`\`\`
|
|
269
|
+
Every state/variant attribute is set on the root element only. Any CSS overrides for child elements
|
|
270
|
+
in a given state must be written as \`.container[data-X="Y"] .child\`, never \`.child[data-X="Y"]\`.
|
|
271
|
+
The CSS skeleton already shows the correct descendant-selector form — follow it exactly.`;
|
|
272
|
+
const WRITE_FILE_TOOL = {
|
|
273
|
+
type: "function",
|
|
274
|
+
function: {
|
|
275
|
+
name: "write_file",
|
|
276
|
+
description: "Write a generated implementation file for the component. Call this once per file.",
|
|
277
|
+
parameters: {
|
|
278
|
+
type: "object",
|
|
279
|
+
properties: {
|
|
280
|
+
path: {
|
|
281
|
+
type: "string",
|
|
282
|
+
description: "File path relative to the component folder, e.g. Button.tsx or Button.module.css"
|
|
283
|
+
},
|
|
284
|
+
content: {
|
|
285
|
+
type: "string",
|
|
286
|
+
description: "Full file content — no PTB_METADATA header needed, PTB adds that automatically"
|
|
287
|
+
}
|
|
288
|
+
},
|
|
289
|
+
required: ["path", "content"]
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
};
|
|
293
|
+
// GPT-5.x and o-series reasoning models use max_completion_tokens instead of max_tokens.
|
|
294
|
+
function tokenLimitParam(model, value) {
|
|
295
|
+
return /^(gpt-5|o1|o3|o4)/.test(model)
|
|
296
|
+
? { max_completion_tokens: value }
|
|
297
|
+
: { max_tokens: value };
|
|
298
|
+
}
|
|
299
|
+
export class OpenAIProvider {
|
|
300
|
+
name = "OpenAI";
|
|
301
|
+
client;
|
|
302
|
+
model;
|
|
303
|
+
constructor(apiKey, model = "gpt-4o") {
|
|
304
|
+
this.client = new OpenAI({ apiKey });
|
|
305
|
+
this.model = model;
|
|
306
|
+
}
|
|
307
|
+
async implementComponent(params) {
|
|
308
|
+
const { componentName, framework, promptPackage } = params;
|
|
309
|
+
const response = await this.client.chat.completions.create({
|
|
310
|
+
model: this.model,
|
|
311
|
+
...tokenLimitParam(this.model, calcMaxTokens(promptPackage)),
|
|
312
|
+
tools: [WRITE_FILE_TOOL],
|
|
313
|
+
tool_choice: "auto",
|
|
314
|
+
messages: [
|
|
315
|
+
{ role: "system", content: SYSTEM_PROMPT },
|
|
316
|
+
{ role: "user", content: buildUserMessage(promptPackage, componentName, framework) }
|
|
317
|
+
]
|
|
318
|
+
});
|
|
319
|
+
const usage = response.usage;
|
|
320
|
+
if (usage) {
|
|
321
|
+
console.log(formatTokenUsage(usage.prompt_tokens, usage.completion_tokens, usage.prompt_tokens_details?.cached_tokens ?? 0));
|
|
322
|
+
}
|
|
323
|
+
const files = [];
|
|
324
|
+
const toolCalls = response.choices[0]?.message?.tool_calls ?? [];
|
|
325
|
+
for (const call of toolCalls) {
|
|
326
|
+
if (call.type === "function" && call.function.name === "write_file") {
|
|
327
|
+
try {
|
|
328
|
+
const input = JSON.parse(call.function.arguments);
|
|
329
|
+
if (input.path && input.content !== undefined) {
|
|
330
|
+
files.push({ path: input.path, content: input.content });
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
catch {
|
|
334
|
+
// malformed tool call — skip
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
if (files.length === 0) {
|
|
339
|
+
throw new Error(`OpenAI returned no files for "${componentName}". ` +
|
|
340
|
+
`Finish reason: ${response.choices[0]?.finish_reason}. Check your API key and model access.`);
|
|
341
|
+
}
|
|
342
|
+
return { files };
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
//# sourceMappingURL=openai-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai-provider.js","sourceRoot":"","sources":["../../src/ai/openai-provider.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { ComponentPromptPackage } from "@calibrate-ds/shared-types";
|
|
2
|
+
/**
|
|
3
|
+
* Calculates an appropriate max_tokens ceiling based on component complexity.
|
|
4
|
+
* Avoids reserving 8096 for components that only need ~2000 output tokens.
|
|
5
|
+
*
|
|
6
|
+
* Base 2048 covers 4 files at ~500 tokens each.
|
|
7
|
+
* Each structural feature adds headroom for the extra code it requires.
|
|
8
|
+
*/
|
|
9
|
+
export declare function calcMaxTokens(pkg: ComponentPromptPackage): number;
|
|
10
|
+
/**
|
|
11
|
+
* Builds a compact user message from the prompt package.
|
|
12
|
+
*
|
|
13
|
+
* Two passes of trimming:
|
|
14
|
+
* 1. Strip "Structure Summary" — human-readable recap already covered by data sections below it.
|
|
15
|
+
* 2. Trim "Variant Differences" — for components with many variants this section dominates
|
|
16
|
+
* input tokens (can be 8k+ for 40+ variant combos). The AI doesn't need every structural
|
|
17
|
+
* diff to generate correct code — variant axes + token bindings are sufficient.
|
|
18
|
+
* We keep the first MAX_VARIANT_EXAMPLES as reference and replace the rest with a summary.
|
|
19
|
+
*/
|
|
20
|
+
export declare function buildUserMessage(pkg: ComponentPromptPackage, componentName: string, framework: string | null): string;
|
|
21
|
+
/** Formats token usage for display after a generation call. */
|
|
22
|
+
export declare function formatTokenUsage(input: number, output: number, cached?: number): string;
|
|
23
|
+
//# sourceMappingURL=prompt-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt-utils.d.ts","sourceRoot":"","sources":["../../src/ai/prompt-utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AAEzE;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,sBAAsB,GAAG,MAAM,CAajE;AAID;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAC5B,GAAG,EAAE,sBAAsB,EAC3B,aAAa,EAAE,MAAM,EACrB,SAAS,EAAE,MAAM,GAAG,IAAI,GACzB,MAAM,CA4BR;AAED,+DAA+D;AAC/D,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAMvF"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Calculates an appropriate max_tokens ceiling based on component complexity.
|
|
3
|
+
* Avoids reserving 8096 for components that only need ~2000 output tokens.
|
|
4
|
+
*
|
|
5
|
+
* Base 2048 covers 4 files at ~500 tokens each.
|
|
6
|
+
* Each structural feature adds headroom for the extra code it requires.
|
|
7
|
+
*/
|
|
8
|
+
export function calcMaxTokens(pkg) {
|
|
9
|
+
const s = pkg.structureSummary;
|
|
10
|
+
let max = 2048;
|
|
11
|
+
if (s?.hasVariants)
|
|
12
|
+
max += 512;
|
|
13
|
+
if (s?.hasStateContract)
|
|
14
|
+
max += 768;
|
|
15
|
+
if (s?.hasInteractionContract)
|
|
16
|
+
max += 512;
|
|
17
|
+
if (s?.hasPrototypeInteractionContract)
|
|
18
|
+
max += 512;
|
|
19
|
+
if (s?.hasTokenBindings)
|
|
20
|
+
max += 512;
|
|
21
|
+
if (s?.hasDependencies)
|
|
22
|
+
max += (s.dependencyCount ?? 1) * 256;
|
|
23
|
+
// Cap at 6144 — enough for complex components without over-reserving
|
|
24
|
+
return Math.min(max, 6144);
|
|
25
|
+
}
|
|
26
|
+
const MAX_VARIANT_EXAMPLES = 3;
|
|
27
|
+
/**
|
|
28
|
+
* Builds a compact user message from the prompt package.
|
|
29
|
+
*
|
|
30
|
+
* Two passes of trimming:
|
|
31
|
+
* 1. Strip "Structure Summary" — human-readable recap already covered by data sections below it.
|
|
32
|
+
* 2. Trim "Variant Differences" — for components with many variants this section dominates
|
|
33
|
+
* input tokens (can be 8k+ for 40+ variant combos). The AI doesn't need every structural
|
|
34
|
+
* diff to generate correct code — variant axes + token bindings are sufficient.
|
|
35
|
+
* We keep the first MAX_VARIANT_EXAMPLES as reference and replace the rest with a summary.
|
|
36
|
+
*/
|
|
37
|
+
export function buildUserMessage(pkg, componentName, framework) {
|
|
38
|
+
// Pass 1: strip redundant Structure Summary section
|
|
39
|
+
let text = pkg.promptText.replace(/\n## Structure Summary\n(?:- .+\n)*/, "\n");
|
|
40
|
+
// Pass 2: trim Variant Differences to MAX_VARIANT_EXAMPLES + summary
|
|
41
|
+
text = text.replace(/(\n## Variant Differences\n)([\s\S]*?)(?=\n## [A-Z]|\n---|\s*$)/, (_match, header, body) => {
|
|
42
|
+
// Each variant block starts with "### Variant:"
|
|
43
|
+
const blocks = body.split(/(?=### Variant:)/).filter((b) => b.trim());
|
|
44
|
+
if (blocks.length <= MAX_VARIANT_EXAMPLES)
|
|
45
|
+
return header + body;
|
|
46
|
+
const kept = blocks.slice(0, MAX_VARIANT_EXAMPLES).join("");
|
|
47
|
+
const omitted = blocks.length - MAX_VARIANT_EXAMPLES;
|
|
48
|
+
const note = `\n> ${omitted} more variant combinations omitted. Implement all ${blocks.length} combinations using the Variant Axes and Token Bindings defined above.\n`;
|
|
49
|
+
return header + kept + note;
|
|
50
|
+
});
|
|
51
|
+
return [
|
|
52
|
+
`Implement component: **${componentName}**`,
|
|
53
|
+
`Framework: ${framework || "react"}`,
|
|
54
|
+
``,
|
|
55
|
+
text.trimStart()
|
|
56
|
+
].join("\n");
|
|
57
|
+
}
|
|
58
|
+
/** Formats token usage for display after a generation call. */
|
|
59
|
+
export function formatTokenUsage(input, output, cached) {
|
|
60
|
+
const dim = "\x1b[2m";
|
|
61
|
+
const reset = "\x1b[0m";
|
|
62
|
+
const parts = [`${input.toLocaleString()} in`, `${output.toLocaleString()} out`];
|
|
63
|
+
if (cached && cached > 0)
|
|
64
|
+
parts.push(`${cached.toLocaleString()} cached`);
|
|
65
|
+
return `${dim} ↳ tokens: ${parts.join(" | ")}${reset}`;
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=prompt-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt-utils.js","sourceRoot":"","sources":["../../src/ai/prompt-utils.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAAC,GAA2B;IACrD,MAAM,CAAC,GAAG,GAAG,CAAC,gBAAgB,CAAC;IAC/B,IAAI,GAAG,GAAG,IAAI,CAAC;IAEf,IAAI,CAAC,EAAE,WAAW;QAAuB,GAAG,IAAI,GAAG,CAAC;IACpD,IAAI,CAAC,EAAE,gBAAgB;QAAkB,GAAG,IAAI,GAAG,CAAC;IACpD,IAAI,CAAC,EAAE,sBAAsB;QAAY,GAAG,IAAI,GAAG,CAAC;IACpD,IAAI,CAAC,EAAE,+BAA+B;QAAG,GAAG,IAAI,GAAG,CAAC;IACpD,IAAI,CAAC,EAAE,gBAAgB;QAAkB,GAAG,IAAI,GAAG,CAAC;IACpD,IAAI,CAAC,EAAE,eAAe;QAAmB,GAAG,IAAI,CAAC,CAAC,CAAC,eAAe,IAAI,CAAC,CAAC,GAAG,GAAG,CAAC;IAE/E,qEAAqE;IACrE,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;AAC/B,CAAC;AAED,MAAM,oBAAoB,GAAG,CAAC,CAAC;AAE/B;;;;;;;;;GASG;AACH,MAAM,UAAU,gBAAgB,CAC5B,GAA2B,EAC3B,aAAqB,EACrB,SAAwB;IAExB,oDAAoD;IACpD,IAAI,IAAI,GAAG,GAAG,CAAC,UAAU,CAAC,OAAO,CAC7B,qCAAqC,EACrC,IAAI,CACP,CAAC;IAEF,qEAAqE;IACrE,IAAI,GAAG,IAAI,CAAC,OAAO,CACf,iEAAiE,EACjE,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE;QACrB,gDAAgD;QAChD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC,MAAM,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;QAC9E,IAAI,MAAM,CAAC,MAAM,IAAI,oBAAoB;YAAE,OAAO,MAAM,GAAG,IAAI,CAAC;QAEhE,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,oBAAoB,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC5D,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,GAAG,oBAAoB,CAAC;QACrD,MAAM,IAAI,GAAG,OAAO,OAAO,qDAAqD,MAAM,CAAC,MAAM,0EAA0E,CAAC;QACxK,OAAO,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC;IAChC,CAAC,CACJ,CAAC;IAEF,OAAO;QACH,0BAA0B,aAAa,IAAI;QAC3C,cAAc,SAAS,IAAI,OAAO,EAAE;QACpC,EAAE;QACF,IAAI,CAAC,SAAS,EAAE;KACnB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACjB,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,gBAAgB,CAAC,KAAa,EAAE,MAAc,EAAE,MAAe;IAC3E,MAAM,GAAG,GAAI,SAAS,CAAC;IACvB,MAAM,KAAK,GAAG,SAAS,CAAC;IACxB,MAAM,KAAK,GAAG,CAAC,GAAG,KAAK,CAAC,cAAc,EAAE,KAAK,EAAE,GAAG,MAAM,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC;IACjF,IAAI,MAAM,IAAI,MAAM,GAAG,CAAC;QAAE,KAAK,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,cAAc,EAAE,SAAS,CAAC,CAAC;IAC1E,OAAO,GAAG,GAAG,eAAe,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,KAAK,EAAE,CAAC;AAC9D,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare function aiStatusCommand(): Promise<void>;
|
|
2
|
+
export declare function aiListCommand(): Promise<void>;
|
|
3
|
+
export declare function aiProvidersCommand(): Promise<void>;
|
|
4
|
+
export declare function aiUseCommand(provider: string): Promise<void>;
|
|
5
|
+
export declare function aiRemoveCommand(provider: string): Promise<void>;
|
|
6
|
+
export declare function aiModelCommand(modelId?: string): Promise<void>;
|
|
7
|
+
export declare function aiSetupCommand(): Promise<void>;
|
|
8
|
+
//# sourceMappingURL=ai.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai.d.ts","sourceRoot":"","sources":["../../src/commands/ai.ts"],"names":[],"mappings":"AAyWA,wBAAsB,eAAe,kBA2GpC;AAID,wBAAsB,aAAa,kBA8BlC;AAID,wBAAsB,kBAAkB,kBAEvC;AAID,wBAAsB,YAAY,CAAC,QAAQ,EAAE,MAAM,iBAyBlD;AAID,wBAAsB,eAAe,CAAC,QAAQ,EAAE,MAAM,iBAyBrD;AAID,wBAAsB,cAAc,CAAC,OAAO,CAAC,EAAE,MAAM,iBA4EpD;AAID,wBAAsB,cAAc,kBAGnC"}
|