From 0e27d6925a8af478d7576e34ed606c605ad2e2ef Mon Sep 17 00:00:00 2001 From: konard Date: Mon, 2 Feb 2026 21:00:44 +0100 Subject: [PATCH 1/3] Initial commit with task details Adding CLAUDE.md with task information for AI processing. This file will be removed when the task is complete. Issue: https://github.com/lak7/devildev/issues/43 --- CLAUDE.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..db9a0a1 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,7 @@ +Issue to solve: https://github.com/lak7/devildev/issues/43 +Your prepared branch: issue-43-2f06ca64e20d +Your prepared working directory: /tmp/gh-issue-solver-1770062438500 +Your forked repository: konard/lak7-devildev +Original repository (upstream): lak7/devildev + +Proceed. From ce3556070d3b2fb87fe04bfcef36cf8b26af138b Mon Sep 17 00:00:00 2001 From: konard Date: Mon, 2 Feb 2026 21:03:08 +0100 Subject: [PATCH 2/3] Improve framework detection by searching subdirectories for package.json When package.json is not found in the repository root, use the Git tree API to recursively search subdirectories and pick the shallowest match. This handles monorepos and projects where the main app lives in a subdirectory. Fixes lak7/devildev#43 Co-Authored-By: Claude Opus 4.5 --- actions/reverse-architecture.ts | 64 ++++++++++++++++++++++------- src/app/api/github/import/route.ts | 65 +++++++++++++++++++++++++++--- 2 files changed, 108 insertions(+), 21 deletions(-) diff --git a/actions/reverse-architecture.ts b/actions/reverse-architecture.ts index 88ca36b..5a1cc67 100644 --- a/actions/reverse-architecture.ts +++ b/actions/reverse-architecture.ts @@ -288,17 +288,51 @@ export async function checkPackageAndFramework(repositoryId: string, repoFullNam return { error: 'Failed to fetch repository contents' }; } - // Get package.json if exists - try{ - if(repoContent){ - - const packageJsonResponse = repoContent.find((item: any) => item === 'package.json'); - - if(packageJsonResponse){ - + // Get package.json if exists (check root first, then subdirectories) + try{ + if(repoContent){ + + const packageJsonInRoot = repoContent.find((item: any) => item === 'package.json'); + + // Determine the path to package.json: root or first match in subdirectories + let packageJsonPath: string | null = null; + + if(packageJsonInRoot){ + packageJsonPath = 'package.json'; + } else { + // Search subdirectories for package.json using the Git tree API + try { + const treeResponse = await fetch( + `https://api.github.com/repos/${repoFullName}/git/trees/${defaultBranch || 'main'}?recursive=1`, + { + headers: { + 'Authorization': `Bearer ${authToken}`, + 'Accept': 'application/vnd.github.v3+json', + 'User-Agent': 'DevilDev-App', + }, + } + ); + if (treeResponse.ok) { + const treeData = await treeResponse.json(); + if (treeData.tree && Array.isArray(treeData.tree)) { + // Find the shallowest package.json (prefer fewer nested levels) + const packageJsonEntries = treeData.tree + .filter((node: any) => node.type === 'blob' && node.path.endsWith('/package.json')) + .sort((a: any, b: any) => a.path.split('/').length - b.path.split('/').length); + if (packageJsonEntries.length > 0) { + packageJsonPath = packageJsonEntries[0].path; + } + } + } + } catch (treeError) { + console.error('Error searching subdirectories for package.json:', treeError); + } + } + + if(packageJsonPath){ const packageJsonContent = await fetch( - `https://api.github.com/repos/${repoFullName}/contents/package.json`, - { + `https://api.github.com/repos/${repoFullName}/contents/${packageJsonPath}`, + { headers: { 'Authorization': `Bearer ${authToken}`, 'Accept': 'application/vnd.github.v3+json', @@ -306,22 +340,22 @@ export async function checkPackageAndFramework(repositoryId: string, repoFullNam }, } ); - + if (packageJsonContent.ok) { - + packageJson = await packageJsonContent.json(); - + // Decode the Base64 content to plain text if (packageJson.content && packageJson.encoding === "base64") { const decoded = Buffer.from(packageJson.content, "base64").toString("utf-8"); packageJson = JSON.parse(decoded); // Now it's the actual JSON object } - + }else{ return { error: 'Failed to fetch package.json' }; } }else{ - + return { isValid: false, framework: "" }; } } diff --git a/src/app/api/github/import/route.ts b/src/app/api/github/import/route.ts index 678ead7..de57849 100644 --- a/src/app/api/github/import/route.ts +++ b/src/app/api/github/import/route.ts @@ -69,17 +69,17 @@ export async function POST(request: NextRequest) { } ); - + if (contentsResponse.ok) { theProjectStructure = await contentsResponse.json(); } - // Get package.json if it exists (for Node.js projects) - + // Get package.json if it exists (check root first, then subdirectories) + try { const packageResponse = await fetch( `https://api.github.com/repos/${fullName}/contents/package.json`, - { + { headers: { 'Authorization': `Bearer ${authToken}`, 'Accept': 'application/vnd.github.v3+json', @@ -87,12 +87,65 @@ export async function POST(request: NextRequest) { }, } ); - + if (packageResponse.ok) { const packageData = await packageResponse.json(); - if (packageData.content) { + if (packageData.content) { packageJson = JSON.parse(atob(packageData.content)); } + } else { + // package.json not in root, search subdirectories using Git tree API + const repoInfoResponse = await fetch( + `https://api.github.com/repos/${fullName}`, + { + headers: { + 'Authorization': `Bearer ${authToken}`, + 'Accept': 'application/vnd.github.v3+json', + 'User-Agent': 'DevilDev-App', + }, + } + ); + if (repoInfoResponse.ok) { + const repoInfo = await repoInfoResponse.json(); + const branch = repoInfo.default_branch || 'main'; + const treeResponse = await fetch( + `https://api.github.com/repos/${fullName}/git/trees/${branch}?recursive=1`, + { + headers: { + 'Authorization': `Bearer ${authToken}`, + 'Accept': 'application/vnd.github.v3+json', + 'User-Agent': 'DevilDev-App', + }, + } + ); + if (treeResponse.ok) { + const treeData = await treeResponse.json(); + if (treeData.tree && Array.isArray(treeData.tree)) { + // Find the shallowest package.json in subdirectories + const packageJsonEntries = treeData.tree + .filter((node: any) => node.type === 'blob' && node.path.endsWith('/package.json')) + .sort((a: any, b: any) => a.path.split('/').length - b.path.split('/').length); + if (packageJsonEntries.length > 0) { + const subPackageResponse = await fetch( + `https://api.github.com/repos/${fullName}/contents/${packageJsonEntries[0].path}`, + { + headers: { + 'Authorization': `Bearer ${authToken}`, + 'Accept': 'application/vnd.github.v3+json', + 'User-Agent': 'DevilDev-App', + }, + } + ); + if (subPackageResponse.ok) { + const packageData = await subPackageResponse.json(); + if (packageData.content) { + packageJson = JSON.parse(atob(packageData.content)); + } + } + } + } + } + } } } catch (error) { // Package.json might not exist, that's fine From 01e860f06f97991a0291ec80246ec42054200e35 Mon Sep 17 00:00:00 2001 From: konard Date: Mon, 2 Feb 2026 21:03:49 +0100 Subject: [PATCH 3/3] Revert "Initial commit with task details" This reverts commit 0e27d6925a8af478d7576e34ed606c605ad2e2ef. --- CLAUDE.md | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index db9a0a1..0000000 --- a/CLAUDE.md +++ /dev/null @@ -1,7 +0,0 @@ -Issue to solve: https://github.com/lak7/devildev/issues/43 -Your prepared branch: issue-43-2f06ca64e20d -Your prepared working directory: /tmp/gh-issue-solver-1770062438500 -Your forked repository: konard/lak7-devildev -Original repository (upstream): lak7/devildev - -Proceed.