@ruu5lp/dev-init 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/README.md +95 -0
  2. package/dist/cli/index.d.ts +3 -0
  3. package/dist/cli/index.d.ts.map +1 -0
  4. package/dist/cli/index.js +63 -0
  5. package/dist/cli/index.js.map +1 -0
  6. package/dist/cli/prompts.d.ts +3 -0
  7. package/dist/cli/prompts.d.ts.map +1 -0
  8. package/dist/cli/prompts.js +65 -0
  9. package/dist/cli/prompts.js.map +1 -0
  10. package/dist/core/fetcher.d.ts +7 -0
  11. package/dist/core/fetcher.d.ts.map +1 -0
  12. package/dist/core/fetcher.js +33 -0
  13. package/dist/core/fetcher.js.map +1 -0
  14. package/dist/core/generator.d.ts +3 -0
  15. package/dist/core/generator.d.ts.map +1 -0
  16. package/dist/core/generator.js +120 -0
  17. package/dist/core/generator.js.map +1 -0
  18. package/dist/core/merger.d.ts +3 -0
  19. package/dist/core/merger.d.ts.map +1 -0
  20. package/dist/core/merger.js +18 -0
  21. package/dist/core/merger.js.map +1 -0
  22. package/dist/core/renderer.d.ts +14 -0
  23. package/dist/core/renderer.d.ts.map +1 -0
  24. package/dist/core/renderer.js +23 -0
  25. package/dist/core/renderer.js.map +1 -0
  26. package/dist/core/resolver.d.ts +8 -0
  27. package/dist/core/resolver.d.ts.map +1 -0
  28. package/dist/core/resolver.js +41 -0
  29. package/dist/core/resolver.js.map +1 -0
  30. package/dist/registry/ai-providers.d.ts +5 -0
  31. package/dist/registry/ai-providers.d.ts.map +1 -0
  32. package/dist/registry/ai-providers.js +37 -0
  33. package/dist/registry/ai-providers.js.map +1 -0
  34. package/dist/registry/features.d.ts +5 -0
  35. package/dist/registry/features.d.ts.map +1 -0
  36. package/dist/registry/features.js +73 -0
  37. package/dist/registry/features.js.map +1 -0
  38. package/dist/registry/languages.d.ts +4 -0
  39. package/dist/registry/languages.d.ts.map +1 -0
  40. package/dist/registry/languages.js +21 -0
  41. package/dist/registry/languages.js.map +1 -0
  42. package/dist/types/index.d.ts +75 -0
  43. package/dist/types/index.d.ts.map +1 -0
  44. package/dist/types/index.js +26 -0
  45. package/dist/types/index.js.map +1 -0
  46. package/package.json +62 -0
package/README.md ADDED
@@ -0,0 +1,95 @@
1
+ # dev-init
2
+
3
+ CLI tool to scaffold new projects with language, AI, and feature composition.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install -g dev-init
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```bash
14
+ # Interactive mode (creates ./project-name/ directory)
15
+ dev-init
16
+
17
+ # Generate in current directory
18
+ dev-init --here
19
+
20
+ # Specify output directory
21
+ dev-init --output ~/projects
22
+
23
+ # Update cached templates
24
+ dev-init update-templates
25
+ ```
26
+
27
+ ## What it generates
28
+
29
+ ```
30
+ my-project/
31
+ ├── README.md
32
+ ├── .gitignore
33
+ ├── .env.example
34
+ ├── package.json # merged from language + feature patches
35
+ ├── tsconfig.json # (TypeScript only)
36
+ ├── CLAUDE.md # symlink → .ai/claude/CLAUDE.md
37
+ ├── CODEX.md # symlink → .ai/codex/CODEX.md
38
+ ├── src/
39
+ │ └── index.ts
40
+ ├── tests/ # (if Vitest selected)
41
+ ├── .github/workflows/ # (if GitHub Actions selected)
42
+ ├── docker-compose.yml # (if Docker selected)
43
+ ├── eslint.config.js # (if ESLint selected)
44
+ ├── .prettierrc # (if Prettier selected)
45
+ └── .ai/
46
+ ├── company/
47
+ │ ├── coding-standard.md
48
+ │ ├── git-workflow.md
49
+ │ ├── review-policy.md
50
+ │ └── security.md
51
+ ├── project/
52
+ │ ├── overview.md
53
+ │ ├── architecture.md
54
+ │ ├── conventions.md
55
+ │ └── testing.md
56
+ ├── claude/
57
+ │ └── CLAUDE.md
58
+ └── codex/
59
+ └── CODEX.md
60
+ ```
61
+
62
+ ## Supported Combinations
63
+
64
+ ### Languages
65
+ | ID | Label |
66
+ |---|---|
67
+ | `typescript` | TypeScript (Node.js ESM) |
68
+ | `laravel` | Laravel (PHP) |
69
+ | `python` | Python 3.x |
70
+
71
+ ### AI Providers
72
+ | ID | Config file |
73
+ |---|---|
74
+ | `claude` | `CLAUDE.md` |
75
+ | `codex` | `CODEX.md` |
76
+
77
+ ### Features
78
+ | ID | Compatible Languages |
79
+ |---|---|
80
+ | `github-actions` | All |
81
+ | `docker` | All |
82
+ | `discord` | All |
83
+ | `line-bot` | TypeScript, Python |
84
+ | `lark` | All |
85
+ | `eslint` | TypeScript |
86
+ | `prettier` | TypeScript |
87
+ | `vitest` | TypeScript |
88
+
89
+ ## Templates
90
+
91
+ Templates are fetched from [dev-init-templates](https://github.com/Ruu5LP/dev-init-templates) and cached in `~/.dev-init/templates/`.
92
+
93
+ ## License
94
+
95
+ MIT
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":""}
@@ -0,0 +1,63 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from 'commander';
3
+ import { readFileSync } from 'fs';
4
+ import { join, dirname } from 'path';
5
+ import { fileURLToPath } from 'url';
6
+ import pc from 'picocolors';
7
+ import { runPrompts } from './prompts.js';
8
+ import { generate } from '../core/generator.js';
9
+ import { fetchTemplates } from '../core/fetcher.js';
10
+ import { resolveConfig } from '../core/resolver.js';
11
+ import { ProjectConfig } from '../types/index.js';
12
+ const __dirname = dirname(fileURLToPath(import.meta.url));
13
+ const pkg = JSON.parse(readFileSync(join(__dirname, '../../package.json'), 'utf-8'));
14
+ const program = new Command();
15
+ program
16
+ .name('dev-init')
17
+ .description('Scaffold a new project with language, AI, and feature composition')
18
+ .version(pkg.version);
19
+ program
20
+ .command('create', { isDefault: true })
21
+ .description('Create a new project (interactive)')
22
+ .option('-o, --output <dir>', 'Output base directory', '.')
23
+ .option('--here', 'Generate in the current directory instead of a subdirectory')
24
+ .option('--update-templates', 'Force re-download of templates before generating')
25
+ .action(async (opts) => {
26
+ try {
27
+ const templatesDir = await fetchTemplates({ force: opts.updateTemplates });
28
+ const config = await runPrompts(opts.here ? '.' : opts.output);
29
+ if (opts.here) {
30
+ config.outputDir = opts.output === '.' ? '.' : opts.output;
31
+ }
32
+ const validated = ProjectConfig.safeParse(config);
33
+ if (!validated.success) {
34
+ console.error(pc.red('Invalid configuration:'));
35
+ console.error(validated.error.format());
36
+ process.exit(1);
37
+ }
38
+ const resolved = resolveConfig(validated.data);
39
+ if (!resolved.valid) {
40
+ console.error(pc.red('Configuration errors:'));
41
+ resolved.errors.forEach((e) => console.error(pc.red(` • ${e}`)));
42
+ process.exit(1);
43
+ }
44
+ const finalConfig = { ...validated.data, features: resolved.resolvedFeatures };
45
+ await generate(finalConfig, templatesDir);
46
+ }
47
+ catch (err) {
48
+ if (err instanceof Error && err.message.includes('ExitPromptError')) {
49
+ console.log(pc.yellow('\nCancelled.'));
50
+ process.exit(0);
51
+ }
52
+ console.error(pc.red('Error:'), err instanceof Error ? err.message : err);
53
+ process.exit(1);
54
+ }
55
+ });
56
+ program
57
+ .command('update-templates')
58
+ .description('Update cached templates from the remote repository')
59
+ .action(async () => {
60
+ await fetchTemplates({ force: true });
61
+ });
62
+ program.parse();
63
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { ProjectConfig } from '../types/index.js';
2
+ export declare function runPrompts(outputBase: string): Promise<ProjectConfig>;
3
+ //# sourceMappingURL=prompts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../src/cli/prompts.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAuC,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAE3F,wBAAsB,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAmE3E"}
@@ -0,0 +1,65 @@
1
+ import { input, select, checkbox, confirm } from '@inquirer/prompts';
2
+ import pc from 'picocolors';
3
+ import { languages } from '../registry/languages.js';
4
+ import { availableAiProviders } from '../registry/ai-providers.js';
5
+ import { getFeaturesForLanguage } from '../registry/features.js';
6
+ export async function runPrompts(outputBase) {
7
+ console.log(pc.bold(pc.cyan('\n dev-init — Project Generator\n')));
8
+ const projectName = await input({
9
+ message: 'Project name:',
10
+ validate: (v) => (v.trim().length > 0 ? true : 'Project name is required'),
11
+ });
12
+ const description = await input({
13
+ message: 'Description (optional):',
14
+ default: '',
15
+ });
16
+ const language = await select({
17
+ message: 'Language:',
18
+ choices: languages.map((l) => ({
19
+ name: l.label,
20
+ value: l.id,
21
+ description: l.description,
22
+ })),
23
+ });
24
+ const aiProviders = await checkbox({
25
+ message: 'AI providers (space to select):',
26
+ choices: availableAiProviders.map((p) => ({
27
+ name: p.label,
28
+ value: p.id,
29
+ description: p.description,
30
+ checked: true,
31
+ })),
32
+ validate: (v) => (v.length > 0 ? true : 'Select at least one AI provider'),
33
+ });
34
+ const compatibleFeatures = getFeaturesForLanguage(language);
35
+ const features = await checkbox({
36
+ message: 'Features (space to select):',
37
+ choices: compatibleFeatures.map((f) => ({
38
+ name: f.label,
39
+ value: f.id,
40
+ description: f.description,
41
+ })),
42
+ });
43
+ const outputDir = `${outputBase}/${projectName}`;
44
+ console.log(pc.bold('\n Summary'));
45
+ console.log(` ${pc.dim('Project :')} ${projectName}`);
46
+ console.log(` ${pc.dim('Language :')} ${language}`);
47
+ console.log(` ${pc.dim('AI :')} ${aiProviders.join(', ')}`);
48
+ console.log(` ${pc.dim('Features :')} ${features.length > 0 ? features.join(', ') : 'none'}`);
49
+ console.log(` ${pc.dim('Output :')} ${outputDir}`);
50
+ console.log();
51
+ const confirmed = await confirm({ message: 'Generate project?', default: true });
52
+ if (!confirmed) {
53
+ console.log(pc.yellow('Cancelled.'));
54
+ process.exit(0);
55
+ }
56
+ return {
57
+ projectName,
58
+ description,
59
+ language,
60
+ aiProviders,
61
+ features,
62
+ outputDir,
63
+ };
64
+ }
65
+ //# sourceMappingURL=prompts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompts.js","sourceRoot":"","sources":["../../src/cli/prompts.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export interface FetchOptions {
2
+ force?: boolean;
3
+ ref?: string;
4
+ }
5
+ export declare function fetchTemplates(options?: FetchOptions): Promise<string>;
6
+ export declare function getTemplatesDir(): string;
7
+ //# sourceMappingURL=fetcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetcher.d.ts","sourceRoot":"","sources":["../../src/core/fetcher.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,GAAG,CAAC,EAAE,MAAM,CAAA;CACb;AAED,wBAAsB,cAAc,CAAC,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,CA2BhF;AAED,wBAAgB,eAAe,IAAI,MAAM,CAExC"}
@@ -0,0 +1,33 @@
1
+ import { execSync } from 'child_process';
2
+ import { existsSync, mkdirSync } from 'fs';
3
+ import { join } from 'path';
4
+ import { homedir } from 'os';
5
+ import pc from 'picocolors';
6
+ const TEMPLATES_REPO = 'github:Ruu5LP/dev-init-templates';
7
+ const CACHE_DIR = join(homedir(), '.dev-init', 'templates');
8
+ export async function fetchTemplates(options = {}) {
9
+ const { force = false, ref = 'main' } = options;
10
+ if (!force && existsSync(CACHE_DIR)) {
11
+ return CACHE_DIR;
12
+ }
13
+ console.log(pc.cyan('Fetching templates...'));
14
+ mkdirSync(CACHE_DIR, { recursive: true });
15
+ try {
16
+ // Use degit via CLI since ESM import can be tricky
17
+ execSync(`npx degit ${TEMPLATES_REPO}#${ref} ${CACHE_DIR} --force`, { stdio: 'pipe' });
18
+ console.log(pc.green('✓ Templates ready'));
19
+ }
20
+ catch {
21
+ // Fallback: if network is unavailable, check cache
22
+ if (existsSync(join(CACHE_DIR, 'base'))) {
23
+ console.log(pc.yellow('⚠ Using cached templates (network unavailable)'));
24
+ return CACHE_DIR;
25
+ }
26
+ throw new Error('Failed to fetch templates and no cache found. Check your network connection.');
27
+ }
28
+ return CACHE_DIR;
29
+ }
30
+ export function getTemplatesDir() {
31
+ return CACHE_DIR;
32
+ }
33
+ //# sourceMappingURL=fetcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetcher.js","sourceRoot":"","sources":["../../src/core/fetcher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACxC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,IAAI,CAAA;AAC1C,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAC3B,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAA;AAC5B,OAAO,EAAE,MAAM,YAAY,CAAA;AAE3B,MAAM,cAAc,GAAG,kCAAkC,CAAA;AACzD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,WAAW,EAAE,WAAW,CAAC,CAAA;AAO3D,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,UAAwB,EAAE;IAC7D,MAAM,EAAE,KAAK,GAAG,KAAK,EAAE,GAAG,GAAG,MAAM,EAAE,GAAG,OAAO,CAAA;IAE/C,IAAI,CAAC,KAAK,IAAI,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QACpC,OAAO,SAAS,CAAA;IAClB,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC,CAAA;IAC7C,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAEzC,IAAI,CAAC;QACH,mDAAmD;QACnD,QAAQ,CACN,aAAa,cAAc,IAAI,GAAG,IAAI,SAAS,UAAU,EACzD,EAAE,KAAK,EAAE,MAAM,EAAE,CAClB,CAAA;QACD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC,CAAA;IAC5C,CAAC;IAAC,MAAM,CAAC;QACP,mDAAmD;QACnD,IAAI,UAAU,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC;YACxC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,gDAAgD,CAAC,CAAC,CAAA;YACxE,OAAO,SAAS,CAAA;QAClB,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,8EAA8E,CAAC,CAAA;IACjG,CAAC;IAED,OAAO,SAAS,CAAA;AAClB,CAAC;AAED,MAAM,UAAU,eAAe;IAC7B,OAAO,SAAS,CAAA;AAClB,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { ProjectConfig } from '../types/index.js';
2
+ export declare function generate(config: ProjectConfig, templatesDir: string): Promise<void>;
3
+ //# sourceMappingURL=generator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../src/core/generator.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,aAAa,EAAmB,MAAM,mBAAmB,CAAA;AAOvE,wBAAsB,QAAQ,CAAC,MAAM,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAqEzF"}
@@ -0,0 +1,120 @@
1
+ import { readdir, readFile, writeFile, mkdir, symlink } from 'fs/promises';
2
+ import { existsSync } from 'fs';
3
+ import { join, dirname, extname, basename } from 'path';
4
+ import pc from 'picocolors';
5
+ import { buildContext, renderFile, renderString } from './renderer.js';
6
+ import { mergePackageJsonObjects } from './merger.js';
7
+ import { getLanguage } from '../registry/languages.js';
8
+ import { getAiProvider } from '../registry/ai-providers.js';
9
+ import { getFeature } from '../registry/features.js';
10
+ export async function generate(config, templatesDir) {
11
+ const lang = getLanguage(config.language);
12
+ const aiProviders = config.aiProviders.map((id) => getAiProvider(id));
13
+ const featureMetas = config.features.map((id) => getFeature(id));
14
+ const ctx = buildContext({
15
+ projectName: config.projectName,
16
+ description: config.description,
17
+ language: config.language,
18
+ languageLabel: lang.label,
19
+ aiProviders: config.aiProviders,
20
+ aiProviderLabels: aiProviders.map((a) => a.label),
21
+ features: config.features,
22
+ featureLabels: featureMetas.map((f) => f.label),
23
+ });
24
+ const files = [];
25
+ let packageJsonBase = {};
26
+ const packageJsonPatches = [];
27
+ // ── Layer 1: base ────────────────────────────────────────────────────────
28
+ const baseDir = join(templatesDir, 'base');
29
+ await collectLayer(baseDir, '', ctx, files);
30
+ // ── Layer 2: language ────────────────────────────────────────────────────
31
+ const langDir = join(templatesDir, 'languages', config.language);
32
+ await collectLayer(langDir, '', ctx, files);
33
+ const langPkgPath = join(langDir, 'package.json.patch');
34
+ if (existsSync(langPkgPath)) {
35
+ const raw = await readFile(langPkgPath, 'utf-8');
36
+ packageJsonBase = mergePackageJsonObjects(packageJsonBase, JSON.parse(raw));
37
+ }
38
+ // ── Layer 3: features ────────────────────────────────────────────────────
39
+ for (const featureId of config.features) {
40
+ const featureDir = join(templatesDir, 'features', featureId);
41
+ await collectLayer(featureDir, '', ctx, files);
42
+ const patchPath = join(featureDir, 'package.json.patch');
43
+ if (existsSync(patchPath)) {
44
+ const raw = await readFile(patchPath, 'utf-8');
45
+ packageJsonPatches.push(JSON.parse(raw));
46
+ }
47
+ }
48
+ // Merge all package.json patches
49
+ if (Object.keys(packageJsonBase).length > 0 || packageJsonPatches.length > 0) {
50
+ const merged = mergePackageJsonObjects(packageJsonBase, ...packageJsonPatches);
51
+ const rendered = renderString(JSON.stringify(merged, null, 2), ctx);
52
+ files.push({ path: 'package.json', content: rendered });
53
+ }
54
+ // ── Layer 4: AI docs ─────────────────────────────────────────────────────
55
+ const commonAiDir = join(templatesDir, 'ai', '_common');
56
+ await collectLayer(commonAiDir, '.ai', ctx, files);
57
+ for (const provider of aiProviders) {
58
+ const aiDir = join(templatesDir, 'ai', provider.id);
59
+ await collectLayer(aiDir, join('.ai', provider.id), ctx, files);
60
+ }
61
+ // ── Write files ──────────────────────────────────────────────────────────
62
+ await writeFiles(config.outputDir, files);
63
+ // ── Symlinks: CLAUDE.md / CODEX.md at root ───────────────────────────────
64
+ await createAiSymlinks(config.outputDir, aiProviders);
65
+ console.log(pc.green(`\n✓ ${files.length} files generated in ${config.outputDir}/`));
66
+ }
67
+ async function collectLayer(layerDir, outputPrefix, ctx, files) {
68
+ if (!existsSync(layerDir))
69
+ return;
70
+ const entries = await readdir(layerDir, { recursive: true, withFileTypes: true });
71
+ for (const entry of entries) {
72
+ if (!entry.isFile())
73
+ continue;
74
+ const rel = join(entry.parentPath ?? entry.path, entry.name)
75
+ .replace(layerDir, '')
76
+ .replace(/^\//, '');
77
+ // Skip meta/patch files
78
+ if (rel === '_meta.ts' || rel.endsWith('package.json.patch'))
79
+ continue;
80
+ const fullSrc = join(layerDir, rel);
81
+ const isTemplate = extname(entry.name) === '.hbs';
82
+ const destRel = join(outputPrefix, isTemplate ? rel.replace(/\.hbs$/, '') : rel);
83
+ let content;
84
+ if (isTemplate) {
85
+ content = await renderFile(fullSrc, ctx);
86
+ }
87
+ else {
88
+ content = await readFile(fullSrc, 'utf-8');
89
+ }
90
+ files.push({ path: destRel, content });
91
+ }
92
+ }
93
+ async function writeFiles(outputDir, files) {
94
+ for (const file of files) {
95
+ const dest = join(outputDir, file.path);
96
+ await mkdir(dirname(dest), { recursive: true });
97
+ await writeFile(dest, file.content, 'utf-8');
98
+ console.log(pc.dim(` ${file.path}`));
99
+ }
100
+ }
101
+ async function createAiSymlinks(outputDir, providers) {
102
+ for (const provider of providers) {
103
+ if (!provider)
104
+ continue;
105
+ const configFile = provider.configFile;
106
+ const symlinkName = basename(configFile);
107
+ const symlinkDest = join(outputDir, symlinkName);
108
+ const target = join('.ai', provider.id, symlinkName);
109
+ if (!existsSync(symlinkDest)) {
110
+ try {
111
+ await symlink(target, symlinkDest);
112
+ console.log(pc.dim(` ${symlinkName} → ${target}`));
113
+ }
114
+ catch {
115
+ // Symlink creation can fail on some systems; silently skip
116
+ }
117
+ }
118
+ }
119
+ }
120
+ //# sourceMappingURL=generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generator.js","sourceRoot":"","sources":["../../src/core/generator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export declare function mergePackageJson(base: Record<string, unknown>, patchPath: string): Promise<Record<string, unknown>>;
2
+ export declare function mergePackageJsonObjects(...patches: Record<string, unknown>[]): Record<string, unknown>;
3
+ //# sourceMappingURL=merger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merger.d.ts","sourceRoot":"","sources":["../../src/core/merger.ts"],"names":[],"mappings":"AAKA,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CASlC;AAED,wBAAgB,uBAAuB,CACrC,GAAG,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GACpC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAQzB"}
@@ -0,0 +1,18 @@
1
+ import deepmerge from 'deepmerge';
2
+ import { readFile } from 'fs/promises';
3
+ import { existsSync } from 'fs';
4
+ export async function mergePackageJson(base, patchPath) {
5
+ if (!existsSync(patchPath))
6
+ return base;
7
+ const raw = await readFile(patchPath, 'utf-8');
8
+ const patch = JSON.parse(raw);
9
+ return deepmerge(base, patch, {
10
+ arrayMerge: (dest, src) => [...new Set([...dest, ...src])],
11
+ });
12
+ }
13
+ export function mergePackageJsonObjects(...patches) {
14
+ return patches.reduce((acc, patch) => deepmerge(acc, patch, {
15
+ arrayMerge: (dest, src) => [...new Set([...dest, ...src])],
16
+ }), {});
17
+ }
18
+ //# sourceMappingURL=merger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merger.js","sourceRoot":"","sources":["../../src/core/merger.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,WAAW,CAAA;AACjC,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AACtC,OAAO,EAAE,UAAU,EAAE,MAAM,IAAI,CAAA;AAG/B,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,IAA6B,EAC7B,SAAiB;IAEjB,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC;QAAE,OAAO,IAAI,CAAA;IAEvC,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC,CAAA;IAC9C,MAAM,KAAK,GAAqB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IAE/C,OAAO,SAAS,CAAC,IAAI,EAAE,KAAK,EAAE;QAC5B,UAAU,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,IAAI,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC;KAC3D,CAAC,CAAA;AACJ,CAAC;AAED,MAAM,UAAU,uBAAuB,CACrC,GAAG,OAAkC;IAErC,OAAO,OAAO,CAAC,MAAM,CACnB,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,CACb,SAAS,CAAC,GAAG,EAAE,KAAK,EAAE;QACpB,UAAU,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,IAAI,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC;KAC3D,CAAC,EACJ,EAA6B,CAC9B,CAAA;AACH,CAAC"}
@@ -0,0 +1,14 @@
1
+ import type { TemplateContext } from '../types/index.js';
2
+ export declare function buildContext(config: {
3
+ projectName: string;
4
+ description: string;
5
+ language: string;
6
+ languageLabel: string;
7
+ aiProviders: string[];
8
+ aiProviderLabels: string[];
9
+ features: string[];
10
+ featureLabels: string[];
11
+ }): TemplateContext;
12
+ export declare function renderFile(filePath: string, context: TemplateContext): Promise<string>;
13
+ export declare function renderString(source: string, context: TemplateContext): string;
14
+ //# sourceMappingURL=renderer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../src/core/renderer.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AAQxD,wBAAgB,YAAY,CAC1B,MAAM,EAAE;IACN,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE,MAAM,CAAA;IACnB,QAAQ,EAAE,MAAM,CAAA;IAChB,aAAa,EAAE,MAAM,CAAA;IACrB,WAAW,EAAE,MAAM,EAAE,CAAA;IACrB,gBAAgB,EAAE,MAAM,EAAE,CAAA;IAC1B,QAAQ,EAAE,MAAM,EAAE,CAAA;IAClB,aAAa,EAAE,MAAM,EAAE,CAAA;CACxB,GACA,eAAe,CAOjB;AAED,wBAAsB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,CAI5F;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,MAAM,CAG7E"}
@@ -0,0 +1,23 @@
1
+ import Handlebars from 'handlebars';
2
+ import { readFile } from 'fs/promises';
3
+ // Register helpers
4
+ Handlebars.registerHelper('eq', (a, b) => a === b);
5
+ Handlebars.registerHelper('includes', (arr, val) => Array.isArray(arr) && arr.includes(val));
6
+ export function buildContext(config) {
7
+ return {
8
+ ...config,
9
+ year: new Date().getFullYear(),
10
+ hasFeature: (id) => config.features.includes(id),
11
+ hasAi: (id) => config.aiProviders.includes(id),
12
+ };
13
+ }
14
+ export async function renderFile(filePath, context) {
15
+ const source = await readFile(filePath, 'utf-8');
16
+ const template = Handlebars.compile(source, { noEscape: true });
17
+ return template(context);
18
+ }
19
+ export function renderString(source, context) {
20
+ const template = Handlebars.compile(source, { noEscape: true });
21
+ return template(context);
22
+ }
23
+ //# sourceMappingURL=renderer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renderer.js","sourceRoot":"","sources":["../../src/core/renderer.ts"],"names":[],"mappings":"AAAA,OAAO,UAAU,MAAM,YAAY,CAAA;AACnC,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAGtC,mBAAmB;AACnB,UAAU,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC,CAAU,EAAE,CAAU,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAA;AACpE,UAAU,CAAC,cAAc,CAAC,UAAU,EAAE,CAAC,GAAc,EAAE,GAAY,EAAE,EAAE,CACrE,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CACxC,CAAA;AAED,MAAM,UAAU,YAAY,CAC1B,MASC;IAED,OAAO;QACL,GAAG,MAAM;QACT,IAAI,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QAC9B,UAAU,EAAE,CAAC,EAAU,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QACxD,KAAK,EAAE,CAAC,EAAU,EAAE,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC;KACvD,CAAA;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,QAAgB,EAAE,OAAwB;IACzE,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAA;IAChD,MAAM,QAAQ,GAAG,UAAU,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAA;IAC/D,OAAO,QAAQ,CAAC,OAAO,CAAC,CAAA;AAC1B,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,MAAc,EAAE,OAAwB;IACnE,MAAM,QAAQ,GAAG,UAAU,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAA;IAC/D,OAAO,QAAQ,CAAC,OAAO,CAAC,CAAA;AAC1B,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { FeatureId, ProjectConfig } from '../types/index.js';
2
+ export interface ResolveResult {
3
+ valid: boolean;
4
+ errors: string[];
5
+ resolvedFeatures: FeatureId[];
6
+ }
7
+ export declare function resolveConfig(config: ProjectConfig): ResolveResult;
8
+ //# sourceMappingURL=resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolver.d.ts","sourceRoot":"","sources":["../../src/core/resolver.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAc,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAE7E,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,OAAO,CAAA;IACd,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,gBAAgB,EAAE,SAAS,EAAE,CAAA;CAC9B;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,aAAa,GAAG,aAAa,CAwClE"}
@@ -0,0 +1,41 @@
1
+ import { getFeature, getFeaturesForLanguage } from '../registry/features.js';
2
+ export function resolveConfig(config) {
3
+ const errors = [];
4
+ const resolvedFeatures = new Set(config.features);
5
+ const compatibleFeatures = getFeaturesForLanguage(config.language);
6
+ const compatibleIds = new Set(compatibleFeatures.map((f) => f.id));
7
+ // Check language compatibility
8
+ for (const featureId of config.features) {
9
+ if (!compatibleIds.has(featureId)) {
10
+ errors.push(`Feature "${featureId}" is not compatible with language "${config.language}"`);
11
+ }
12
+ }
13
+ // Auto-resolve required dependencies
14
+ for (const featureId of config.features) {
15
+ const meta = getFeature(featureId);
16
+ if (!meta)
17
+ continue;
18
+ for (const required of meta.requiredFeatures) {
19
+ if (!resolvedFeatures.has(required)) {
20
+ resolvedFeatures.add(required);
21
+ }
22
+ }
23
+ }
24
+ // Check conflicts
25
+ for (const featureId of resolvedFeatures) {
26
+ const meta = getFeature(featureId);
27
+ if (!meta)
28
+ continue;
29
+ for (const conflict of meta.conflicts) {
30
+ if (resolvedFeatures.has(conflict)) {
31
+ errors.push(`Feature "${featureId}" conflicts with "${conflict}"`);
32
+ }
33
+ }
34
+ }
35
+ return {
36
+ valid: errors.length === 0,
37
+ errors,
38
+ resolvedFeatures: Array.from(resolvedFeatures),
39
+ };
40
+ }
41
+ //# sourceMappingURL=resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolver.js","sourceRoot":"","sources":["../../src/core/resolver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAA;AAS5E,MAAM,UAAU,aAAa,CAAC,MAAqB;IACjD,MAAM,MAAM,GAAa,EAAE,CAAA;IAC3B,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAY,MAAM,CAAC,QAAQ,CAAC,CAAA;IAC5D,MAAM,kBAAkB,GAAG,sBAAsB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;IAClE,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;IAElE,+BAA+B;IAC/B,KAAK,MAAM,SAAS,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;QACxC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;YAClC,MAAM,CAAC,IAAI,CAAC,YAAY,SAAS,sCAAsC,MAAM,CAAC,QAAQ,GAAG,CAAC,CAAA;QAC5F,CAAC;IACH,CAAC;IAED,qCAAqC;IACrC,KAAK,MAAM,SAAS,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;QACxC,MAAM,IAAI,GAAG,UAAU,CAAC,SAAS,CAAC,CAAA;QAClC,IAAI,CAAC,IAAI;YAAE,SAAQ;QACnB,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;YAC7C,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACpC,gBAAgB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;YAChC,CAAC;QACH,CAAC;IACH,CAAC;IAED,kBAAkB;IAClB,KAAK,MAAM,SAAS,IAAI,gBAAgB,EAAE,CAAC;QACzC,MAAM,IAAI,GAAG,UAAU,CAAC,SAAS,CAAC,CAAA;QAClC,IAAI,CAAC,IAAI;YAAE,SAAQ;QACnB,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACtC,IAAI,gBAAgB,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACnC,MAAM,CAAC,IAAI,CAAC,YAAY,SAAS,qBAAqB,QAAQ,GAAG,CAAC,CAAA;YACpE,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO;QACL,KAAK,EAAE,MAAM,CAAC,MAAM,KAAK,CAAC;QAC1B,MAAM;QACN,gBAAgB,EAAE,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC;KAC/C,CAAA;AACH,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { AiProviderMeta } from '../types/index.js';
2
+ export declare const aiProviders: AiProviderMeta[];
3
+ export declare const availableAiProviders: AiProviderMeta[];
4
+ export declare function getAiProvider(id: string): AiProviderMeta | undefined;
5
+ //# sourceMappingURL=ai-providers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-providers.d.ts","sourceRoot":"","sources":["../../src/registry/ai-providers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAEvD,eAAO,MAAM,WAAW,EAAE,cAAc,EA+BvC,CAAA;AAED,eAAO,MAAM,oBAAoB,kBAEhC,CAAA;AAED,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAEpE"}
@@ -0,0 +1,37 @@
1
+ export const aiProviders = [
2
+ {
3
+ id: 'claude',
4
+ label: 'Claude Code',
5
+ description: 'Anthropic Claude Code',
6
+ configFile: 'CLAUDE.md',
7
+ },
8
+ {
9
+ id: 'codex',
10
+ label: 'Codex',
11
+ description: 'OpenAI Codex',
12
+ configFile: 'CODEX.md',
13
+ },
14
+ {
15
+ id: 'copilot',
16
+ label: 'GitHub Copilot',
17
+ description: 'GitHub Copilot (coming soon)',
18
+ configFile: '.github/copilot-instructions.md',
19
+ },
20
+ {
21
+ id: 'gemini',
22
+ label: 'Gemini',
23
+ description: 'Google Gemini (coming soon)',
24
+ configFile: 'GEMINI.md',
25
+ },
26
+ {
27
+ id: 'cursor',
28
+ label: 'Cursor',
29
+ description: 'Cursor AI (coming soon)',
30
+ configFile: '.cursorrules',
31
+ },
32
+ ];
33
+ export const availableAiProviders = aiProviders.filter((p) => ['claude', 'codex'].includes(p.id));
34
+ export function getAiProvider(id) {
35
+ return aiProviders.find((p) => p.id === id);
36
+ }
37
+ //# sourceMappingURL=ai-providers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-providers.js","sourceRoot":"","sources":["../../src/registry/ai-providers.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,WAAW,GAAqB;IAC3C;QACE,EAAE,EAAE,QAAQ;QACZ,KAAK,EAAE,aAAa;QACpB,WAAW,EAAE,uBAAuB;QACpC,UAAU,EAAE,WAAW;KACxB;IACD;QACE,EAAE,EAAE,OAAO;QACX,KAAK,EAAE,OAAO;QACd,WAAW,EAAE,cAAc;QAC3B,UAAU,EAAE,UAAU;KACvB;IACD;QACE,EAAE,EAAE,SAAS;QACb,KAAK,EAAE,gBAAgB;QACvB,WAAW,EAAE,8BAA8B;QAC3C,UAAU,EAAE,iCAAiC;KAC9C;IACD;QACE,EAAE,EAAE,QAAQ;QACZ,KAAK,EAAE,QAAQ;QACf,WAAW,EAAE,6BAA6B;QAC1C,UAAU,EAAE,WAAW;KACxB;IACD;QACE,EAAE,EAAE,QAAQ;QACZ,KAAK,EAAE,QAAQ;QACf,WAAW,EAAE,yBAAyB;QACtC,UAAU,EAAE,cAAc;KAC3B;CACF,CAAA;AAED,MAAM,CAAC,MAAM,oBAAoB,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAC3D,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CACnC,CAAA;AAED,MAAM,UAAU,aAAa,CAAC,EAAU;IACtC,OAAO,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAA;AAC7C,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { FeatureMeta } from '../types/index.js';
2
+ export declare const features: FeatureMeta[];
3
+ export declare function getFeature(id: string): FeatureMeta | undefined;
4
+ export declare function getFeaturesForLanguage(languageId: string): FeatureMeta[];
5
+ //# sourceMappingURL=features.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"features.d.ts","sourceRoot":"","sources":["../../src/registry/features.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAEpD,eAAO,MAAM,QAAQ,EAAE,WAAW,EAiEjC,CAAA;AAED,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CAE9D;AAED,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,MAAM,GAAG,WAAW,EAAE,CAIxE"}
@@ -0,0 +1,73 @@
1
+ export const features = [
2
+ {
3
+ id: 'github-actions',
4
+ label: 'GitHub Actions',
5
+ description: 'CI/CD with GitHub Actions',
6
+ compatibleLanguages: 'all',
7
+ requiredFeatures: [],
8
+ conflicts: [],
9
+ },
10
+ {
11
+ id: 'docker',
12
+ label: 'Docker',
13
+ description: 'Docker + docker-compose',
14
+ compatibleLanguages: 'all',
15
+ requiredFeatures: [],
16
+ conflicts: [],
17
+ },
18
+ {
19
+ id: 'discord',
20
+ label: 'Discord',
21
+ description: 'Discord Bot / Webhook integration',
22
+ compatibleLanguages: 'all',
23
+ requiredFeatures: [],
24
+ conflicts: [],
25
+ },
26
+ {
27
+ id: 'line-bot',
28
+ label: 'LINE Bot',
29
+ description: 'LINE Messaging API integration',
30
+ compatibleLanguages: ['typescript', 'python'],
31
+ requiredFeatures: [],
32
+ conflicts: [],
33
+ },
34
+ {
35
+ id: 'lark',
36
+ label: 'Lark',
37
+ description: 'Lark (Feishu) Bot integration',
38
+ compatibleLanguages: 'all',
39
+ requiredFeatures: [],
40
+ conflicts: [],
41
+ },
42
+ {
43
+ id: 'eslint',
44
+ label: 'ESLint',
45
+ description: 'JavaScript/TypeScript linter',
46
+ compatibleLanguages: ['typescript'],
47
+ requiredFeatures: [],
48
+ conflicts: [],
49
+ },
50
+ {
51
+ id: 'prettier',
52
+ label: 'Prettier',
53
+ description: 'Code formatter',
54
+ compatibleLanguages: ['typescript'],
55
+ requiredFeatures: [],
56
+ conflicts: [],
57
+ },
58
+ {
59
+ id: 'vitest',
60
+ label: 'Vitest',
61
+ description: 'Unit testing framework',
62
+ compatibleLanguages: ['typescript'],
63
+ requiredFeatures: [],
64
+ conflicts: [],
65
+ },
66
+ ];
67
+ export function getFeature(id) {
68
+ return features.find((f) => f.id === id);
69
+ }
70
+ export function getFeaturesForLanguage(languageId) {
71
+ return features.filter((f) => f.compatibleLanguages === 'all' || f.compatibleLanguages.includes(languageId));
72
+ }
73
+ //# sourceMappingURL=features.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"features.js","sourceRoot":"","sources":["../../src/registry/features.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,QAAQ,GAAkB;IACrC;QACE,EAAE,EAAE,gBAAgB;QACpB,KAAK,EAAE,gBAAgB;QACvB,WAAW,EAAE,2BAA2B;QACxC,mBAAmB,EAAE,KAAK;QAC1B,gBAAgB,EAAE,EAAE;QACpB,SAAS,EAAE,EAAE;KACd;IACD;QACE,EAAE,EAAE,QAAQ;QACZ,KAAK,EAAE,QAAQ;QACf,WAAW,EAAE,yBAAyB;QACtC,mBAAmB,EAAE,KAAK;QAC1B,gBAAgB,EAAE,EAAE;QACpB,SAAS,EAAE,EAAE;KACd;IACD;QACE,EAAE,EAAE,SAAS;QACb,KAAK,EAAE,SAAS;QAChB,WAAW,EAAE,mCAAmC;QAChD,mBAAmB,EAAE,KAAK;QAC1B,gBAAgB,EAAE,EAAE;QACpB,SAAS,EAAE,EAAE;KACd;IACD;QACE,EAAE,EAAE,UAAU;QACd,KAAK,EAAE,UAAU;QACjB,WAAW,EAAE,gCAAgC;QAC7C,mBAAmB,EAAE,CAAC,YAAY,EAAE,QAAQ,CAAC;QAC7C,gBAAgB,EAAE,EAAE;QACpB,SAAS,EAAE,EAAE;KACd;IACD;QACE,EAAE,EAAE,MAAM;QACV,KAAK,EAAE,MAAM;QACb,WAAW,EAAE,+BAA+B;QAC5C,mBAAmB,EAAE,KAAK;QAC1B,gBAAgB,EAAE,EAAE;QACpB,SAAS,EAAE,EAAE;KACd;IACD;QACE,EAAE,EAAE,QAAQ;QACZ,KAAK,EAAE,QAAQ;QACf,WAAW,EAAE,8BAA8B;QAC3C,mBAAmB,EAAE,CAAC,YAAY,CAAC;QACnC,gBAAgB,EAAE,EAAE;QACpB,SAAS,EAAE,EAAE;KACd;IACD;QACE,EAAE,EAAE,UAAU;QACd,KAAK,EAAE,UAAU;QACjB,WAAW,EAAE,gBAAgB;QAC7B,mBAAmB,EAAE,CAAC,YAAY,CAAC;QACnC,gBAAgB,EAAE,EAAE;QACpB,SAAS,EAAE,EAAE;KACd;IACD;QACE,EAAE,EAAE,QAAQ;QACZ,KAAK,EAAE,QAAQ;QACf,WAAW,EAAE,wBAAwB;QACrC,mBAAmB,EAAE,CAAC,YAAY,CAAC;QACnC,gBAAgB,EAAE,EAAE;QACpB,SAAS,EAAE,EAAE;KACd;CACF,CAAA;AAED,MAAM,UAAU,UAAU,CAAC,EAAU;IACnC,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAA;AAC1C,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,UAAkB;IACvD,OAAO,QAAQ,CAAC,MAAM,CACpB,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,mBAAmB,KAAK,KAAK,IAAI,CAAC,CAAC,mBAAmB,CAAC,QAAQ,CAAC,UAAmB,CAAC,CAC9F,CAAA;AACH,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { LanguageMeta } from '../types/index.js';
2
+ export declare const languages: LanguageMeta[];
3
+ export declare function getLanguage(id: string): LanguageMeta | undefined;
4
+ //# sourceMappingURL=languages.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"languages.d.ts","sourceRoot":"","sources":["../../src/registry/languages.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAErD,eAAO,MAAM,SAAS,EAAE,YAAY,EAgBnC,CAAA;AAED,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAEhE"}
@@ -0,0 +1,21 @@
1
+ export const languages = [
2
+ {
3
+ id: 'typescript',
4
+ label: 'TypeScript',
5
+ description: 'Node.js + TypeScript (ESM)',
6
+ },
7
+ {
8
+ id: 'laravel',
9
+ label: 'Laravel',
10
+ description: 'PHP Laravel framework',
11
+ },
12
+ {
13
+ id: 'python',
14
+ label: 'Python',
15
+ description: 'Python 3.x',
16
+ },
17
+ ];
18
+ export function getLanguage(id) {
19
+ return languages.find((l) => l.id === id);
20
+ }
21
+ //# sourceMappingURL=languages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"languages.js","sourceRoot":"","sources":["../../src/registry/languages.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,SAAS,GAAmB;IACvC;QACE,EAAE,EAAE,YAAY;QAChB,KAAK,EAAE,YAAY;QACnB,WAAW,EAAE,4BAA4B;KAC1C;IACD;QACE,EAAE,EAAE,SAAS;QACb,KAAK,EAAE,SAAS;QAChB,WAAW,EAAE,uBAAuB;KACrC;IACD;QACE,EAAE,EAAE,QAAQ;QACZ,KAAK,EAAE,QAAQ;QACf,WAAW,EAAE,YAAY;KAC1B;CACF,CAAA;AAED,MAAM,UAAU,WAAW,CAAC,EAAU;IACpC,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAA;AAC3C,CAAC"}
@@ -0,0 +1,75 @@
1
+ import { z } from 'zod';
2
+ export declare const LanguageId: z.ZodEnum<["typescript", "laravel", "python"]>;
3
+ export type LanguageId = z.infer<typeof LanguageId>;
4
+ export interface LanguageMeta {
5
+ id: LanguageId;
6
+ label: string;
7
+ description: string;
8
+ }
9
+ export declare const AiProviderId: z.ZodEnum<["claude", "codex", "copilot", "gemini", "cursor"]>;
10
+ export type AiProviderId = z.infer<typeof AiProviderId>;
11
+ export interface AiProviderMeta {
12
+ id: AiProviderId;
13
+ label: string;
14
+ description: string;
15
+ configFile: string;
16
+ }
17
+ export declare const FeatureId: z.ZodEnum<["github-actions", "docker", "discord", "line-bot", "lark", "eslint", "prettier", "vitest"]>;
18
+ export type FeatureId = z.infer<typeof FeatureId>;
19
+ export interface FeatureMeta {
20
+ id: FeatureId;
21
+ label: string;
22
+ description: string;
23
+ compatibleLanguages: LanguageId[] | 'all';
24
+ requiredFeatures: FeatureId[];
25
+ conflicts: FeatureId[];
26
+ }
27
+ export declare const ProjectConfig: z.ZodObject<{
28
+ projectName: z.ZodString;
29
+ description: z.ZodDefault<z.ZodString>;
30
+ language: z.ZodEnum<["typescript", "laravel", "python"]>;
31
+ aiProviders: z.ZodArray<z.ZodEnum<["claude", "codex", "copilot", "gemini", "cursor"]>, "many">;
32
+ features: z.ZodArray<z.ZodEnum<["github-actions", "docker", "discord", "line-bot", "lark", "eslint", "prettier", "vitest"]>, "many">;
33
+ outputDir: z.ZodString;
34
+ }, "strip", z.ZodTypeAny, {
35
+ projectName: string;
36
+ description: string;
37
+ language: "typescript" | "laravel" | "python";
38
+ aiProviders: ("claude" | "codex" | "copilot" | "gemini" | "cursor")[];
39
+ features: ("github-actions" | "docker" | "discord" | "line-bot" | "lark" | "eslint" | "prettier" | "vitest")[];
40
+ outputDir: string;
41
+ }, {
42
+ projectName: string;
43
+ language: "typescript" | "laravel" | "python";
44
+ aiProviders: ("claude" | "codex" | "copilot" | "gemini" | "cursor")[];
45
+ features: ("github-actions" | "docker" | "discord" | "line-bot" | "lark" | "eslint" | "prettier" | "vitest")[];
46
+ outputDir: string;
47
+ description?: string | undefined;
48
+ }>;
49
+ export type ProjectConfig = z.infer<typeof ProjectConfig>;
50
+ export interface TemplateContext {
51
+ projectName: string;
52
+ description: string;
53
+ language: string;
54
+ languageLabel: string;
55
+ aiProviders: string[];
56
+ aiProviderLabels: string[];
57
+ features: string[];
58
+ featureLabels: string[];
59
+ year: number;
60
+ hasFeature: (id: string) => boolean;
61
+ hasAi: (id: string) => boolean;
62
+ }
63
+ export interface PackageJsonPatch {
64
+ scripts?: Record<string, string>;
65
+ dependencies?: Record<string, string>;
66
+ devDependencies?: Record<string, string>;
67
+ [key: string]: unknown;
68
+ }
69
+ export type LayerType = 'base' | 'language' | 'feature' | 'ai';
70
+ export interface GeneratorLayer {
71
+ type: LayerType;
72
+ id: string;
73
+ sourcePath: string;
74
+ }
75
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAIvB,eAAO,MAAM,UAAU,gDAA8C,CAAA;AACrE,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAA;AAEnD,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,UAAU,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,MAAM,CAAA;CACpB;AAID,eAAO,MAAM,YAAY,+DAA6D,CAAA;AACtF,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAA;AAEvD,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,YAAY,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,MAAM,CAAA;IACnB,UAAU,EAAE,MAAM,CAAA;CACnB;AAID,eAAO,MAAM,SAAS,wGASpB,CAAA;AACF,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,SAAS,CAAC,CAAA;AAEjD,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,SAAS,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,MAAM,CAAA;IACnB,mBAAmB,EAAE,UAAU,EAAE,GAAG,KAAK,CAAA;IACzC,gBAAgB,EAAE,SAAS,EAAE,CAAA;IAC7B,SAAS,EAAE,SAAS,EAAE,CAAA;CACvB;AAID,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;EAOxB,CAAA;AACF,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAA;AAIzD,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE,MAAM,CAAA;IACnB,QAAQ,EAAE,MAAM,CAAA;IAChB,aAAa,EAAE,MAAM,CAAA;IACrB,WAAW,EAAE,MAAM,EAAE,CAAA;IACrB,gBAAgB,EAAE,MAAM,EAAE,CAAA;IAC1B,QAAQ,EAAE,MAAM,EAAE,CAAA;IAClB,aAAa,EAAE,MAAM,EAAE,CAAA;IACvB,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAA;IACnC,KAAK,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAA;CAC/B;AAID,MAAM,WAAW,gBAAgB;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAChC,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACrC,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACxC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACvB;AAID,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,UAAU,GAAG,SAAS,GAAG,IAAI,CAAA;AAE9D,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,SAAS,CAAA;IACf,EAAE,EAAE,MAAM,CAAA;IACV,UAAU,EAAE,MAAM,CAAA;CACnB"}
@@ -0,0 +1,26 @@
1
+ import { z } from 'zod';
2
+ // ─── Language ────────────────────────────────────────────────────────────────
3
+ export const LanguageId = z.enum(['typescript', 'laravel', 'python']);
4
+ // ─── AI Provider ─────────────────────────────────────────────────────────────
5
+ export const AiProviderId = z.enum(['claude', 'codex', 'copilot', 'gemini', 'cursor']);
6
+ // ─── Feature ─────────────────────────────────────────────────────────────────
7
+ export const FeatureId = z.enum([
8
+ 'github-actions',
9
+ 'docker',
10
+ 'discord',
11
+ 'line-bot',
12
+ 'lark',
13
+ 'eslint',
14
+ 'prettier',
15
+ 'vitest',
16
+ ]);
17
+ // ─── Project Config ───────────────────────────────────────────────────────────
18
+ export const ProjectConfig = z.object({
19
+ projectName: z.string().min(1),
20
+ description: z.string().default(''),
21
+ language: LanguageId,
22
+ aiProviders: z.array(AiProviderId).min(1),
23
+ features: z.array(FeatureId),
24
+ outputDir: z.string(),
25
+ });
26
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,gFAAgF;AAEhF,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,YAAY,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAA;AASrE,gFAAgF;AAEhF,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAA;AAUtF,gFAAgF;AAEhF,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,CAAC,IAAI,CAAC;IAC9B,gBAAgB;IAChB,QAAQ;IACR,SAAS;IACT,UAAU;IACV,MAAM;IACN,QAAQ;IACR,UAAU;IACV,QAAQ;CACT,CAAC,CAAA;AAYF,iFAAiF;AAEjF,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,CAAC;IACpC,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC9B,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;IACnC,QAAQ,EAAE,UAAU;IACpB,WAAW,EAAE,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IACzC,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC;IAC5B,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;CACtB,CAAC,CAAA"}
package/package.json ADDED
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "@ruu5lp/dev-init",
3
+ "version": "0.1.0",
4
+ "description": "CLI tool to scaffold new projects with language, AI, and feature composition",
5
+ "type": "module",
6
+ "bin": {
7
+ "dev-init": "./dist/cli/index.js"
8
+ },
9
+ "scripts": {
10
+ "build": "tsc",
11
+ "dev": "tsx src/cli/index.ts",
12
+ "test": "vitest",
13
+ "test:coverage": "vitest --coverage",
14
+ "lint": "eslint src",
15
+ "typecheck": "tsc --noEmit",
16
+ "prepublishOnly": "npm run typecheck && npm run build"
17
+ },
18
+ "dependencies": {
19
+ "@inquirer/prompts": "^7.0.0",
20
+ "commander": "^12.0.0",
21
+ "deepmerge": "^4.3.1",
22
+ "degit": "^2.8.4",
23
+ "handlebars": "^4.7.8",
24
+ "js-yaml": "^4.1.0",
25
+ "picocolors": "^1.1.0",
26
+ "zod": "^3.23.0"
27
+ },
28
+ "devDependencies": {
29
+ "@types/deepmerge": "^2.2.0",
30
+ "@types/degit": "^2.8.6",
31
+ "@types/handlebars": "^4.1.0",
32
+ "@types/js-yaml": "^4.0.9",
33
+ "@types/node": "^22.0.0",
34
+ "@vitest/coverage-v8": "^2.0.0",
35
+ "eslint": "^9.0.0",
36
+ "tsx": "^4.0.0",
37
+ "typescript": "^5.5.0",
38
+ "vitest": "^2.0.0"
39
+ },
40
+ "engines": {
41
+ "node": ">=20.0.0"
42
+ },
43
+ "files": [
44
+ "dist"
45
+ ],
46
+ "keywords": [
47
+ "cli",
48
+ "scaffold",
49
+ "template",
50
+ "generator",
51
+ "dev-init"
52
+ ],
53
+ "license": "MIT",
54
+ "repository": {
55
+ "type": "git",
56
+ "url": "https://github.com/Ruu5LP/dev-init.git"
57
+ },
58
+ "homepage": "https://github.com/Ruu5LP/dev-init#readme",
59
+ "bugs": {
60
+ "url": "https://github.com/Ruu5LP/dev-init/issues"
61
+ }
62
+ }