Skip to content

Commit 2c327e2

Browse files
YAYLABS-Snooclaude
andcommitted
Remove project type inference from scanner
- Set type to undefined in RepositoryInfo (AI will analyze) - Made type field optional in types.ts - Removed type display from init.ts repository list and selection - Added project type to "To be analyzed by AI" list in SETUP_GUIDE All analysis (type, stack, description) now done by AI during setup phase. No more inaccurate inference during init. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 573d4e4 commit 2c327e2

3 files changed

Lines changed: 10 additions & 142 deletions

File tree

src/commands/init.ts

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -96,11 +96,7 @@ export async function initCommand(options: InitOptions) {
9696
// Display found repositories
9797
console.log(chalk.bold(`\n${lang === 'ko' ? '📁 발견된 레포지토리:' : '📁 Discovered Repositories:'}\n`));
9898
foundRepos.forEach((repo) => {
99-
const typeLabel = lang === 'ko'
100-
? { frontend: '프론트엔드', backend: '백엔드', mobile: '모바일', fullstack: '풀스택' }[repo.type]
101-
: repo.type;
102-
103-
console.log(` ${chalk.cyan('●')} ${chalk.bold(repo.name)} ${chalk.gray(`(${typeLabel})`)}`);
99+
console.log(` ${chalk.cyan('●')} ${chalk.bold(repo.name)}`);
104100
});
105101
console.log();
106102

@@ -113,12 +109,8 @@ export async function initCommand(options: InitOptions) {
113109
? '포함할 레포지토리를 선택하세요:'
114110
: 'Select repositories to include:',
115111
choices: foundRepos.map(repo => {
116-
const typeLabel = lang === 'ko'
117-
? { frontend: '프론트엔드', backend: '백엔드', mobile: '모바일', fullstack: '풀스택' }[repo.type]
118-
: repo.type;
119-
120112
return {
121-
name: `${repo.name} (${typeLabel})`,
113+
name: repo.name,
122114
value: repo.name,
123115
checked: true, // 기본적으로 모두 선택
124116
};
@@ -149,13 +141,10 @@ export async function initCommand(options: InitOptions) {
149141

150142
// Generate repository list for SETUP_GUIDE (only selected repos)
151143
const repoListText = includedRepos.map(repo => {
152-
const typeLabel = lang === 'ko'
153-
? { frontend: '프론트엔드', backend: '백엔드', mobile: '모바일', fullstack: '풀스택' }[repo.type]
154-
: repo.type;
155-
156-
return `- **${repo.name}** (${typeLabel})
144+
return `- **${repo.name}**
157145
- Path: \`./${repo.name}\`
158146
- ${lang === 'ko' ? 'AI가 분석할 내용' : 'To be analyzed by AI'}:
147+
- ${lang === 'ko' ? '프로젝트 유형 (프론트엔드/백엔드/모바일/풀스택)' : 'Project type (frontend/backend/mobile/fullstack)'}
159148
- ${lang === 'ko' ? '기술 스택' : 'Tech stack'}
160149
- ${lang === 'ko' ? '프로젝트 설명' : 'Project description'}
161150
- ${lang === 'ko' ? '주요 기능' : 'Main features'}`;

src/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export interface ProjectConfig {
3636
export interface RepositoryInfo {
3737
name: string;
3838
path: string;
39-
type: ProjectType;
39+
type?: ProjectType; // AI will analyze during setup
4040
description?: string; // AI will analyze during setup
4141
techStack?: string[]; // AI will analyze during setup
4242
hasCodeSyncer: boolean;

src/utils/scanner.ts

Lines changed: 5 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,12 @@ export async function scanForRepositories(rootPath: string): Promise<RepositoryI
2424
const isRepo = await isValidRepository(folderPath);
2525

2626
if (isRepo) {
27-
const type = await detectProjectType(folderPath, entry.name);
2827
const hasCodeSyncer = await hasCodeSyncerSetup(folderPath);
2928

3029
repos.push({
3130
name: entry.name,
3231
path: folderPath,
33-
type,
32+
type: undefined, // AI will analyze
3433
description: undefined, // AI will analyze
3534
techStack: undefined, // AI will analyze
3635
hasCodeSyncer,
@@ -83,130 +82,10 @@ async function isValidRepository(folderPath: string): Promise<boolean> {
8382
}
8483
}
8584

86-
/**
87-
* Detect project type based on folder structure, files, and repository name
88-
*/
89-
async function detectProjectType(folderPath: string, repoName: string): Promise<'frontend' | 'backend' | 'mobile' | 'fullstack'> {
90-
try {
91-
// Analyze repository name for hints
92-
const nameLower = repoName.toLowerCase();
93-
const nameHints = {
94-
backend: ['server', 'api', 'backend', 'service', 'socket', 'gateway', 'middleware'],
95-
frontend: ['client', 'frontend', 'web', 'app', 'ui', 'admin', 'dashboard'],
96-
mobile: ['mobile', 'ios', 'android', 'app'],
97-
};
98-
99-
// Check for Java projects (Spring Boot)
100-
const hasPomXml = await fs.pathExists(path.join(folderPath, 'pom.xml'));
101-
const hasGradle = await fs.pathExists(path.join(folderPath, 'build.gradle'));
102-
if (hasPomXml || hasGradle) {
103-
// Check if it's Android (mobile) or Spring (backend)
104-
const hasAndroid = await fs.pathExists(path.join(folderPath, 'app', 'src', 'main', 'AndroidManifest.xml'));
105-
if (hasAndroid) {
106-
return 'mobile';
107-
}
108-
return 'backend'; // Java Spring Boot
109-
}
110-
111-
// Check for Python projects (Django, FastAPI)
112-
const hasRequirements = await fs.pathExists(path.join(folderPath, 'requirements.txt'));
113-
const hasPipfile = await fs.pathExists(path.join(folderPath, 'Pipfile'));
114-
if (hasRequirements || hasPipfile) {
115-
try {
116-
let content = '';
117-
if (hasRequirements) {
118-
content = await fs.readFile(path.join(folderPath, 'requirements.txt'), 'utf-8');
119-
}
120-
// Check for web frameworks
121-
if (content.includes('django') || content.includes('fastapi') || content.includes('flask')) {
122-
return 'backend';
123-
}
124-
} catch {
125-
// If can't read file, default to backend
126-
}
127-
return 'backend'; // Python backend
128-
}
129-
130-
// Check for Node.js projects
131-
const packageJsonPath = path.join(folderPath, 'package.json');
132-
if (await fs.pathExists(packageJsonPath)) {
133-
const packageJson = await fs.readJson(packageJsonPath);
134-
const deps = {
135-
...packageJson.dependencies,
136-
...packageJson.devDependencies,
137-
};
138-
139-
// Check for mobile
140-
if (deps['react-native'] || deps['expo'] || deps['@react-native']) {
141-
return 'mobile';
142-
}
143-
144-
// Strong hint from repo name (socket server, api server, etc.)
145-
if (nameHints.backend.some(keyword => nameLower.includes(keyword))) {
146-
// If it has socket.io or backend keywords in name, prioritize backend
147-
if (deps['socket.io'] || deps['express'] || deps['fastify'] || deps['@nestjs/core']) {
148-
return 'backend';
149-
}
150-
}
151-
152-
// Check for frontend (React, Vue, etc.)
153-
if (deps['react'] || deps['vue'] || deps['angular'] || deps['svelte']) {
154-
// Check repo name hints
155-
if (nameHints.frontend.some(keyword => nameLower.includes(keyword))) {
156-
return 'frontend';
157-
}
158-
159-
// Check if it's Next.js (could be fullstack)
160-
if (deps['next']) {
161-
// If has database or backend hints in name, it's fullstack
162-
if (deps['prisma'] || deps['mongoose'] || deps['@prisma/client'] ||
163-
nameLower.includes('fullstack') || nameLower.includes('full-stack')) {
164-
return 'fullstack';
165-
}
166-
// If name suggests frontend only, return frontend
167-
if (nameHints.frontend.some(keyword => nameLower.includes(keyword))) {
168-
return 'frontend';
169-
}
170-
// Next.js with no DB is usually frontend
171-
return 'frontend';
172-
}
173-
return 'frontend';
174-
}
175-
176-
// Check for backend (Express, Fastify, NestJS, Socket.IO)
177-
if (deps['express'] || deps['fastify'] || deps['koa'] || deps['@nestjs/core'] ||
178-
deps['socket.io'] || deps['ws']) {
179-
return 'backend';
180-
}
181-
}
182-
183-
// Check for mobile-specific files
184-
const hasPodfile = await fs.pathExists(path.join(folderPath, 'ios', 'Podfile'));
185-
const hasAndroidGradle = await fs.pathExists(path.join(folderPath, 'android', 'build.gradle'));
186-
if (hasPodfile || hasAndroidGradle) {
187-
return 'mobile';
188-
}
189-
190-
// Use repo name as fallback
191-
if (nameHints.backend.some(keyword => nameLower.includes(keyword))) {
192-
return 'backend';
193-
}
194-
if (nameHints.frontend.some(keyword => nameLower.includes(keyword))) {
195-
return 'frontend';
196-
}
197-
if (nameHints.mobile.some(keyword => nameLower.includes(keyword))) {
198-
return 'mobile';
199-
}
200-
201-
// Default to fullstack if can't determine
202-
return 'fullstack';
203-
} catch {
204-
return 'fullstack';
205-
}
206-
}
207-
208-
// Tech stack and description detection removed
209-
// AI will analyze these accurately during setup phase
85+
// All project analysis removed - AI will analyze during setup phase
86+
// - Project type (frontend/backend/mobile/fullstack)
87+
// - Tech stack
88+
// - Description
21089

21190
/**
21291
* Check if CodeSyncer is already set up in the repository

0 commit comments

Comments
 (0)