mini-coder 0.0.4 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -53,7 +53,10 @@ I can also connect to **MCP servers** (like Exa for web search), giving you supe
53
53
  - **Multi-provider** — set `OPENCODE_API_KEY` for Zen, `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `GOOGLE_API_KEY`, or just run Ollama locally. I auto-discover whatever's available.
54
54
  - **Session memory** — conversations are saved in a local SQLite database. Resume where you left off with `-c` or pick a specific session with `-r <id>`.
55
55
  - **Shell integration** — prefix with `!` to run shell commands inline. Use `@` to reference files in your prompt (with Tab completion).
56
- - **Slash commands** — `/model` to switch models, `/plan` for read-only thinking mode, `/ralph` for autonomous looping (agent re-runs your goal with fresh context each iteration until it signals done), `/review` for a code review, `/undo` to roll back a turn, `/new` for a clean session, `/mcp` to manage MCP servers.
56
+ - **Slash commands** — `/model` to switch models, `/plan` for read-only thinking mode, `/ralph` for autonomous looping, `/review` for a code review, `/undo` to roll back a turn, `/new` for a clean session, `/mcp` to manage MCP servers. See all with `/help`.
57
+ - **Custom commands** — drop a `.md` file in `.agents/commands/` and it becomes a `/command`. Supports argument placeholders (`$ARGUMENTS`, `$1`…`$9`) and shell interpolation (`` !`cmd` ``). Global commands live in `~/.agents/commands/`. Custom commands take precedence over built-ins. → [docs/custom-commands.md](docs/custom-commands.md)
58
+ - **Custom agents** — drop a `.md` file in `.agents/agents/` (or `~/.agents/agents/` globally) and reference it with `@agent-name` in your prompt. The agent runs in its own context window with a custom system prompt and optional model override. → [docs/custom-agents.md](docs/custom-agents.md)
59
+ - **Skills** — place a `SKILL.md` in `.agents/skills/<name>/` and inject it into any prompt with `@skill-name`. Skills are *never* auto-loaded — always explicit. → [docs/skills.md](docs/skills.md)
57
60
  - **Post-tool hooks** — drop an executable at `.agents/hooks/post-<tool>` and I'll run it after every matching tool call.
58
61
  - **Beautiful, minimal output** — diffs for edits, formatted trees for file searches, a live status bar with model, git branch, and token counts.
59
62
  - **16 ANSI colors only** — my output inherits *your* terminal theme. Dark mode, light mode, Solarized, Gruvbox — I fit right in.
@@ -64,17 +67,35 @@ I can also connect to **MCP servers** (like Exa for web search), giving you supe
64
67
 
65
68
  - **I eat my own dog food.** I was built *by* a mini-coder agent. It's agents all the way down. 🐢
66
69
  - **I'm tiny but mighty.** The whole runtime is [Bun.js](https://bun.com) — fast startup, native TypeScript, and a built-in SQLite driver.
67
- - **I respect existing conventions.** Hook scripts live in `.agents/hooks/`, context in `AGENTS.md` or `CLAUDE.md` — I follow the ecosystem instead of inventing new standards.
70
+ - **I respect existing conventions.** Hook scripts live in `.agents/hooks/`, context in `AGENTS.md` or `CLAUDE.md`, commands in `.agents/commands/`, agents in `.agents/agents/`, skills in `.agents/skills/` — I follow the ecosystem instead of inventing new standards.
68
71
  - **I spin while I think.** ⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏ (It's the little things.)
69
72
  - **I can clone myself.** The `subagent` tool lets me spin up parallel instances of myself to tackle independent subtasks simultaneously. Divide and conquer! (Up to 3 levels deep.)
70
73
 
71
74
  ---
72
75
 
76
+ ## 📁 The `.agents` folder
77
+
78
+ mini-coder follows the [`.agents` convention](https://github.com/agentsmd/agents) used across the AI coding tool ecosystem. Drop files in `.agents/` to extend behaviour for the current repo, or `~/.agents/` to apply them globally.
79
+
80
+ | Path | What it does |
81
+ |---|---|
82
+ | `.agents/commands/*.md` | Custom slash commands (`/name`) |
83
+ | `.agents/agents/*.md` | Custom agents (`@name`) |
84
+ | `.agents/skills/<name>/SKILL.md` | Reusable skill instructions (`@name`) |
85
+ | `.agents/hooks/post-<tool>` | Scripts run after a tool call |
86
+ | `AGENTS.md` | Project context injected into every system prompt |
87
+
88
+ Local always overrides global. The same `~/.agents/` folder is shared with Claude Code, Opencode, and other compatible tools — skills and agents you write once work everywhere.
89
+
90
+ ---
91
+
92
+
73
93
  ## 🚀 Getting Started
74
94
 
75
95
  ```bash
76
- # Install globally
77
- bun run build && bun add -g mini-coder@file:$(pwd)
96
+ # Install from npm
97
+ bun add -g mini-coder
98
+ # or: npm install -g mini-coder
78
99
 
79
100
  # Set your provider key (pick one — or run Ollama locally)
80
101
  export OPENCODE_API_KEY=your-zen-key # recommended
@@ -137,4 +158,12 @@ I believe the best tools disappear into your workflow. I don't want to be the st
137
158
 
138
159
  ---
139
160
 
161
+ ## 💬 What People Are Saying
162
+
163
+ > "sean this is fucking sick"
164
+ > — [vpr99](https://github.com/vpr99) (eric)
165
+
166
+ ---
167
+
168
+
140
169
  *Built with ❤️ and a healthy obsession with terminal aesthetics.*
@@ -0,0 +1,96 @@
1
+ # Better Errors — Implementation Plan
2
+
3
+ ## Overview
4
+
5
+ Add structured error logging to file and friendly error parsing for display. Three concerns: (1) log full error details to `~/.config/mini-coder/errors.log`, (2) map known AI SDK errors to terse user-facing messages, (3) wire both into existing error surfaces.
6
+
7
+ ---
8
+
9
+ ## Files to Create
10
+
11
+ | File | Purpose |
12
+ |---|---|
13
+ | `src/cli/error-log.ts` | `initErrorLog()`, `logError()` |
14
+ | `src/cli/error-parse.ts` | `parseAppError()` |
15
+
16
+ ## Files to Modify
17
+
18
+ | File | Change |
19
+ |---|---|
20
+ | `src/index.ts` | Call `initErrorLog()` at startup; use `logError` + `parseAppError` in top-level catch and `main().catch()` |
21
+ | `src/cli/output.ts` | Update `renderError(err: unknown)` to call log + parse; update `turn-error` branch in `renderTurn()` |
22
+ | `src/agent/agent.ts` | Pass `unknown` to `renderError()` — no logic change needed if signature widens correctly |
23
+
24
+ ---
25
+
26
+ ## Implementation Steps
27
+
28
+ 1. **Create `src/cli/error-log.ts`**
29
+ - Module-level `let writer: ReturnType<ReturnType<typeof Bun.file>['writer']> | null = null`
30
+ - `initErrorLog()`: if `writer` is not null, return early (idempotency). Otherwise resolve path `~/.config/mini-coder/errors.log`, open with `Bun.file(path).writer()` (truncates on open), assign to `writer`. Register `process.on('uncaughtException', (err) => { logError(err, 'uncaught'); process.exit(1) })`.
31
+ - `logError(err: unknown, context?: string)`: if `writer` is null, return. Build log entry string (see Log Format), call `writer.write(entry)`. Keep sync-ish by not awaiting — `write()` on a Bun file writer is buffered; call `writer.flush()` after each write so data lands before a crash.
32
+ - Extract error fields via type-narrowing helpers (not exported): `isObject(err)`, read `.name`, `.message`, `.stack`, `.statusCode`, `.url`, `.isRetryable` defensively.
33
+
34
+ 2. **Create `src/cli/error-parse.ts`**
35
+ - Import AI SDK error classes: `APICallError`, `RetryError`, `NoContentGeneratedError`, `LoadAPIKeyError`, `NoSuchModelError` from `ai`.
36
+ - Export `parseAppError(err: unknown): { headline: string; hint?: string }`.
37
+ - Implement as a chain of `instanceof` checks (see Error Parse Table). For `RetryError`, recurse on `.lastError` and prepend `"Retries exhausted: "` to `headline`.
38
+ - Fallback: extract first non-empty line of `(err as any)?.message ?? String(err)`, no hint.
39
+ - Network check: before the fallback, check if `(err as any)?.code === 'ECONNREFUSED'` or message includes `'ECONNREFUSED'`.
40
+
41
+ 3. **Update `src/cli/output.ts`**
42
+ - Change `renderError` signature from `(msg: string)` to `(err: unknown)`. Inside: call `logError(err, 'render')`, call `parseAppError(err)`, print `✖ red(headline)`, if `hint` print a dim indented hint line (e.g. ` dim(hint)`).
43
+ - In `renderTurn()` `turn-error` branch (non-abort path): replace raw `event.error.message` display with `logError(event.error, 'turn')` then `parseAppError(event.error)` → print `✖ red(headline)`, optional dim hint. Keep the abort quiet-note branch unchanged.
44
+ - All callers of `renderError` that currently pass a string (e.g. in `agent.ts`) — check each call site; if passing a plain string, wrap in `new Error(string)` or let `parseAppError` fallback handle a string gracefully (add string branch at top of `parseAppError`: `if (typeof err === 'string') return { headline: err }`).
45
+
46
+ 4. **Update `src/index.ts`**
47
+ - After `registerTerminalCleanup()` (or equivalent startup call), add `initErrorLog()`.
48
+ - Top-level `catch` around `runAgent()`: replace any raw print with `logError(err, 'agent')` + `parseAppError(err)` → print `✖ red(headline)` + dim hint, then `process.exit(1)`.
49
+ - `main().catch()`: same pattern — `logError(err, 'main')` + parse + print + `process.exit(1)`. Remove bare `console.error(err)`.
50
+
51
+ 5. **Tests (`src/cli/error-parse.test.ts`)**
52
+ - Test `parseAppError` for each mapped error type.
53
+ - Construct real instances where possible (e.g. `new APICallError({ ... })`); check `headline` and `hint` values.
54
+ - Test `RetryError` unwrapping.
55
+ - Test fallback for plain `Error` and plain string.
56
+ - No mocks, no file I/O, no server calls.
57
+
58
+ ---
59
+
60
+ ## Error Parse Table
61
+
62
+ | Condition | `headline` | `hint` |
63
+ |---|---|---|
64
+ | `APICallError` with `statusCode === 429` | `"Rate limit hit"` | `"Wait a moment and retry, or switch model with /model"` |
65
+ | `APICallError` with `statusCode === 401 \|\| 403` | `"Auth failed"` | `"Check the relevant provider API key env var"` |
66
+ | `APICallError` other | `"API error \${statusCode}"` | `url` if present |
67
+ | `RetryError` | `"Retries exhausted: \${inner.headline}"` | inner `hint` |
68
+ | `NoContentGeneratedError` | `"Model returned empty response"` | `"Try rephrasing or switching model with /model"` |
69
+ | `LoadAPIKeyError` | `"API key not found"` | `"Set the relevant provider env var"` |
70
+ | `NoSuchModelError` | `"Model not found"` | `"Use /model to pick a valid model"` |
71
+ | `code === 'ECONNREFUSED'` or message contains `'ECONNREFUSED'` | `"Connection failed"` | `"Check network or local server"` |
72
+ | `string` input | string value | — |
73
+ | fallback | first line of `err.message` | — |
74
+
75
+ > `AbortError` is never passed to `parseAppError` — abort is handled at the call sites before reaching these functions.
76
+
77
+ ---
78
+
79
+ ## Log Format
80
+
81
+ ```
82
+ [2026-02-25T22:38:53.123Z] context=turn
83
+ name: APICallError
84
+ message: 429 Too Many Requests
85
+ statusCode: 429
86
+ url: https://api.anthropic.com/v1/messages
87
+ isRetryable: true
88
+ stack: APICallError: 429 Too Many Requests
89
+ at ...
90
+ ---
91
+ ```
92
+
93
+ - Each entry ends with `---\n`.
94
+ - Extra fields (`statusCode`, `url`, `isRetryable`) are only emitted if present on the error object.
95
+ - Stack is indented two spaces per line.
96
+ - File is truncated on each app start (writer opened without append flag).