@salesforce/b2c-dx-mcp 0.4.3 → 0.4.5
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 +82 -370
- package/content/pwav3/components.md +400 -0
- package/content/pwav3/config.md +124 -0
- package/content/pwav3/data-fetching.md +213 -0
- package/content/pwav3/extensibility.md +167 -0
- package/content/pwav3/i18n.md +214 -0
- package/content/pwav3/quick-reference.md +169 -0
- package/content/pwav3/routing.md +107 -0
- package/content/pwav3/state-management.md +193 -0
- package/content/pwav3/styling.md +248 -0
- package/content/pwav3/testing.md +124 -0
- package/content/site-theming/theming-accessibility.md +126 -0
- package/content/site-theming/theming-questions.md +208 -0
- package/content/site-theming/theming-validation.md +174 -0
- package/dist/registry.js +1 -1
- package/dist/services.d.ts +10 -10
- package/dist/services.js +19 -12
- package/dist/tools/cartridges/index.js +1 -6
- package/dist/tools/index.d.ts +1 -4
- package/dist/tools/index.js +1 -4
- package/dist/tools/mrt/index.js +1 -6
- package/dist/tools/pwav3/index.d.ts +12 -3
- package/dist/tools/pwav3/index.js +5 -63
- package/dist/tools/pwav3/pwa-kit-development-guidelines.d.ts +9 -0
- package/dist/tools/pwav3/pwa-kit-development-guidelines.js +151 -0
- package/dist/tools/scapi/index.d.ts +1 -1
- package/dist/tools/scapi/index.js +6 -1
- package/dist/tools/scapi/scapi-custom-api-scaffold.d.ts +60 -0
- package/dist/tools/scapi/scapi-custom-api-scaffold.js +175 -0
- package/dist/tools/storefrontnext/figma/figma-to-component/figma-url-parser.d.ts +24 -0
- package/dist/tools/storefrontnext/figma/figma-to-component/figma-url-parser.js +53 -0
- package/dist/tools/storefrontnext/figma/figma-to-component/index.d.ts +42 -0
- package/dist/tools/storefrontnext/figma/figma-to-component/index.js +325 -0
- package/dist/tools/storefrontnext/figma/generate-component/decision.d.ts +40 -0
- package/dist/tools/storefrontnext/figma/generate-component/decision.js +312 -0
- package/dist/tools/storefrontnext/figma/generate-component/formatter.d.ts +9 -0
- package/dist/tools/storefrontnext/figma/generate-component/formatter.js +92 -0
- package/dist/tools/storefrontnext/figma/generate-component/index.d.ts +114 -0
- package/dist/tools/storefrontnext/figma/generate-component/index.js +98 -0
- package/dist/tools/storefrontnext/figma/map-tokens/css-parser.d.ts +71 -0
- package/dist/tools/storefrontnext/figma/map-tokens/css-parser.js +260 -0
- package/dist/tools/storefrontnext/figma/map-tokens/index.d.ts +61 -0
- package/dist/tools/storefrontnext/figma/map-tokens/index.js +234 -0
- package/dist/tools/storefrontnext/figma/map-tokens/token-matcher.d.ts +65 -0
- package/dist/tools/storefrontnext/figma/map-tokens/token-matcher.js +268 -0
- package/dist/tools/storefrontnext/index.d.ts +17 -0
- package/dist/tools/storefrontnext/index.js +10 -60
- package/dist/tools/storefrontnext/page-designer-decorator/analyzer.js +15 -0
- package/dist/tools/storefrontnext/page-designer-decorator/index.js +3 -3
- package/dist/tools/storefrontnext/{developer-guidelines.js → sfnext-development-guidelines.js} +3 -3
- package/dist/tools/storefrontnext/site-theming/color-contrast.d.ts +92 -0
- package/dist/tools/storefrontnext/site-theming/color-contrast.js +186 -0
- package/dist/tools/storefrontnext/site-theming/color-mapping.d.ts +16 -0
- package/dist/tools/storefrontnext/site-theming/color-mapping.js +131 -0
- package/dist/tools/storefrontnext/site-theming/guidance-merger.d.ts +11 -0
- package/dist/tools/storefrontnext/site-theming/guidance-merger.js +78 -0
- package/dist/tools/storefrontnext/site-theming/index.d.ts +14 -0
- package/dist/tools/storefrontnext/site-theming/index.js +122 -0
- package/dist/tools/storefrontnext/site-theming/response-builder.d.ts +16 -0
- package/dist/tools/storefrontnext/site-theming/response-builder.js +316 -0
- package/dist/tools/storefrontnext/site-theming/theming-store.d.ts +62 -0
- package/dist/tools/storefrontnext/site-theming/theming-store.js +410 -0
- package/dist/tools/storefrontnext/site-theming/types.d.ts +35 -0
- package/dist/tools/storefrontnext/site-theming/types.js +7 -0
- package/oclif.manifest.json +1 -1
- package/package.json +9 -6
- /package/content/{auth.md → sfnext/auth.md} +0 -0
- /package/content/{components.md → sfnext/components.md} +0 -0
- /package/content/{config.md → sfnext/config.md} +0 -0
- /package/content/{data-fetching.md → sfnext/data-fetching.md} +0 -0
- /package/content/{extensions.md → sfnext/extensions.md} +0 -0
- /package/content/{i18n.md → sfnext/i18n.md} +0 -0
- /package/content/{page-designer.md → sfnext/page-designer.md} +0 -0
- /package/content/{performance.md → sfnext/performance.md} +0 -0
- /package/content/{pitfalls.md → sfnext/pitfalls.md} +0 -0
- /package/content/{quick-reference.md → sfnext/quick-reference.md} +0 -0
- /package/content/{state-management.md → sfnext/state-management.md} +0 -0
- /package/content/{styling.md → sfnext/styling.md} +0 -0
- /package/content/{testing.md → sfnext/testing.md} +0 -0
- /package/dist/tools/storefrontnext/{developer-guidelines.d.ts → sfnext-development-guidelines.d.ts} +0 -0
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2025, Salesforce, Inc.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2
|
|
4
|
+
* For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { buildColorCombinations, appendValidationSection } from './color-mapping.js';
|
|
7
|
+
function isComponentScopeQuestion(question) {
|
|
8
|
+
const questionLower = question.question.toLowerCase();
|
|
9
|
+
return (questionLower.includes('which components') ||
|
|
10
|
+
questionLower.includes('component scope') ||
|
|
11
|
+
questionLower.includes('component group'));
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Returns questions relevant to the current conversation state, filtered and sorted.
|
|
15
|
+
*/
|
|
16
|
+
export function getRelevantQuestions(guidance, context) {
|
|
17
|
+
if (!context || !context.questionsAsked || context.questionsAsked.length === 0) {
|
|
18
|
+
return guidance.questions
|
|
19
|
+
.filter((q) => !isComponentScopeQuestion(q))
|
|
20
|
+
.sort((a, b) => {
|
|
21
|
+
if (a.required !== b.required) {
|
|
22
|
+
return a.required ? -1 : 1;
|
|
23
|
+
}
|
|
24
|
+
const categoryOrder = { colors: 0, typography: 1, general: 2 };
|
|
25
|
+
return ((categoryOrder[a.category] || 2) -
|
|
26
|
+
(categoryOrder[b.category] || 2));
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
const askedIds = new Set(context.questionsAsked);
|
|
30
|
+
const remaining = guidance.questions.filter((q) => !askedIds.has(q.id) && !isComponentScopeQuestion(q));
|
|
31
|
+
if (context.collectedAnswers) {
|
|
32
|
+
const followUps = [];
|
|
33
|
+
for (const q of remaining) {
|
|
34
|
+
if (q.followUpQuestions && context.collectedAnswers?.[q.id]) {
|
|
35
|
+
for (const [index, followUp] of q.followUpQuestions.entries()) {
|
|
36
|
+
followUps.push({
|
|
37
|
+
id: `${q.id}-followup-${index}`,
|
|
38
|
+
question: followUp,
|
|
39
|
+
category: q.category,
|
|
40
|
+
required: false,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return [...remaining, ...followUps];
|
|
46
|
+
}
|
|
47
|
+
return remaining;
|
|
48
|
+
}
|
|
49
|
+
export function hasProvidedThemingInfo(context) {
|
|
50
|
+
if (!context?.collectedAnswers) {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
const collectedAnswers = context.collectedAnswers;
|
|
54
|
+
const hasColors = Boolean(collectedAnswers.colors && Array.isArray(collectedAnswers.colors));
|
|
55
|
+
const hasFonts = Boolean(collectedAnswers.fonts && Array.isArray(collectedAnswers.fonts));
|
|
56
|
+
return hasColors || hasFonts;
|
|
57
|
+
}
|
|
58
|
+
function buildExtractionResponse(extractionInstructions) {
|
|
59
|
+
const internal = '# ⚠️ MANDATORY: Extract User-Provided Theming Information\n\n## 🚨 CRITICAL: Information Extraction Required\n\n' +
|
|
60
|
+
extractionInstructions;
|
|
61
|
+
const user = "I need to extract the theming information from your input first.\n\nLet me review what you've shared and structure it properly, then I'll proceed with clarifying questions.\n\n";
|
|
62
|
+
return `${internal}\n\n---\n\n# USER-FACING RESPONSE (What to say to the user):\n\n${user}`;
|
|
63
|
+
}
|
|
64
|
+
function appendValidationInstructions(out, validation) {
|
|
65
|
+
let s = out +
|
|
66
|
+
'## ⚠️ MANDATORY: Input Validation\n\n**BEFORE implementing, you MUST validate ALL user-provided inputs:**\n\n';
|
|
67
|
+
if (validation.colorValidation)
|
|
68
|
+
s +=
|
|
69
|
+
'**A. Color Combination Validation (MANDATORY if colors provided):**\n\n' + validation.colorValidation + '\n\n';
|
|
70
|
+
if (validation.fontValidation)
|
|
71
|
+
s += '**B. Font Validation (MANDATORY if fonts provided):**\n\n' + validation.fontValidation + '\n\n';
|
|
72
|
+
if (validation.generalValidation)
|
|
73
|
+
s += '**C. General Input Validation:**\n\n' + validation.generalValidation + '\n\n';
|
|
74
|
+
if (validation.requirements)
|
|
75
|
+
s += '**IMPORTANT:**\n\n' + validation.requirements + '\n\n';
|
|
76
|
+
return s;
|
|
77
|
+
}
|
|
78
|
+
function appendCriticalAndRules(out, guidance) {
|
|
79
|
+
let s = out;
|
|
80
|
+
const critical = guidance.guidelines.filter((g) => g.critical);
|
|
81
|
+
if (critical.length > 0) {
|
|
82
|
+
s += '## ⚠️ Critical Guidelines (INTERNAL - Follow these rules)\n\n';
|
|
83
|
+
for (const g of critical)
|
|
84
|
+
s += `### ${g.title}\n\n${g.content}\n\n`;
|
|
85
|
+
}
|
|
86
|
+
if (guidance.rules.length > 0) {
|
|
87
|
+
s += '## Rules to Follow (INTERNAL)\n\n';
|
|
88
|
+
const doRules = guidance.rules.filter((r) => r.type === 'do');
|
|
89
|
+
const dontRules = guidance.rules.filter((r) => r.type === 'dont');
|
|
90
|
+
if (doRules.length > 0) {
|
|
91
|
+
s += '### ✅ What TO Do:\n\n';
|
|
92
|
+
for (const r of doRules)
|
|
93
|
+
s += `- ${r.description}\n`;
|
|
94
|
+
s += '\n';
|
|
95
|
+
}
|
|
96
|
+
if (dontRules.length > 0) {
|
|
97
|
+
s += '### ❌ What NOT to Do:\n\n';
|
|
98
|
+
for (const r of dontRules)
|
|
99
|
+
s += `- ${r.description}\n`;
|
|
100
|
+
s += '\n';
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return s;
|
|
104
|
+
}
|
|
105
|
+
function extractColorsFromArray(colors) {
|
|
106
|
+
if (!colors || !Array.isArray(colors))
|
|
107
|
+
return [];
|
|
108
|
+
const out = [];
|
|
109
|
+
for (const color of colors) {
|
|
110
|
+
if (color.hex && color.type)
|
|
111
|
+
out.push(`${color.hex} (${color.type})`);
|
|
112
|
+
else if (color.hex)
|
|
113
|
+
out.push(color.hex);
|
|
114
|
+
}
|
|
115
|
+
return out;
|
|
116
|
+
}
|
|
117
|
+
function extractFontsFromArray(fonts) {
|
|
118
|
+
if (!fonts || !Array.isArray(fonts))
|
|
119
|
+
return [];
|
|
120
|
+
const out = [];
|
|
121
|
+
for (const font of fonts) {
|
|
122
|
+
if (font.name)
|
|
123
|
+
out.push(font.type ? `${font.name} (${font.type})` : font.name);
|
|
124
|
+
}
|
|
125
|
+
return out;
|
|
126
|
+
}
|
|
127
|
+
function extractColorFromValue(value) {
|
|
128
|
+
if (typeof value === 'string')
|
|
129
|
+
return value;
|
|
130
|
+
if (typeof value === 'object' && value && 'hex' in value) {
|
|
131
|
+
const v = value;
|
|
132
|
+
if (v.hex === undefined)
|
|
133
|
+
return null;
|
|
134
|
+
return v.type ? `${v.hex} (${v.type})` : v.hex;
|
|
135
|
+
}
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
function extractFontFromValue(value) {
|
|
139
|
+
if (typeof value === 'string')
|
|
140
|
+
return value;
|
|
141
|
+
if (typeof value === 'object' && value && 'name' in value) {
|
|
142
|
+
const v = value;
|
|
143
|
+
if (v.name === undefined)
|
|
144
|
+
return null;
|
|
145
|
+
return v.type ? `${v.name} (${v.type})` : v.name;
|
|
146
|
+
}
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
function shouldSkipKeyForOtherInfo(key, lowerKey) {
|
|
150
|
+
if (key === 'colors' || key === 'fonts')
|
|
151
|
+
return true;
|
|
152
|
+
if (lowerKey.includes('question') || lowerKey.includes('step'))
|
|
153
|
+
return true;
|
|
154
|
+
if (lowerKey.includes('color') || lowerKey.includes('font'))
|
|
155
|
+
return true;
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
158
|
+
function extractOtherInfoFromEntries(collectedAnswers) {
|
|
159
|
+
const otherInfo = [];
|
|
160
|
+
for (const key of Object.keys(collectedAnswers)) {
|
|
161
|
+
const lowerKey = key.toLowerCase();
|
|
162
|
+
if (shouldSkipKeyForOtherInfo(key, lowerKey))
|
|
163
|
+
continue;
|
|
164
|
+
const value = collectedAnswers[key];
|
|
165
|
+
if (value === null || value === undefined)
|
|
166
|
+
continue;
|
|
167
|
+
otherInfo.push(`${key}: ${typeof value === 'object' ? JSON.stringify(value) : value}`);
|
|
168
|
+
}
|
|
169
|
+
return otherInfo;
|
|
170
|
+
}
|
|
171
|
+
function collectUserInfo(collectedAnswers) {
|
|
172
|
+
const colorsInfo = [...extractColorsFromArray(collectedAnswers.colors)];
|
|
173
|
+
const fontsInfo = [...extractFontsFromArray(collectedAnswers.fonts)];
|
|
174
|
+
for (const key of Object.keys(collectedAnswers)) {
|
|
175
|
+
const lowerKey = key.toLowerCase();
|
|
176
|
+
const value = collectedAnswers[key];
|
|
177
|
+
if (key === 'colors' || key === 'fonts' || lowerKey.includes('question') || lowerKey.includes('step'))
|
|
178
|
+
continue;
|
|
179
|
+
if (lowerKey.includes('color') && !key.includes('colors')) {
|
|
180
|
+
const c = extractColorFromValue(value);
|
|
181
|
+
if (c)
|
|
182
|
+
colorsInfo.push(c);
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
if (lowerKey.includes('font') && !key.includes('fonts')) {
|
|
186
|
+
const f = extractFontFromValue(value);
|
|
187
|
+
if (f)
|
|
188
|
+
fontsInfo.push(f);
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
const otherInfo = extractOtherInfoFromEntries(collectedAnswers);
|
|
193
|
+
return { colorsInfo, fontsInfo, otherInfo };
|
|
194
|
+
}
|
|
195
|
+
function buildUserInfoSection(info) {
|
|
196
|
+
const { colorsInfo, fontsInfo, otherInfo } = info;
|
|
197
|
+
if (colorsInfo.length === 0 && fontsInfo.length === 0 && otherInfo.length === 0) {
|
|
198
|
+
return 'Following the theming workflow. I need a few clarifications before implementing.\n\n';
|
|
199
|
+
}
|
|
200
|
+
let s = "## Information You've Provided\n\n";
|
|
201
|
+
if (colorsInfo.length > 0) {
|
|
202
|
+
s += '### Colors:\n';
|
|
203
|
+
for (const c of colorsInfo)
|
|
204
|
+
s += `- ${c}\n`;
|
|
205
|
+
s += '\n';
|
|
206
|
+
}
|
|
207
|
+
if (fontsInfo.length > 0) {
|
|
208
|
+
s += '### Fonts:\n';
|
|
209
|
+
for (const f of fontsInfo)
|
|
210
|
+
s += `- ${f}\n`;
|
|
211
|
+
s += '\n';
|
|
212
|
+
}
|
|
213
|
+
if (otherInfo.length > 0) {
|
|
214
|
+
s += '### Other Information:\n';
|
|
215
|
+
for (const o of otherInfo)
|
|
216
|
+
s += `- ${o}\n`;
|
|
217
|
+
s += '\n';
|
|
218
|
+
}
|
|
219
|
+
return (s +
|
|
220
|
+
"I've noted the information above. Before implementing, I need a few clarifications to ensure everything is set up correctly.\n\n");
|
|
221
|
+
}
|
|
222
|
+
function buildInternalInstructionsBase(guidance, context) {
|
|
223
|
+
let s = '# ⚠️ MANDATORY: Site Theming Guidelines and Questions\n\n## 🚨 CRITICAL: Read This First\n\n';
|
|
224
|
+
if (guidance.workflow?.steps && guidance.workflow.steps.length > 0) {
|
|
225
|
+
s += '**YOU MUST FOLLOW THIS WORKFLOW - NO EXCEPTIONS:**\n\n';
|
|
226
|
+
for (const [i, step] of guidance.workflow.steps.entries())
|
|
227
|
+
s += `${i + 1}. ${step}\n`;
|
|
228
|
+
s += '\n**VIOLATION OF THIS WORKFLOW IS A CRITICAL ERROR.**\n\n';
|
|
229
|
+
}
|
|
230
|
+
if (guidance.validation)
|
|
231
|
+
s = appendValidationInstructions(s, guidance.validation);
|
|
232
|
+
const colorMapping = context?.collectedAnswers?.colorMapping;
|
|
233
|
+
if (colorMapping && Object.keys(colorMapping).length > 0) {
|
|
234
|
+
s +=
|
|
235
|
+
'## 🎨 AUTOMATED COLOR VALIDATION RESULTS\n\n**The following validation has been automatically performed using built-in contrast calculation:**\n\n';
|
|
236
|
+
s = appendValidationSection(s, buildColorCombinations(colorMapping));
|
|
237
|
+
}
|
|
238
|
+
return appendCriticalAndRules(s, guidance);
|
|
239
|
+
}
|
|
240
|
+
function appendQuestionsToResponse(internal, user, nextQuestions, relevantQuestions) {
|
|
241
|
+
let userOut = user + '## Questions\n\n';
|
|
242
|
+
const categories = [
|
|
243
|
+
{ category: 'colors', title: 'Color Questions' },
|
|
244
|
+
{ category: 'typography', title: 'Font Questions' },
|
|
245
|
+
{ category: 'general', title: 'General Questions' },
|
|
246
|
+
];
|
|
247
|
+
for (const { category, title } of categories) {
|
|
248
|
+
const qs = nextQuestions.filter((q) => q.category === category);
|
|
249
|
+
if (qs.length > 0) {
|
|
250
|
+
userOut += `### ${title}\n\n`;
|
|
251
|
+
for (const [i, q] of qs.entries())
|
|
252
|
+
userOut += `**Question ${i + 1}**: ${q.question}\n\n`;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
const remaining = relevantQuestions.length - nextQuestions.length;
|
|
256
|
+
if (remaining > 0)
|
|
257
|
+
userOut += `\n_Note: I have ${remaining} more question${remaining > 1 ? 's' : ''} to ask after you answer these._\n\n`;
|
|
258
|
+
userOut += 'Please answer these questions so I can proceed with the implementation.\n\n';
|
|
259
|
+
let internalOut = internal +
|
|
260
|
+
"## Questions to Ask the User\n\n**IMPORTANT**: Ask these questions ONE AT A TIME and WAIT for the user's response before proceeding.\n\n**CRITICAL RULE**: NEVER implement changes after asking questions without waiting for the user's response.\n\n";
|
|
261
|
+
internalOut += `**You have ${relevantQuestions.length} total questions to ask. Show ${nextQuestions.length} now, then continue with the rest after user responds.**\n\n`;
|
|
262
|
+
for (const [i, q] of nextQuestions.entries()) {
|
|
263
|
+
internalOut += `### Question ${i + 1} (${q.category}): ${q.id}\n\n${q.question}\n\n`;
|
|
264
|
+
if (q.required)
|
|
265
|
+
internalOut += '**Required**: Yes\n\n';
|
|
266
|
+
}
|
|
267
|
+
return { internal: internalOut, user: userOut };
|
|
268
|
+
}
|
|
269
|
+
function appendReadyOrWarningToResponse(internal, user, guidance, context) {
|
|
270
|
+
const required = guidance.questions.filter((q) => q.required);
|
|
271
|
+
const answered = required.filter((q) => context.collectedAnswers?.[q.id] !== undefined);
|
|
272
|
+
if (answered.length < required.length) {
|
|
273
|
+
return {
|
|
274
|
+
internal: internal +
|
|
275
|
+
'## ⚠️ WARNING: Not all required questions have been answered!\n\n**DO NOT implement yet. Continue asking questions.**\n\n',
|
|
276
|
+
user: user + 'I still need answers to some required questions before I can proceed.\n\n',
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
let internalOut = internal;
|
|
280
|
+
if (guidance.workflow?.preImplementationChecklist) {
|
|
281
|
+
internalOut +=
|
|
282
|
+
'## ⚠️ MANDATORY PRE-IMPLEMENTATION CHECKLIST\n\n' + guidance.workflow.preImplementationChecklist + '\n\n';
|
|
283
|
+
}
|
|
284
|
+
const userOut = user +
|
|
285
|
+
'## Ready to Implement\n\nI have collected all necessary information. Before implementing, I will validate all provided inputs (colors, fonts, etc.) for accessibility, availability, and best practices.\n\n';
|
|
286
|
+
return { internal: internalOut, user: userOut };
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Generates the full theming tool response from guidance and conversation context.
|
|
290
|
+
*/
|
|
291
|
+
export function generateResponse(guidance, context) {
|
|
292
|
+
const isFirstCall = !context || !context.questionsAsked || context.questionsAsked.length === 0;
|
|
293
|
+
if (isFirstCall && !hasProvidedThemingInfo(context) && guidance.workflow?.extractionInstructions) {
|
|
294
|
+
return buildExtractionResponse(guidance.workflow.extractionInstructions);
|
|
295
|
+
}
|
|
296
|
+
const relevantQuestions = getRelevantQuestions(guidance, context);
|
|
297
|
+
const questionLimit = !context || context.questionsAsked?.length === 0 ? 5 : 3;
|
|
298
|
+
const nextQuestions = relevantQuestions.slice(0, questionLimit);
|
|
299
|
+
let internalInstructions = buildInternalInstructionsBase(guidance, context);
|
|
300
|
+
const info = context?.collectedAnswers
|
|
301
|
+
? collectUserInfo(context.collectedAnswers)
|
|
302
|
+
: { colorsInfo: [], fontsInfo: [], otherInfo: [] };
|
|
303
|
+
let userResponse = buildUserInfoSection(info);
|
|
304
|
+
if (nextQuestions.length > 0) {
|
|
305
|
+
const appended = appendQuestionsToResponse(internalInstructions, userResponse, nextQuestions, relevantQuestions);
|
|
306
|
+
internalInstructions = appended.internal;
|
|
307
|
+
userResponse = appended.user;
|
|
308
|
+
}
|
|
309
|
+
else if (context?.collectedAnswers && Object.keys(context.collectedAnswers).length > 0) {
|
|
310
|
+
const appended = appendReadyOrWarningToResponse(internalInstructions, userResponse, guidance, context);
|
|
311
|
+
internalInstructions = appended.internal;
|
|
312
|
+
userResponse = appended.user;
|
|
313
|
+
}
|
|
314
|
+
return `${internalInstructions}\n\n---\n\n# USER-FACING RESPONSE (What to say to the user):\n\n${userResponse}`;
|
|
315
|
+
}
|
|
316
|
+
//# sourceMappingURL=response-builder.js.map
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
export interface ThemingGuidance {
|
|
2
|
+
questions: Array<{
|
|
3
|
+
id: string;
|
|
4
|
+
question: string;
|
|
5
|
+
category: string;
|
|
6
|
+
required: boolean;
|
|
7
|
+
followUpQuestions?: string[];
|
|
8
|
+
}>;
|
|
9
|
+
guidelines: Array<{
|
|
10
|
+
category: string;
|
|
11
|
+
title: string;
|
|
12
|
+
content: string;
|
|
13
|
+
critical: boolean;
|
|
14
|
+
}>;
|
|
15
|
+
rules: Array<{
|
|
16
|
+
type: 'do' | 'dont';
|
|
17
|
+
description: string;
|
|
18
|
+
examples?: string[];
|
|
19
|
+
}>;
|
|
20
|
+
workflow?: {
|
|
21
|
+
steps: string[];
|
|
22
|
+
extractionInstructions?: string;
|
|
23
|
+
preImplementationChecklist?: string;
|
|
24
|
+
};
|
|
25
|
+
validation?: {
|
|
26
|
+
colorValidation?: string;
|
|
27
|
+
fontValidation?: string;
|
|
28
|
+
generalValidation?: string;
|
|
29
|
+
requirements?: string;
|
|
30
|
+
};
|
|
31
|
+
metadata: {
|
|
32
|
+
filePath: string;
|
|
33
|
+
fileName: string;
|
|
34
|
+
loadedAt: Date;
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Theming Data Store
|
|
39
|
+
* Loads and caches theming guidance from .md/.mdc files
|
|
40
|
+
*/
|
|
41
|
+
export interface InitializeOptions {
|
|
42
|
+
/** Override content directory for default files (used in tests). */
|
|
43
|
+
contentDirOverride?: string;
|
|
44
|
+
}
|
|
45
|
+
declare class ThemingStore {
|
|
46
|
+
private initializedForRoot;
|
|
47
|
+
private store;
|
|
48
|
+
get(fileKey: string): ThemingGuidance | undefined;
|
|
49
|
+
getKeys(): string[];
|
|
50
|
+
has(fileKey: string): boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Initialize store with default files from content/site-theming.
|
|
53
|
+
* Uses workspaceRoot for THEMING_FILES env paths (relative to project).
|
|
54
|
+
* Skips re-loading when already initialized for the same root.
|
|
55
|
+
*/
|
|
56
|
+
initialize(workspaceRoot?: string, options?: InitializeOptions): void;
|
|
57
|
+
loadFile(fileKey: string, filePath: string): void;
|
|
58
|
+
private loadThemingFilesFromEnv;
|
|
59
|
+
private tryLoadEnvFile;
|
|
60
|
+
}
|
|
61
|
+
export declare const siteThemingStore: ThemingStore;
|
|
62
|
+
export {};
|