@compilr-dev/sdk 0.2.5 → 0.2.7
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/index.d.ts +4 -1
- package/dist/index.js +13 -1
- package/dist/platform/file-anchor-service.d.ts +62 -0
- package/dist/platform/file-anchor-service.js +241 -0
- package/dist/platform/index.d.ts +2 -0
- package/dist/platform/index.js +2 -0
- package/dist/project-generator/detection.d.ts +42 -0
- package/dist/project-generator/detection.js +401 -0
- package/dist/project-generator/generator.d.ts +14 -0
- package/dist/project-generator/generator.js +245 -0
- package/dist/project-generator/index.d.ts +11 -0
- package/dist/project-generator/index.js +13 -0
- package/dist/project-generator/templates/coding-standards.d.ts +7 -0
- package/dist/project-generator/templates/coding-standards.js +299 -0
- package/dist/project-generator/templates/compilr-md-import.d.ts +8 -0
- package/dist/project-generator/templates/compilr-md-import.js +241 -0
- package/dist/project-generator/templates/compilr-md.d.ts +7 -0
- package/dist/project-generator/templates/compilr-md.js +141 -0
- package/dist/project-generator/templates/config-json.d.ts +13 -0
- package/dist/project-generator/templates/config-json.js +39 -0
- package/dist/project-generator/templates/gitignore.d.ts +7 -0
- package/dist/project-generator/templates/gitignore.js +85 -0
- package/dist/project-generator/templates/index.d.ts +11 -0
- package/dist/project-generator/templates/index.js +11 -0
- package/dist/project-generator/templates/package-json.d.ts +7 -0
- package/dist/project-generator/templates/package-json.js +111 -0
- package/dist/project-generator/templates/readme-md.d.ts +7 -0
- package/dist/project-generator/templates/readme-md.js +165 -0
- package/dist/project-generator/templates/tsconfig.d.ts +7 -0
- package/dist/project-generator/templates/tsconfig.js +61 -0
- package/dist/project-generator/types.d.ts +95 -0
- package/dist/project-generator/types.js +24 -0
- package/package.json +1 -1
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project Detection Utilities
|
|
3
|
+
*
|
|
4
|
+
* Utilities for detecting project information from an existing directory.
|
|
5
|
+
* Used by the import project feature.
|
|
6
|
+
*/
|
|
7
|
+
import * as fs from 'fs';
|
|
8
|
+
import * as path from 'path';
|
|
9
|
+
import { execSync } from 'child_process';
|
|
10
|
+
const LANGUAGE_MARKERS = [
|
|
11
|
+
// Node.js / JavaScript / TypeScript
|
|
12
|
+
{
|
|
13
|
+
file: 'package.json',
|
|
14
|
+
language: 'node',
|
|
15
|
+
packageManager: 'npm',
|
|
16
|
+
frameworkDetector: (content) => {
|
|
17
|
+
try {
|
|
18
|
+
const pkg = JSON.parse(content);
|
|
19
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
20
|
+
if (deps['next'])
|
|
21
|
+
return 'next';
|
|
22
|
+
if (deps['nuxt'])
|
|
23
|
+
return 'nuxt';
|
|
24
|
+
if (deps['react'])
|
|
25
|
+
return 'react';
|
|
26
|
+
if (deps['vue'])
|
|
27
|
+
return 'vue';
|
|
28
|
+
if (deps['svelte'])
|
|
29
|
+
return 'svelte';
|
|
30
|
+
if (deps['@angular/core'])
|
|
31
|
+
return 'angular';
|
|
32
|
+
if (deps['express'])
|
|
33
|
+
return 'express';
|
|
34
|
+
if (deps['fastify'])
|
|
35
|
+
return 'fastify';
|
|
36
|
+
if (deps['koa'])
|
|
37
|
+
return 'koa';
|
|
38
|
+
if (deps['hono'])
|
|
39
|
+
return 'hono';
|
|
40
|
+
if (deps['electron'])
|
|
41
|
+
return 'electron';
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
nameExtractor: (content) => {
|
|
49
|
+
try {
|
|
50
|
+
const pkg = JSON.parse(content);
|
|
51
|
+
return pkg.name ?? null;
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
// Go
|
|
59
|
+
{
|
|
60
|
+
file: 'go.mod',
|
|
61
|
+
language: 'go',
|
|
62
|
+
packageManager: 'go',
|
|
63
|
+
nameExtractor: (content) => {
|
|
64
|
+
const match = content.match(/^module\s+(.+)$/m);
|
|
65
|
+
if (match) {
|
|
66
|
+
const parts = match[1].split('/');
|
|
67
|
+
return parts[parts.length - 1];
|
|
68
|
+
}
|
|
69
|
+
return null;
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
// Python
|
|
73
|
+
{
|
|
74
|
+
file: 'pyproject.toml',
|
|
75
|
+
language: 'python',
|
|
76
|
+
packageManager: 'pip',
|
|
77
|
+
frameworkDetector: (content) => {
|
|
78
|
+
if (content.includes('fastapi'))
|
|
79
|
+
return 'fastapi';
|
|
80
|
+
if (content.includes('django'))
|
|
81
|
+
return 'django';
|
|
82
|
+
if (content.includes('flask'))
|
|
83
|
+
return 'flask';
|
|
84
|
+
return null;
|
|
85
|
+
},
|
|
86
|
+
nameExtractor: (content) => {
|
|
87
|
+
const match = content.match(/^name\s*=\s*["'](.+)["']/m);
|
|
88
|
+
return match ? match[1] : null;
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
file: 'requirements.txt',
|
|
93
|
+
language: 'python',
|
|
94
|
+
packageManager: 'pip',
|
|
95
|
+
frameworkDetector: (content) => {
|
|
96
|
+
if (content.includes('fastapi'))
|
|
97
|
+
return 'fastapi';
|
|
98
|
+
if (content.includes('django'))
|
|
99
|
+
return 'django';
|
|
100
|
+
if (content.includes('flask'))
|
|
101
|
+
return 'flask';
|
|
102
|
+
return null;
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
file: 'setup.py',
|
|
107
|
+
language: 'python',
|
|
108
|
+
packageManager: 'pip',
|
|
109
|
+
},
|
|
110
|
+
// Rust
|
|
111
|
+
{
|
|
112
|
+
file: 'Cargo.toml',
|
|
113
|
+
language: 'rust',
|
|
114
|
+
packageManager: 'cargo',
|
|
115
|
+
nameExtractor: (content) => {
|
|
116
|
+
const match = content.match(/^name\s*=\s*["'](.+)["']/m);
|
|
117
|
+
return match ? match[1] : null;
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
// Java
|
|
121
|
+
{ file: 'pom.xml', language: 'java', packageManager: 'maven' },
|
|
122
|
+
{ file: 'build.gradle', language: 'java', packageManager: 'gradle' },
|
|
123
|
+
{ file: 'build.gradle.kts', language: 'kotlin', packageManager: 'gradle' },
|
|
124
|
+
// PHP
|
|
125
|
+
{
|
|
126
|
+
file: 'composer.json',
|
|
127
|
+
language: 'php',
|
|
128
|
+
packageManager: 'composer',
|
|
129
|
+
frameworkDetector: (content) => {
|
|
130
|
+
try {
|
|
131
|
+
const pkg = JSON.parse(content);
|
|
132
|
+
const deps = pkg.require ?? {};
|
|
133
|
+
if (deps['laravel/framework'])
|
|
134
|
+
return 'laravel';
|
|
135
|
+
if (deps['symfony/framework-bundle'])
|
|
136
|
+
return 'symfony';
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
},
|
|
143
|
+
nameExtractor: (content) => {
|
|
144
|
+
try {
|
|
145
|
+
const pkg = JSON.parse(content);
|
|
146
|
+
if (pkg.name) {
|
|
147
|
+
const parts = pkg.name.split('/');
|
|
148
|
+
return parts[parts.length - 1];
|
|
149
|
+
}
|
|
150
|
+
return null;
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
},
|
|
157
|
+
// Ruby
|
|
158
|
+
{
|
|
159
|
+
file: 'Gemfile',
|
|
160
|
+
language: 'ruby',
|
|
161
|
+
packageManager: 'bundler',
|
|
162
|
+
frameworkDetector: (content) => {
|
|
163
|
+
if (content.includes("'rails'") || content.includes('"rails"'))
|
|
164
|
+
return 'rails';
|
|
165
|
+
if (content.includes("'sinatra'") || content.includes('"sinatra"'))
|
|
166
|
+
return 'sinatra';
|
|
167
|
+
return null;
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
// .NET
|
|
171
|
+
{ file: '*.csproj', language: 'dotnet', packageManager: 'nuget' },
|
|
172
|
+
{ file: '*.fsproj', language: 'dotnet', packageManager: 'nuget' },
|
|
173
|
+
];
|
|
174
|
+
// =============================================================================
|
|
175
|
+
// Main Detection Functions
|
|
176
|
+
// =============================================================================
|
|
177
|
+
/**
|
|
178
|
+
* Detect project information from a directory path
|
|
179
|
+
*/
|
|
180
|
+
export function detectProjectInfo(projectPath) {
|
|
181
|
+
const folderName = path.basename(projectPath);
|
|
182
|
+
const result = {
|
|
183
|
+
name: folderName,
|
|
184
|
+
displayName: prettifyName(folderName),
|
|
185
|
+
nameSource: 'folder',
|
|
186
|
+
language: null,
|
|
187
|
+
framework: null,
|
|
188
|
+
packageManager: null,
|
|
189
|
+
hasGit: false,
|
|
190
|
+
gitRemote: null,
|
|
191
|
+
gitBranch: null,
|
|
192
|
+
hasCompilrMd: false,
|
|
193
|
+
hasClaudeMd: false,
|
|
194
|
+
};
|
|
195
|
+
// Check for COMPILR.md and CLAUDE.md
|
|
196
|
+
result.hasCompilrMd = fs.existsSync(path.join(projectPath, 'COMPILR.md'));
|
|
197
|
+
result.hasClaudeMd = fs.existsSync(path.join(projectPath, 'CLAUDE.md'));
|
|
198
|
+
// Detect git info
|
|
199
|
+
const gitInfo = detectGitInfo(projectPath);
|
|
200
|
+
result.hasGit = gitInfo.hasGit;
|
|
201
|
+
result.gitRemote = gitInfo.remote;
|
|
202
|
+
result.gitBranch = gitInfo.branch;
|
|
203
|
+
// Detect language and framework from markers
|
|
204
|
+
for (const marker of LANGUAGE_MARKERS) {
|
|
205
|
+
let filePath = null;
|
|
206
|
+
if (marker.file.includes('*')) {
|
|
207
|
+
const pattern = marker.file.replace('*', '');
|
|
208
|
+
try {
|
|
209
|
+
const files = fs.readdirSync(projectPath);
|
|
210
|
+
const match = files.find((f) => f.endsWith(pattern));
|
|
211
|
+
if (match) {
|
|
212
|
+
filePath = path.join(projectPath, match);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
catch {
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
filePath = path.join(projectPath, marker.file);
|
|
221
|
+
}
|
|
222
|
+
if (filePath && fs.existsSync(filePath)) {
|
|
223
|
+
if (!result.language) {
|
|
224
|
+
result.language = marker.language;
|
|
225
|
+
}
|
|
226
|
+
try {
|
|
227
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
228
|
+
if (marker.nameExtractor && result.nameSource === 'folder') {
|
|
229
|
+
const extractedName = marker.nameExtractor(content);
|
|
230
|
+
if (extractedName) {
|
|
231
|
+
result.name = extractedName;
|
|
232
|
+
result.displayName = prettifyName(extractedName);
|
|
233
|
+
result.nameSource = marker.file;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
if (!result.framework && marker.frameworkDetector) {
|
|
237
|
+
result.framework = marker.frameworkDetector(content);
|
|
238
|
+
}
|
|
239
|
+
if (!result.packageManager && marker.packageManager) {
|
|
240
|
+
result.packageManager = marker.packageManager;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
catch {
|
|
244
|
+
// File read failed, continue
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
// Detect package manager overrides for Node.js
|
|
249
|
+
if (result.language === 'node') {
|
|
250
|
+
if (fs.existsSync(path.join(projectPath, 'pnpm-lock.yaml'))) {
|
|
251
|
+
result.packageManager = 'pnpm';
|
|
252
|
+
}
|
|
253
|
+
else if (fs.existsSync(path.join(projectPath, 'yarn.lock'))) {
|
|
254
|
+
result.packageManager = 'yarn';
|
|
255
|
+
}
|
|
256
|
+
else if (fs.existsSync(path.join(projectPath, 'bun.lockb'))) {
|
|
257
|
+
result.packageManager = 'bun';
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
// Detect package manager overrides for Python
|
|
261
|
+
if (result.language === 'python') {
|
|
262
|
+
if (fs.existsSync(path.join(projectPath, 'poetry.lock'))) {
|
|
263
|
+
result.packageManager = 'poetry';
|
|
264
|
+
}
|
|
265
|
+
else if (fs.existsSync(path.join(projectPath, 'pdm.lock'))) {
|
|
266
|
+
result.packageManager = 'pdm';
|
|
267
|
+
}
|
|
268
|
+
else if (fs.existsSync(path.join(projectPath, 'uv.lock'))) {
|
|
269
|
+
result.packageManager = 'uv';
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
return result;
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Detect git repository information
|
|
276
|
+
*/
|
|
277
|
+
export function detectGitInfo(projectPath) {
|
|
278
|
+
const result = {
|
|
279
|
+
hasGit: false,
|
|
280
|
+
remote: null,
|
|
281
|
+
branch: null,
|
|
282
|
+
};
|
|
283
|
+
const gitPath = path.join(projectPath, '.git');
|
|
284
|
+
if (!fs.existsSync(gitPath)) {
|
|
285
|
+
return result;
|
|
286
|
+
}
|
|
287
|
+
result.hasGit = true;
|
|
288
|
+
try {
|
|
289
|
+
const remote = execSync('git remote get-url origin', {
|
|
290
|
+
cwd: projectPath,
|
|
291
|
+
encoding: 'utf8',
|
|
292
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
293
|
+
}).trim();
|
|
294
|
+
if (remote) {
|
|
295
|
+
result.remote = remote;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
catch {
|
|
299
|
+
// No remote configured
|
|
300
|
+
}
|
|
301
|
+
try {
|
|
302
|
+
const branch = execSync('git branch --show-current', {
|
|
303
|
+
cwd: projectPath,
|
|
304
|
+
encoding: 'utf8',
|
|
305
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
306
|
+
}).trim();
|
|
307
|
+
if (branch) {
|
|
308
|
+
result.branch = branch;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
catch {
|
|
312
|
+
// Detached HEAD or git command failed
|
|
313
|
+
}
|
|
314
|
+
return result;
|
|
315
|
+
}
|
|
316
|
+
// =============================================================================
|
|
317
|
+
// Helper Functions
|
|
318
|
+
// =============================================================================
|
|
319
|
+
/**
|
|
320
|
+
* Convert kebab-case or snake_case to Title Case
|
|
321
|
+
*/
|
|
322
|
+
export function prettifyName(name) {
|
|
323
|
+
return name.replace(/[-_]/g, ' ').replace(/\b\w/g, (c) => c.toUpperCase());
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Get a human-readable label for detected language
|
|
327
|
+
*/
|
|
328
|
+
export function getLanguageLabel(language) {
|
|
329
|
+
if (!language)
|
|
330
|
+
return 'Unknown';
|
|
331
|
+
const labels = {
|
|
332
|
+
node: 'Node.js / TypeScript',
|
|
333
|
+
go: 'Go',
|
|
334
|
+
python: 'Python',
|
|
335
|
+
rust: 'Rust',
|
|
336
|
+
java: 'Java',
|
|
337
|
+
kotlin: 'Kotlin',
|
|
338
|
+
php: 'PHP',
|
|
339
|
+
ruby: 'Ruby',
|
|
340
|
+
dotnet: '.NET (C#/F#)',
|
|
341
|
+
};
|
|
342
|
+
return labels[language] ?? language;
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* Get a human-readable label for detected framework
|
|
346
|
+
*/
|
|
347
|
+
export function getFrameworkLabel(framework) {
|
|
348
|
+
if (!framework)
|
|
349
|
+
return 'Not detected';
|
|
350
|
+
const labels = {
|
|
351
|
+
react: 'React',
|
|
352
|
+
vue: 'Vue.js',
|
|
353
|
+
svelte: 'Svelte',
|
|
354
|
+
angular: 'Angular',
|
|
355
|
+
next: 'Next.js',
|
|
356
|
+
nuxt: 'Nuxt.js',
|
|
357
|
+
express: 'Express.js',
|
|
358
|
+
fastify: 'Fastify',
|
|
359
|
+
koa: 'Koa',
|
|
360
|
+
hono: 'Hono',
|
|
361
|
+
electron: 'Electron',
|
|
362
|
+
fastapi: 'FastAPI',
|
|
363
|
+
django: 'Django',
|
|
364
|
+
flask: 'Flask',
|
|
365
|
+
rails: 'Ruby on Rails',
|
|
366
|
+
sinatra: 'Sinatra',
|
|
367
|
+
laravel: 'Laravel',
|
|
368
|
+
symfony: 'Symfony',
|
|
369
|
+
};
|
|
370
|
+
return labels[framework] ?? framework;
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* Check if a path is a valid directory that can be imported
|
|
374
|
+
*/
|
|
375
|
+
export function validateImportPath(importPath) {
|
|
376
|
+
if (!fs.existsSync(importPath)) {
|
|
377
|
+
return { valid: false, error: 'Path does not exist' };
|
|
378
|
+
}
|
|
379
|
+
try {
|
|
380
|
+
const stats = fs.statSync(importPath);
|
|
381
|
+
if (!stats.isDirectory()) {
|
|
382
|
+
return { valid: false, error: 'Path is not a directory' };
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
catch {
|
|
386
|
+
return { valid: false, error: 'Cannot access path' };
|
|
387
|
+
}
|
|
388
|
+
return { valid: true };
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* Validate project name
|
|
392
|
+
*/
|
|
393
|
+
export function isValidProjectName(name) {
|
|
394
|
+
return /^[a-z][a-z0-9-]{1,49}$/.test(name);
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* Check if project directory already exists
|
|
398
|
+
*/
|
|
399
|
+
export function projectExists(name, basePath) {
|
|
400
|
+
return fs.existsSync(path.join(basePath, name));
|
|
401
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project Generator
|
|
3
|
+
*
|
|
4
|
+
* Main module for generating project scaffolding.
|
|
5
|
+
*/
|
|
6
|
+
import type { ProjectConfig, GenerationResult } from './types.js';
|
|
7
|
+
/**
|
|
8
|
+
* Generate a new project from configuration
|
|
9
|
+
*/
|
|
10
|
+
export declare function generateProject(config: ProjectConfig, basePath: string): GenerationResult;
|
|
11
|
+
/**
|
|
12
|
+
* Check if git user.name and user.email are configured
|
|
13
|
+
*/
|
|
14
|
+
export declare function isGitConfigured(): boolean;
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project Generator
|
|
3
|
+
*
|
|
4
|
+
* Main module for generating project scaffolding.
|
|
5
|
+
*/
|
|
6
|
+
import * as fs from 'fs';
|
|
7
|
+
import * as path from 'path';
|
|
8
|
+
import { execSync } from 'child_process';
|
|
9
|
+
import { generateCompilrMd } from './templates/compilr-md.js';
|
|
10
|
+
import { generateCodingStandardsMd } from './templates/coding-standards.js';
|
|
11
|
+
import { generateConfigJson } from './templates/config-json.js';
|
|
12
|
+
import { generateReadmeMd } from './templates/readme-md.js';
|
|
13
|
+
import { generatePackageJson } from './templates/package-json.js';
|
|
14
|
+
import { generateGitignore } from './templates/gitignore.js';
|
|
15
|
+
import { generateTsconfig } from './templates/tsconfig.js';
|
|
16
|
+
// =============================================================================
|
|
17
|
+
// Main Generator
|
|
18
|
+
// =============================================================================
|
|
19
|
+
/**
|
|
20
|
+
* Generate a new project from configuration
|
|
21
|
+
*/
|
|
22
|
+
export function generateProject(config, basePath) {
|
|
23
|
+
const filesCreated = [];
|
|
24
|
+
try {
|
|
25
|
+
if (config.repoPattern === 'single') {
|
|
26
|
+
return generateSingleRepoProject(config, basePath, filesCreated);
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
return generateTwoRepoProject(config, basePath, filesCreated);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
return {
|
|
34
|
+
success: false,
|
|
35
|
+
projectPath: path.join(basePath, config.name),
|
|
36
|
+
filesCreated,
|
|
37
|
+
error: error instanceof Error ? error.message : String(error),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
// =============================================================================
|
|
42
|
+
// Single Repo Pattern
|
|
43
|
+
// =============================================================================
|
|
44
|
+
function generateSingleRepoProject(config, basePath, filesCreated) {
|
|
45
|
+
const projectPath = path.join(basePath, config.name);
|
|
46
|
+
// Create directory structure
|
|
47
|
+
const dirs = [
|
|
48
|
+
projectPath,
|
|
49
|
+
path.join(projectPath, 'src'),
|
|
50
|
+
path.join(projectPath, '.compilr'),
|
|
51
|
+
path.join(projectPath, '.compilr', 'architecture'),
|
|
52
|
+
path.join(projectPath, '.compilr', 'architecture', 'decisions'),
|
|
53
|
+
path.join(projectPath, '.compilr', 'docs'),
|
|
54
|
+
path.join(projectPath, '.compilr', 'sessions'),
|
|
55
|
+
];
|
|
56
|
+
for (const dir of dirs) {
|
|
57
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
58
|
+
}
|
|
59
|
+
// Generate and write files
|
|
60
|
+
const files = [
|
|
61
|
+
{ path: path.join(projectPath, 'COMPILR.md'), content: generateCompilrMd(config) },
|
|
62
|
+
{ path: path.join(projectPath, 'README.md'), content: generateReadmeMd(config) },
|
|
63
|
+
{ path: path.join(projectPath, 'package.json'), content: generatePackageJson(config) },
|
|
64
|
+
{ path: path.join(projectPath, '.gitignore'), content: generateGitignore(config) },
|
|
65
|
+
{ path: path.join(projectPath, 'tsconfig.json'), content: generateTsconfig(config) },
|
|
66
|
+
{
|
|
67
|
+
path: path.join(projectPath, '.compilr', 'config.json'),
|
|
68
|
+
content: generateConfigJson(config, projectPath),
|
|
69
|
+
},
|
|
70
|
+
{ path: path.join(projectPath, '.compilr', 'roadmap.md'), content: generateRoadmapMd(config) },
|
|
71
|
+
{
|
|
72
|
+
path: path.join(projectPath, '.compilr', 'architecture', 'coding-standards.md'),
|
|
73
|
+
content: generateCodingStandardsMd(config),
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
path: path.join(projectPath, '.compilr', 'docs', 'README.md'),
|
|
77
|
+
content: '# Documentation\n\n*Add your documentation here*\n',
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
path: path.join(projectPath, '.compilr', 'sessions', 'README.md'),
|
|
81
|
+
content: '# Session Notes\n\n*Session notes will be auto-generated here*\n',
|
|
82
|
+
},
|
|
83
|
+
];
|
|
84
|
+
for (const file of files) {
|
|
85
|
+
fs.writeFileSync(file.path, file.content, 'utf-8');
|
|
86
|
+
filesCreated.push(file.path);
|
|
87
|
+
}
|
|
88
|
+
// Initialize git if requested
|
|
89
|
+
if (config.initGit) {
|
|
90
|
+
initGit(projectPath);
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
success: true,
|
|
94
|
+
projectPath,
|
|
95
|
+
filesCreated,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
// =============================================================================
|
|
99
|
+
// Two Repo Pattern
|
|
100
|
+
// =============================================================================
|
|
101
|
+
function generateTwoRepoProject(config, basePath, filesCreated) {
|
|
102
|
+
const projectPath = path.join(basePath, config.name);
|
|
103
|
+
const docsPath = path.join(basePath, `${config.name}-docs`);
|
|
104
|
+
// Create code repo structure
|
|
105
|
+
const codeDirs = [projectPath, path.join(projectPath, 'src')];
|
|
106
|
+
for (const dir of codeDirs) {
|
|
107
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
108
|
+
}
|
|
109
|
+
// Create docs repo structure
|
|
110
|
+
const docsDirs = [
|
|
111
|
+
docsPath,
|
|
112
|
+
path.join(docsPath, '.compilr'),
|
|
113
|
+
path.join(docsPath, '01-planning'),
|
|
114
|
+
path.join(docsPath, '02-architecture'),
|
|
115
|
+
path.join(docsPath, '02-architecture', 'decisions'),
|
|
116
|
+
path.join(docsPath, '03-documentation'),
|
|
117
|
+
path.join(docsPath, '04-session-notes'),
|
|
118
|
+
];
|
|
119
|
+
for (const dir of docsDirs) {
|
|
120
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
121
|
+
}
|
|
122
|
+
// Generate code repo files
|
|
123
|
+
const codeFiles = [
|
|
124
|
+
{ path: path.join(projectPath, 'README.md'), content: generateReadmeMd(config) },
|
|
125
|
+
{ path: path.join(projectPath, 'package.json'), content: generatePackageJson(config) },
|
|
126
|
+
{ path: path.join(projectPath, '.gitignore'), content: generateGitignore(config) },
|
|
127
|
+
{ path: path.join(projectPath, 'tsconfig.json'), content: generateTsconfig(config) },
|
|
128
|
+
];
|
|
129
|
+
for (const file of codeFiles) {
|
|
130
|
+
fs.writeFileSync(file.path, file.content, 'utf-8');
|
|
131
|
+
filesCreated.push(file.path);
|
|
132
|
+
}
|
|
133
|
+
// Generate docs repo files
|
|
134
|
+
const docsFiles = [
|
|
135
|
+
{ path: path.join(docsPath, 'COMPILR.md'), content: generateCompilrMd(config) },
|
|
136
|
+
{
|
|
137
|
+
path: path.join(docsPath, '.compilr', 'config.json'),
|
|
138
|
+
content: generateConfigJson(config, projectPath, docsPath),
|
|
139
|
+
},
|
|
140
|
+
{ path: path.join(docsPath, '01-planning', 'roadmap.md'), content: generateRoadmapMd(config) },
|
|
141
|
+
{
|
|
142
|
+
path: path.join(docsPath, '02-architecture', 'coding-standards.md'),
|
|
143
|
+
content: generateCodingStandardsMd(config),
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
path: path.join(docsPath, '03-documentation', 'README.md'),
|
|
147
|
+
content: '# Documentation\n\n*Add your documentation here*\n',
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
path: path.join(docsPath, '04-session-notes', 'README.md'),
|
|
151
|
+
content: '# Session Notes\n\n*Session notes will be auto-generated here*\n',
|
|
152
|
+
},
|
|
153
|
+
];
|
|
154
|
+
for (const file of docsFiles) {
|
|
155
|
+
fs.writeFileSync(file.path, file.content, 'utf-8');
|
|
156
|
+
filesCreated.push(file.path);
|
|
157
|
+
}
|
|
158
|
+
// Initialize git if requested
|
|
159
|
+
if (config.initGit) {
|
|
160
|
+
initGit(projectPath);
|
|
161
|
+
initGit(docsPath);
|
|
162
|
+
}
|
|
163
|
+
return {
|
|
164
|
+
success: true,
|
|
165
|
+
projectPath,
|
|
166
|
+
docsPath,
|
|
167
|
+
filesCreated,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
// =============================================================================
|
|
171
|
+
// Helper Functions
|
|
172
|
+
// =============================================================================
|
|
173
|
+
/**
|
|
174
|
+
* Check if git user.name and user.email are configured
|
|
175
|
+
*/
|
|
176
|
+
export function isGitConfigured() {
|
|
177
|
+
try {
|
|
178
|
+
const name = execSync('git config --global user.name', {
|
|
179
|
+
encoding: 'utf8',
|
|
180
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
181
|
+
}).trim();
|
|
182
|
+
const email = execSync('git config --global user.email', {
|
|
183
|
+
encoding: 'utf8',
|
|
184
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
185
|
+
}).trim();
|
|
186
|
+
return Boolean(name && email);
|
|
187
|
+
}
|
|
188
|
+
catch {
|
|
189
|
+
return false;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Initialize git repository
|
|
194
|
+
* If git config is not set, only runs git init (skips commit)
|
|
195
|
+
*/
|
|
196
|
+
function initGit(projectPath) {
|
|
197
|
+
try {
|
|
198
|
+
execSync('git init', { cwd: projectPath, stdio: 'ignore' });
|
|
199
|
+
execSync('git add .', { cwd: projectPath, stdio: 'ignore' });
|
|
200
|
+
if (isGitConfigured()) {
|
|
201
|
+
execSync('git commit -m "Initial commit from compilr init"', {
|
|
202
|
+
cwd: projectPath,
|
|
203
|
+
stdio: 'ignore',
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
catch {
|
|
208
|
+
// Git init failed - not critical
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
function generateRoadmapMd(config) {
|
|
212
|
+
return `# Roadmap - ${config.name}
|
|
213
|
+
|
|
214
|
+
## Vision
|
|
215
|
+
|
|
216
|
+
${config.description}
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## Milestones
|
|
221
|
+
|
|
222
|
+
### Milestone 1: Foundation
|
|
223
|
+
- [ ] Project setup
|
|
224
|
+
- [ ] Development environment
|
|
225
|
+
- [ ] CI/CD pipeline
|
|
226
|
+
|
|
227
|
+
### Milestone 2: Core Features
|
|
228
|
+
- [ ] *Define your core features*
|
|
229
|
+
|
|
230
|
+
### Milestone 3: Launch
|
|
231
|
+
- [ ] Testing
|
|
232
|
+
- [ ] Documentation
|
|
233
|
+
- [ ] Deploy to production
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
## Timeline
|
|
238
|
+
|
|
239
|
+
*Add your timeline here*
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
*Last Updated: ${new Date().toISOString().split('T')[0]}*
|
|
244
|
+
`;
|
|
245
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project Generator — SDK module for creating and importing projects.
|
|
3
|
+
*
|
|
4
|
+
* Provides template generation, project scaffolding, and project detection
|
|
5
|
+
* shared by CLI and Desktop apps.
|
|
6
|
+
*/
|
|
7
|
+
export type { TechStack, CodingStandards, GeneratorRepoPattern, ProjectConfig, GenerationResult, CompilrConfig, DetectedProject, GitInfo, ImportProjectConfig, } from './types.js';
|
|
8
|
+
export { TECH_STACK_LABELS, CODING_STANDARDS_LABELS, REPO_PATTERN_LABELS, WORKFLOW_VERSION, } from './types.js';
|
|
9
|
+
export { generateProject, isGitConfigured } from './generator.js';
|
|
10
|
+
export { generateCompilrMd, generateConfigJson, generateReadmeMd, generateCodingStandardsMd, generatePackageJson, generateTsconfig, generateGitignore, generateCompilrMdForImport, } from './templates/index.js';
|
|
11
|
+
export { detectProjectInfo, detectGitInfo, prettifyName, getLanguageLabel, getFrameworkLabel, validateImportPath, isValidProjectName, projectExists, } from './detection.js';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project Generator — SDK module for creating and importing projects.
|
|
3
|
+
*
|
|
4
|
+
* Provides template generation, project scaffolding, and project detection
|
|
5
|
+
* shared by CLI and Desktop apps.
|
|
6
|
+
*/
|
|
7
|
+
export { TECH_STACK_LABELS, CODING_STANDARDS_LABELS, REPO_PATTERN_LABELS, WORKFLOW_VERSION, } from './types.js';
|
|
8
|
+
// Generator
|
|
9
|
+
export { generateProject, isGitConfigured } from './generator.js';
|
|
10
|
+
// Templates (individual generators for preview/customization)
|
|
11
|
+
export { generateCompilrMd, generateConfigJson, generateReadmeMd, generateCodingStandardsMd, generatePackageJson, generateTsconfig, generateGitignore, generateCompilrMdForImport, } from './templates/index.js';
|
|
12
|
+
// Detection
|
|
13
|
+
export { detectProjectInfo, detectGitInfo, prettifyName, getLanguageLabel, getFrameworkLabel, validateImportPath, isValidProjectName, projectExists, } from './detection.js';
|