mini-coder 0.1.0 โ†’ 0.1.2

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.
@@ -1,32 +1,45 @@
1
1
  {
2
- "permissions": {
3
- "allow": [
4
- "WebSearch",
5
- "WebFetch(domain:github.com)",
6
- "WebFetch(domain:dev.to)",
7
- "WebFetch(domain:mariozechner.at)",
8
- "WebFetch(domain:lobste.rs)",
9
- "WebFetch(domain:reading.sh)",
10
- "WebFetch(domain:daveswift.com)",
11
- "Bash(grep:*)",
12
- "Bash(ls:*)",
13
- "Bash(bun run:*)",
14
- "Bash(git stash:*)",
15
- "Bash(gh pr:*)",
16
- "Bash(git status:*)",
17
- "Bash(git add:*)",
18
- "Bash(git commit:*)",
19
- "Bash(sqlite3:*)",
20
- "Bash(git branch:*)",
21
- "Bash(git checkout:*)",
22
- "Bash(npm info:*)",
23
- "Bash(npm install:*)",
24
- "Bash(find:*)",
25
- "Bash(git log:*)",
26
- "Bash(npm ls:*)",
27
- "Bash(gh api:*)",
28
- "Bash(bun:*)",
29
- "Bash(npx tsc:*)"
30
- ]
31
- }
2
+ "permissions": {
3
+ "allow": [
4
+ "WebSearch",
5
+ "WebFetch(domain:github.com)",
6
+ "WebFetch(domain:dev.to)",
7
+ "WebFetch(domain:mariozechner.at)",
8
+ "WebFetch(domain:lobste.rs)",
9
+ "WebFetch(domain:reading.sh)",
10
+ "WebFetch(domain:daveswift.com)",
11
+ "Bash(grep:*)",
12
+ "Bash(ls:*)",
13
+ "Bash(bun run:*)",
14
+ "Bash(git stash:*)",
15
+ "Bash(gh pr:*)",
16
+ "Bash(git status:*)",
17
+ "Bash(git add:*)",
18
+ "Bash(git commit:*)",
19
+ "Bash(sqlite3:*)",
20
+ "Bash(git branch:*)",
21
+ "Bash(git checkout:*)",
22
+ "Bash(npm info:*)",
23
+ "Bash(npm install:*)",
24
+ "Bash(find:*)",
25
+ "Bash(git log:*)",
26
+ "Bash(npm ls:*)",
27
+ "Bash(gh api:*)",
28
+ "Bash(bun:*)",
29
+ "Bash(npx tsc:*)",
30
+ "WebFetch(domain:docs.anthropic.com)",
31
+ "WebFetch(domain:sdk.vercel.ai)",
32
+ "WebFetch(domain:ai-sdk.dev)",
33
+ "WebFetch(domain:www.npmjs.com)",
34
+ "Bash(curl -sL https://registry.npmjs.org/opencode-anthropic-auth/-/opencode-anthropic-auth-0.0.13.tgz)",
35
+ "Bash(tar xz:*)",
36
+ "Bash(tmux new-session:*)",
37
+ "Bash(tmux capture-pane:*)",
38
+ "Bash(tmux list-sessions:*)",
39
+ "Bash(tmux kill-session:*)",
40
+ "Bash(python3:*)",
41
+ "Bash(echo \"EXIT: $?\")",
42
+ "Bash(xargs cat:*)"
43
+ ]
44
+ }
32
45
  }
package/README.md CHANGED
@@ -6,194 +6,75 @@
6
6
 
7
7
  > _Small. Fast. Gets out of your way._
8
8
 
9
- [๐Ÿ“– Read the Full Manual](https://sacenox.github.io/mini-coder/)
9
+ [๐Ÿ“– Read the Full Manual](docs/mini-coder.1.md)
10
10
 
11
- Hey there! I'm **mini-coder** โ€” a CLI coding agent built for developers who want a sharp tool, not a bloated IDE plugin. Think of me as the pocket knife of AI coding assistants: lightweight, reliable, and always ready.
12
-
13
- ---
14
-
15
- ## ๐Ÿค™ Who Am I?
16
-
17
- I'm `mc` โ€” your new terminal companion. I live in your shell, speak to large language models, and help you explore, understand, and modify code at the speed of thought.
18
-
19
- I was built with a simple philosophy: **dev flow first**. No slow startup. No clunky GUI. No vendor lock-in. Just you, your terminal, and an AI that keeps up.
11
+ A terminal coding agent for developers who want a sharp tool, not a bloated IDE plugin. Shell-first, multi-provider, minimal tool surface. Just you, your terminal, and an AI that keeps up.
20
12
 
21
13
  ![Minicoder Preview](./assets/preview.gif)
22
14
 
23
15
  ---
24
16
 
25
- ## ๐Ÿ› ๏ธ What Can I Do?
26
-
27
- My toolkit is lean on purpose โ€” every tool earns its spot, no passengers:
28
-
29
- | Tool | What it does |
30
- | --------------- | -------------------------------------------------------------------------- |
31
- | ๐Ÿš `shell` | Run shell commands, inspect the repo, and use `mc-edit` for targeted edits |
32
- | ๐Ÿค– `subagent` | Spawn a focused mini-me for parallel subtasks |
33
- | ๐Ÿงฐ `listSkills` | List discovered skills without loading full skill bodies |
34
- | ๐Ÿ“˜ `readSkill` | Load one `SKILL.md` on demand |
35
- | ๐ŸŒ `webSearch` | Search the web when `EXA_API_KEY` is set |
36
- | ๐Ÿ“„ `webContent` | Fetch full page content from URLs when `EXA_API_KEY` is set |
37
-
38
- mini-coder is intentionally **shell-first**: inspect with shell, edit with `mc-edit`, verify with shell.
39
-
40
- Need more firepower? I also connect to **MCP servers** over HTTP or stdio โ€” attached MCP tools show up dynamically whenever the job calls for them.
41
-
42
- ---
43
-
44
- ## โšก Key Features
45
-
46
- - **Multi-provider** โ€” set `OPENCODE_API_KEY` for Zen, `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `GOOGLE_API_KEY` or `GEMINI_API_KEY`, or just run Ollama locally (`OLLAMA_BASE_URL` optional). I auto-discover whatever's available.
47
- - **Built-in web search** โ€” set `EXA_API_KEY` and I expose `webSearch` + `webContent` tools.
48
- - **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>`.
49
- - **Shell integration** โ€” prefix with `!` to run shell commands inline. Use `@` to reference files in your prompt (with Tab completion).
50
- - **Slash commands** โ€” `/model` or `/models` to list/switch models, `/model effort <low|medium|high|xhigh|off>` for reasoning effort, `/reasoning [on|off]` to toggle reasoning display, `/context` to inspect or tune pruning/tool-result caps, `/cache` to configure prompt caching, `/review` for a code review (global custom command, auto-created at `~/.agents/commands/review.md`), `/agent [name]` to set or clear an active primary agent, `/undo` to remove the last conversation turn (it does not revert filesystem changes), `/new` for a clean session, `/mcp list|add|remove` to manage MCP servers, and `/exit` (`/quit`, `/q`) to leave. See all with `/help`.
51
-
52
- - **Custom commands** โ€” drop a `.md` file in `.agents/commands/` and it becomes a `/command`. Claude-compatible `.claude/commands/` works too. Supports argument placeholders (`$ARGUMENTS`, `$1`โ€ฆ`$9`) and shell interpolation (`` !`cmd` ``). Global commands live in `~/.agents/commands/` and `~/.claude/commands/`. Custom commands take precedence over built-ins. โ†’ [docs/custom-commands.md](docs/custom-commands.md)
53
- - **Custom agents** โ€” drop a `.md` file in `.agents/agents/` or `.claude/agents/` (or `~/.agents/agents/` / `~/.claude/agents/` globally) and activate it with `/agent [name]`. Agent definitions are also exposed to subagent delegation unless `mode: primary`. โ†’ [docs/custom-agents.md](docs/custom-agents.md)
54
- - **Skills** โ€” place a `SKILL.md` in `.agents/skills/<name>/` and inject it into any prompt with `@skill-name`. Claude-compatible `.claude/skills/<name>/SKILL.md` works too. Skills are _never_ auto-loaded โ€” always explicit. โ†’ [docs/skills.md](docs/skills.md)
55
- - **Beautiful, minimal output** โ€” compact tool output, formatted trees for file searches, a live status bar with model, git branch, and token counts.
56
- - **16 ANSI colors only** โ€” my output inherits _your_ terminal theme. Dark mode, light mode, Solarized, Gruvbox โ€” I fit right in.
57
-
58
- ---
59
-
60
- ## ๐Ÿง  Interesting Things About Me
61
-
62
- - **I eat my own dog food.** I was built _by_ a mini-coder agent. It's agents all the way down. ๐Ÿข
63
- - **I'm tiny but mighty.** The whole runtime is [Bun.js](https://bun.com) โ€” fast startup, native TypeScript, and a built-in SQLite driver.
64
- - **I respect existing conventions.** Context lives 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.
65
- - **I spin while I think.** โ ‹โ ™โ นโ ธโ ผโ ดโ ฆโ งโ ‡โ  (It's the little things.)
66
- - **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 10 levels deep.)
67
-
68
- ---
69
-
70
- ## ๐Ÿ“ Config folders
71
-
72
- I follow the [`.agents` convention](https://github.com/agentsmd/agents) โ€” the shared standard across AI coding tools โ€” and I also understand `.claude` layouts for **commands**, **skills**, and **agents**.
73
-
74
- | Path | What it does |
75
- | -------------------------------- | ----------------------------------------------------- |
76
- | `.agents/commands/*.md` | Custom slash commands (`/name`) |
77
- | `.claude/commands/*.md` | Claude-compatible custom commands |
78
- | `.agents/agents/*.md` | Custom agents |
79
- | `.claude/agents/*.md` | Alternate `.claude` path for custom agents |
80
- | `.agents/skills/<name>/SKILL.md` | Reusable skill instructions (`@name`) |
81
- | `.claude/skills/<name>/SKILL.md` | Claude-compatible skills |
82
- | `.agents/AGENTS.md` | Preferred local project context |
83
- | `CLAUDE.md` | Local fallback context if `.agents/AGENTS.md` is absent |
84
- | `AGENTS.md` | Local fallback context if `.agents/AGENTS.md` and `CLAUDE.md` are absent |
85
- | `~/.agents/AGENTS.md` | Preferred global context, prepended before local context |
86
- | `~/.agents/CLAUDE.md` | Global fallback context if `~/.agents/AGENTS.md` is absent |
87
-
88
- Global commands, agents, and skills also work from `~/.agents/...` and `~/.claude/...`.
89
-
90
- For commands, skills, and agents: local overrides global, and `.agents` overrides `.claude` at the same scope. Context files are combined differently: global context is injected first, then local context. โ†’ [docs/configs.md](docs/configs.md)
91
-
92
- ---
93
-
94
- ## ๐Ÿš€ Getting Started
17
+ ## โšก Quick Start
95
18
 
96
- One thing before you dive in: **I run on Bun**. You can install me via npm just fine, but [Bun](https://bun.com) still needs to be on your machine โ€” no way around it.
19
+ I run on [Bun](https://bun.com) โ€” install me via bun or npm, but Bun needs to be on your machine.
97
20
 
98
21
  ```bash
99
- # Install globally
100
- bun add -g mini-coder
101
- # or: npm install -g mini-coder
102
-
103
- # Set a provider key (pick one โ€” or run Ollama locally)
104
- export OPENCODE_API_KEY=your-zen-key # recommended
105
- export ANTHROPIC_API_KEY=your-key # direct Anthropic
106
- export OPENAI_API_KEY=your-key # direct OpenAI
107
- export GOOGLE_API_KEY=your-key # direct Gemini
108
- # or: export GEMINI_API_KEY=your-key
109
-
110
- # Optional extras
111
- export OLLAMA_BASE_URL=http://localhost:11434
112
- export EXA_API_KEY=your-exa-key # enables webSearch/webContent
113
-
114
- # Launch
115
- mc
116
- ```
117
-
118
- Or drop me a prompt straight away for one-shot mode (runs once, then exits):
22
+ # Install
23
+ bun add -g mini-coder # or: npm install -g mini-coder
119
24
 
120
- ```bash
121
- mc "Refactor the auth module to use async/await"
122
- ```
25
+ # Set one API key (pick any)
26
+ export OPENCODE_API_KEY=your-key # recommended
27
+ export ANTHROPIC_API_KEY=your-key # direct Anthropic
28
+ export OPENAI_API_KEY=your-key # direct OpenAI
29
+ export GOOGLE_API_KEY=your-key # direct Gemini (or GEMINI_API_KEY)
123
30
 
124
- Useful flags:
31
+ # Optional
32
+ export OLLAMA_BASE_URL=http://localhost:11434 # local models
33
+ export EXA_API_KEY=your-key # web search tools
125
34
 
126
- ```bash
127
- mc -c # continue last session
128
- mc -r <id> # resume a specific session
129
- mc -l # list recent sessions
130
- mc -m zen/claude-sonnet-4-6 # pick a model
131
- mc --cwd ~/src/other-project # set working directory
132
- mc -h # show help
35
+ # Go
36
+ mc
133
37
  ```
134
38
 
135
- ---
136
-
137
- ## ๐Ÿ—ƒ๏ธ App data
138
-
139
- Everything I remember lives in `~/.config/mini-coder/` โ€” here's what I'm holding onto:
39
+ One-shot mode: `mc "refactor auth to use async/await"` โ€” runs once, then exits.
140
40
 
141
- - `sessions.db` โ€” your full session history, MCP server config, and model metadata, all in one tidy SQLite file
142
- - `api.log` โ€” a request/response log for every provider call this run, if you want to peek under the hood
143
- - `errors.log` โ€” anything that went sideways, caught and written down so you can actually debug it
41
+ Useful flags: `-c` continue last session, `-r <id>` resume, `-l` list sessions, `-m <model>` pick a model, `-h` help.
144
42
 
145
43
  ---
146
44
 
147
- ## ๐Ÿ“š Go Deeper
45
+ ## ๐Ÿ”‘ OAuth Login
148
46
 
149
- The README hits the highlights โ€” the docs have the full story:
150
-
151
- - [docs/custom-commands.md](docs/custom-commands.md)
152
- - [docs/custom-agents.md](docs/custom-agents.md)
153
- - [docs/skills.md](docs/skills.md)
154
- - [docs/configs.md](docs/configs.md)
155
-
156
- ## ๐Ÿ—‚๏ธ Project Structure
157
-
158
- ```
159
- src/
160
- index.ts # Entry point + CLI arg parsing
161
- agent/ # Main REPL loop + tool registry
162
- cli/ # Input, output, slash commands, markdown rendering
163
- llm-api/ # Provider factory + streaming turn logic
164
- tools/ # shell, subagent, skill tools
165
- # + webSearch, webContent
166
- internal/ # shared internals, including the mc-edit helper implementation
167
- mcp/ # MCP server connections
168
- session/ # SQLite-backed session & history management
169
- ```
47
+ Use `/login` inside the REPL to authenticate via browser-based OAuth (currently Anthropic). No need to manage API keys manually.
170
48
 
171
49
  ---
172
50
 
173
- ## ๐Ÿ”ฎ Tech Stack
51
+ ## ๐Ÿ› ๏ธ Features
174
52
 
175
- - **Runtime:** [Bun.js](https://bun.com) โ€” fast, modern, all-in-one
176
- - **LLM routing:** [AI SDK](https://ai-sdk.dev) โ€” multi-provider with streaming
177
- - **Colors:** [yoctocolors](https://github.com/sindresorhus/yoctocolors) โ€” tiny and terminal-theme-aware
178
- - **Schema validation:** [Zod](https://zod.dev)
179
- - **Linting/formatting:** [Biome](https://biomejs.dev)
180
- - **Storage:** `bun:sqlite` โ€” zero-dependency local sessions
53
+ - **Multi-provider** โ€” auto-discovers Anthropic, OpenAI, Gemini, Ollama, or any OpenAI-compatible endpoint
54
+ - **Session memory** โ€” SQLite-backed. Resume with `-c` or `-r <id>`
55
+ - **Shell integration** โ€” `!` prefix for inline commands, `@` to reference files with tab completion
56
+ - **Web search** โ€” `webSearch` + `webContent` tools when `EXA_API_KEY` is set
57
+ - **MCP support** โ€” connect external tool servers over HTTP or stdio
58
+ - **Custom commands** โ€” drop `.md` files in `.agents/commands/` โ†’ instant `/slash` commands
59
+ - **Custom agents** โ€” `.agents/agents/*.md` for specialized personas you can activate with `/agent`
60
+ - **Skills** โ€” `.agents/skills/<name>/SKILL.md`, inject with `@name`
61
+ - **`mc-edit`** โ€” safe, exact-text file editing (no full-file rewrites)
62
+ - **16 ANSI colors** โ€” inherits your terminal theme. Always looks right.
181
63
 
182
64
  ---
183
65
 
184
- ## ๐Ÿ’ฌ Philosophy
66
+ ## ๐Ÿ“š Getting Deeper
185
67
 
186
- > Accurate. Fast. Focused on the conversation.
68
+ The README is the highlight reel. For the full story โ€” slash commands, config folders, context files, app data, and everything else:
187
69
 
188
- I believe the best tools disappear into your workflow. I don't want to be the star of the show โ€” I want _you_ to ship great code, faster.
70
+ **[๐Ÿ“– Read the Full Manual](docs/mini-coder.1.md)**
189
71
 
190
72
  ---
191
73
 
192
- ## ๐Ÿ’ฌ What People Are Saying
74
+ ## ๐Ÿ”ฎ Tech Stack
193
75
 
194
- > "sean this is fucking sick"
195
- > โ€” [vpr99](https://github.com/vpr99)
76
+ [Bun.js](https://bun.com) ยท [AI SDK](https://ai-sdk.dev) ยท [yoctocolors](https://github.com/sindresorhus/yoctocolors)
196
77
 
197
- ---
78
+ ## ๐Ÿ“„ License
198
79
 
199
- _Built with โค๏ธ and a healthy obsession with terminal aesthetics._
80
+ MIT โ€” [github.com/sacenox/mini-coder](https://github.com/sacenox/mini-coder)
package/dist/mc-edit.js CHANGED
@@ -3,6 +3,7 @@
3
3
 
4
4
  // src/cli/structured-output.ts
5
5
  import { createTwoFilesPatch } from "diff";
6
+ import * as c from "yoctocolors";
6
7
  function normalizePatchLines(patchText) {
7
8
  const patchLines = patchText.split(`
8
9
  `);
@@ -17,14 +18,30 @@ function normalizePatchLines(patchText) {
17
18
  return line;
18
19
  });
19
20
  }
20
- function renderUnifiedDiff(filePath, before, after) {
21
+ function colorizeDiffLine(line) {
22
+ if (line.startsWith("---") || line.startsWith("+++"))
23
+ return c.dim(line);
24
+ if (line.startsWith("@@"))
25
+ return c.cyan(line);
26
+ if (line.startsWith("+"))
27
+ return c.green(line);
28
+ if (line.startsWith("-"))
29
+ return c.red(line);
30
+ return line;
31
+ }
32
+ function renderUnifiedDiff(filePath, before, after, options) {
21
33
  if (before === after) {
22
34
  return "(no changes)";
23
35
  }
24
36
  const patchText = createTwoFilesPatch(filePath, filePath, before, after, "", "", {
25
37
  context: 3
26
38
  });
27
- return normalizePatchLines(patchText).join(`
39
+ const lines = normalizePatchLines(patchText);
40
+ if (options?.colorize) {
41
+ return lines.map(colorizeDiffLine).join(`
42
+ `);
43
+ }
44
+ return lines.join(`
28
45
  `);
29
46
  }
30
47
  function renderMetadataBlock(result) {
@@ -43,8 +60,11 @@ function renderMetadataBlock(result) {
43
60
  }
44
61
  function writeFileEditResult(io, result) {
45
62
  if (result.ok) {
63
+ const colorize = process.env.FORCE_COLOR === "1" || process.env.FORCE_COLOR === "true";
46
64
  const sections = [
47
- renderUnifiedDiff(result.path, result.before, result.after),
65
+ renderUnifiedDiff(result.path, result.before, result.after, {
66
+ colorize
67
+ }),
48
68
  renderMetadataBlock(result)
49
69
  ];
50
70
  io.stdout(`${sections.join(`
@@ -64,7 +84,7 @@ function stripMatchingQuotes(value) {
64
84
  if (value.length < 2)
65
85
  return value;
66
86
  const first = value[0];
67
- const last = value[value.length - 1];
87
+ const last = value.at(-1);
68
88
  if ((first === '"' || first === "'") && first === last) {
69
89
  return value.slice(1, -1);
70
90
  }
@@ -76,7 +96,11 @@ function normalizePathInput(pathInput) {
76
96
  function resolvePath(cwdInput, pathInput) {
77
97
  const cwd = cwdInput ?? process.cwd();
78
98
  const normalizedInput = normalizePathInput(pathInput);
79
- const expanded = normalizedInput.startsWith("~/") ? join(homedir(), normalizedInput.slice(2)) : normalizedInput === "~" ? homedir() : normalizedInput;
99
+ let expanded = normalizedInput;
100
+ if (normalizedInput.startsWith("~/"))
101
+ expanded = join(homedir(), normalizedInput.slice(2));
102
+ else if (normalizedInput === "~")
103
+ expanded = homedir();
80
104
  const filePath = expanded.startsWith("/") ? expanded : join(cwd, expanded);
81
105
  const relPath = relative(cwd, filePath);
82
106
  return { cwd, filePath, relPath };