shipfolio 1.0.8 → 1.0.9

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.
@@ -302,10 +302,10 @@ function extractFirstParagraph(readme) {
302
302
  continue;
303
303
  }
304
304
  if (collecting && trimmed === "" && paragraphLines.length > 0) break;
305
- if (collecting && trimmed !== "") {
305
+ if (collecting && trimmed !== "" && !trimmed.startsWith("![") && !trimmed.startsWith("[![")) {
306
306
  paragraphLines.push(trimmed);
307
307
  }
308
- if (!collecting && trimmed !== "" && !trimmed.startsWith("[")) {
308
+ if (!collecting && trimmed !== "" && !trimmed.startsWith("[") && !trimmed.startsWith("!") && !trimmed.startsWith("[![")) {
309
309
  paragraphLines.push(trimmed);
310
310
  collecting = true;
311
311
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/scanner/git.ts","../../../src/utils/fs.ts","../../../src/scanner/detectors/node.ts","../../../src/scanner/detectors/python.ts","../../../src/scanner/detectors/rust.ts","../../../src/scanner/detectors/go.ts","../../../src/scanner/detectors/generic.ts","../../../src/scanner/extractors.ts","../../../src/utils/logger.ts","../../../src/scanner/index.ts"],"sourcesContent":["import simpleGit from \"simple-git\";\nimport { basename } from \"node:path\";\n\nexport interface GitMeta {\n isRepo: boolean;\n firstCommitDate: string | null;\n lastCommitDate: string | null;\n totalCommits: number;\n remoteUrl: string | null;\n lastCommitHash: string | null;\n}\n\nexport async function getGitMeta(projectPath: string): Promise<GitMeta> {\n const git = simpleGit(projectPath);\n const empty: GitMeta = {\n isRepo: false,\n firstCommitDate: null,\n lastCommitDate: null,\n totalCommits: 0,\n remoteUrl: null,\n lastCommitHash: null,\n };\n\n try {\n const isRepo = await git.checkIsRepo();\n if (!isRepo) return empty;\n } catch {\n return empty;\n }\n\n try {\n const log = await git.log({ maxCount: 1 });\n\n // Get first commit date\n let firstCommitDate: string | null = null;\n try {\n const firstResult = await git.raw([\"log\", \"--reverse\", \"--format=%aI\", \"--max-count=1\"]);\n firstCommitDate = firstResult.trim() || null;\n } catch {\n // ignore\n }\n\n let remoteUrl: string | null = null;\n try {\n const remotes = await git.getRemotes(true);\n const origin = remotes.find((r) => r.name === \"origin\");\n if (origin?.refs?.fetch) {\n remoteUrl = normalizeGitUrl(origin.refs.fetch);\n }\n } catch {\n // no remotes\n }\n\n // Get total commit count\n let totalCommits = 0;\n try {\n const result = await git.raw([\"rev-list\", \"--count\", \"HEAD\"]);\n totalCommits = parseInt(result.trim(), 10) || 0;\n } catch {\n totalCommits = 0;\n }\n\n return {\n isRepo: true,\n firstCommitDate,\n lastCommitDate: log.latest?.date || null,\n totalCommits,\n remoteUrl,\n lastCommitHash: log.latest?.hash || null,\n };\n } catch {\n return { ...empty, isRepo: true };\n }\n}\n\nfunction normalizeGitUrl(url: string): string {\n // Convert SSH to HTTPS\n if (url.startsWith(\"git@\")) {\n url = url.replace(\":\", \"/\").replace(\"git@\", \"https://\");\n }\n // Remove .git suffix\n if (url.endsWith(\".git\")) {\n url = url.slice(0, -4);\n }\n return url;\n}\n\nexport async function findGitRepos(\n rootPath: string,\n maxDepth: number = 3\n): Promise<string[]> {\n const { glob } = await import(\"glob\");\n const gitDirs = await glob(\"**/.git\", {\n cwd: rootPath,\n maxDepth: maxDepth + 1,\n dot: true,\n ignore: [\n \"**/node_modules/**/.git\",\n \"**/vendor/**/.git\",\n \"**/__pycache__/**/.git\",\n ],\n });\n\n return gitDirs\n .map((gitDir) => {\n const parts = gitDir.split(\"/\");\n parts.pop(); // remove .git\n return parts.length > 0\n ? `${rootPath}/${parts.join(\"/\")}`\n : rootPath;\n })\n .sort();\n}\n","import { readFile, writeFile, access, mkdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nexport async function fileExists(path: string): Promise<boolean> {\n try {\n await access(path);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function readJson<T = unknown>(path: string): Promise<T> {\n const content = await readFile(path, \"utf-8\");\n return JSON.parse(content) as T;\n}\n\nexport async function writeJson(path: string, data: unknown): Promise<void> {\n await writeFile(path, JSON.stringify(data, null, 2), \"utf-8\");\n}\n\nexport async function readText(path: string): Promise<string> {\n return readFile(path, \"utf-8\");\n}\n\nexport async function writeText(path: string, content: string): Promise<void> {\n await writeFile(path, content, \"utf-8\");\n}\n\nexport async function ensureDir(path: string): Promise<void> {\n await mkdir(path, { recursive: true });\n}\n\nexport { join };\n","import { fileExists, readJson, join } from \"../../utils/fs.js\";\n\ninterface PackageJson {\n name?: string;\n description?: string;\n homepage?: string;\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n}\n\nexport async function detectNode(projectPath: string) {\n const pkgPath = join(projectPath, \"package.json\");\n if (!(await fileExists(pkgPath))) return null;\n\n const pkg = await readJson<PackageJson>(pkgPath);\n const allDeps = {\n ...pkg.dependencies,\n ...pkg.devDependencies,\n };\n const depNames = Object.keys(allDeps);\n\n const techStack: string[] = [];\n\n // Frameworks\n if (depNames.includes(\"next\")) techStack.push(\"Next.js\");\n else if (depNames.includes(\"nuxt\")) techStack.push(\"Nuxt\");\n else if (depNames.includes(\"astro\")) techStack.push(\"Astro\");\n else if (depNames.includes(\"svelte\") || depNames.includes(\"@sveltejs/kit\"))\n techStack.push(\"Svelte\");\n\n // UI libraries\n if (depNames.includes(\"react\")) techStack.push(\"React\");\n if (depNames.includes(\"vue\")) techStack.push(\"Vue\");\n\n // Styling\n if (depNames.includes(\"tailwindcss\")) techStack.push(\"Tailwind CSS\");\n\n // Backend\n if (depNames.includes(\"express\")) techStack.push(\"Express\");\n if (depNames.includes(\"fastify\")) techStack.push(\"Fastify\");\n if (depNames.includes(\"hono\")) techStack.push(\"Hono\");\n\n // Database\n if (depNames.includes(\"prisma\") || depNames.includes(\"@prisma/client\"))\n techStack.push(\"Prisma\");\n if (depNames.includes(\"drizzle-orm\")) techStack.push(\"Drizzle\");\n if (depNames.includes(\"mongoose\")) techStack.push(\"MongoDB\");\n\n // AI/ML\n if (depNames.includes(\"openai\")) techStack.push(\"OpenAI\");\n if (depNames.includes(\"@anthropic-ai/sdk\")) techStack.push(\"Claude API\");\n if (depNames.includes(\"langchain\")) techStack.push(\"LangChain\");\n\n // Language\n if (depNames.includes(\"typescript\")) techStack.push(\"TypeScript\");\n else techStack.push(\"JavaScript\");\n\n return {\n name: pkg.name || null,\n description: pkg.description || null,\n homepage: pkg.homepage || null,\n techStack,\n };\n}\n","import { fileExists, readText, join } from \"../../utils/fs.js\";\n\nexport async function detectPython(projectPath: string) {\n const techStack: string[] = [\"Python\"];\n\n const reqPath = join(projectPath, \"requirements.txt\");\n const pyprojectPath = join(projectPath, \"pyproject.toml\");\n const setupPath = join(projectPath, \"setup.py\");\n\n let deps = \"\";\n\n if (await fileExists(reqPath)) {\n deps = await readText(reqPath);\n } else if (await fileExists(pyprojectPath)) {\n deps = await readText(pyprojectPath);\n } else if (await fileExists(setupPath)) {\n deps = await readText(setupPath);\n } else {\n return null;\n }\n\n const depsLower = deps.toLowerCase();\n\n if (depsLower.includes(\"django\")) techStack.push(\"Django\");\n if (depsLower.includes(\"flask\")) techStack.push(\"Flask\");\n if (depsLower.includes(\"fastapi\")) techStack.push(\"FastAPI\");\n if (depsLower.includes(\"pytorch\") || depsLower.includes(\"torch\"))\n techStack.push(\"PyTorch\");\n if (depsLower.includes(\"tensorflow\")) techStack.push(\"TensorFlow\");\n if (depsLower.includes(\"transformers\")) techStack.push(\"Transformers\");\n if (depsLower.includes(\"langchain\")) techStack.push(\"LangChain\");\n if (depsLower.includes(\"openai\")) techStack.push(\"OpenAI\");\n if (depsLower.includes(\"pandas\")) techStack.push(\"Pandas\");\n if (depsLower.includes(\"numpy\")) techStack.push(\"NumPy\");\n if (depsLower.includes(\"scikit\")) techStack.push(\"Scikit-learn\");\n\n return { techStack };\n}\n","import { fileExists, readText, join } from \"../../utils/fs.js\";\n\nexport async function detectRust(projectPath: string) {\n const cargoPath = join(projectPath, \"Cargo.toml\");\n if (!(await fileExists(cargoPath))) return null;\n\n const content = await readText(cargoPath);\n const techStack: string[] = [\"Rust\"];\n\n if (content.includes(\"actix\")) techStack.push(\"Actix\");\n if (content.includes(\"axum\")) techStack.push(\"Axum\");\n if (content.includes(\"tokio\")) techStack.push(\"Tokio\");\n if (content.includes(\"wasm\")) techStack.push(\"WebAssembly\");\n if (content.includes(\"tauri\")) techStack.push(\"Tauri\");\n if (content.includes(\"diesel\")) techStack.push(\"Diesel\");\n if (content.includes(\"sqlx\")) techStack.push(\"SQLx\");\n\n // Extract name from [package] section\n const nameMatch = content.match(/\\[package\\][\\s\\S]*?name\\s*=\\s*\"([^\"]+)\"/);\n const descMatch = content.match(\n /\\[package\\][\\s\\S]*?description\\s*=\\s*\"([^\"]+)\"/\n );\n\n return {\n name: nameMatch?.[1] || null,\n description: descMatch?.[1] || null,\n techStack,\n };\n}\n","import { fileExists, readText, join } from \"../../utils/fs.js\";\n\nexport async function detectGo(projectPath: string) {\n const goModPath = join(projectPath, \"go.mod\");\n if (!(await fileExists(goModPath))) return null;\n\n const content = await readText(goModPath);\n const techStack: string[] = [\"Go\"];\n\n if (content.includes(\"gin-gonic\")) techStack.push(\"Gin\");\n if (content.includes(\"echo\")) techStack.push(\"Echo\");\n if (content.includes(\"fiber\")) techStack.push(\"Fiber\");\n if (content.includes(\"grpc\")) techStack.push(\"gRPC\");\n if (content.includes(\"gorm\")) techStack.push(\"GORM\");\n if (content.includes(\"cobra\")) techStack.push(\"Cobra\");\n if (content.includes(\"ent\")) techStack.push(\"Ent\");\n\n return { techStack };\n}\n","import { glob } from \"glob\";\nimport { basename, extname } from \"node:path\";\n\nconst EXTENSION_MAP: Record<string, string> = {\n \".ts\": \"TypeScript\",\n \".tsx\": \"TypeScript\",\n \".js\": \"JavaScript\",\n \".jsx\": \"JavaScript\",\n \".py\": \"Python\",\n \".rs\": \"Rust\",\n \".go\": \"Go\",\n \".java\": \"Java\",\n \".kt\": \"Kotlin\",\n \".swift\": \"Swift\",\n \".rb\": \"Ruby\",\n \".php\": \"PHP\",\n \".cs\": \"C#\",\n \".cpp\": \"C++\",\n \".c\": \"C\",\n \".dart\": \"Dart\",\n \".lua\": \"Lua\",\n \".zig\": \"Zig\",\n \".sol\": \"Solidity\",\n \".ex\": \"Elixir\",\n \".exs\": \"Elixir\",\n};\n\nconst IGNORE_DIRS = [\n \"node_modules\",\n \".git\",\n \"dist\",\n \"build\",\n \"out\",\n \".next\",\n \"target\",\n \"vendor\",\n \"__pycache__\",\n \".venv\",\n \"venv\",\n];\n\nexport async function detectLanguages(\n projectPath: string\n): Promise<Record<string, number>> {\n const ignorePattern = IGNORE_DIRS.map((d) => `**/${d}/**`);\n const files = await glob(\"**/*.*\", {\n cwd: projectPath,\n ignore: ignorePattern,\n nodir: true,\n maxDepth: 5,\n });\n\n const counts: Record<string, number> = {};\n for (const file of files) {\n const ext = extname(file).toLowerCase();\n const lang = EXTENSION_MAP[ext];\n if (lang) {\n counts[lang] = (counts[lang] || 0) + 1;\n }\n }\n\n return counts;\n}\n\nexport function deriveNameFromPath(projectPath: string): string {\n return basename(projectPath);\n}\n","import { fileExists, readText, join } from \"../utils/fs.js\";\n\nexport async function extractReadme(\n projectPath: string\n): Promise<string | null> {\n const candidates = [\n \"README.md\",\n \"readme.md\",\n \"Readme.md\",\n \"README.txt\",\n \"README\",\n ];\n for (const name of candidates) {\n const p = join(projectPath, name);\n if (await fileExists(p)) {\n const content = await readText(p);\n // Limit to first 3000 chars to keep spec manageable\n return content.slice(0, 3000);\n }\n }\n return null;\n}\n\nexport function extractFirstParagraph(readme: string | null): string | null {\n if (!readme) return null;\n // Skip title lines (# heading)\n const lines = readme.split(\"\\n\");\n let collecting = false;\n const paragraphLines: string[] = [];\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (trimmed.startsWith(\"#\")) {\n if (collecting && paragraphLines.length > 0) break;\n collecting = true;\n continue;\n }\n if (collecting && trimmed === \"\" && paragraphLines.length > 0) break;\n if (collecting && trimmed !== \"\") {\n paragraphLines.push(trimmed);\n }\n if (!collecting && trimmed !== \"\" && !trimmed.startsWith(\"[\")) {\n paragraphLines.push(trimmed);\n collecting = true;\n }\n }\n\n return paragraphLines.length > 0 ? paragraphLines.join(\" \") : null;\n}\n\nexport function extractDemoUrl(readme: string | null): string | null {\n if (!readme) return null;\n // Look for common demo URL patterns\n const patterns = [\n /(?:demo|live|website|site|url|link)[\\s:]*\\[?[^\\]]*\\]?\\(?(https?:\\/\\/[^\\s)]+)/i,\n /\\[(?:demo|live|website|try it)\\]\\((https?:\\/\\/[^\\s)]+)\\)/i,\n /(https?:\\/\\/[^\\s)]+\\.(?:vercel|netlify|pages\\.dev|herokuapp|railway)\\.app[^\\s)]*)/i,\n ];\n for (const pattern of patterns) {\n const match = readme.match(pattern);\n if (match?.[1]) return match[1];\n }\n return null;\n}\n","import chalk from \"chalk\";\n\nexport const logger = {\n info(msg: string) {\n console.log(chalk.cyan(`-- ${msg}`));\n },\n success(msg: string) {\n console.log(chalk.green(`-- ${msg}`));\n },\n warn(msg: string) {\n console.log(chalk.yellow(`-- ${msg}`));\n },\n error(msg: string) {\n console.error(chalk.red(`-- ${msg}`));\n },\n plain(msg: string) {\n console.log(msg);\n },\n blank() {\n console.log();\n },\n header(msg: string) {\n console.log();\n console.log(chalk.bold(msg));\n console.log();\n },\n table(rows: string[][]) {\n if (rows.length === 0) return;\n const colWidths = rows[0].map((_, colIdx) =>\n Math.max(...rows.map((row) => (row[colIdx] || \"\").length))\n );\n for (const row of rows) {\n const line = row\n .map((cell, i) => (cell || \"\").padEnd(colWidths[i] + 2))\n .join(\"\");\n console.log(` ${line}`);\n }\n },\n};\n","import { findGitRepos, getGitMeta } from \"./git.js\";\nimport { detectNode } from \"./detectors/node.js\";\nimport { detectPython } from \"./detectors/python.js\";\nimport { detectRust } from \"./detectors/rust.js\";\nimport { detectGo } from \"./detectors/go.js\";\nimport { detectLanguages, deriveNameFromPath } from \"./detectors/generic.js\";\nimport {\n extractReadme,\n extractFirstParagraph,\n extractDemoUrl,\n} from \"./extractors.js\";\nimport type { ProjectMeta } from \"../spec/schema.js\";\nimport { logger } from \"../utils/logger.js\";\nimport ora from \"ora\";\n\nexport async function scanProjects(\n directories: string[]\n): Promise<ProjectMeta[]> {\n const allPaths: string[] = [];\n\n const spinner = ora(\"Scanning for projects...\").start();\n\n for (const dir of directories) {\n try {\n // Find git repos\n const repos = await findGitRepos(dir);\n allPaths.push(...repos);\n\n // Also find non-git project directories (with package.json, Cargo.toml, etc.)\n const nonGitDirs = await findNonGitProjects(dir, new Set(repos));\n allPaths.push(...nonGitDirs);\n } catch (err) {\n logger.warn(`Could not scan ${dir}: ${err}`);\n }\n }\n\n // Deduplicate\n const uniquePaths = [...new Set(allPaths)];\n spinner.text = `Found ${uniquePaths.length} projects. Extracting metadata...`;\n\n const projects: ProjectMeta[] = [];\n\n for (const projectPath of uniquePaths) {\n try {\n const project = await extractProjectMeta(projectPath);\n if (project) {\n projects.push(project);\n }\n } catch (err) {\n // Skip projects that fail extraction\n }\n }\n\n // Deduplicate IDs (same folder name in different parent dirs)\n const idCounts = new Map<string, number>();\n for (const project of projects) {\n const count = idCounts.get(project.id) || 0;\n if (count > 0) {\n project.id = `${project.id}-${count}`;\n }\n idCounts.set(project.id.replace(/-\\d+$/, \"\"), count + 1);\n }\n\n spinner.succeed(`Scanned ${projects.length} projects`);\n return projects;\n}\n\nasync function findNonGitProjects(\n rootPath: string,\n gitRepos: Set<string>\n): Promise<string[]> {\n const { glob } = await import(\"glob\");\n const indicators = [\n \"*/package.json\",\n \"*/Cargo.toml\",\n \"*/go.mod\",\n \"*/pyproject.toml\",\n \"*/requirements.txt\",\n \"*/setup.py\",\n ];\n const found = new Set<string>();\n for (const pattern of indicators) {\n const matches = await glob(pattern, {\n cwd: rootPath,\n ignore: [\"**/node_modules/**\", \"**/vendor/**\"],\n });\n for (const match of matches) {\n const dir = `${rootPath}/${match.split(\"/\")[0]}`;\n if (!gitRepos.has(dir) && !found.has(dir)) {\n found.add(dir);\n }\n }\n }\n return [...found].sort();\n}\n\nasync function extractProjectMeta(\n projectPath: string\n): Promise<ProjectMeta | null> {\n const gitMeta = await getGitMeta(projectPath);\n\n // Detect tech stack from various sources\n let techStack: string[] = [];\n let name: string | null = null;\n let description: string | null = null;\n let homepage: string | null = null;\n\n const nodeInfo = await detectNode(projectPath);\n if (nodeInfo) {\n techStack.push(...nodeInfo.techStack);\n name = nodeInfo.name || name;\n description = nodeInfo.description || description;\n homepage = nodeInfo.homepage || homepage;\n }\n\n const pythonInfo = await detectPython(projectPath);\n if (pythonInfo) {\n techStack.push(...pythonInfo.techStack);\n }\n\n const rustInfo = await detectRust(projectPath);\n if (rustInfo) {\n techStack.push(...rustInfo.techStack);\n name = rustInfo.name || name;\n description = rustInfo.description || description;\n }\n\n const goInfo = await detectGo(projectPath);\n if (goInfo) {\n techStack.push(...goInfo.techStack);\n }\n\n // Deduplicate tech stack\n techStack = [...new Set(techStack)];\n\n // Language breakdown\n const languages = await detectLanguages(projectPath);\n\n // If no tech stack detected, derive from languages\n if (techStack.length === 0) {\n const topLangs = Object.entries(languages)\n .sort((a, b) => b[1] - a[1])\n .slice(0, 3)\n .map(([lang]) => lang);\n techStack = topLangs;\n }\n\n // README\n const readmeContent = await extractReadme(projectPath);\n if (!description) {\n description = extractFirstParagraph(readmeContent) || \"\";\n }\n\n // Demo URL\n const demoUrl = homepage || extractDemoUrl(readmeContent);\n\n // Name fallback\n if (!name) {\n name = deriveNameFromPath(projectPath);\n }\n\n // Generate stable ID from path (use folder name to keep it readable, but\n // append a hash suffix when the same folder name appears in multiple paths)\n const folderName = deriveNameFromPath(projectPath);\n const id = folderName\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-|-$/g, \"\");\n\n return {\n id,\n name,\n localPath: projectPath,\n description: description || \"\",\n techStack,\n languages,\n firstCommitDate: gitMeta.firstCommitDate || \"\",\n lastCommitDate: gitMeta.lastCommitDate || \"\",\n totalCommits: gitMeta.totalCommits,\n remoteUrl: gitMeta.remoteUrl,\n demoUrl,\n readmeContent,\n lastScannedCommit: gitMeta.lastCommitHash || \"\",\n };\n}\n"],"mappings":"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","names":["glob","glob"]}
1
+ {"version":3,"sources":["../../../src/scanner/git.ts","../../../src/utils/fs.ts","../../../src/scanner/detectors/node.ts","../../../src/scanner/detectors/python.ts","../../../src/scanner/detectors/rust.ts","../../../src/scanner/detectors/go.ts","../../../src/scanner/detectors/generic.ts","../../../src/scanner/extractors.ts","../../../src/utils/logger.ts","../../../src/scanner/index.ts"],"sourcesContent":["import simpleGit from \"simple-git\";\nimport { basename } from \"node:path\";\n\nexport interface GitMeta {\n isRepo: boolean;\n firstCommitDate: string | null;\n lastCommitDate: string | null;\n totalCommits: number;\n remoteUrl: string | null;\n lastCommitHash: string | null;\n}\n\nexport async function getGitMeta(projectPath: string): Promise<GitMeta> {\n const git = simpleGit(projectPath);\n const empty: GitMeta = {\n isRepo: false,\n firstCommitDate: null,\n lastCommitDate: null,\n totalCommits: 0,\n remoteUrl: null,\n lastCommitHash: null,\n };\n\n try {\n const isRepo = await git.checkIsRepo();\n if (!isRepo) return empty;\n } catch {\n return empty;\n }\n\n try {\n const log = await git.log({ maxCount: 1 });\n\n // Get first commit date\n let firstCommitDate: string | null = null;\n try {\n const firstResult = await git.raw([\"log\", \"--reverse\", \"--format=%aI\", \"--max-count=1\"]);\n firstCommitDate = firstResult.trim() || null;\n } catch {\n // ignore\n }\n\n let remoteUrl: string | null = null;\n try {\n const remotes = await git.getRemotes(true);\n const origin = remotes.find((r) => r.name === \"origin\");\n if (origin?.refs?.fetch) {\n remoteUrl = normalizeGitUrl(origin.refs.fetch);\n }\n } catch {\n // no remotes\n }\n\n // Get total commit count\n let totalCommits = 0;\n try {\n const result = await git.raw([\"rev-list\", \"--count\", \"HEAD\"]);\n totalCommits = parseInt(result.trim(), 10) || 0;\n } catch {\n totalCommits = 0;\n }\n\n return {\n isRepo: true,\n firstCommitDate,\n lastCommitDate: log.latest?.date || null,\n totalCommits,\n remoteUrl,\n lastCommitHash: log.latest?.hash || null,\n };\n } catch {\n return { ...empty, isRepo: true };\n }\n}\n\nfunction normalizeGitUrl(url: string): string {\n // Convert SSH to HTTPS\n if (url.startsWith(\"git@\")) {\n url = url.replace(\":\", \"/\").replace(\"git@\", \"https://\");\n }\n // Remove .git suffix\n if (url.endsWith(\".git\")) {\n url = url.slice(0, -4);\n }\n return url;\n}\n\nexport async function findGitRepos(\n rootPath: string,\n maxDepth: number = 3\n): Promise<string[]> {\n const { glob } = await import(\"glob\");\n const gitDirs = await glob(\"**/.git\", {\n cwd: rootPath,\n maxDepth: maxDepth + 1,\n dot: true,\n ignore: [\n \"**/node_modules/**/.git\",\n \"**/vendor/**/.git\",\n \"**/__pycache__/**/.git\",\n ],\n });\n\n return gitDirs\n .map((gitDir) => {\n const parts = gitDir.split(\"/\");\n parts.pop(); // remove .git\n return parts.length > 0\n ? `${rootPath}/${parts.join(\"/\")}`\n : rootPath;\n })\n .sort();\n}\n","import { readFile, writeFile, access, mkdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nexport async function fileExists(path: string): Promise<boolean> {\n try {\n await access(path);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function readJson<T = unknown>(path: string): Promise<T> {\n const content = await readFile(path, \"utf-8\");\n return JSON.parse(content) as T;\n}\n\nexport async function writeJson(path: string, data: unknown): Promise<void> {\n await writeFile(path, JSON.stringify(data, null, 2), \"utf-8\");\n}\n\nexport async function readText(path: string): Promise<string> {\n return readFile(path, \"utf-8\");\n}\n\nexport async function writeText(path: string, content: string): Promise<void> {\n await writeFile(path, content, \"utf-8\");\n}\n\nexport async function ensureDir(path: string): Promise<void> {\n await mkdir(path, { recursive: true });\n}\n\nexport { join };\n","import { fileExists, readJson, join } from \"../../utils/fs.js\";\n\ninterface PackageJson {\n name?: string;\n description?: string;\n homepage?: string;\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n}\n\nexport async function detectNode(projectPath: string) {\n const pkgPath = join(projectPath, \"package.json\");\n if (!(await fileExists(pkgPath))) return null;\n\n const pkg = await readJson<PackageJson>(pkgPath);\n const allDeps = {\n ...pkg.dependencies,\n ...pkg.devDependencies,\n };\n const depNames = Object.keys(allDeps);\n\n const techStack: string[] = [];\n\n // Frameworks\n if (depNames.includes(\"next\")) techStack.push(\"Next.js\");\n else if (depNames.includes(\"nuxt\")) techStack.push(\"Nuxt\");\n else if (depNames.includes(\"astro\")) techStack.push(\"Astro\");\n else if (depNames.includes(\"svelte\") || depNames.includes(\"@sveltejs/kit\"))\n techStack.push(\"Svelte\");\n\n // UI libraries\n if (depNames.includes(\"react\")) techStack.push(\"React\");\n if (depNames.includes(\"vue\")) techStack.push(\"Vue\");\n\n // Styling\n if (depNames.includes(\"tailwindcss\")) techStack.push(\"Tailwind CSS\");\n\n // Backend\n if (depNames.includes(\"express\")) techStack.push(\"Express\");\n if (depNames.includes(\"fastify\")) techStack.push(\"Fastify\");\n if (depNames.includes(\"hono\")) techStack.push(\"Hono\");\n\n // Database\n if (depNames.includes(\"prisma\") || depNames.includes(\"@prisma/client\"))\n techStack.push(\"Prisma\");\n if (depNames.includes(\"drizzle-orm\")) techStack.push(\"Drizzle\");\n if (depNames.includes(\"mongoose\")) techStack.push(\"MongoDB\");\n\n // AI/ML\n if (depNames.includes(\"openai\")) techStack.push(\"OpenAI\");\n if (depNames.includes(\"@anthropic-ai/sdk\")) techStack.push(\"Claude API\");\n if (depNames.includes(\"langchain\")) techStack.push(\"LangChain\");\n\n // Language\n if (depNames.includes(\"typescript\")) techStack.push(\"TypeScript\");\n else techStack.push(\"JavaScript\");\n\n return {\n name: pkg.name || null,\n description: pkg.description || null,\n homepage: pkg.homepage || null,\n techStack,\n };\n}\n","import { fileExists, readText, join } from \"../../utils/fs.js\";\n\nexport async function detectPython(projectPath: string) {\n const techStack: string[] = [\"Python\"];\n\n const reqPath = join(projectPath, \"requirements.txt\");\n const pyprojectPath = join(projectPath, \"pyproject.toml\");\n const setupPath = join(projectPath, \"setup.py\");\n\n let deps = \"\";\n\n if (await fileExists(reqPath)) {\n deps = await readText(reqPath);\n } else if (await fileExists(pyprojectPath)) {\n deps = await readText(pyprojectPath);\n } else if (await fileExists(setupPath)) {\n deps = await readText(setupPath);\n } else {\n return null;\n }\n\n const depsLower = deps.toLowerCase();\n\n if (depsLower.includes(\"django\")) techStack.push(\"Django\");\n if (depsLower.includes(\"flask\")) techStack.push(\"Flask\");\n if (depsLower.includes(\"fastapi\")) techStack.push(\"FastAPI\");\n if (depsLower.includes(\"pytorch\") || depsLower.includes(\"torch\"))\n techStack.push(\"PyTorch\");\n if (depsLower.includes(\"tensorflow\")) techStack.push(\"TensorFlow\");\n if (depsLower.includes(\"transformers\")) techStack.push(\"Transformers\");\n if (depsLower.includes(\"langchain\")) techStack.push(\"LangChain\");\n if (depsLower.includes(\"openai\")) techStack.push(\"OpenAI\");\n if (depsLower.includes(\"pandas\")) techStack.push(\"Pandas\");\n if (depsLower.includes(\"numpy\")) techStack.push(\"NumPy\");\n if (depsLower.includes(\"scikit\")) techStack.push(\"Scikit-learn\");\n\n return { techStack };\n}\n","import { fileExists, readText, join } from \"../../utils/fs.js\";\n\nexport async function detectRust(projectPath: string) {\n const cargoPath = join(projectPath, \"Cargo.toml\");\n if (!(await fileExists(cargoPath))) return null;\n\n const content = await readText(cargoPath);\n const techStack: string[] = [\"Rust\"];\n\n if (content.includes(\"actix\")) techStack.push(\"Actix\");\n if (content.includes(\"axum\")) techStack.push(\"Axum\");\n if (content.includes(\"tokio\")) techStack.push(\"Tokio\");\n if (content.includes(\"wasm\")) techStack.push(\"WebAssembly\");\n if (content.includes(\"tauri\")) techStack.push(\"Tauri\");\n if (content.includes(\"diesel\")) techStack.push(\"Diesel\");\n if (content.includes(\"sqlx\")) techStack.push(\"SQLx\");\n\n // Extract name from [package] section\n const nameMatch = content.match(/\\[package\\][\\s\\S]*?name\\s*=\\s*\"([^\"]+)\"/);\n const descMatch = content.match(\n /\\[package\\][\\s\\S]*?description\\s*=\\s*\"([^\"]+)\"/\n );\n\n return {\n name: nameMatch?.[1] || null,\n description: descMatch?.[1] || null,\n techStack,\n };\n}\n","import { fileExists, readText, join } from \"../../utils/fs.js\";\n\nexport async function detectGo(projectPath: string) {\n const goModPath = join(projectPath, \"go.mod\");\n if (!(await fileExists(goModPath))) return null;\n\n const content = await readText(goModPath);\n const techStack: string[] = [\"Go\"];\n\n if (content.includes(\"gin-gonic\")) techStack.push(\"Gin\");\n if (content.includes(\"echo\")) techStack.push(\"Echo\");\n if (content.includes(\"fiber\")) techStack.push(\"Fiber\");\n if (content.includes(\"grpc\")) techStack.push(\"gRPC\");\n if (content.includes(\"gorm\")) techStack.push(\"GORM\");\n if (content.includes(\"cobra\")) techStack.push(\"Cobra\");\n if (content.includes(\"ent\")) techStack.push(\"Ent\");\n\n return { techStack };\n}\n","import { glob } from \"glob\";\nimport { basename, extname } from \"node:path\";\n\nconst EXTENSION_MAP: Record<string, string> = {\n \".ts\": \"TypeScript\",\n \".tsx\": \"TypeScript\",\n \".js\": \"JavaScript\",\n \".jsx\": \"JavaScript\",\n \".py\": \"Python\",\n \".rs\": \"Rust\",\n \".go\": \"Go\",\n \".java\": \"Java\",\n \".kt\": \"Kotlin\",\n \".swift\": \"Swift\",\n \".rb\": \"Ruby\",\n \".php\": \"PHP\",\n \".cs\": \"C#\",\n \".cpp\": \"C++\",\n \".c\": \"C\",\n \".dart\": \"Dart\",\n \".lua\": \"Lua\",\n \".zig\": \"Zig\",\n \".sol\": \"Solidity\",\n \".ex\": \"Elixir\",\n \".exs\": \"Elixir\",\n};\n\nconst IGNORE_DIRS = [\n \"node_modules\",\n \".git\",\n \"dist\",\n \"build\",\n \"out\",\n \".next\",\n \"target\",\n \"vendor\",\n \"__pycache__\",\n \".venv\",\n \"venv\",\n];\n\nexport async function detectLanguages(\n projectPath: string\n): Promise<Record<string, number>> {\n const ignorePattern = IGNORE_DIRS.map((d) => `**/${d}/**`);\n const files = await glob(\"**/*.*\", {\n cwd: projectPath,\n ignore: ignorePattern,\n nodir: true,\n maxDepth: 5,\n });\n\n const counts: Record<string, number> = {};\n for (const file of files) {\n const ext = extname(file).toLowerCase();\n const lang = EXTENSION_MAP[ext];\n if (lang) {\n counts[lang] = (counts[lang] || 0) + 1;\n }\n }\n\n return counts;\n}\n\nexport function deriveNameFromPath(projectPath: string): string {\n return basename(projectPath);\n}\n","import { fileExists, readText, join } from \"../utils/fs.js\";\n\nexport async function extractReadme(\n projectPath: string\n): Promise<string | null> {\n const candidates = [\n \"README.md\",\n \"readme.md\",\n \"Readme.md\",\n \"README.txt\",\n \"README\",\n ];\n for (const name of candidates) {\n const p = join(projectPath, name);\n if (await fileExists(p)) {\n const content = await readText(p);\n // Limit to first 3000 chars to keep spec manageable\n return content.slice(0, 3000);\n }\n }\n return null;\n}\n\nexport function extractFirstParagraph(readme: string | null): string | null {\n if (!readme) return null;\n // Skip title lines (# heading)\n const lines = readme.split(\"\\n\");\n let collecting = false;\n const paragraphLines: string[] = [];\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (trimmed.startsWith(\"#\")) {\n if (collecting && paragraphLines.length > 0) break;\n collecting = true;\n continue;\n }\n if (collecting && trimmed === \"\" && paragraphLines.length > 0) break;\n if (collecting && trimmed !== \"\" && !trimmed.startsWith(\"![\") && !trimmed.startsWith(\"[![\")) {\n paragraphLines.push(trimmed);\n }\n if (!collecting && trimmed !== \"\" && !trimmed.startsWith(\"[\") && !trimmed.startsWith(\"!\") && !trimmed.startsWith(\"[![\")) {\n paragraphLines.push(trimmed);\n collecting = true;\n }\n }\n\n return paragraphLines.length > 0 ? paragraphLines.join(\" \") : null;\n}\n\nexport function extractDemoUrl(readme: string | null): string | null {\n if (!readme) return null;\n // Look for common demo URL patterns\n const patterns = [\n /(?:demo|live|website|site|url|link)[\\s:]*\\[?[^\\]]*\\]?\\(?(https?:\\/\\/[^\\s)]+)/i,\n /\\[(?:demo|live|website|try it)\\]\\((https?:\\/\\/[^\\s)]+)\\)/i,\n /(https?:\\/\\/[^\\s)]+\\.(?:vercel|netlify|pages\\.dev|herokuapp|railway)\\.app[^\\s)]*)/i,\n ];\n for (const pattern of patterns) {\n const match = readme.match(pattern);\n if (match?.[1]) return match[1];\n }\n return null;\n}\n","import chalk from \"chalk\";\n\nexport const logger = {\n info(msg: string) {\n console.log(chalk.cyan(`-- ${msg}`));\n },\n success(msg: string) {\n console.log(chalk.green(`-- ${msg}`));\n },\n warn(msg: string) {\n console.log(chalk.yellow(`-- ${msg}`));\n },\n error(msg: string) {\n console.error(chalk.red(`-- ${msg}`));\n },\n plain(msg: string) {\n console.log(msg);\n },\n blank() {\n console.log();\n },\n header(msg: string) {\n console.log();\n console.log(chalk.bold(msg));\n console.log();\n },\n table(rows: string[][]) {\n if (rows.length === 0) return;\n const colWidths = rows[0].map((_, colIdx) =>\n Math.max(...rows.map((row) => (row[colIdx] || \"\").length))\n );\n for (const row of rows) {\n const line = row\n .map((cell, i) => (cell || \"\").padEnd(colWidths[i] + 2))\n .join(\"\");\n console.log(` ${line}`);\n }\n },\n};\n","import { findGitRepos, getGitMeta } from \"./git.js\";\nimport { detectNode } from \"./detectors/node.js\";\nimport { detectPython } from \"./detectors/python.js\";\nimport { detectRust } from \"./detectors/rust.js\";\nimport { detectGo } from \"./detectors/go.js\";\nimport { detectLanguages, deriveNameFromPath } from \"./detectors/generic.js\";\nimport {\n extractReadme,\n extractFirstParagraph,\n extractDemoUrl,\n} from \"./extractors.js\";\nimport type { ProjectMeta } from \"../spec/schema.js\";\nimport { logger } from \"../utils/logger.js\";\nimport ora from \"ora\";\n\nexport async function scanProjects(\n directories: string[]\n): Promise<ProjectMeta[]> {\n const allPaths: string[] = [];\n\n const spinner = ora(\"Scanning for projects...\").start();\n\n for (const dir of directories) {\n try {\n // Find git repos\n const repos = await findGitRepos(dir);\n allPaths.push(...repos);\n\n // Also find non-git project directories (with package.json, Cargo.toml, etc.)\n const nonGitDirs = await findNonGitProjects(dir, new Set(repos));\n allPaths.push(...nonGitDirs);\n } catch (err) {\n logger.warn(`Could not scan ${dir}: ${err}`);\n }\n }\n\n // Deduplicate\n const uniquePaths = [...new Set(allPaths)];\n spinner.text = `Found ${uniquePaths.length} projects. Extracting metadata...`;\n\n const projects: ProjectMeta[] = [];\n\n for (const projectPath of uniquePaths) {\n try {\n const project = await extractProjectMeta(projectPath);\n if (project) {\n projects.push(project);\n }\n } catch (err) {\n // Skip projects that fail extraction\n }\n }\n\n // Deduplicate IDs (same folder name in different parent dirs)\n const idCounts = new Map<string, number>();\n for (const project of projects) {\n const count = idCounts.get(project.id) || 0;\n if (count > 0) {\n project.id = `${project.id}-${count}`;\n }\n idCounts.set(project.id.replace(/-\\d+$/, \"\"), count + 1);\n }\n\n spinner.succeed(`Scanned ${projects.length} projects`);\n return projects;\n}\n\nasync function findNonGitProjects(\n rootPath: string,\n gitRepos: Set<string>\n): Promise<string[]> {\n const { glob } = await import(\"glob\");\n const indicators = [\n \"*/package.json\",\n \"*/Cargo.toml\",\n \"*/go.mod\",\n \"*/pyproject.toml\",\n \"*/requirements.txt\",\n \"*/setup.py\",\n ];\n const found = new Set<string>();\n for (const pattern of indicators) {\n const matches = await glob(pattern, {\n cwd: rootPath,\n ignore: [\"**/node_modules/**\", \"**/vendor/**\"],\n });\n for (const match of matches) {\n const dir = `${rootPath}/${match.split(\"/\")[0]}`;\n if (!gitRepos.has(dir) && !found.has(dir)) {\n found.add(dir);\n }\n }\n }\n return [...found].sort();\n}\n\nasync function extractProjectMeta(\n projectPath: string\n): Promise<ProjectMeta | null> {\n const gitMeta = await getGitMeta(projectPath);\n\n // Detect tech stack from various sources\n let techStack: string[] = [];\n let name: string | null = null;\n let description: string | null = null;\n let homepage: string | null = null;\n\n const nodeInfo = await detectNode(projectPath);\n if (nodeInfo) {\n techStack.push(...nodeInfo.techStack);\n name = nodeInfo.name || name;\n description = nodeInfo.description || description;\n homepage = nodeInfo.homepage || homepage;\n }\n\n const pythonInfo = await detectPython(projectPath);\n if (pythonInfo) {\n techStack.push(...pythonInfo.techStack);\n }\n\n const rustInfo = await detectRust(projectPath);\n if (rustInfo) {\n techStack.push(...rustInfo.techStack);\n name = rustInfo.name || name;\n description = rustInfo.description || description;\n }\n\n const goInfo = await detectGo(projectPath);\n if (goInfo) {\n techStack.push(...goInfo.techStack);\n }\n\n // Deduplicate tech stack\n techStack = [...new Set(techStack)];\n\n // Language breakdown\n const languages = await detectLanguages(projectPath);\n\n // If no tech stack detected, derive from languages\n if (techStack.length === 0) {\n const topLangs = Object.entries(languages)\n .sort((a, b) => b[1] - a[1])\n .slice(0, 3)\n .map(([lang]) => lang);\n techStack = topLangs;\n }\n\n // README\n const readmeContent = await extractReadme(projectPath);\n if (!description) {\n description = extractFirstParagraph(readmeContent) || \"\";\n }\n\n // Demo URL\n const demoUrl = homepage || extractDemoUrl(readmeContent);\n\n // Name fallback\n if (!name) {\n name = deriveNameFromPath(projectPath);\n }\n\n // Generate stable ID from path (use folder name to keep it readable, but\n // append a hash suffix when the same folder name appears in multiple paths)\n const folderName = deriveNameFromPath(projectPath);\n const id = folderName\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-|-$/g, \"\");\n\n return {\n id,\n name,\n localPath: projectPath,\n description: description || \"\",\n techStack,\n languages,\n firstCommitDate: gitMeta.firstCommitDate || \"\",\n lastCommitDate: gitMeta.lastCommitDate || \"\",\n totalCommits: gitMeta.totalCommits,\n remoteUrl: gitMeta.remoteUrl,\n demoUrl,\n readmeContent,\n lastScannedCommit: gitMeta.lastCommitHash || \"\",\n };\n}\n"],"mappings":"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","names":["glob","glob"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shipfolio",
3
- "version": "1.0.8",
3
+ "version": "1.0.9",
4
4
  "description": "Generate and deploy your personal portfolio site from local projects using AI",
5
5
  "type": "module",
6
6
  "bin": {