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 +33 -4
- package/better-errors.md +96 -0
- package/dist/mc.js +574 -242
- package/docs/configs.md +77 -0
- package/docs/custom-agents.md +70 -0
- package/docs/custom-commands.md +133 -0
- package/docs/skills.md +71 -0
- package/docs/tool-hooks.md +142 -0
- package/package.json +1 -1
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
|
|
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
|
|
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
|
|
77
|
-
bun
|
|
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.*
|
package/better-errors.md
ADDED
|
@@ -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).
|