projex-cli 0.2.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.
Files changed (85) hide show
  1. package/dist/cli.d.ts +6 -0
  2. package/dist/cli.d.ts.map +1 -0
  3. package/dist/cli.js +321 -0
  4. package/dist/cli.js.map +1 -0
  5. package/dist/event-bus.d.ts +35 -0
  6. package/dist/event-bus.d.ts.map +1 -0
  7. package/dist/event-bus.js +71 -0
  8. package/dist/event-bus.js.map +1 -0
  9. package/dist/events/event-bus.d.ts +35 -0
  10. package/dist/events/event-bus.d.ts.map +1 -0
  11. package/dist/events/event-bus.js +71 -0
  12. package/dist/events/event-bus.js.map +1 -0
  13. package/dist/events/index.d.ts +3 -0
  14. package/dist/events/index.d.ts.map +1 -0
  15. package/dist/events/index.js +3 -0
  16. package/dist/events/index.js.map +1 -0
  17. package/dist/events/types.d.ts +143 -0
  18. package/dist/events/types.d.ts.map +1 -0
  19. package/dist/events/types.js +6 -0
  20. package/dist/events/types.js.map +1 -0
  21. package/dist/index.d.ts +11 -0
  22. package/dist/index.d.ts.map +1 -0
  23. package/dist/index.js +12 -0
  24. package/dist/index.js.map +1 -0
  25. package/dist/inference/enricher.d.ts +18 -0
  26. package/dist/inference/enricher.d.ts.map +1 -0
  27. package/dist/inference/enricher.js +290 -0
  28. package/dist/inference/enricher.js.map +1 -0
  29. package/dist/inference/index.d.ts +5 -0
  30. package/dist/inference/index.d.ts.map +1 -0
  31. package/dist/inference/index.js +5 -0
  32. package/dist/inference/index.js.map +1 -0
  33. package/dist/inference/lifecycle-tracker.d.ts +40 -0
  34. package/dist/inference/lifecycle-tracker.d.ts.map +1 -0
  35. package/dist/inference/lifecycle-tracker.js +132 -0
  36. package/dist/inference/lifecycle-tracker.js.map +1 -0
  37. package/dist/inference/portfolio-generator.d.ts +44 -0
  38. package/dist/inference/portfolio-generator.d.ts.map +1 -0
  39. package/dist/inference/portfolio-generator.js +239 -0
  40. package/dist/inference/portfolio-generator.js.map +1 -0
  41. package/dist/inference/project-detector.d.ts +17 -0
  42. package/dist/inference/project-detector.d.ts.map +1 -0
  43. package/dist/inference/project-detector.js +127 -0
  44. package/dist/inference/project-detector.js.map +1 -0
  45. package/dist/ingestion/github-client.d.ts +56 -0
  46. package/dist/ingestion/github-client.d.ts.map +1 -0
  47. package/dist/ingestion/github-client.js +213 -0
  48. package/dist/ingestion/github-client.js.map +1 -0
  49. package/dist/ingestion/github-poller.d.ts +41 -0
  50. package/dist/ingestion/github-poller.d.ts.map +1 -0
  51. package/dist/ingestion/github-poller.js +121 -0
  52. package/dist/ingestion/github-poller.js.map +1 -0
  53. package/dist/ingestion/normalizer.d.ts +41 -0
  54. package/dist/ingestion/normalizer.d.ts.map +1 -0
  55. package/dist/ingestion/normalizer.js +173 -0
  56. package/dist/ingestion/normalizer.js.map +1 -0
  57. package/dist/integrations/analyzer.d.ts +74 -0
  58. package/dist/integrations/analyzer.d.ts.map +1 -0
  59. package/dist/integrations/analyzer.js +287 -0
  60. package/dist/integrations/analyzer.js.map +1 -0
  61. package/dist/integrations/index.d.ts +4 -0
  62. package/dist/integrations/index.d.ts.map +1 -0
  63. package/dist/integrations/index.js +5 -0
  64. package/dist/integrations/index.js.map +1 -0
  65. package/dist/integrations/injectors.d.ts +60 -0
  66. package/dist/integrations/injectors.d.ts.map +1 -0
  67. package/dist/integrations/injectors.js +361 -0
  68. package/dist/integrations/injectors.js.map +1 -0
  69. package/dist/integrations/template-generator.d.ts +45 -0
  70. package/dist/integrations/template-generator.d.ts.map +1 -0
  71. package/dist/integrations/template-generator.js +187 -0
  72. package/dist/integrations/template-generator.js.map +1 -0
  73. package/dist/storage/index.d.ts +2 -0
  74. package/dist/storage/index.d.ts.map +1 -0
  75. package/dist/storage/index.js +2 -0
  76. package/dist/storage/index.js.map +1 -0
  77. package/dist/storage/project-store.d.ts +23 -0
  78. package/dist/storage/project-store.d.ts.map +1 -0
  79. package/dist/storage/project-store.js +107 -0
  80. package/dist/storage/project-store.js.map +1 -0
  81. package/dist/types.d.ts +143 -0
  82. package/dist/types.d.ts.map +1 -0
  83. package/dist/types.js +6 -0
  84. package/dist/types.js.map +1 -0
  85. package/package.json +55 -0
@@ -0,0 +1,361 @@
1
+ /**
2
+ * Portfolio Injectors - Insert generated project cards into portfolio files
3
+ * Supports: HTML, Markdown, React/JSX
4
+ */
5
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
6
+ import { dirname, join } from 'path';
7
+ import { execSync } from 'child_process';
8
+ /**
9
+ * Base class for portfolio injectors
10
+ */
11
+ class BaseInjector {
12
+ portfolioPath;
13
+ analysis;
14
+ options;
15
+ constructor(portfolioPath, analysis, options) {
16
+ this.portfolioPath = portfolioPath;
17
+ this.analysis = analysis;
18
+ this.options = options;
19
+ }
20
+ backup(filePath) {
21
+ if (!this.options.createBackup)
22
+ return undefined;
23
+ const backupPath = `${filePath}.backup.${Date.now()}`;
24
+ const content = readFileSync(filePath, 'utf-8');
25
+ writeFileSync(backupPath, content);
26
+ return backupPath;
27
+ }
28
+ gitCommit(files, message) {
29
+ if (!this.options.autoCommit)
30
+ return;
31
+ try {
32
+ for (const file of files) {
33
+ execSync(`git add "${file}"`, { cwd: this.portfolioPath });
34
+ }
35
+ execSync(`git commit -m "${message}"`, { cwd: this.portfolioPath });
36
+ console.log(`[Injector] Committed: ${message}`);
37
+ }
38
+ catch (error) {
39
+ console.error('[Injector] Git commit failed:', error);
40
+ }
41
+ }
42
+ }
43
+ /**
44
+ * HTML Portfolio Injector
45
+ */
46
+ export class HTMLInjector extends BaseInjector {
47
+ async inject(card, projectId) {
48
+ const targetFile = this.findTargetFile();
49
+ if (!targetFile) {
50
+ return {
51
+ success: false,
52
+ file: '',
53
+ message: 'Could not find projects section in HTML files',
54
+ };
55
+ }
56
+ const filePath = join(this.portfolioPath, targetFile);
57
+ const backup = this.backup(filePath);
58
+ try {
59
+ let content = readFileSync(filePath, 'utf-8');
60
+ // Find the projects container
61
+ const selector = this.analysis.projectSelector || '.projects';
62
+ const containerPattern = this.findContainerPattern(content, selector);
63
+ if (!containerPattern) {
64
+ return {
65
+ success: false,
66
+ file: targetFile,
67
+ message: `Could not find container matching "${selector}"`,
68
+ };
69
+ }
70
+ // Insert the new card
71
+ content = this.insertCard(content, containerPattern, card.html, projectId);
72
+ writeFileSync(filePath, content);
73
+ const commitMsg = this.options.commitMessage || `feat: add project ${projectId}`;
74
+ this.gitCommit([filePath], commitMsg);
75
+ return {
76
+ success: true,
77
+ file: targetFile,
78
+ message: 'Project card injected successfully',
79
+ backup,
80
+ };
81
+ }
82
+ catch (error) {
83
+ return {
84
+ success: false,
85
+ file: targetFile,
86
+ message: `Injection failed: ${error}`,
87
+ backup,
88
+ };
89
+ }
90
+ }
91
+ findTargetFile() {
92
+ const candidates = ['index.html', 'projects.html', 'portfolio.html', 'work.html'];
93
+ for (const file of candidates) {
94
+ const filePath = join(this.portfolioPath, file);
95
+ if (existsSync(filePath)) {
96
+ const content = readFileSync(filePath, 'utf-8');
97
+ if (/project|portfolio|work/i.test(content)) {
98
+ return file;
99
+ }
100
+ }
101
+ }
102
+ return candidates.find(f => existsSync(join(this.portfolioPath, f))) || null;
103
+ }
104
+ findContainerPattern(content, selector) {
105
+ const className = selector.replace('.', '').replace('#', '');
106
+ // Find opening tag with the class/id
107
+ const patterns = [
108
+ new RegExp(`<(div|section|main)[^>]*(?:class|id)=["'][^"']*${className}[^"']*["'][^>]*>`, 'i'),
109
+ new RegExp(`<(div|section|main)[^>]*(?:class|id)="${className}"[^>]*>`, 'i'),
110
+ ];
111
+ for (const pattern of patterns) {
112
+ const match = content.match(pattern);
113
+ if (match && match.index !== undefined) {
114
+ const start = match.index + match[0].length;
115
+ // Find the closing tag
116
+ const tagName = match[1];
117
+ const closePattern = new RegExp(`</${tagName}>`, 'gi');
118
+ let depth = 1;
119
+ let pos = start;
120
+ while (depth > 0 && pos < content.length) {
121
+ const openMatch = content.slice(pos).match(new RegExp(`<${tagName}[^>]*>`, 'i'));
122
+ const closeMatch = content.slice(pos).match(closePattern);
123
+ if (!closeMatch)
124
+ break;
125
+ const openPos = openMatch ? openMatch.index : Infinity;
126
+ const closePos = closeMatch.index;
127
+ if (openPos < closePos) {
128
+ depth++;
129
+ pos += openPos + openMatch[0].length;
130
+ }
131
+ else {
132
+ depth--;
133
+ if (depth === 0) {
134
+ return { start, end: pos + closePos };
135
+ }
136
+ pos += closePos + closeMatch[0].length;
137
+ }
138
+ }
139
+ }
140
+ }
141
+ return null;
142
+ }
143
+ insertCard(content, container, cardHtml, projectId) {
144
+ const indent = this.detectIndent(content, container.start);
145
+ const indentedCard = cardHtml
146
+ .split('\n')
147
+ .map((line, i) => i === 0 ? line : indent + line)
148
+ .join('\n');
149
+ // Insert before the closing tag
150
+ const before = content.slice(0, container.end);
151
+ const after = content.slice(container.end);
152
+ return `${before}\n${indent}<!-- projex:${projectId} -->\n${indent}${indentedCard}\n${indent}<!-- /projex:${projectId} -->\n${after}`;
153
+ }
154
+ detectIndent(content, position) {
155
+ const lineStart = content.lastIndexOf('\n', position) + 1;
156
+ const match = content.slice(lineStart, position).match(/^(\s*)/);
157
+ return match ? match[1] + ' ' : ' ';
158
+ }
159
+ }
160
+ /**
161
+ * Markdown Portfolio Injector
162
+ */
163
+ export class MarkdownInjector extends BaseInjector {
164
+ async inject(card, projectId) {
165
+ const targetFile = this.findTargetFile();
166
+ if (!targetFile) {
167
+ return {
168
+ success: false,
169
+ file: '',
170
+ message: 'Could not find projects section in Markdown files',
171
+ };
172
+ }
173
+ const filePath = join(this.portfolioPath, targetFile);
174
+ const backup = this.backup(filePath);
175
+ try {
176
+ let content = readFileSync(filePath, 'utf-8');
177
+ // Find the projects section (## Projects, ## Work, etc.)
178
+ const sectionMatch = content.match(/^(##?\s*(?:Projects|Portfolio|Work|My Work)[^\n]*)/mi);
179
+ if (sectionMatch && sectionMatch.index !== undefined) {
180
+ // Find the next section or end of file
181
+ const sectionStart = sectionMatch.index + sectionMatch[0].length;
182
+ const nextSection = content.slice(sectionStart).search(/\n##?\s+[A-Z]/);
183
+ const insertPos = nextSection === -1
184
+ ? content.length
185
+ : sectionStart + nextSection;
186
+ // Insert the card
187
+ const markedCard = `\n<!-- projex:${projectId} -->\n${card.markdown}\n<!-- /projex:${projectId} -->\n`;
188
+ content = content.slice(0, insertPos) + markedCard + content.slice(insertPos);
189
+ }
190
+ else {
191
+ // Append to end
192
+ content += `\n\n## Projects\n\n<!-- projex:${projectId} -->\n${card.markdown}\n<!-- /projex:${projectId} -->\n`;
193
+ }
194
+ writeFileSync(filePath, content);
195
+ const commitMsg = this.options.commitMessage || `feat: add project ${projectId}`;
196
+ this.gitCommit([filePath], commitMsg);
197
+ return {
198
+ success: true,
199
+ file: targetFile,
200
+ message: 'Project card injected successfully',
201
+ backup,
202
+ };
203
+ }
204
+ catch (error) {
205
+ return {
206
+ success: false,
207
+ file: targetFile,
208
+ message: `Injection failed: ${error}`,
209
+ backup,
210
+ };
211
+ }
212
+ }
213
+ findTargetFile() {
214
+ const candidates = [
215
+ 'README.md',
216
+ 'index.md',
217
+ 'projects.md',
218
+ 'portfolio.md',
219
+ '_pages/projects.md',
220
+ 'content/projects.md',
221
+ ];
222
+ for (const file of candidates) {
223
+ const filePath = join(this.portfolioPath, file);
224
+ if (existsSync(filePath)) {
225
+ return file;
226
+ }
227
+ }
228
+ return null;
229
+ }
230
+ }
231
+ /**
232
+ * React/JSX Portfolio Injector
233
+ */
234
+ export class ReactInjector extends BaseInjector {
235
+ async inject(card, projectId) {
236
+ // For React, we update a data file rather than injecting JSX directly
237
+ const dataFile = this.findOrCreateDataFile();
238
+ const filePath = join(this.portfolioPath, dataFile);
239
+ const backup = existsSync(filePath) ? this.backup(filePath) : undefined;
240
+ try {
241
+ let projects = [];
242
+ if (existsSync(filePath)) {
243
+ const content = readFileSync(filePath, 'utf-8');
244
+ // Parse existing projects
245
+ const match = content.match(/export\s+(?:const|let)\s+projects\s*=\s*(\[[\s\S]*?\]);/);
246
+ if (match) {
247
+ try {
248
+ // Simple JSON-like parsing (won't work for complex expressions)
249
+ projects = JSON.parse(match[1].replace(/'/g, '"'));
250
+ }
251
+ catch {
252
+ projects = [];
253
+ }
254
+ }
255
+ }
256
+ // Add new project
257
+ const newProject = {
258
+ id: projectId,
259
+ ...this.parseCardToObject(card),
260
+ };
261
+ // Check if already exists
262
+ const existingIndex = projects.findIndex((p) => p.id === projectId);
263
+ if (existingIndex >= 0) {
264
+ projects[existingIndex] = newProject;
265
+ }
266
+ else {
267
+ projects.push(newProject);
268
+ }
269
+ // Write data file
270
+ const content = `// Auto-generated by Projex
271
+ export const projects = ${JSON.stringify(projects, null, 2)};
272
+ `;
273
+ writeFileSync(filePath, content);
274
+ const commitMsg = this.options.commitMessage || `feat: add project ${projectId}`;
275
+ this.gitCommit([filePath], commitMsg);
276
+ return {
277
+ success: true,
278
+ file: dataFile,
279
+ message: 'Project data updated successfully',
280
+ backup,
281
+ };
282
+ }
283
+ catch (error) {
284
+ return {
285
+ success: false,
286
+ file: dataFile,
287
+ message: `Injection failed: ${error}`,
288
+ backup,
289
+ };
290
+ }
291
+ }
292
+ findOrCreateDataFile() {
293
+ const candidates = [
294
+ 'src/data/projects.ts',
295
+ 'src/data/projects.js',
296
+ 'data/projects.ts',
297
+ 'data/projects.js',
298
+ 'src/lib/projects.ts',
299
+ 'lib/projects.ts',
300
+ ];
301
+ for (const file of candidates) {
302
+ if (existsSync(join(this.portfolioPath, file))) {
303
+ return file;
304
+ }
305
+ }
306
+ // Create new data file
307
+ const newFile = 'src/data/projects.ts';
308
+ const dir = dirname(join(this.portfolioPath, newFile));
309
+ if (!existsSync(dir)) {
310
+ mkdirSync(dir, { recursive: true });
311
+ }
312
+ return newFile;
313
+ }
314
+ parseCardToObject(card) {
315
+ // Extract props from JSX string
316
+ const props = {};
317
+ const patterns = [
318
+ { key: 'title', pattern: /title="([^"]+)"/ },
319
+ { key: 'tagline', pattern: /tagline="([^"]+)"/ },
320
+ { key: 'description', pattern: /description="([^"]+)"/ },
321
+ { key: 'githubUrl', pattern: /githubUrl="([^"]+)"/ },
322
+ { key: 'liveUrl', pattern: /liveUrl="([^"]+)"/ },
323
+ ];
324
+ for (const { key, pattern } of patterns) {
325
+ const match = card.react.match(pattern);
326
+ if (match) {
327
+ props[key] = match[1];
328
+ }
329
+ }
330
+ // Extract techStack array
331
+ const techMatch = card.react.match(/techStack=\{(\[[^\]]+\])\}/);
332
+ if (techMatch) {
333
+ try {
334
+ props.techStack = JSON.parse(techMatch[1]);
335
+ }
336
+ catch {
337
+ props.techStack = [];
338
+ }
339
+ }
340
+ return props;
341
+ }
342
+ }
343
+ /**
344
+ * Factory function to create the appropriate injector
345
+ */
346
+ export function createInjector(portfolioPath, analysis, options) {
347
+ switch (analysis.type) {
348
+ case 'react':
349
+ case 'nextjs':
350
+ case 'gatsby':
351
+ return new ReactInjector(portfolioPath, analysis, options);
352
+ case 'jekyll':
353
+ case 'hugo':
354
+ case 'markdown':
355
+ return new MarkdownInjector(portfolioPath, analysis, options);
356
+ case 'html':
357
+ default:
358
+ return new HTMLInjector(portfolioPath, analysis, options);
359
+ }
360
+ }
361
+ //# sourceMappingURL=injectors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"injectors.js","sourceRoot":"","sources":["../../src/integrations/injectors.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Template Generator - Creates project cards matching the detected portfolio style
3
+ */
4
+ import type { Project } from '../events/types.js';
5
+ import type { PortfolioAnalysis } from './analyzer.js';
6
+ export interface GeneratedCard {
7
+ html: string;
8
+ markdown: string;
9
+ react: string;
10
+ }
11
+ export declare class TemplateGenerator {
12
+ private analysis;
13
+ constructor(analysis: PortfolioAnalysis);
14
+ /**
15
+ * Generate a project card in all formats
16
+ */
17
+ generate(project: Project): GeneratedCard;
18
+ /**
19
+ * Generate HTML card matching detected template
20
+ */
21
+ private generateHTML;
22
+ /**
23
+ * Fill detected template with project data
24
+ */
25
+ private fillTemplate;
26
+ /**
27
+ * Generate default HTML card with detected styles
28
+ */
29
+ private generateDefaultHTML;
30
+ /**
31
+ * Generate Markdown card
32
+ */
33
+ private generateMarkdown;
34
+ /**
35
+ * Generate React/JSX component
36
+ */
37
+ private generateReact;
38
+ /**
39
+ * Generate a generic ProjectCard component definition
40
+ */
41
+ generateProjectCardComponent(): string;
42
+ private escapeRegex;
43
+ private escapeJSX;
44
+ }
45
+ //# sourceMappingURL=template-generator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template-generator.d.ts","sourceRoot":"","sources":["../../src/integrations/template-generator.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAkB,MAAM,oBAAoB,CAAC;AAClE,OAAO,KAAK,EAAE,iBAAiB,EAAgB,MAAM,eAAe,CAAC;AAErE,MAAM,WAAW,aAAa;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,iBAAiB;IAC1B,OAAO,CAAC,QAAQ,CAAoB;gBAExB,QAAQ,EAAE,iBAAiB;IAIvC;;OAEG;IACH,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,aAAa;IAazC;;OAEG;IACH,OAAO,CAAC,YAAY;IAYpB;;OAEG;IACH,OAAO,CAAC,YAAY;IA6CpB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IA0B3B;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAoBxB;;OAEG;IACH,OAAO,CAAC,aAAa;IAarB;;OAEG;IACH,4BAA4B,IAAI,MAAM;IAyCtC,OAAO,CAAC,WAAW;IAInB,OAAO,CAAC,SAAS;CAMpB"}
@@ -0,0 +1,187 @@
1
+ /**
2
+ * Template Generator - Creates project cards matching the detected portfolio style
3
+ */
4
+ export class TemplateGenerator {
5
+ analysis;
6
+ constructor(analysis) {
7
+ this.analysis = analysis;
8
+ }
9
+ /**
10
+ * Generate a project card in all formats
11
+ */
12
+ generate(project) {
13
+ const draft = project.portfolioDraft;
14
+ if (!draft) {
15
+ throw new Error(`Project ${project.id} has no portfolio draft`);
16
+ }
17
+ return {
18
+ html: this.generateHTML(project, draft),
19
+ markdown: this.generateMarkdown(project, draft),
20
+ react: this.generateReact(project, draft),
21
+ };
22
+ }
23
+ /**
24
+ * Generate HTML card matching detected template
25
+ */
26
+ generateHTML(project, draft) {
27
+ const { cardTemplate } = this.analysis;
28
+ // If we have a detected template, clone and fill it
29
+ if (cardTemplate) {
30
+ return this.fillTemplate(cardTemplate, project, draft);
31
+ }
32
+ // Otherwise use a styled default
33
+ return this.generateDefaultHTML(project, draft);
34
+ }
35
+ /**
36
+ * Fill detected template with project data
37
+ */
38
+ fillTemplate(template, project, draft) {
39
+ let html = template.html;
40
+ // Common placeholder patterns
41
+ const replacements = {
42
+ // Title patterns
43
+ '{{title}}': draft.title,
44
+ '{{name}}': draft.title,
45
+ '{{project.title}}': draft.title,
46
+ '{{project.name}}': draft.title,
47
+ // Description patterns
48
+ '{{description}}': draft.description,
49
+ '{{summary}}': draft.tagline,
50
+ '{{project.description}}': draft.description,
51
+ // URL patterns
52
+ '{{url}}': draft.githubUrl,
53
+ '{{link}}': draft.githubUrl,
54
+ '{{github}}': draft.githubUrl,
55
+ '{{project.url}}': draft.githubUrl,
56
+ // Tech stack
57
+ '{{tech}}': draft.techStack.join(', '),
58
+ '{{technologies}}': draft.techStack.join(', '),
59
+ '{{stack}}': draft.techStack.join(', '),
60
+ };
61
+ // Apply replacements
62
+ for (const [pattern, value] of Object.entries(replacements)) {
63
+ html = html.replace(new RegExp(this.escapeRegex(pattern), 'gi'), value);
64
+ }
65
+ // Handle tech stack lists
66
+ if (html.includes('{{#each tech}}') || html.includes('{{#tech}}')) {
67
+ const techListHTML = draft.techStack
68
+ .map(tech => `<span class="tech-tag">${tech}</span>`)
69
+ .join('\n');
70
+ html = html.replace(/\{\{#each tech\}\}[\s\S]*?\{\{\/each\}\}/gi, techListHTML);
71
+ html = html.replace(/\{\{#tech\}\}[\s\S]*?\{\{\/tech\}\}/gi, techListHTML);
72
+ }
73
+ return html;
74
+ }
75
+ /**
76
+ * Generate default HTML card with detected styles
77
+ */
78
+ generateDefaultHTML(project, draft) {
79
+ const { colors, typography, cssVariables } = this.analysis;
80
+ // Build inline styles from detected palette
81
+ const primaryColor = cssVariables['--primary'] || colors.primary[0] || '#0ea5e9';
82
+ const bgColor = cssVariables['--bg-card'] || colors.background[0] || '#1e293b';
83
+ const textColor = cssVariables['--text'] || colors.text[0] || '#f8fafc';
84
+ const font = typography.bodyFont || 'system-ui, sans-serif';
85
+ const techBadges = draft.techStack
86
+ .map(tech => `<span style="display: inline-block; padding: 4px 12px; background: ${primaryColor}22; color: ${primaryColor}; border-radius: 9999px; font-size: 12px; margin: 4px;">${tech}</span>`)
87
+ .join('\n ');
88
+ return `<article class="project-card" style="background: ${bgColor}; border-radius: 12px; padding: 24px; font-family: ${font}; color: ${textColor};">
89
+ <h3 style="margin: 0 0 8px 0; font-size: 20px; font-weight: 600;">${draft.title}</h3>
90
+ <p style="margin: 0 0 16px 0; color: ${textColor}99; font-size: 14px;">${draft.tagline}</p>
91
+ <p style="margin: 0 0 16px 0; line-height: 1.6;">${draft.description}</p>
92
+ <div style="margin-bottom: 16px;">
93
+ ${techBadges}
94
+ </div>
95
+ <a href="${draft.githubUrl}" target="_blank" rel="noopener" style="display: inline-flex; align-items: center; color: ${primaryColor}; text-decoration: none; font-weight: 500;">
96
+ View on GitHub →
97
+ </a>
98
+ </article>`;
99
+ }
100
+ /**
101
+ * Generate Markdown card
102
+ */
103
+ generateMarkdown(project, draft) {
104
+ const techList = draft.techStack.map(t => `\`${t}\``).join(' · ');
105
+ const highlights = draft.highlights.length > 0
106
+ ? '\n\n**Highlights:**\n' + draft.highlights.map(h => `- ${h}`).join('\n')
107
+ : '';
108
+ return `### ${draft.title}
109
+
110
+ ${draft.tagline}
111
+
112
+ ${draft.description}
113
+
114
+ **Tech Stack:** ${techList}
115
+ ${highlights}
116
+
117
+ [View on GitHub](${draft.githubUrl})
118
+
119
+ ---`;
120
+ }
121
+ /**
122
+ * Generate React/JSX component
123
+ */
124
+ generateReact(project, draft) {
125
+ const techArray = JSON.stringify(draft.techStack);
126
+ return `<ProjectCard
127
+ title="${this.escapeJSX(draft.title)}"
128
+ tagline="${this.escapeJSX(draft.tagline)}"
129
+ description="${this.escapeJSX(draft.description)}"
130
+ techStack={${techArray}}
131
+ githubUrl="${draft.githubUrl}"
132
+ ${draft.liveUrl ? `liveUrl="${draft.liveUrl}"` : ''}
133
+ />`;
134
+ }
135
+ /**
136
+ * Generate a generic ProjectCard component definition
137
+ */
138
+ generateProjectCardComponent() {
139
+ const { colors, typography, cssVariables } = this.analysis;
140
+ const primaryColor = cssVariables['--primary'] || colors.primary[0] || '#0ea5e9';
141
+ return `interface ProjectCardProps {
142
+ title: string;
143
+ tagline: string;
144
+ description: string;
145
+ techStack: string[];
146
+ githubUrl: string;
147
+ liveUrl?: string;
148
+ }
149
+
150
+ export function ProjectCard({ title, tagline, description, techStack, githubUrl, liveUrl }: ProjectCardProps) {
151
+ return (
152
+ <article className="project-card bg-surface-800 rounded-xl p-6 hover:bg-surface-700 transition-colors">
153
+ <h3 className="text-xl font-semibold mb-2">{title}</h3>
154
+ <p className="text-surface-400 text-sm mb-4">{tagline}</p>
155
+ <p className="text-surface-200 mb-4">{description}</p>
156
+ <div className="flex flex-wrap gap-2 mb-4">
157
+ {techStack.map((tech) => (
158
+ <span key={tech} className="px-3 py-1 text-xs rounded-full bg-primary-500/20 text-primary-400">
159
+ {tech}
160
+ </span>
161
+ ))}
162
+ </div>
163
+ <div className="flex gap-4">
164
+ <a href={githubUrl} target="_blank" rel="noopener" className="text-primary-400 hover:underline">
165
+ GitHub →
166
+ </a>
167
+ {liveUrl && (
168
+ <a href={liveUrl} target="_blank" rel="noopener" className="text-primary-400 hover:underline">
169
+ Live Demo →
170
+ </a>
171
+ )}
172
+ </div>
173
+ </article>
174
+ );
175
+ }`;
176
+ }
177
+ escapeRegex(str) {
178
+ return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
179
+ }
180
+ escapeJSX(str) {
181
+ return str
182
+ .replace(/\\/g, '\\\\')
183
+ .replace(/"/g, '\\"')
184
+ .replace(/\n/g, '\\n');
185
+ }
186
+ }
187
+ //# sourceMappingURL=template-generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template-generator.js","sourceRoot":"","sources":["../../src/integrations/template-generator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export * from './project-store.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/storage/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export * from './project-store.js';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/storage/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Project Store - JSON file-based storage for projects
3
+ * Simple MVP storage that can be swapped for a database later.
4
+ */
5
+ import type { Project, Config } from '../events/types.js';
6
+ export declare class ProjectStore {
7
+ private projects;
8
+ private filePath;
9
+ constructor(config: Config);
10
+ private ensureDataDir;
11
+ private load;
12
+ save(): void;
13
+ getProject(id: string): Project | undefined;
14
+ saveProject(project: Project): void;
15
+ deleteProject(id: string): boolean;
16
+ getAllProjects(): Project[];
17
+ getProjectsByStatus(status: Project['status']): Project[];
18
+ getProjectsNeedingReview(): Project[];
19
+ getApprovedPortfolios(): Project[];
20
+ private serialize;
21
+ private deserialize;
22
+ }
23
+ //# sourceMappingURL=project-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-store.d.ts","sourceRoot":"","sources":["../../src/storage/project-store.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE1D,qBAAa,YAAY;IACrB,OAAO,CAAC,QAAQ,CAAmC;IACnD,OAAO,CAAC,QAAQ,CAAS;gBAEb,MAAM,EAAE,MAAM;IAM1B,OAAO,CAAC,aAAa;IAOrB,OAAO,CAAC,IAAI;IAqBZ,IAAI,IAAI,IAAI;IASZ,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS;IAI3C,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAKnC,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAMlC,cAAc,IAAI,OAAO,EAAE;IAI3B,mBAAmB,CAAC,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAC,GAAG,OAAO,EAAE;IAIzD,wBAAwB,IAAI,OAAO,EAAE;IAIrC,qBAAqB,IAAI,OAAO,EAAE;IAKlC,OAAO,CAAC,SAAS;IAiBjB,OAAO,CAAC,WAAW;CAgBtB"}