Skip to content

Instantly share code, notes, and snippets.

@stenuto
Last active January 16, 2025 17:02
Show Gist options
  • Save stenuto/db2e61f499f7feee94c5640b0c82db82 to your computer and use it in GitHub Desktop.
Save stenuto/db2e61f499f7feee94c5640b0c82db82 to your computer and use it in GitHub Desktop.

Revisions

  1. stenuto revised this gist Dec 13, 2024. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion gather.js
    Original file line number Diff line number Diff line change
    @@ -158,7 +158,7 @@ I will provide separate prompts after I paste this code.
    // Copy to clipboard using pbcopy (macOS)
    try {
    execSync('pbcopy', { input: blob })
    console.log('✅ Prompt coipied to clipboard')
    console.log('✅ Prompt copied to clipboard')
    } catch (error) {
    console.error("Failed to copy to clipboard. Here's the blob for reference:\n")
    console.log(blob)
  2. stenuto revised this gist Dec 10, 2024. No changes.
  3. stenuto renamed this gist Dec 10, 2024. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  4. stenuto created this gist Dec 10, 2024.
    166 changes: 166 additions & 0 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,166 @@
    #!/usr/bin/env node

    /**
    * gather.js
    *
    * A CLI tool to gather code files from given directories/files, annotate them,
    * and copy the resulting annotated code blob into the clipboard.
    *
    * Usage:
    * node gather.js relative/path/to/dir relative/path/to/file.js ...
    *
    * This tool will:
    * - Recursively crawl directories and pick up files with common code extensions.
    * - Concatenate their contents into a single annotated blob.
    * - Copy the blob to your clipboard using `pbcopy`.
    *
    * Example prompt annotation (this will be included at the top of the blob):
    *
    * "Below is a codebase comprised of multiple files and directories. Each file is
    * annotated with a header so that you know its path and language. I'll use this
    * codebase as context for my next questions. Please carefully read through it
    * so that when I ask my questions, you can refer to the relevant parts of the code.
    * I will provide separate prompts after I paste this code."
    */

    const fs = require('fs')
    const path = require('path')
    const { execSync } = require('child_process')

    // Extensions of files we consider to be "code" files
    const CODE_EXTENSIONS = [
    '.js',
    '.ts',
    '.jsx',
    '.tsx',
    '.php',
    '.rb',
    '.py',
    '.java',
    '.cs',
    '.go',
    '.html',
    '.css',
    '.scss',
    '.sass',
    '.json',
    '.yml',
    '.yaml'
    ]

    // Recursively gather code files from a given path
    async function gatherFilesFromPath(rootPath) {
    let results = []
    const stats = fs.statSync(rootPath)

    if (stats.isDirectory()) {
    const entries = fs.readdirSync(rootPath)
    for (const entry of entries) {
    const entryPath = path.join(rootPath, entry)
    const entryStats = fs.statSync(entryPath)
    if (entryStats.isDirectory()) {
    // Recurse into subdirectory
    const subResults = await gatherFilesFromPath(entryPath)
    results = results.concat(subResults)
    } else {
    // If it's a file, check extension
    const ext = path.extname(entryPath).toLowerCase()
    if (CODE_EXTENSIONS.includes(ext)) {
    results.push(entryPath)
    }
    }
    }
    } else if (stats.isFile()) {
    const ext = path.extname(rootPath).toLowerCase()
    if (CODE_EXTENSIONS.includes(ext)) {
    results.push(rootPath)
    }
    }

    return results
    }

    ;(async function main() {
    const args = process.argv.slice(2)
    if (args.length === 0) {
    console.error('Usage: gather.js <file|directory> [<file|directory>...]')
    process.exit(1)
    }

    // Gather all files from the specified arguments
    let allFiles = []
    for (const arg of args) {
    const files = await gatherFilesFromPath(arg)
    allFiles = allFiles.concat(files)
    }

    // Deduplicate files (just in case)
    allFiles = [...new Set(allFiles)]

    // Create an annotated blob
    let blob = `
    Below is a codebase comprised of multiple files and directories. Each file is annotated with a header so that you know its path and language. I'll use this codebase as context for my next questions. Please carefully read through it so that when I ask my questions, you can refer to the relevant parts of the code.
    I will provide separate prompts after I paste this code.
    ------------------------------------------------------------
    `

    for (const file of allFiles) {
    const relPath = path.relative(process.cwd(), file)
    const ext = path.extname(file).toLowerCase()
    const languageHint = (() => {
    // Simple heuristic: pick a language name based on extension for display purposes
    switch (ext) {
    case '.js':
    return 'JavaScript'
    case '.ts':
    return 'TypeScript'
    case '.jsx':
    return 'JavaScript (JSX)'
    case '.tsx':
    return 'TypeScript (TSX)'
    case '.php':
    return 'PHP'
    case '.rb':
    return 'Ruby'
    case '.py':
    return 'Python'
    case '.java':
    return 'Java'
    case '.cs':
    return 'C#'
    case '.go':
    return 'Go'
    case '.html':
    return 'HTML'
    case '.css':
    return 'CSS'
    case '.scss':
    case '.sass':
    return 'Sass/SCSS'
    case '.json':
    return 'JSON'
    case '.yml':
    case '.yaml':
    return 'YAML'
    default:
    return 'Code'
    }
    })()

    const code = fs.readFileSync(file, 'utf8')
    blob += `\n\n### File: ${relPath} (${languageHint})\n\`\`\`${languageHint.toLowerCase()}\n${code}\n\`\`\`\n`
    }

    blob += '\n------------------------------------------------------------\n'

    // Copy to clipboard using pbcopy (macOS)
    try {
    execSync('pbcopy', { input: blob })
    console.log('✅ Prompt coipied to clipboard')
    } catch (error) {
    console.error("Failed to copy to clipboard. Here's the blob for reference:\n")
    console.log(blob)
    }
    })()