You are browsing as a guest. Sign up (or log in) to start making projects!

CLI Calculator

  • 5 Devlogs
  • 12 Total hours

An interactive CLI-based computation tool built with Node.js that supports both command-driven operations and direct mathematical expressions, featuring result memory, advanced math functions, persistent history, and a REPL-based interface.

Open comments for this post

4h 38m 42s logged

Devlog 5 — Expressions, Memory and a Real “Calculator Feel”


What I learned:

  • How to evaluate user input dynamically using Function() (and why it needs to be handled carefully)
  • How to replace parts of user input using regex.
  • How to structure commands when the number of arguments isn’t always fixed (min/max validation)
  • How small UX details (like colors using chalk) make a big difference in usability
  • How to maintain state across a REPL session
  • How to design a fallback system where unknown commands are treated as expressions

Biggest struggle:

This one was definitely more complex than the previous days.

The hardest part was adding expression evaluation.
Using something like Function() to evaluate user input felt powerful but also risky and confusing at first. Making sure it doesn’t break on invalid input and handling errors properly took some time. Another tricky part was implementing a feature (ans) that lets you reuse the previous result in new calculations. Ensuring it worked consistently across both commands and expressions required careful handling of user input. Replacing it correctly in user input without breaking other words or expressions required using regex carefully.

Also, as the number of commands grew, validation started getting messy. Switching to a min/max argument system helped but it took a bit of thinking to get right. This stage felt less like “just coding” and more like designing how the calculator should behave.


Current features:

  • Full REPL-based interactive CLI

  • Support for both commands and direct expressions:

    add 2 3
    2 + 3 * 4
    
  • ans keyword to reuse the previous result

  • Expanded math operations:

    • Trigonometry (sin, cos, tan)
    • Logarithms (ln, log)
    • Factorial (fact)
    • Rounding (round, ceil, floor)
    • Absolute value (abs)
  • Improved validation with flexible argument handling (min/max support)

  • Persistent history with timestamps

  • Optional history limit (history n)

  • Colored and structured output using chalk

  • Better error handling for invalid commands and expressions


Next steps:

  • Improve expression parsing (support more complex cases safely)
  • Possibly replace Function() with a safer custom parser
  • Add command chaining or multi-step calculations
  • Improve UI further (custom prompt, better formatting)
  • Maybe create a simple web version for easier demo access

Reflection:

This version feels like a big step forward. Before, the calculator was command-based and structured. Now it feels much more natural and flexible, especially with expressions and the ans feature. It’s starting to behave like an actual calculator instead of just a program that runs specific commands.


At the same time, the complexity is definitely increasing. It’s getting harder to manage everything cleanly which makes me realize how important structure and planning are as projects grow. It’s not perfect but it finally feels like something I could actually use. Not just something I built to learn.

Devlog 5 — Expressions, Memory and a Real “Calculator Feel”


What I learned:

  • How to evaluate user input dynamically using Function() (and why it needs to be handled carefully)
  • How to replace parts of user input using regex.
  • How to structure commands when the number of arguments isn’t always fixed (min/max validation)
  • How small UX details (like colors using chalk) make a big difference in usability
  • How to maintain state across a REPL session
  • How to design a fallback system where unknown commands are treated as expressions

Biggest struggle:

This one was definitely more complex than the previous days.

The hardest part was adding expression evaluation.
Using something like Function() to evaluate user input felt powerful but also risky and confusing at first. Making sure it doesn’t break on invalid input and handling errors properly took some time. Another tricky part was implementing a feature (ans) that lets you reuse the previous result in new calculations. Ensuring it worked consistently across both commands and expressions required careful handling of user input. Replacing it correctly in user input without breaking other words or expressions required using regex carefully.

Also, as the number of commands grew, validation started getting messy. Switching to a min/max argument system helped but it took a bit of thinking to get right. This stage felt less like “just coding” and more like designing how the calculator should behave.


Current features:

  • Full REPL-based interactive CLI

  • Support for both commands and direct expressions:

    add 2 3
    2 + 3 * 4
    
  • ans keyword to reuse the previous result

  • Expanded math operations:

    • Trigonometry (sin, cos, tan)
    • Logarithms (ln, log)
    • Factorial (fact)
    • Rounding (round, ceil, floor)
    • Absolute value (abs)
  • Improved validation with flexible argument handling (min/max support)

  • Persistent history with timestamps

  • Optional history limit (history n)

  • Colored and structured output using chalk

  • Better error handling for invalid commands and expressions


Next steps:

  • Improve expression parsing (support more complex cases safely)
  • Possibly replace Function() with a safer custom parser
  • Add command chaining or multi-step calculations
  • Improve UI further (custom prompt, better formatting)
  • Maybe create a simple web version for easier demo access

Reflection:

This version feels like a big step forward. Before, the calculator was command-based and structured. Now it feels much more natural and flexible, especially with expressions and the ans feature. It’s starting to behave like an actual calculator instead of just a program that runs specific commands.


At the same time, the complexity is definitely increasing. It’s getting harder to manage everything cleanly which makes me realize how important structure and planning are as projects grow. It’s not perfect but it finally feels like something I could actually use. Not just something I built to learn.

Replying to @AidenHammy

0
1
Open comments for this post

1h 47m 46s logged

Devlog 4 — Making it Interactive (REPL + UX Improvements)

What I learned:

  • How to use readline to keep the program running and take input again and again
  • The difference between a script that runs once vs something interactive
  • How small UX things (like input formatting and cleaner output) actually matter a lot
  • How to handle messy user input using trim() and split(/\s+/)
  • How to structure code so it doesn’t become a mess when it keeps running in a loop

Biggest struggle:

This part wasn’t “hard” in the usual sense but it was confusing at first.

Before this, my program would just run once and end. Now it stays alive and that changes how everything works. I had to think differently about how commands are handled because now the same logic runs over and over again.

Input handling was also kind of annoying. Even small things like extra spaces could break stuff which forced me to actually deal with it properly instead of ignoring it.

Another thing was output. At some points it felt too cluttered and at others it felt like not enough information was being shown. Finding a balance there took a bit of trial and error.


Current features:

  • REPL system using readline (no need to restart the program every time)

  • Continuous input like a real CLI

  • Support for both commands and symbols (add + +, etc.)

  • Better input handling (spaces don’t break things anymore)

  • Validation for:

    • wrong number of arguments
    • invalid numbers
    • division by zero
    • square root of negative numbers
  • Cleaner output (less unnecessary logs)

  • History system:

    • saved to history.txt
    • can view with history
    • can reset with clear
  • cls to clear the screen

  • exit to quit the program


Next steps:

  • Support actual expressions like 2 + 3 * 4 instead of strict commands
  • Make history a bit smarter (maybe timestamps or search)
  • Reduce repeated logic even more
  • Add vector/matrix operations
  • Add autocomplete for commands
  • Add colored terminal output

Reflection:

This is probably the first version that actually feels like a real program.

The REPL made a huge difference. Before, it felt like I was just testing functions. Now it actually feels like something you can use.

Most of the improvements in this version aren’t big features, but small things that make the experience smoother. Stuff like handling spaces properly or adding aliases doesn’t sound like much but it changes how the program feels.

I’m starting to notice that building something usable is very different from just making something work.

It’s still simple and there’s a lot more I could improve but this is the first time the calculator feels complete in its own way.

Devlog 4 — Making it Interactive (REPL + UX Improvements)

What I learned:

  • How to use readline to keep the program running and take input again and again
  • The difference between a script that runs once vs something interactive
  • How small UX things (like input formatting and cleaner output) actually matter a lot
  • How to handle messy user input using trim() and split(/\s+/)
  • How to structure code so it doesn’t become a mess when it keeps running in a loop

Biggest struggle:

This part wasn’t “hard” in the usual sense but it was confusing at first.

Before this, my program would just run once and end. Now it stays alive and that changes how everything works. I had to think differently about how commands are handled because now the same logic runs over and over again.

Input handling was also kind of annoying. Even small things like extra spaces could break stuff which forced me to actually deal with it properly instead of ignoring it.

Another thing was output. At some points it felt too cluttered and at others it felt like not enough information was being shown. Finding a balance there took a bit of trial and error.


Current features:

  • REPL system using readline (no need to restart the program every time)

  • Continuous input like a real CLI

  • Support for both commands and symbols (add + +, etc.)

  • Better input handling (spaces don’t break things anymore)

  • Validation for:

    • wrong number of arguments
    • invalid numbers
    • division by zero
    • square root of negative numbers
  • Cleaner output (less unnecessary logs)

  • History system:

    • saved to history.txt
    • can view with history
    • can reset with clear
  • cls to clear the screen

  • exit to quit the program


Next steps:

  • Support actual expressions like 2 + 3 * 4 instead of strict commands
  • Make history a bit smarter (maybe timestamps or search)
  • Reduce repeated logic even more
  • Add vector/matrix operations
  • Add autocomplete for commands
  • Add colored terminal output

Reflection:

This is probably the first version that actually feels like a real program.

The REPL made a huge difference. Before, it felt like I was just testing functions. Now it actually feels like something you can use.

Most of the improvements in this version aren’t big features, but small things that make the experience smoother. Stuff like handling spaces properly or adding aliases doesn’t sound like much but it changes how the program feels.

I’m starting to notice that building something usable is very different from just making something work.

It’s still simple and there’s a lot more I could improve but this is the first time the calculator feels complete in its own way.

Replying to @AidenHammy

0
4
Open comments for this post

2h 5m 3s logged

Devlog 3 — Persistence and Control (File-based History + Clear Command)

What I learned:

  • Why CLI programs reset completely every time they are executed
  • How to use the fs module to write and read files in Node.js
  • How appendFileSync can be used to store data incrementally
  • How to read stored data using readFileSync
  • The difference between in-memory state and persistent state
  • How small bugs (like variable naming or extra trims) can break logic in subtle ways
  • Why validation, execution and side effects (like saving history) should stay separated

Biggest struggle:

This part was less chaotic than Day 2 but still frustrating in a different way.

The logic itself wasn’t the problem this time. It was understanding how programs behave over time. I had already built a history system before so seeing it disappear every run was confusing at first.

Then came the file system part. Writing to a file felt simple but reading it back properly and formatting it without breaking things took more effort than expected. Small mistakes like misnaming variables or structuring loops incorrectly kept causing issues.

It wasn’t overwhelming chaos but more like constant small friction that slowed everything down.


Current features:

  • Persistent history system using fs
  • Calculations are stored in history.txt across runs
  • history command displays formatted past calculations
  • clear command wipes stored history clean
  • Improved validation and error messages
  • Clean separation between parsing, validation and execution

Next steps:

  • Convert the calculator into an interactive CLI (REPL-style)
  • Reduce repeated validation logic into reusable helpers
  • Improve overall UX (cleaner outputs and command feedback)

Reflection:

The biggest realization was understanding that programs don’t remember anything unless you explicitly store it. That changed how I think about state completely.

Compared to earlier struggles, this one felt quieter but still tiring. Less confusion, more persistence. Fixing small issues, understanding behavior and slowly making things more stable.

It still isn’t perfect but it finally feels like the calculator has some sense of continuity instead of resetting every time.

Note: The screenshot does not show all features (full validation system).

Devlog 3 — Persistence and Control (File-based History + Clear Command)

What I learned:

  • Why CLI programs reset completely every time they are executed
  • How to use the fs module to write and read files in Node.js
  • How appendFileSync can be used to store data incrementally
  • How to read stored data using readFileSync
  • The difference between in-memory state and persistent state
  • How small bugs (like variable naming or extra trims) can break logic in subtle ways
  • Why validation, execution and side effects (like saving history) should stay separated

Biggest struggle:

This part was less chaotic than Day 2 but still frustrating in a different way.

The logic itself wasn’t the problem this time. It was understanding how programs behave over time. I had already built a history system before so seeing it disappear every run was confusing at first.

Then came the file system part. Writing to a file felt simple but reading it back properly and formatting it without breaking things took more effort than expected. Small mistakes like misnaming variables or structuring loops incorrectly kept causing issues.

It wasn’t overwhelming chaos but more like constant small friction that slowed everything down.


Current features:

  • Persistent history system using fs
  • Calculations are stored in history.txt across runs
  • history command displays formatted past calculations
  • clear command wipes stored history clean
  • Improved validation and error messages
  • Clean separation between parsing, validation and execution

Next steps:

  • Convert the calculator into an interactive CLI (REPL-style)
  • Reduce repeated validation logic into reusable helpers
  • Improve overall UX (cleaner outputs and command feedback)

Reflection:

The biggest realization was understanding that programs don’t remember anything unless you explicitly store it. That changed how I think about state completely.

Compared to earlier struggles, this one felt quieter but still tiring. Less confusion, more persistence. Fixing small issues, understanding behavior and slowly making things more stable.

It still isn’t perfect but it finally feels like the calculator has some sense of continuity instead of resetting every time.

Note: The screenshot does not show all features (full validation system).

Replying to @AidenHammy

0
4
Open comments for this post

3h 2m 28s logged

Devlog 2 — CLI Calculator Upgrade (Validation + History System)

What I set out to build:

Upgrade the CLI calculator into something more structured and “real tool-like” by adding proper input validation improving command handling and introducing a history system.


What I learned:

  • How to structure validation into layers (arity type domain)
  • How CLI arguments actually behave — missing inputs simply don’t exist in the array
  • How to use slice() + map(Number) to normalize input in one step
  • Why separating parsing validation and execution simplifies reasoning
  • How function hoisting allows referencing functions before declaration
  • How to maintain in-memory state using arrays
  • How for loops and forEach help format structured output
  • How small design choices like a numbers array simplify architecture

Biggest struggle:

This part was genuinely exhausting.

I kept getting stuck on when validation should happen and what exactly needed to be validated. I was duplicating checks mixing raw CLI arguments with parsed numbers and constantly second-guessing my logic.

I also misunderstood CLI arguments. I expected missing inputs to appear as undefined which made my validation more complicated than necessary.

The worst part was the flow. Everything felt tangled. Command lookup parsing validation execution like it was happening all at once. Even when the code worked I didn’t fully trust it which made the whole process frustrating.


Current features:

  • Command routing using a function map (commands[cmd])
  • Argument validation based on expected counts
  • Clean input parsing using slice() and map(Number)
  • Domain rules (division by zero negative square roots)
  • Scientific operations: sqrt pow log
  • In-memory history system
  • history command for session logs
  • Improved help command
  • More consistent error handling

Next steps:

  • Persist history to a file
  • Refactor validation into helper functions
  • Improve error messages

Reflection:

This stage felt like a shift from “writing code” to “understanding how programs behave.”

Validation was mentally draining. I kept mixing up arity type and domain rules and the code felt like a pile of checks instead of a system. It worked but I didn’t trust it.

The biggest reality check was the history system. I built it saw it work then ran another command and everything was gone. That’s when it clicked. CLI programs don’t persist memory. Every run starts fresh.

That was the most important lesson. Not everything you build “stays” unless you store it. It changed how I think about programs.

By the end the calculator is still simple but my understanding of structure and flow is much stronger. It feels less like guessing and more like knowing what I’m doing.

Note: The screenshot only shows a basic run and does not include all implemented features (validation command handling improvements and history tracking).

Devlog 2 — CLI Calculator Upgrade (Validation + History System)

What I set out to build:

Upgrade the CLI calculator into something more structured and “real tool-like” by adding proper input validation improving command handling and introducing a history system.


What I learned:

  • How to structure validation into layers (arity type domain)
  • How CLI arguments actually behave — missing inputs simply don’t exist in the array
  • How to use slice() + map(Number) to normalize input in one step
  • Why separating parsing validation and execution simplifies reasoning
  • How function hoisting allows referencing functions before declaration
  • How to maintain in-memory state using arrays
  • How for loops and forEach help format structured output
  • How small design choices like a numbers array simplify architecture

Biggest struggle:

This part was genuinely exhausting.

I kept getting stuck on when validation should happen and what exactly needed to be validated. I was duplicating checks mixing raw CLI arguments with parsed numbers and constantly second-guessing my logic.

I also misunderstood CLI arguments. I expected missing inputs to appear as undefined which made my validation more complicated than necessary.

The worst part was the flow. Everything felt tangled. Command lookup parsing validation execution like it was happening all at once. Even when the code worked I didn’t fully trust it which made the whole process frustrating.


Current features:

  • Command routing using a function map (commands[cmd])
  • Argument validation based on expected counts
  • Clean input parsing using slice() and map(Number)
  • Domain rules (division by zero negative square roots)
  • Scientific operations: sqrt pow log
  • In-memory history system
  • history command for session logs
  • Improved help command
  • More consistent error handling

Next steps:

  • Persist history to a file
  • Refactor validation into helper functions
  • Improve error messages

Reflection:

This stage felt like a shift from “writing code” to “understanding how programs behave.”

Validation was mentally draining. I kept mixing up arity type and domain rules and the code felt like a pile of checks instead of a system. It worked but I didn’t trust it.

The biggest reality check was the history system. I built it saw it work then ran another command and everything was gone. That’s when it clicked. CLI programs don’t persist memory. Every run starts fresh.

That was the most important lesson. Not everything you build “stays” unless you store it. It changed how I think about programs.

By the end the calculator is still simple but my understanding of structure and flow is much stronger. It feels less like guessing and more like knowing what I’m doing.

Note: The screenshot only shows a basic run and does not include all implemented features (validation command handling improvements and history tracking).

Replying to @AidenHammy

0
6
Open comments for this post

55m 47s logged

Devlog 1 — Building a CLI Calculator

What I set out to build :

A command-based CLI calculator using Node.js that can take input directly from the terminal and perform operations like addition, subtraction multiplication and division.


What I learned:

  • How process.argv works for handling command-line input

  • Why "5" + "3" results in "53" (strings vs numbers in JavaScript)

  • How to convert inputs properly using Number()

  • The difference between calling a function and referencing it

  • How to implement a command map using commands[cmd]()


Biggest struggle:

Understanding how to structure the command system cleanly without relying on long and messy if/else chains.


Breakthrough moment:

Realizing that I could store functions inside an object and dynamically execute them based on user input. That made the whole system feel much cleaner and scalable.


Current features:

  • Supports add, sub, mul and div commands
  • Handles invalid commands with basic error messaging
  • Uses a command map for cleaner execution logic

Next steps:

  • Add scientific functions like sqrt, pow, and log
  • Improve input validation
  • Potentially add a history system

Reflection:

Started this knowing almost nothing about CLI tools or Node.js input handling and ended up building a working command-based system. It’s simple but it actually feels like the foundation of something bigger.

Devlog 1 — Building a CLI Calculator

What I set out to build :

A command-based CLI calculator using Node.js that can take input directly from the terminal and perform operations like addition, subtraction multiplication and division.


What I learned:

  • How process.argv works for handling command-line input

  • Why "5" + "3" results in "53" (strings vs numbers in JavaScript)

  • How to convert inputs properly using Number()

  • The difference between calling a function and referencing it

  • How to implement a command map using commands[cmd]()


Biggest struggle:

Understanding how to structure the command system cleanly without relying on long and messy if/else chains.


Breakthrough moment:

Realizing that I could store functions inside an object and dynamically execute them based on user input. That made the whole system feel much cleaner and scalable.


Current features:

  • Supports add, sub, mul and div commands
  • Handles invalid commands with basic error messaging
  • Uses a command map for cleaner execution logic

Next steps:

  • Add scientific functions like sqrt, pow, and log
  • Improve input validation
  • Potentially add a history system

Reflection:

Started this knowing almost nothing about CLI tools or Node.js input handling and ended up building a working command-based system. It’s simple but it actually feels like the foundation of something bigger.

Replying to @AidenHammy

0
2

Followers

Loading…