Building a Tool to Stop Copy-Pasting Code to ChatGPT
I got tired of copy-pasting files one by one every time I wanted to ask ChatGPT about my code. You know the drill - you're stuck on something, you paste your React component, ChatGPT says "I need to see your imports and the parent component," so you paste those, then it asks about your routing setup, and suddenly you've spent 10 minutes just getting the AI up to speed on your project.
There had to be a better way. So I built one.
What I Made
My Repository Context Packager is a command-line tool that takes your entire codebase and packages it into one clean text file that you can drop into any AI chat. No more piecemeal explanations or missing context - just run the tool and get everything formatted nicely for AI consumption.
Here's what it spits out:
- Your project's file structure (like a fancy tree view)
- All your code files with proper syntax highlighting blocks
- Git info if you want it (commit hash, branch, who last touched what)
- A summary with file counts and even token estimates
Check it out on GitHub: [Your Repository URL Here]
The whole thing started because I was working on this React project and kept having the same frustrating conversation with ChatGPT. I'd paste a component, it would ask for context, I'd paste five more files, then realize I forgot to include the API utilities... you get the picture.
Building It (And What Went Wrong)
I decided to use TypeScript because, honestly, JavaScript without types on a project this size felt like asking for trouble. Node.js was the obvious choice for file system stuff and git integration.
Here's the basic idea:
# One command to package everything
repo-packager . -o my-code.txt
# Or get fancy with filtering
repo-packager . --include "*.ts,*.jsx" --tokens
CLI Design is Harder Than It Looks
The requirements said "support multiple paths" which sounds simple until you realize people might do:
-
tool .
(current directory) -
tool file1.js file2.ts
(specific files) -
tool ./src ./docs
(multiple directories) -
tool . file.js
(mixed)
I went through like three different approaches before settling on treating everything as an array:
// This handles all the cases without losing my mind
constructor(paths: string | string[], options = {}) {
this.paths = Array.isArray(paths) ? paths : [paths];
}
Simple solutions are usually the right ones, but it took me a while to find this one.
File System Reality Check
Reading files sounds easy until you hit the real world:
- What about binary files? (Skip 'em, but nicely)
- What if a file disappears while you're reading it? (Catch and warn)
- What about that 500MB log file? (Truncate with a note)
- Node_modules with 100k files? (Respect .gitignore, obviously)
I ended up with this layered approach using the glob
library:
const files = await glob(patterns, {
cwd: repoPath,
nodir: true,
ignore: ['node_modules/**', '.git/**', ...gitignorePatterns]
});
The glob library saved me from writing my own directory traversal code, which would have been a rabbit hole.
Git Integration Quirks
Getting git info seemed straightforward - just run some git commands, right? Well, sort of:
const commit = execSync('git rev-parse HEAD', options).toString().trim();
This works great... until someone runs your tool in a directory that isn't a git repo. Or in a repo with no commits. Or on Windows where paths work differently. I spent way too much time making this robust, but it's the kind of thing that separates "works on my machine" from "actually useful."
What I Actually Learned
CLI Tools Are Different
Building a proper command-line tool taught me stuff I didn't expect:
- Only your actual output should go to stdout. Messages, warnings, progress updates? All stderr.
- People expect
--help
and--version
to work. Don't disappoint them. - Exit codes matter. 0 for success, anything else for problems.
- Error messages should tell people what went wrong AND what they can do about it.
File Operations at Scale
I've read files before, but not hundreds at once. This taught me:
- Always use async/await for file operations (blocking the event loop is rude)
- Memory adds up fast when you're holding entire codebases in RAM
- File permissions are a real thing that will bite you
- Cross-platform path handling is annoying but necessary
Git Is More Than Version Control
Using git commands in code was eye-opening. Git isn't just for saving your work - it's a database of project history:
const author = execSync('git log -1 --pretty=format:\'%an <%ae>\'').toString().trim();
const date = execSync('git log -1 --format=%cd').toString().trim();
There's so much metadata locked up in git repos that most tools ignore.
Using It in Real Life
Since I finished this thing, I've actually been using it constantly:
- Debugging that weird React hook behavior? Package the whole component tree and ask Claude.
- Code review prep? Generate a context file and review it myself first.
- Joining a new project? Package it up and ask ChatGPT to explain the architecture.
The token counting feature turned out super useful. Knowing my codebase is 8,000 tokens helps me plan my ChatGPT conversations better.
What's Next
I've got ideas for where to take this:
Better Output Formats: Maybe HTML with collapsible sections, or JSON for other tools to consume.
Smart Selection: Use some basic heuristics to suggest which files are most relevant for different types of questions.
Direct Integration: Skip the copy-paste step entirely - upload straight to ChatGPT or Claude APIs.
Change Analysis: Compare branches and highlight what's different, useful for code reviews.
Real Talk for Other Developers
A few things I wish I'd known starting out:
Start stupid simple. I began with basic file reading and added features one at a time. The "everything at once" approach never works.
Test on your own stuff constantly. I used this tool on my own projects while building it, which caught so many edge cases.
Error messages are product features. When something breaks, a good error message can mean the difference between a user fixing it themselves or giving up.
Documentation isn't optional. I wrote the README before I wrote half the code, which helped me think through the user experience.
Tools are only as good as their adoption. The most elegant code in the world doesn't matter if people can't figure out how to use it.
Why This Mattered to Me
This project combined a bunch of technologies I wanted to get better at (TypeScript, Node.js file operations, CLI design) while solving something that genuinely annoyed me every day. That's the sweet spot - when you're learning new stuff and scratching your own itch at the same time.
The best part has been using it in real work. There's something satisfying about a tool you built becoming part of your daily workflow. It's not revolutionary software, but it saves me time every week, and that adds up.
Building developer tools is interesting because you're building for people who think like you do. They'll try weird edge cases, read your error messages carefully, and notice when things are just slightly off. It makes you a better programmer to have those users.
Give It a Shot
If you're thinking about building CLI tools, just start with something small that bugs you personally. File operations, text processing, git integration - Node.js makes all of this approachable, and TypeScript keeps you honest.
My tool is open source, so grab it and see if it's useful. And if you build something cool to scratch your own itch, let me know - I'm always curious what problems other developers are solving.
GitHub: Repo-Context-Packager. I know the kinda sucks I'll work on that later
The whole experience reminded me why I got into programming in the first place - you see something that could work better, and you can just... build it. That never gets old.
Got questions about the code or ideas for improvements? Hit me up at Clevertag. Always happy to talk about developer tools and CLI design.
Top comments (0)