Metadata-Version: 2.4
Name: brojustcode
Version: 0.1.0
Summary: BroJustCode AI coding agent
Author: Your Name
Requires-Python: >=3.10
Description-Content-Type: text/markdown

# Nightcode

A from-scratch clone of the Claude Code CLI: a terminal agent that uses
tool-calling in a loop to read, write, edit, search, and lint code, run
shell commands, and drive git — all from natural language. Powered by the
**Mistral API**.

## Project layout

```
nightcode/
├── main.py                # entry point (loads .env, starts the CLI)
├── server.py               # local HTTP API for the web UI (localhost only)
├── nightcode_ui.html        # browser chat UI — talks to server.py
├── requirements.txt
├── .env.example            # template for your key — copy to .env
├── .gitignore               # keeps .env, logs, and caches out of git
│
├── config/
│   └── settings.py          # all settings — reads env vars, nothing hardcoded
│
├── core/
│   ├── agent.py              # main conversation loop + CLI I/O
│   └── logger.py             # writes each session's transcript to logs/
│
├── tools/                    # every capability the agent has, one file each
│   ├── __init__.py            # aggregates all tool schemas + dispatch
│   ├── files.py                # read_file, write_file, edit_file, list_dir
│   ├── shell.py                 # run_bash
│   ├── git_ops.py               # git_status, git_diff, git_log, git_commit
│   ├── search.py                 # search_code (recursive grep/regex)
│   ├── lint.py                    # lint_file (flake8, or syntax-only fallback)
│   └── web.py                      # fetch_url (no API key needed)
│
└── logs/                     # JSON transcript per session (git-ignored)
```

## Setup

```bash
pip install -r requirements.txt
cp .env.example .env        # Windows: copy .env.example .env
```

Open `.env` and paste in your real key:
```
MISTRAL_API_KEY=your-real-key-here
```

Get a key at https://console.mistral.ai/api-keys — Mistral's free tier
(`mistral-small-latest`) is generous enough for this kind of agent use.

Then run:
```bash
python main.py
```

### Without .env (setting the var directly)

**PowerShell:**
```powershell
$env:MISTRAL_API_KEY = "your-key"
python main.py
```

**bash/zsh:**
```bash
export MISTRAL_API_KEY=your-key
python main.py
```

### Security

- Your key is only ever read from an environment variable (or `.env`,
  loaded via `python-dotenv`). It is never written into any source file.
- `.env` is git-ignored — don't remove that line from `.gitignore`.
- If a key is ever exposed (pasted in chat, committed to a repo,
  screenshotted), revoke and regenerate it immediately at the link above.

## Web UI (chat in your browser instead of the terminal)

Nightcode also ships a browser-based chat UI that talks to a small local
server, which wraps the same agent. Your API key never leaves the server —
the browser only ever talks to `127.0.0.1`.

```bash
python server.py
```

Leave that running, then open `nightcode_ui.html` directly in your browser
(double-click it, or `start nightcode_ui.html` on Windows). It connects
automatically and shows a green "Connected" status once it can reach the
server. Type in the input box and hit Enter — same agent, same tools, same
conversation memory as the CLI, just a different front end.

**Security — read this before running `server.py`:**
- The server executes shell commands and reads/writes files based on
  whatever the agent decides to do in response to a message. It binds to
  `127.0.0.1` (localhost) only, on purpose — do **not** change this to
  `0.0.0.0` or otherwise expose the port to your network or the internet.
  Anyone who can reach it can run commands on your machine through it.
- `nightcode_ui.html` is a static file with no build step — you can open
  it straight from disk (`file://`), no separate web server needed.

## Choosing a model

Default is `mistral-small-latest`. Override in `.env` or your shell:
```
NIGHTCODE_MODEL=mistral-large-latest
```

## Tools available to the agent

| Tool          | What it does                                                    |
|---------------|-------------------------------------------------------------------|
| `read_file`   | Read a file's contents with line numbers                        |
| `write_file`  | Create a file or fully overwrite an existing one                |
| `edit_file`   | Exact string find-and-replace within a file (unique match)      |
| `list_dir`    | List a directory's contents                                     |
| `run_bash`    | Run a shell command (60s timeout) and return stdout/stderr      |
| `git_status`  | Show working tree status                                        |
| `git_diff`    | Show unstaged or staged changes                                 |
| `git_log`     | Show recent commit history                                      |
| `git_commit`  | Stage all changes and commit with a message                     |
| `search_code` | Recursively grep/regex-search files for a pattern               |
| `lint_file`   | Syntax-check a file (flake8 if installed, else py_compile)      |
| `fetch_url`   | Fetch raw text/JSON from a URL — no API key required             |

## Session logs

Every session writes a JSON transcript to `logs/session_<timestamp>.json` —
every user message, assistant reply, and tool call (with args and result)
is recorded. Useful for debugging or reviewing what the agent actually did.
Log files are git-ignored by default since they may contain file contents
from your project.

## Adding a new tool

1. Create `tools/your_module.py` with:
   - a `SCHEMAS` list (OpenAI function-calling format)
   - a `DISPATCH` dict mapping `{"tool_name": lambda args: ...}`
2. Register the module in `tools/__init__.py`'s `_MODULES` list.

That's it — `agent.py` picks up new tools automatically via the aggregator.

## Notes / limitations

This is a compact educational clone, not a production tool:
- No sandboxing — `run_bash` and `git_commit` execute real commands with
  your permissions. Review destructive actions before confirming.
- No streaming output — responses print once the API call completes.
- `lint_file` only fully lints Python; other file types get a syntax/
  existence check at most.
- `search_code` is a plain-Python regex walker, not as fast as `ripgrep`
  on very large repos, but has no external dependency.
