popeye-cli 1.4.6 → 1.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/README.md +222 -63
- package/dist/adapters/gemini.d.ts +1 -0
- package/dist/adapters/gemini.d.ts.map +1 -1
- package/dist/adapters/gemini.js +9 -4
- package/dist/adapters/gemini.js.map +1 -1
- package/dist/adapters/grok.d.ts +1 -0
- package/dist/adapters/grok.d.ts.map +1 -1
- package/dist/adapters/grok.js +9 -4
- package/dist/adapters/grok.js.map +1 -1
- package/dist/adapters/openai.d.ts +1 -1
- package/dist/adapters/openai.d.ts.map +1 -1
- package/dist/adapters/openai.js +35 -9
- package/dist/adapters/openai.js.map +1 -1
- package/dist/cli/interactive.d.ts.map +1 -1
- package/dist/cli/interactive.js +42 -0
- package/dist/cli/interactive.js.map +1 -1
- package/dist/generators/all.d.ts +4 -1
- package/dist/generators/all.d.ts.map +1 -1
- package/dist/generators/all.js +2 -1
- package/dist/generators/all.js.map +1 -1
- package/dist/generators/doc-parser.d.ts +49 -0
- package/dist/generators/doc-parser.d.ts.map +1 -0
- package/dist/generators/doc-parser.js +336 -0
- package/dist/generators/doc-parser.js.map +1 -0
- package/dist/generators/templates/index.d.ts +4 -0
- package/dist/generators/templates/index.d.ts.map +1 -1
- package/dist/generators/templates/index.js +4 -0
- package/dist/generators/templates/index.js.map +1 -1
- package/dist/generators/templates/website-components.d.ts +33 -0
- package/dist/generators/templates/website-components.d.ts.map +1 -0
- package/dist/generators/templates/website-components.js +278 -0
- package/dist/generators/templates/website-components.js.map +1 -0
- package/dist/generators/templates/website-config.d.ts +41 -0
- package/dist/generators/templates/website-config.d.ts.map +1 -0
- package/dist/generators/templates/website-config.js +283 -0
- package/dist/generators/templates/website-config.js.map +1 -0
- package/dist/generators/templates/website-conversion.d.ts +27 -0
- package/dist/generators/templates/website-conversion.d.ts.map +1 -0
- package/dist/generators/templates/website-conversion.js +326 -0
- package/dist/generators/templates/website-conversion.js.map +1 -0
- package/dist/generators/templates/website-seo.d.ts +76 -0
- package/dist/generators/templates/website-seo.d.ts.map +1 -0
- package/dist/generators/templates/website-seo.js +326 -0
- package/dist/generators/templates/website-seo.js.map +1 -0
- package/dist/generators/templates/website.d.ts +14 -47
- package/dist/generators/templates/website.d.ts.map +1 -1
- package/dist/generators/templates/website.js +412 -499
- package/dist/generators/templates/website.js.map +1 -1
- package/dist/generators/website-context.d.ts +83 -0
- package/dist/generators/website-context.d.ts.map +1 -0
- package/dist/generators/website-context.js +190 -0
- package/dist/generators/website-context.js.map +1 -0
- package/dist/generators/website.d.ts +3 -0
- package/dist/generators/website.d.ts.map +1 -1
- package/dist/generators/website.js +73 -10
- package/dist/generators/website.js.map +1 -1
- package/dist/state/index.d.ts +27 -0
- package/dist/state/index.d.ts.map +1 -1
- package/dist/state/index.js +30 -0
- package/dist/state/index.js.map +1 -1
- package/dist/types/consensus.d.ts +3 -0
- package/dist/types/consensus.d.ts.map +1 -1
- package/dist/types/consensus.js +1 -0
- package/dist/types/consensus.js.map +1 -1
- package/dist/types/website-strategy.d.ts +263 -0
- package/dist/types/website-strategy.d.ts.map +1 -0
- package/dist/types/website-strategy.js +105 -0
- package/dist/types/website-strategy.js.map +1 -0
- package/dist/types/workflow.d.ts +15 -0
- package/dist/types/workflow.d.ts.map +1 -1
- package/dist/types/workflow.js +6 -0
- package/dist/types/workflow.js.map +1 -1
- package/dist/workflow/auto-fix.d.ts +7 -1
- package/dist/workflow/auto-fix.d.ts.map +1 -1
- package/dist/workflow/auto-fix.js +55 -3
- package/dist/workflow/auto-fix.js.map +1 -1
- package/dist/workflow/consensus.d.ts.map +1 -1
- package/dist/workflow/consensus.js +2 -0
- package/dist/workflow/consensus.js.map +1 -1
- package/dist/workflow/execution-mode.d.ts.map +1 -1
- package/dist/workflow/execution-mode.js +18 -0
- package/dist/workflow/execution-mode.js.map +1 -1
- package/dist/workflow/index.d.ts +3 -0
- package/dist/workflow/index.d.ts.map +1 -1
- package/dist/workflow/index.js +25 -0
- package/dist/workflow/index.js.map +1 -1
- package/dist/workflow/overview.d.ts +89 -0
- package/dist/workflow/overview.d.ts.map +1 -0
- package/dist/workflow/overview.js +354 -0
- package/dist/workflow/overview.js.map +1 -0
- package/dist/workflow/plan-mode.d.ts +2 -1
- package/dist/workflow/plan-mode.d.ts.map +1 -1
- package/dist/workflow/plan-mode.js +83 -5
- package/dist/workflow/plan-mode.js.map +1 -1
- package/dist/workflow/website-strategy.d.ts +70 -0
- package/dist/workflow/website-strategy.d.ts.map +1 -0
- package/dist/workflow/website-strategy.js +238 -0
- package/dist/workflow/website-strategy.js.map +1 -0
- package/dist/workflow/website-updater.d.ts +17 -0
- package/dist/workflow/website-updater.d.ts.map +1 -0
- package/dist/workflow/website-updater.js +105 -0
- package/dist/workflow/website-updater.js.map +1 -0
- package/dist/workflow/workflow-logger.d.ts +1 -1
- package/dist/workflow/workflow-logger.d.ts.map +1 -1
- package/dist/workflow/workflow-logger.js.map +1 -1
- package/package.json +1 -1
- package/src/adapters/gemini.ts +10 -4
- package/src/adapters/grok.ts +10 -4
- package/src/adapters/openai.ts +38 -6
- package/src/cli/interactive.ts +47 -0
- package/src/generators/all.ts +6 -1
- package/src/generators/doc-parser.ts +372 -0
- package/src/generators/templates/index.ts +4 -0
- package/src/generators/templates/website-components.ts +305 -0
- package/src/generators/templates/website-config.ts +291 -0
- package/src/generators/templates/website-conversion.ts +341 -0
- package/src/generators/templates/website-seo.ts +370 -0
- package/src/generators/templates/website.ts +451 -505
- package/src/generators/website-context.ts +265 -0
- package/src/generators/website.ts +109 -19
- package/src/state/index.ts +42 -0
- package/src/types/consensus.ts +3 -0
- package/src/types/website-strategy.ts +243 -0
- package/src/types/workflow.ts +15 -0
- package/src/workflow/auto-fix.ts +57 -3
- package/src/workflow/consensus.ts +2 -0
- package/src/workflow/execution-mode.ts +21 -0
- package/src/workflow/index.ts +25 -0
- package/src/workflow/overview.ts +469 -0
- package/src/workflow/plan-mode.ts +115 -4
- package/src/workflow/website-strategy.ts +305 -0
- package/src/workflow/website-updater.ts +131 -0
- package/src/workflow/workflow-logger.ts +1 -0
- package/tests/adapters/persona-switching.test.ts +63 -0
- package/tests/generators/website-components.test.ts +159 -0
- package/tests/generators/website-context.test.ts +222 -0
- package/tests/generators/website-seo-quality.test.ts +246 -0
- package/tests/workflow/auto-fix-enhanced.test.ts +61 -1
- package/tests/workflow/overview.test.ts +392 -0
- package/tests/workflow/website-strategy.test.ts +191 -0
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Website strategy type definitions
|
|
3
|
+
* Defines the strategic marketing document, site architecture,
|
|
4
|
+
* design tokens, and brand assets contract for website generation
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { z } from 'zod';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Navigation item for site header/footer
|
|
11
|
+
*/
|
|
12
|
+
export interface NavItem {
|
|
13
|
+
label: string;
|
|
14
|
+
href: string;
|
|
15
|
+
children?: NavItem[];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Footer section with links
|
|
20
|
+
*/
|
|
21
|
+
export interface FooterSection {
|
|
22
|
+
title: string;
|
|
23
|
+
links: Array<{ label: string; href: string }>;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Page definition in site architecture
|
|
28
|
+
*/
|
|
29
|
+
export interface SiteArchitecturePage {
|
|
30
|
+
path: string;
|
|
31
|
+
title: string;
|
|
32
|
+
purpose: string;
|
|
33
|
+
pageType:
|
|
34
|
+
| 'landing'
|
|
35
|
+
| 'pricing'
|
|
36
|
+
| 'solution'
|
|
37
|
+
| 'use-cases'
|
|
38
|
+
| 'about'
|
|
39
|
+
| 'contact'
|
|
40
|
+
| 'blog'
|
|
41
|
+
| 'docs'
|
|
42
|
+
| 'legal';
|
|
43
|
+
sections: string[];
|
|
44
|
+
seoKeywords: string[];
|
|
45
|
+
conversionGoal: string;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Complete website strategy document
|
|
50
|
+
* Generated by AI from product context, user docs, and market inputs
|
|
51
|
+
*/
|
|
52
|
+
export interface WebsiteStrategyDocument {
|
|
53
|
+
icp: {
|
|
54
|
+
primaryPersona: string;
|
|
55
|
+
painPoints: string[];
|
|
56
|
+
goals: string[];
|
|
57
|
+
objections: string[];
|
|
58
|
+
};
|
|
59
|
+
positioning: {
|
|
60
|
+
category: string;
|
|
61
|
+
differentiators: string[];
|
|
62
|
+
valueProposition: string;
|
|
63
|
+
proofPoints: string[];
|
|
64
|
+
};
|
|
65
|
+
messaging: {
|
|
66
|
+
headline: string;
|
|
67
|
+
subheadline: string;
|
|
68
|
+
elevatorPitch: string;
|
|
69
|
+
longDescription: string;
|
|
70
|
+
};
|
|
71
|
+
seoStrategy: {
|
|
72
|
+
primaryKeywords: string[];
|
|
73
|
+
secondaryKeywords: string[];
|
|
74
|
+
longTailKeywords: string[];
|
|
75
|
+
titleTemplates: Record<string, string>;
|
|
76
|
+
metaDescriptions: Record<string, string>;
|
|
77
|
+
};
|
|
78
|
+
siteArchitecture: {
|
|
79
|
+
pages: SiteArchitecturePage[];
|
|
80
|
+
navigation: NavItem[];
|
|
81
|
+
footerSections: FooterSection[];
|
|
82
|
+
};
|
|
83
|
+
conversionStrategy: {
|
|
84
|
+
primaryCta: { text: string; href: string };
|
|
85
|
+
secondaryCta: { text: string; href: string };
|
|
86
|
+
trustSignals: string[];
|
|
87
|
+
socialProof: string[];
|
|
88
|
+
leadCapture: 'none' | 'webhook' | 'resend' | 'postmark';
|
|
89
|
+
};
|
|
90
|
+
competitiveContext: {
|
|
91
|
+
category: string;
|
|
92
|
+
competitors: string[];
|
|
93
|
+
differentiators: string[];
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Strategy metadata for caching and staleness detection
|
|
99
|
+
*/
|
|
100
|
+
export interface StrategyMetadata {
|
|
101
|
+
/** SHA-256 of (docs + spec + tokens) for staleness detection */
|
|
102
|
+
inputHash: string;
|
|
103
|
+
/** ISO timestamp of generation */
|
|
104
|
+
generatedAt: string;
|
|
105
|
+
/** Schema version */
|
|
106
|
+
version: number;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Design tokens extracted from project config or brand docs
|
|
111
|
+
*/
|
|
112
|
+
export interface DesignTokens {
|
|
113
|
+
colors: Record<string, string>;
|
|
114
|
+
fonts: { heading: string; body: string; mono?: string };
|
|
115
|
+
borderRadius: string;
|
|
116
|
+
source: 'tailwind-config' | 'css-variables' | 'brand-docs' | 'defaults';
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Brand assets contract for deterministic logo/favicon placement
|
|
121
|
+
*/
|
|
122
|
+
export interface BrandAssetsContract {
|
|
123
|
+
/** Discovered source path for logo */
|
|
124
|
+
logoPath?: string;
|
|
125
|
+
/** Canonical output path: public/brand/logo.{ext} */
|
|
126
|
+
logoOutputPath: string;
|
|
127
|
+
/** Discovered source path for favicon */
|
|
128
|
+
faviconPath?: string;
|
|
129
|
+
/** Primary brand color */
|
|
130
|
+
primaryColor?: string;
|
|
131
|
+
/** Full color scheme */
|
|
132
|
+
colorScheme?: Record<string, string>;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// --- Zod Schemas ---
|
|
136
|
+
|
|
137
|
+
export const NavItemSchema: z.ZodType<NavItem> = z.lazy(() =>
|
|
138
|
+
z.object({
|
|
139
|
+
label: z.string().min(1),
|
|
140
|
+
href: z.string().min(1),
|
|
141
|
+
children: z.array(NavItemSchema).optional(),
|
|
142
|
+
})
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
export const FooterSectionSchema = z.object({
|
|
146
|
+
title: z.string().min(1),
|
|
147
|
+
links: z.array(
|
|
148
|
+
z.object({
|
|
149
|
+
label: z.string().min(1),
|
|
150
|
+
href: z.string().min(1),
|
|
151
|
+
})
|
|
152
|
+
),
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
export const SiteArchitecturePageSchema = z.object({
|
|
156
|
+
path: z.string().min(1),
|
|
157
|
+
title: z.string().min(1),
|
|
158
|
+
purpose: z.string(),
|
|
159
|
+
pageType: z.enum([
|
|
160
|
+
'landing',
|
|
161
|
+
'pricing',
|
|
162
|
+
'solution',
|
|
163
|
+
'use-cases',
|
|
164
|
+
'about',
|
|
165
|
+
'contact',
|
|
166
|
+
'blog',
|
|
167
|
+
'docs',
|
|
168
|
+
'legal',
|
|
169
|
+
]),
|
|
170
|
+
sections: z.array(z.string()),
|
|
171
|
+
seoKeywords: z.array(z.string()),
|
|
172
|
+
conversionGoal: z.string(),
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
export const WebsiteStrategySchema = z.object({
|
|
176
|
+
icp: z.object({
|
|
177
|
+
primaryPersona: z.string().min(1),
|
|
178
|
+
painPoints: z.array(z.string()),
|
|
179
|
+
goals: z.array(z.string()),
|
|
180
|
+
objections: z.array(z.string()),
|
|
181
|
+
}),
|
|
182
|
+
positioning: z.object({
|
|
183
|
+
category: z.string().min(1),
|
|
184
|
+
differentiators: z.array(z.string()),
|
|
185
|
+
valueProposition: z.string().min(1),
|
|
186
|
+
proofPoints: z.array(z.string()),
|
|
187
|
+
}),
|
|
188
|
+
messaging: z.object({
|
|
189
|
+
headline: z.string().min(1),
|
|
190
|
+
subheadline: z.string().min(1),
|
|
191
|
+
elevatorPitch: z.string().min(1),
|
|
192
|
+
longDescription: z.string().min(1),
|
|
193
|
+
}),
|
|
194
|
+
seoStrategy: z.object({
|
|
195
|
+
primaryKeywords: z.array(z.string()),
|
|
196
|
+
secondaryKeywords: z.array(z.string()),
|
|
197
|
+
longTailKeywords: z.array(z.string()),
|
|
198
|
+
titleTemplates: z.record(z.string(), z.string()),
|
|
199
|
+
metaDescriptions: z.record(z.string(), z.string()),
|
|
200
|
+
}),
|
|
201
|
+
siteArchitecture: z.object({
|
|
202
|
+
pages: z.array(SiteArchitecturePageSchema),
|
|
203
|
+
navigation: z.array(NavItemSchema),
|
|
204
|
+
footerSections: z.array(FooterSectionSchema),
|
|
205
|
+
}),
|
|
206
|
+
conversionStrategy: z.object({
|
|
207
|
+
primaryCta: z.object({ text: z.string().min(1), href: z.string().min(1) }),
|
|
208
|
+
secondaryCta: z.object({ text: z.string().min(1), href: z.string().min(1) }),
|
|
209
|
+
trustSignals: z.array(z.string()),
|
|
210
|
+
socialProof: z.array(z.string()),
|
|
211
|
+
leadCapture: z.enum(['none', 'webhook', 'resend', 'postmark']),
|
|
212
|
+
}),
|
|
213
|
+
competitiveContext: z.object({
|
|
214
|
+
category: z.string(),
|
|
215
|
+
competitors: z.array(z.string()),
|
|
216
|
+
differentiators: z.array(z.string()),
|
|
217
|
+
}),
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
export const StrategyMetadataSchema = z.object({
|
|
221
|
+
inputHash: z.string().min(1),
|
|
222
|
+
generatedAt: z.string().min(1),
|
|
223
|
+
version: z.number(),
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
export const DesignTokensSchema = z.object({
|
|
227
|
+
colors: z.record(z.string(), z.string()),
|
|
228
|
+
fonts: z.object({
|
|
229
|
+
heading: z.string(),
|
|
230
|
+
body: z.string(),
|
|
231
|
+
mono: z.string().optional(),
|
|
232
|
+
}),
|
|
233
|
+
borderRadius: z.string(),
|
|
234
|
+
source: z.enum(['tailwind-config', 'css-variables', 'brand-docs', 'defaults']),
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
export const BrandAssetsContractSchema = z.object({
|
|
238
|
+
logoPath: z.string().optional(),
|
|
239
|
+
logoOutputPath: z.string().min(1),
|
|
240
|
+
faviconPath: z.string().optional(),
|
|
241
|
+
primaryColor: z.string().optional(),
|
|
242
|
+
colorScheme: z.record(z.string(), z.string()).optional(),
|
|
243
|
+
});
|
package/src/types/workflow.ts
CHANGED
|
@@ -192,6 +192,15 @@ export interface ProjectState {
|
|
|
192
192
|
error?: string;
|
|
193
193
|
createdAt: string;
|
|
194
194
|
updatedAt: string;
|
|
195
|
+
/** Raw user documentation discovered from CWD */
|
|
196
|
+
userDocs?: string;
|
|
197
|
+
/** Brand context discovered from CWD */
|
|
198
|
+
brandContext?: {
|
|
199
|
+
logoPath?: string;
|
|
200
|
+
primaryColor?: string;
|
|
201
|
+
};
|
|
202
|
+
/** Path to website strategy JSON file (relative to .popeye/) */
|
|
203
|
+
websiteStrategy?: string;
|
|
195
204
|
}
|
|
196
205
|
|
|
197
206
|
/**
|
|
@@ -229,6 +238,12 @@ export const ProjectStateSchema = z.object({
|
|
|
229
238
|
error: z.string().optional(),
|
|
230
239
|
createdAt: z.string(),
|
|
231
240
|
updatedAt: z.string(),
|
|
241
|
+
userDocs: z.string().optional(),
|
|
242
|
+
brandContext: z.object({
|
|
243
|
+
logoPath: z.string().optional(),
|
|
244
|
+
primaryColor: z.string().optional(),
|
|
245
|
+
}).optional(),
|
|
246
|
+
websiteStrategy: z.string().optional(),
|
|
232
247
|
});
|
|
233
248
|
|
|
234
249
|
/**
|
package/src/workflow/auto-fix.ts
CHANGED
|
@@ -6,6 +6,59 @@
|
|
|
6
6
|
import { promises as fs } from 'node:fs';
|
|
7
7
|
import path from 'node:path';
|
|
8
8
|
import { executePrompt } from '../adapters/claude.js';
|
|
9
|
+
import { isWorkspace, type OutputLanguage } from '../types/project.js';
|
|
10
|
+
|
|
11
|
+
/** Standard workspace subdirectories to search when a file isn't at the root */
|
|
12
|
+
const WORKSPACE_SUBDIRS = ['apps/frontend', 'apps/backend', 'apps/website', 'packages/frontend', 'packages/backend'];
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Resolve a (possibly relative) error file path to an absolute path that exists on disk.
|
|
16
|
+
* For workspace projects, if the file doesn't exist at the project root, searches
|
|
17
|
+
* workspace subdirectories (apps/frontend, apps/backend, etc.).
|
|
18
|
+
*/
|
|
19
|
+
export async function resolveErrorFilePath(
|
|
20
|
+
filePath: string,
|
|
21
|
+
projectDir: string,
|
|
22
|
+
language: string,
|
|
23
|
+
): Promise<string> {
|
|
24
|
+
// If already absolute and exists, use it directly
|
|
25
|
+
if (path.isAbsolute(filePath)) {
|
|
26
|
+
try {
|
|
27
|
+
await fs.access(filePath);
|
|
28
|
+
return filePath;
|
|
29
|
+
} catch {
|
|
30
|
+
// Absolute path doesn't exist — for workspace projects, try searching subdirs
|
|
31
|
+
if (!isWorkspace(language as OutputLanguage)) return filePath;
|
|
32
|
+
const basename = path.basename(filePath);
|
|
33
|
+
for (const subdir of WORKSPACE_SUBDIRS) {
|
|
34
|
+
const candidate = path.join(projectDir, subdir, basename);
|
|
35
|
+
try {
|
|
36
|
+
await fs.access(candidate);
|
|
37
|
+
return candidate;
|
|
38
|
+
} catch { /* continue */ }
|
|
39
|
+
}
|
|
40
|
+
return filePath;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Relative path: try at project root first
|
|
45
|
+
const rootPath = path.join(projectDir, filePath);
|
|
46
|
+
try {
|
|
47
|
+
await fs.access(rootPath);
|
|
48
|
+
return rootPath;
|
|
49
|
+
} catch {
|
|
50
|
+
// Not at root — for workspace projects, search subdirs
|
|
51
|
+
if (!isWorkspace(language as OutputLanguage)) return rootPath;
|
|
52
|
+
for (const subdir of WORKSPACE_SUBDIRS) {
|
|
53
|
+
const candidate = path.join(projectDir, subdir, filePath);
|
|
54
|
+
try {
|
|
55
|
+
await fs.access(candidate);
|
|
56
|
+
return candidate;
|
|
57
|
+
} catch { /* continue */ }
|
|
58
|
+
}
|
|
59
|
+
return rootPath;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
9
62
|
|
|
10
63
|
/**
|
|
11
64
|
* Build error details
|
|
@@ -180,7 +233,8 @@ export async function autoFixTypeScriptErrors(
|
|
|
180
233
|
projectDir: string,
|
|
181
234
|
buildOutput: string,
|
|
182
235
|
maxAttempts: number = 3,
|
|
183
|
-
onProgress?: (message: string) => void
|
|
236
|
+
onProgress?: (message: string) => void,
|
|
237
|
+
language: string = 'typescript',
|
|
184
238
|
): Promise<AutoFixResult> {
|
|
185
239
|
const fixes: Array<{ file: string; description: string }> = [];
|
|
186
240
|
let attempts = 0;
|
|
@@ -237,7 +291,7 @@ export async function autoFixTypeScriptErrors(
|
|
|
237
291
|
|
|
238
292
|
// Fix each file
|
|
239
293
|
for (const [filePath, fileErrors] of errorsByFile) {
|
|
240
|
-
const absolutePath =
|
|
294
|
+
const absolutePath = await resolveErrorFilePath(filePath, projectDir, language);
|
|
241
295
|
|
|
242
296
|
try {
|
|
243
297
|
// Read current file content
|
|
@@ -401,7 +455,7 @@ export async function buildWithAutoFix(
|
|
|
401
455
|
|
|
402
456
|
// Try auto-fix for TypeScript-based projects (includes fullstack, website, all)
|
|
403
457
|
if (isTypeScriptBased) {
|
|
404
|
-
const fixResult = await autoFixTypeScriptErrors(projectDir, output, maxAttempts, onProgress);
|
|
458
|
+
const fixResult = await autoFixTypeScriptErrors(projectDir, output, maxAttempts, onProgress, language);
|
|
405
459
|
|
|
406
460
|
// Log structural issue if detected
|
|
407
461
|
if (fixResult.isStructuralIssue) {
|
|
@@ -79,6 +79,7 @@ async function requestReviewerConsensus(
|
|
|
79
79
|
model: config.geminiModel,
|
|
80
80
|
temperature: config.temperature,
|
|
81
81
|
maxTokens: config.maxTokens,
|
|
82
|
+
reviewerPersona: config.reviewerPersona,
|
|
82
83
|
});
|
|
83
84
|
}
|
|
84
85
|
if (reviewer === 'grok') {
|
|
@@ -86,6 +87,7 @@ async function requestReviewerConsensus(
|
|
|
86
87
|
model: config.grokModel,
|
|
87
88
|
temperature: config.temperature,
|
|
88
89
|
maxTokens: config.maxTokens,
|
|
90
|
+
reviewerPersona: config.reviewerPersona,
|
|
89
91
|
});
|
|
90
92
|
}
|
|
91
93
|
return requestOpenAIConsensus(plan, context, config);
|
|
@@ -782,6 +782,14 @@ function buildTaskContext(
|
|
|
782
782
|
): string {
|
|
783
783
|
const lines: string[] = [];
|
|
784
784
|
|
|
785
|
+
// No-hardcode enforcement rule
|
|
786
|
+
lines.push('## CRITICAL RULES');
|
|
787
|
+
lines.push('- NEVER use hardcoded placeholder content, mock data, or invented copy.');
|
|
788
|
+
lines.push('- ALL text, features, pricing, colors, and data MUST come from the project specification and user documentation below.');
|
|
789
|
+
lines.push('- If information is not available in the spec, leave a TODO comment rather than inventing content.');
|
|
790
|
+
lines.push('- Do NOT hallucinate product names, features, pricing tiers, testimonials, or blog content.');
|
|
791
|
+
lines.push('');
|
|
792
|
+
|
|
785
793
|
lines.push(`## Project: ${state.name}`);
|
|
786
794
|
lines.push(`Language: ${state.language}`);
|
|
787
795
|
lines.push('');
|
|
@@ -798,6 +806,19 @@ function buildTaskContext(
|
|
|
798
806
|
lines.push('');
|
|
799
807
|
}
|
|
800
808
|
|
|
809
|
+
// Include user documentation if available
|
|
810
|
+
if (state.userDocs) {
|
|
811
|
+
lines.push('## Project Documentation');
|
|
812
|
+
lines.push(state.userDocs.slice(0, 3000));
|
|
813
|
+
lines.push('');
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
// Include brand context if available
|
|
817
|
+
if (state.brandContext?.primaryColor) {
|
|
818
|
+
lines.push(`## Brand: Primary color ${state.brandContext.primaryColor}`);
|
|
819
|
+
lines.push('');
|
|
820
|
+
}
|
|
821
|
+
|
|
801
822
|
// Include UI design context if available
|
|
802
823
|
if (uiDesignContext) {
|
|
803
824
|
lines.push(uiDesignContext);
|
package/src/workflow/index.ts
CHANGED
|
@@ -50,6 +50,9 @@ export * from './task-workflow.js';
|
|
|
50
50
|
export * from './milestone-workflow.js';
|
|
51
51
|
export * from './plan-storage.js';
|
|
52
52
|
export * from './workspace-manager.js';
|
|
53
|
+
export * from './website-updater.js';
|
|
54
|
+
export * from './website-strategy.js';
|
|
55
|
+
export * from './overview.js';
|
|
53
56
|
|
|
54
57
|
/**
|
|
55
58
|
* Workflow options
|
|
@@ -116,6 +119,17 @@ export async function runWorkflow(
|
|
|
116
119
|
};
|
|
117
120
|
}
|
|
118
121
|
|
|
122
|
+
// Post-plan: Update website content with project context
|
|
123
|
+
if (spec.language === 'website' || spec.language === 'all' || spec.language === 'fullstack') {
|
|
124
|
+
try {
|
|
125
|
+
onProgress?.('website-update', 'Updating website with project context...');
|
|
126
|
+
const { updateWebsiteContent } = await import('./website-updater.js');
|
|
127
|
+
await updateWebsiteContent(projectDir, planResult.state, spec.language, (msg) => onProgress?.('website-update', msg));
|
|
128
|
+
} catch {
|
|
129
|
+
// Non-blocking: website content update failure should not stop workflow
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
119
133
|
// Phase 2: Execution Mode
|
|
120
134
|
onProgress?.('workflow', 'Starting Execution Mode...');
|
|
121
135
|
|
|
@@ -224,6 +238,17 @@ export async function resumeWorkflow(
|
|
|
224
238
|
};
|
|
225
239
|
}
|
|
226
240
|
|
|
241
|
+
// Post-plan: Update website content with project context
|
|
242
|
+
if (state.language === 'website' || state.language === 'all' || state.language === 'fullstack') {
|
|
243
|
+
try {
|
|
244
|
+
onProgress?.('website-update', 'Updating website with project context...');
|
|
245
|
+
const { updateWebsiteContent } = await import('./website-updater.js');
|
|
246
|
+
await updateWebsiteContent(projectDir, planResult.state, state.language, (msg) => onProgress?.('website-update', msg));
|
|
247
|
+
} catch {
|
|
248
|
+
// Non-blocking
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
227
252
|
// Continue to execution
|
|
228
253
|
onProgress?.('workflow', 'Starting Execution Mode...');
|
|
229
254
|
|