LogoStarterkitpro
AI

Project Snapshot Script

Generate project snapshots to enhance AI development assistance

This utility script helps accelerate development with AI by creating comprehensive snapshots of your codebase. The script generates two reference files that can be fed to any LLM (like ChatGPT, Claude, or Gemini) to provide context about your project structure and code.

How to use

This script is also very helpful if using projects in chatgpt.

Usage:

  • Upload your project-structure.txt and project-code.txt files to chatgpt projects.
  • Ask chatgpt to analyze your project structure or implement new features.
  • The Chatgpt will have comprehensive context about your codebase now.

What It Does

The script creates two files:

  • project-structure.txt - A hierarchical view of your project's files and directories
  • project-code.txt - The complete code of your project with file paths as headers

The Script

project-snapshot.js (Add in route of project)
const fs = require("fs");
const path = require("path");
 
// Configuration options
const config = {
  // File where the project structure will be saved
  projectStructureFile: "./project-structure.txt",
  // File where the complete project code will be saved
  projectCodeFile: "./project-code.txt",
  // Files and directories to exclude from both outputs
  excludeList: [
    "node_modules",
    ".next",
    "package-lock.json",
    ".git",
    ".DS_Store",
    // ".vscode",
    ".source",
    "project-snapshot.js", // Exclude this script itself
  ],
  // Additional exclusions just for the project structure
  structureExcludeList: [
    // Add files/directories to exclude from structure only
    // '.env',
    // '.env.local',
    // '.env.development',
    // '.env.production',
  ],
  // Additional exclusions just for the project code
  codeExcludeList: [
    // Add files/directories to exclude from code snapshot only
    // For example, you might want to exclude large generated files
    // "dist",
    // "build",
  ],
  // File extensions to exclude (typically binary files like images)
  excludeExtensions: [
    ".png",
    ".jpg",
    ".jpeg",
    ".gif",
    ".bmp",
    ".svg",
    ".webp",
    ".ico",
    ".woff",
    ".ttf",
    ".eot",
    ".mp3",
    ".mp4",
    ".mov",
    ".avi",
    ".pdf",
  ],
};
 
/**
 * Checks if a file or directory should be excluded from the output
 * @param {string} relPath - Relative path of the file or directory
 * @param {boolean} structureOnly - Whether to apply structure-only exclusions
 * @param {boolean} codeOnly - Whether to apply code-only exclusions
 * @returns {boolean} True if the item should be excluded
 */
function shouldExclude(relPath, structureOnly = false, codeOnly = false) {
  // Get the base name of the path
  const baseName = path.basename(relPath);
 
  // Check if the base name is in the exclude list
  if (config.excludeList.includes(baseName)) {
    return true;
  }
 
  // Check if the path starts with any excluded directory
  for (const excludeDir of config.excludeList) {
    if (relPath.startsWith(excludeDir + path.sep) || relPath === excludeDir) {
      return true;
    }
  }
 
  // Apply structure-only exclusions if requested
  if (structureOnly) {
    if (config.structureExcludeList.includes(baseName)) {
      return true;
    }
 
    for (const excludeDir of config.structureExcludeList) {
      if (relPath.startsWith(excludeDir + path.sep) || relPath === excludeDir) {
        return true;
      }
    }
  }
 
  // Apply code-only exclusions if requested
  if (codeOnly) {
    if (config.codeExcludeList.includes(baseName)) {
      return true;
    }
 
    for (const excludeDir of config.codeExcludeList) {
      if (relPath.startsWith(excludeDir + path.sep) || relPath === excludeDir) {
        return true;
      }
    }
  }
 
  // Exclude based on file extension
  const ext = path.extname(relPath).toLowerCase();
  if (config.excludeExtensions.includes(ext)) {
    return true;
  }
 
  return false;
}
 
/**
 * Generate the project structure (just file paths)
 * @param {string} dir - Directory to start from
 * @param {string} relativePath - Relative path from the project root
 * @returns {string} String containing the project structure
 */
function generateProjectStructure(dir, relativePath = "") {
  const files = fs.readdirSync(dir);
  let output = "";
 
  for (const file of files) {
    const fullPath = path.join(dir, file);
    const relPath = path.join(relativePath, file);
 
    // Skip excluded files and directories
    if (shouldExclude(relPath, true, false)) continue;
 
    const stats = fs.statSync(fullPath);
 
    if (stats.isDirectory()) {
      output += `Directory: ${relPath}/\n`;
      output += generateProjectStructure(fullPath, relPath);
    } else {
      output += `File: ${relPath}\n`;
    }
  }
 
  return output;
}
 
/**
 * Generate the full project code file by file
 * @param {string} dir - Directory to start from
 * @param {string} relativePath - Relative path from the project root
 * @returns {string} String containing all project code
 */
function generateProjectCode(dir, relativePath = "") {
  const files = fs.readdirSync(dir);
  let output = "";
 
  for (const file of files) {
    const fullPath = path.join(dir, file);
    const relPath = path.join(relativePath, file);
 
    // Skip excluded files and directories
    if (shouldExclude(relPath, false, true)) continue;
 
    const stats = fs.statSync(fullPath);
 
    if (stats.isDirectory()) {
      output += generateProjectCode(fullPath, relPath);
    } else {
      const ext = path.extname(relPath).toLowerCase();
 
      output += `\n\n${"=".repeat(80)}\n`;
      output += `File: ${relPath}\n`;
      output += `${"=".repeat(80)}\n\n`;
 
      try {
        // Try to read as text first
        output += fs.readFileSync(fullPath, "utf8");
      } catch (e) {
        // For binary files that somehow weren't excluded
        output += `/* Binary file - content not included */\n`;
      }
    }
  }
 
  return output;
}
 
/**
 * Main function to execute the script
 */
function main() {
  const projectDir = path.resolve("./");
  const timestamp = new Date().toISOString().replace(/:/g, "-").split(".")[0];
 
  // Create the scripts directory if it doesn't exist
  const scriptsDir = path.dirname(config.projectStructureFile);
  if (!fs.existsSync(scriptsDir)) {
    fs.mkdirSync(scriptsDir, { recursive: true });
  }
 
  // Generate and save project structure
  console.log("Generating project structure...");
  const projectStructure =
    `Project Structure Generated: ${timestamp}\n` +
    `${"=".repeat(80)}\n\n` +
    generateProjectStructure(projectDir);
 
  fs.writeFileSync(config.projectStructureFile, projectStructure);
  console.log(`Project structure saved to ${config.projectStructureFile}`);
 
  // Generate and save project code
  console.log("Generating complete project code snapshot...");
  const projectCode =
    `Project Code Generated: ${timestamp}\n` +
    `${"=".repeat(80)}\n\n` +
    generateProjectCode(projectDir);
 
  fs.writeFileSync(config.projectCodeFile, projectCode);
  console.log(`Project code saved to ${config.projectCodeFile}`);
}
 
// Execute the script
main();

How to run

Terminal
// first got to the root directory where script is placed
 node project-snapshot.js

Add to .gitignore (Optional)

Add these files to .gitignore so it will ot get pushed to github. Even windsurf and cursor will not track these files.

.gitignore
project-structure.txt
project-code.txt
project-snapshot.js

Be cautious about uploading sensitive code to external AI services. Consider excluding sensitive files like API keys, credentials, or proprietary algorithms by adding them to the exclude lists.

Customization

You can customize the script by modifying the config object:

  • excludeList: Files and directories to exclude from both outputs
  • structureExcludeList: Additional exclusions for the structure file only
  • codeExcludeList: Additional exclusions for the code file only
  • excludeExtensions: File types to exclude (typically binary files)

Benefits

  • Faster Development: AI can understand your codebase more quickly
  • Consistent Code Generation: AI-generated code follows your existing patterns
  • Better Integration: New features fit seamlessly into your architecture
  • Time Savings: Reduce the need to explain your project structure repeatedly

On this page