Category: utilities

Digging into the Claude Code source (and also saved by Sublime Text)

As I mentioned yesterday, Anthropic released Claude Code. I saw it pop up fairly soon after it was announced and downloaded it rather quickly. One thing that I thought was notable was that you install it via npm:

> npm install -g @anthropic-ai/claude-code

As a seasoned TypeScript / JavaScript developer myself, I was excited to take a peek into the (probably minified) source code and see if I could glean any insights into making my own CLI tool. It’s always fun to see how different applications and tools are created.

Sidenote: I’ve been using Aider with great success as of late. It is a fantastic piece of open-source software — it’s another agentic coding tool, written in Python. I’ve been meaning to look under the hood, but building applications with Python definitely is not something that’s ever been in my wheelhouse.

Since Claude Code was installed into my global node_modules folder, I opened things up and immediately found what I was looking for. A 23mb file: cli.mjs.

I click on it, and as expected, it is minified.

Ah, well! I guess I should get on with my–

Wait a minute! What is this: --enable-source-maps?

I scroll through the file and at the bottom, I see what I’m looking for:

//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKIC...

Sublime Text tells me there are 18,360,183 characters selected in that line.

Interesting! Since this part of the file seems to take up such a huge chunk of the original 23mb size, this means that it potentially contains full inline sources — we can rebuild the original source code from scratch!

However, this would have to wait. I had to take Benson to a vet appointment. I throw my laptop in a bag and head out.

While in the waiting room at the vet, I noticed a message in my terminal from Claude Code, telling me “Update installed, restart to apply.

Hey, I love fresh software! So, I restart the app and go on my merry way. Benson finishes his appointment and I head back home.

Later that evening, I open up my machine and decide to open up the Claude Code folder again to start taking a look at the source code. I already had Sublime running from my earlier escapades, but out of habit I click on the file in Finder and open it up again in Sublime. I scroll down to the bottom of cli.mjs and see… nothing. The sourceMappingURL string was gone!

Apparently, the fine folks at Anthropic realized they made a huge oopsie and pushed an update to remove the source map. No matter! I’ll just head over to NPM to download an earlier version of the packa- oh! They removed that, too! History was being wiped away before my very eyes.

As a last resort, I decide to check my npm cache. I know it exists, I just don’t know how to access it. So, I head over to ChatGPT (sorry, Claude — I’m a bit miffed with you at the moment) to get myself some handy knowledge:

> grep -R "claude-code" ~/.npm/_cacache/index-v5

We run it and see:

/Users/daves/.npm/_cacache/index-v5/52/9d/8563b3040bf26f697f081c67231e28e76f1ee89a0a4bcab3343e22bf846b:1d2ea01fc887d7e852cc5c50c1a9a3339bfe701f	{"key":"make-fetch-happen:request-cache:https://registry.npmjs.org/@anthropic-ai/claude-code/-/claude-code-0.2.9.tgz","integrity":"sha512-UGSEQbgDvhlEXC8rf5ASDXRSaq6Nfd4owY7k9bDdRhX9N5q8cMN+5vfTN1ezZhBcRFMOnpEK4eRSEgXW3eDeOQ==","time":1740430395073,"size":12426984,"metadata":{"time":1740430394350,"url":"https://registry.npmjs.org/@anthropic-ai/claude-code/-/claude-code-0.2.9.tgz","reqHeaders":{},"resHeaders":{"cache-control":"public, must-revalidate, max-age=31557600","content-type":"application/octet-stream","date":"Mon, 24 Feb 2025 20:53:14 GMT","etag":"\"e418979ea5818a01d8521c4444121866\"","last-modified":"Mon, 24 Feb 2025 20:50:13 GMT","vary":"Accept-Encoding"},"options":{"compress":true}}}
/Users/daves/.npm/_cacache/index-v5/e9/3d/23a534d1aba42fbc8872c12453726161938c5e09f7683f7d2a6e91d5f7a5:994d4c4319d624cdeff1de6b06abc4fab37351c3	{"key":"make-fetch-happen:request-cache:https://registry.npmjs.org/@anthropic-ai/claude-code/-/claude-code-0.2.8.tgz","integrity":"sha512-HUWSdB42W7ePUkvWSUb4PVUeHRv6pbeTCZYOeOZFmaErhmqkKXhVcUmtJQIsyOTt45yL/FGWM+aLeVSJznsqvg==","time":1740423101718,"size":16886762,"metadata":{"time":1740423099892,"url":"https://registry.npmjs.org/@anthropic-ai/claude-code/-/claude-code-0.2.8.tgz","reqHeaders":{},"resHeaders":{"cache-control":"public, must-revalidate, max-age=31557600","content-type":"application/octet-stream","date":"Mon, 24 Feb 2025 18:51:39 GMT","etag":"\"c55154d01b28837d7a3776daa652d5be\"","last-modified":"Mon, 24 Feb 2025 18:38:10 GMT","vary":"Accept-Encoding"},"options":{"compress":true}}}
/Users/daves/.npm/_cacache/index-v5/41/c5/4270bf1cd1aae004ed6fee83989ac428601f4c060987660e9a1aef9d53b6:fafd3a8f86ee5c463eafda7c481f2aedeb106b6f	{"key":"make-fetch-happen:request-cache:https://registry.npmjs.org/@anthropic-ai%2fclaude-code","integrity":"sha512-ctyMJltXByT93UZK2zuC3DTQHY7O99wHH85TnzcraUJLMbWw4l86vj/rNWtQXnaOrWOQ+e64zH50rNSfoXSmGQ==","time":1740442959315,"size":4056,"metadata":{"time":1740442959294,"url":"https://registry.npmjs.org/@anthropic-ai%2fclaude-code","reqHeaders":{"accept":"application/json"},"resHeaders":{"cache-control":"public, max-age=300","content-encoding":"gzip","content-type":"application/json","date":"Tue, 25 Feb 2025 00:22:39 GMT","etag":"W/\"02f3d2cbd30f67b8a886ebf81741a655\"","last-modified":"Mon, 24 Feb 2025 20:54:05 GMT","vary":"accept-encoding, accept"},"options":{"compress":true}}}

Your eyes may glaze over, but what that big wall of text tells me is that a reference to claude-code-0.2.8.tgz exists within my cache. Brilliant!

More ChatGPT chatting (again, still smarting over this whole thing in the first place) and I get a nifty bash script to help extract the cached file. Only to find… they purged it from the npm cache. Noooooooooooo!

I stare at my computer screen in defeat. You got me this time, Anthropic.

As I decide to shut things down for the night, I’m tabbing through my open applications and get to Sublime Text, which is still open to cli.mjs. On a whim, I decide to try something: ⌘ + Z.

And there it is. The Holy Grail. The source map string.

And wouldn’t you know, it had a lot of interesting stuff! Due to the nature of parsing the source map, nothing is organized, but it’s still kind of fun to look through.

A few things struck me:

  • It’s written in React (!) using an interesting tool called Ink (this allows you to create CLI apps using React). I hadn’t used Ink before but this looks like a lot of fun.
  • While processing requests, Claude Code will show a nifty animated asterisk. I wondered how they did this, since (AFAIK) those aren’t standard unicode characters. claude-asterisk-ascii-art.tsx is the answer to that!
  • In terms of system prompts, there’s no secret sauce to leak that you can’t already read by just looking at the minified JS file.
  • These files are probably going to go out of date pretty dang quick, as the Anthropic team is actively developing the tool. As of right now, it’s already up to v2.19. This whole post was trying to look at the source code for v2.8, which went live yesterday.
  • Lastly, I look forward to receiving my Anthropic stickers… before everyone else.

Quickly bootstrapping a new Node.js project

A problem that often happens to me: I get the inspiration to whip up something in Node.js  (for fun, for experimentation, for a side project, etc) but then I realize that I need to go through the process of actually setting things up before I can even start writing some code.

Usually, I have to dig through previous projects and copy over my eslint and prettier config files, read through some documentation and remember how to setup TypeScript again, install the correct dependencies for running tests. Before I know it, I’m bored and tired and no longer interested in doing whatever I was going to do.

I decided to experiment with some command line tools and created a Node.js script that can help me quickly bootstrap a new project with common configuration parameters that I use. It’s available on GitHub: Bootstrap Node Project.

The GIF above shows this tool in action. I’m able to get the scaffolding for a new project up and running within about 20 seconds! After running, the project structure looks like this (with associated npm start and test scripts, all ready to go). That is pretty awesome.

my-cool-project/
├─ .husky/
├─ node_modules/
├─ src/
│ ├─ index.js (.ts)
│ ├─ index.test.js (.ts)
├─ .eslintrc.json
├─ .gitignore
├─ .prettierrc
├─ package-lock.json
├─ package.json
├─ README.md
├─ tsconfig.json (optional)

Obviously, it’s highly opinionated and caters to configuration options that I personally like to use. But I figure it’s a great resource for anyone who wishes to roll their own utility to quickly bootstrap projects as well.

 

Setting up tests using Tape

Test driven development has become an important process in the software engineering world. It allows coders to develop functions by first creating a series of tests that the new function must solve. The benefit of this is that once your app grows more complex and you add new functionality, you can see if any existing tests have failed, meaning that something broke (and now you know where to find it). Look no further than any popular project on Github and you’ll often see a “tests” folder.

Today, we’re going to talk about setting up tests using Tape.

Tape is an alternative to popular testing suites such as Jasmine and Mocha. Like any tool related to software engineering, there are some developers that strongly prefer Tape over other options. It’s fairly easy to setup and can easily be run in automated task runner tools such as Grunt and Gulp.

To use it as part of your project, you can install it through npm:

  npm install tape --save-dev

Once it’s been added as part of your project, you can create a new tests.js file and require the module.

For our demonstration, we’re going to write a simple test that checks if my name is Dave, plus a few additional parameters.

Start off by setting up your test.js file like so (you can name it whatever you prefer). I’ve commented the code for some additional clarity on what’s happening here.

// Require the Tape module imported from npm
var test = require('tape');

// Write your tests in the code block
test('All about Dave', function (t) {
    // The number of tests that you plan to run.
    // NOTE: If this number doesn't match up with the number
    // of tests that are run, your test will fail.
    t.plan(2);
    
    // Let's setup some variables to test
    var name = "Seymore";
    var city = "Oakland";
    var favBaseballTeam = "Athletics";

    // This test will check for my favorite baseball team.
    // The first parameter is the result, the second is
    // the value you're expecting, and the third is the message
    t.equal(favBaseballTeam, "Athletics", "Favorite baseball team should be Athletics");

    // This test will check for my name.
    // As you can probably assume, it will fail.
    t.equal(name, "Dave", "Name should be Dave");

    // This test will check if city has been set:
    if (city) {
      t.pass("City set");
    } else {
      t.fail("City not set");
    }
});

That’s it! You can run Tape from your terminal and point it to your newly created test.js file in order to run it.

Screenshot 2015-09-01 14.00.18

A favorite Sublime Text shortcut: moving lines of code

3Ga4NL2mdm

Sublime Text is an indispensable tool to have in your arsenal of web development goodies. There’s a nearly infinite amount of shortcuts and tricks one can use to improve their workflow.

One of my favorite shortcuts is moving either lines (or entire blocks) of code up or down a page without cutting and pasting all over the place.

Simply select the line (or multiple lines of code) that you want to move, then simply hit

CONTROL + CMD + (Up or Down arrows) on OS X
CONTROL + SHIFT + (Up or Down arrows) on Windows

I guarantee if you do this in front of your friends or family, you will look like a wizard.