mini-coder 0.5.13 → 0.6.0

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.
Files changed (67) hide show
  1. package/README.md +25 -108
  2. package/bin/mc.ts +8 -11
  3. package/bun.lock +79 -269
  4. package/package.json +17 -22
  5. package/src/agent.ts +242 -915
  6. package/src/args.ts +289 -0
  7. package/src/headless.ts +43 -385
  8. package/src/index.ts +29 -836
  9. package/src/oauth.ts +117 -0
  10. package/src/prompt.ts +227 -276
  11. package/src/session.ts +57 -961
  12. package/src/shared.ts +117 -38
  13. package/src/tool-bash.ts +110 -0
  14. package/src/tool-edit.ts +133 -0
  15. package/src/tool-task.ts +114 -0
  16. package/src/tui-components.ts +150 -0
  17. package/src/tui-conversation.ts +262 -0
  18. package/src/tui-editor.ts +29 -0
  19. package/src/tui-overlay.ts +403 -0
  20. package/src/tui.ts +236 -0
  21. package/src/types.ts +160 -0
  22. package/tsconfig.json +17 -0
  23. package/BENCHMARK.md +0 -107
  24. package/LICENSE +0 -9
  25. package/PROGRESS.md +0 -4
  26. package/assets/icon-1-minimal.svg +0 -31
  27. package/assets/icon-2-dark-terminal.svg +0 -48
  28. package/assets/icon-3-gradient-modern.svg +0 -45
  29. package/assets/icon-4-filled-bold.svg +0 -54
  30. package/assets/icon-5-community-badge.svg +0 -63
  31. package/assets/mc-claude-smart.png +0 -0
  32. package/assets/mc-gpt-smart.png +0 -0
  33. package/assets/preview-0-5-0.png +0 -0
  34. package/assets/preview.gif +0 -0
  35. package/benchmark-baseline.sh +0 -15
  36. package/benchmark-loop.sh +0 -19
  37. package/skills-lock.json +0 -15
  38. package/src/cli.ts +0 -134
  39. package/src/errors.ts +0 -15
  40. package/src/git.ts +0 -247
  41. package/src/input.ts +0 -168
  42. package/src/mcp.ts +0 -609
  43. package/src/paths.ts +0 -37
  44. package/src/session-message.ts +0 -393
  45. package/src/settings.ts +0 -449
  46. package/src/skills.ts +0 -271
  47. package/src/submit.ts +0 -371
  48. package/src/text.ts +0 -71
  49. package/src/theme.ts +0 -330
  50. package/src/tool-common.ts +0 -93
  51. package/src/tool-grep.ts +0 -606
  52. package/src/tool-read.ts +0 -313
  53. package/src/tool-shell.ts +0 -1001
  54. package/src/tools.ts +0 -854
  55. package/src/ui/agent.ts +0 -317
  56. package/src/ui/commands.test.ts +0 -913
  57. package/src/ui/commands.ts +0 -834
  58. package/src/ui/conversation.test.ts +0 -585
  59. package/src/ui/conversation.ts +0 -1836
  60. package/src/ui/help.ts +0 -158
  61. package/src/ui/input.test.ts +0 -64
  62. package/src/ui/input.ts +0 -138
  63. package/src/ui/overlay.ts +0 -59
  64. package/src/ui/runtime.ts +0 -69
  65. package/src/ui/status.ts +0 -220
  66. package/src/ui.ts +0 -1190
  67. package/src/version.ts +0 -48
@@ -1,54 +0,0 @@
1
- <!-- Mini Coder Icon v4: Filled Bold
2
- Chunky solid brackets form a unified shape. Bolt cuts through like a slash.
3
- Inspired by: "accurate and reliable", sturdy and trustworthy feel -->
4
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100" height="100">
5
- <!-- Left bracket { — filled, bold, warm off-white bg -->
6
- <rect x="0" y="0" width="100" height="100" rx="0" fill="#f7f3ee"/>
7
-
8
- <!-- Left brace as thick filled path -->
9
- <path
10
- d="M40 10
11
- C32 10 28 15 28 23
12
- L28 39
13
- C28 45 24 48 19 50
14
- C24 52 28 55 28 61
15
- L28 77
16
- C28 85 32 90 40 90
17
- L40 83
18
- C35 83 35 79 35 75
19
- L35 62
20
- C35 55 31 52 28 50
21
- C31 48 35 45 35 38
22
- L35 25
23
- C35 21 35 17 40 17
24
- Z"
25
- fill="#1a1a2e"
26
- />
27
- <!-- Right brace as thick filled path -->
28
- <path
29
- d="M60 10
30
- C68 10 72 15 72 23
31
- L72 39
32
- C72 45 76 48 81 50
33
- C76 52 72 55 72 61
34
- L72 77
35
- C72 85 68 90 60 90
36
- L60 83
37
- C65 83 65 79 65 75
38
- L65 62
39
- C65 55 69 52 72 50
40
- C69 48 65 45 65 38
41
- L65 25
42
- C65 21 65 17 60 17
43
- Z"
44
- fill="#1a1a2e"
45
- />
46
- <!-- Lightning bolt — punchy orange-red -->
47
- <path
48
- d="M58 16 L41 51 L52 51 L42 84 L64 47 L53 47 Z"
49
- fill="#e8390e"
50
- stroke="#f7f3ee"
51
- stroke-width="1.5"
52
- stroke-linejoin="round"
53
- />
54
- </svg>
@@ -1,63 +0,0 @@
1
- <!-- Mini Coder Icon v5: Community Badge
2
- Hexagonal badge shape (nod to community/open-source), teal + amber palette.
3
- Bolt doubles as a "play / run" symbol. Inspired by: "community oriented",
4
- open source tools like Codex & opencode. -->
5
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100" height="100">
6
- <defs>
7
- <linearGradient id="hexGrad" x1="0%" y1="0%" x2="100%" y2="100%">
8
- <stop offset="0%" stop-color="#0a3d62"/>
9
- <stop offset="100%" stop-color="#0c6e6e"/>
10
- </linearGradient>
11
- <filter id="shadow" x="-10%" y="-10%" width="120%" height="120%">
12
- <feDropShadow dx="0" dy="2" stdDeviation="3" flood-color="rgba(0,0,0,0.35)"/>
13
- </filter>
14
- </defs>
15
-
16
- <!-- Hexagon background -->
17
- <polygon
18
- points="50,4 93,27 93,73 50,96 7,73 7,27"
19
- fill="url(#hexGrad)"
20
- filter="url(#shadow)"
21
- />
22
- <!-- Subtle inner hex ring -->
23
- <polygon
24
- points="50,10 88,30 88,70 50,90 12,70 12,30"
25
- fill="none"
26
- stroke="rgba(255,255,255,0.1)"
27
- stroke-width="1.5"
28
- />
29
-
30
- <!-- Left bracket { — teal/white -->
31
- <path
32
- d="M37 18 C29 18 26 23 26 30 L26 43 C26 48 22 51 18 52 C22 53 26 56 26 61 L26 71 C26 78 29 83 37 83"
33
- fill="none"
34
- stroke="#7fffd4"
35
- stroke-width="4"
36
- stroke-linecap="round"
37
- stroke-linejoin="round"
38
- />
39
- <!-- Right bracket } — teal/white -->
40
- <path
41
- d="M63 18 C71 18 74 23 74 30 L74 43 C74 48 78 51 82 52 C78 53 74 56 74 61 L74 71 C74 78 71 83 63 83"
42
- fill="none"
43
- stroke="#7fffd4"
44
- stroke-width="4"
45
- stroke-linecap="round"
46
- stroke-linejoin="round"
47
- />
48
-
49
- <!-- Lightning bolt — amber gold -->
50
- <path
51
- d="M56 22 L42 52 L52 52 L44 78 L62 46 L51 46 Z"
52
- fill="#ffc107"
53
- stroke="#fff8e1"
54
- stroke-width="1"
55
- stroke-linejoin="round"
56
- />
57
- <!-- Tiny speed lines left of bolt -->
58
- <line x1="28" y1="46" x2="36" y2="46" stroke="#7fffd4" stroke-width="1.5" stroke-linecap="round" opacity="0.5"/>
59
- <line x1="30" y1="51" x2="36" y2="51" stroke="#7fffd4" stroke-width="1.5" stroke-linecap="round" opacity="0.35"/>
60
- <!-- Tiny speed lines right of bolt -->
61
- <line x1="64" y1="46" x2="72" y2="46" stroke="#7fffd4" stroke-width="1.5" stroke-linecap="round" opacity="0.5"/>
62
- <line x1="64" y1="51" x2="70" y2="51" stroke="#7fffd4" stroke-width="1.5" stroke-linecap="round" opacity="0.35"/>
63
- </svg>
Binary file
Binary file
Binary file
Binary file
@@ -1,15 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
-
4
- cd -- "$(dirname -- "${BASH_SOURCE[0]}")"
5
-
6
- PYTHONPATH="$PWD/terminal-bench" harbor run -y \
7
- --job-name benchmark-baseline-full-$(date +%F__%H-%M-%S) \
8
- --jobs-dir "$PWD/terminal-bench/jobs" \
9
- --agent-import-path mini_coder_agent:MiniCoderAgent \
10
- --ak version=0.5.12 \
11
- --model openai-codex/gpt-5.4 \
12
- --dataset terminal-bench@2.0 \
13
- --n-attempts 2 \
14
- --n-concurrent 2 \
15
- --max-retries 0
package/benchmark-loop.sh DELETED
@@ -1,19 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
-
4
- stop() {
5
- echo "stopping loop"
6
- exit 0
7
- }
8
-
9
- trap stop INT TERM
10
-
11
- while :; do
12
- echo ""
13
- echo "> Running step"
14
- echo ""
15
- mc -p "See BENCHMARK.md and PROGRESS.md first. Do the next step in the process. Once the step is complete update PROGRESS.md"
16
-
17
- sleep 60
18
- done
19
-
package/skills-lock.json DELETED
@@ -1,15 +0,0 @@
1
- {
2
- "version": 1,
3
- "skills": {
4
- "bun-development": {
5
- "source": "sickn33/antigravity-awesome-skills",
6
- "sourceType": "github",
7
- "computedHash": "87e59a1e7f7fe512333aad64022955501a4e36be6e65487196dfc311e5b786b7"
8
- },
9
- "typescript-advanced-types": {
10
- "source": "wshobson/agents",
11
- "sourceType": "github",
12
- "computedHash": "3a3be8c925f96ac4e1280db28a01677e7ca5197f3792de2bbf35ab3bb324b6dd"
13
- }
14
- }
15
- }
package/src/cli.ts DELETED
@@ -1,134 +0,0 @@
1
- /**
2
- * CLI argument parsing and launch-mode selection.
3
- *
4
- * @module
5
- */
6
-
7
- // ---------------------------------------------------------------------------
8
- // Types
9
- // ---------------------------------------------------------------------------
10
-
11
- /** Parsed CLI options for the current launch. */
12
- export interface CliOptions {
13
- /** One-shot prompt text, or `null` when not provided. */
14
- prompt: string | null;
15
- /** Whether to stream headless output as NDJSON instead of final text. */
16
- json: boolean;
17
- }
18
-
19
- /** TTY availability for stdin/stdout. */
20
- export interface TtyState {
21
- /** Whether stdin is attached to a TTY. */
22
- stdinIsTTY: boolean;
23
- /** Whether stdout is attached to a TTY. */
24
- stdoutIsTTY: boolean;
25
- }
26
-
27
- // ---------------------------------------------------------------------------
28
- // Argument parsing
29
- // ---------------------------------------------------------------------------
30
-
31
- /**
32
- * Parse supported CLI arguments.
33
- *
34
- * Supports `-p, --prompt <text>` for headless one-shot mode and `--json`
35
- * to stream NDJSON events instead of the default final-text mode
36
- * (stdout final answer plus stderr activity snippets).
37
- * Unknown flags and positional arguments fail eagerly.
38
- *
39
- * @param argv - Process arguments excluding the Bun executable and script path.
40
- * @returns The parsed CLI options.
41
- */
42
- export function parseCliArgs(argv: readonly string[]): CliOptions {
43
- let prompt: string | null = null;
44
- let json = false;
45
-
46
- for (let index = 0; index < argv.length; index += 1) {
47
- const arg = argv[index];
48
- if (!arg) {
49
- continue;
50
- }
51
-
52
- if (arg === "-p" || arg === "--prompt") {
53
- const value = argv[index + 1];
54
- if (value == null) {
55
- throw new Error("Missing value for -p/--prompt.");
56
- }
57
- prompt = value;
58
- index += 1;
59
- continue;
60
- }
61
-
62
- if (arg.startsWith("--prompt=")) {
63
- prompt = arg.slice("--prompt=".length);
64
- continue;
65
- }
66
-
67
- if (arg === "--json") {
68
- json = true;
69
- continue;
70
- }
71
-
72
- if (arg.startsWith("-")) {
73
- throw new Error(`Unknown argument: ${arg}`);
74
- }
75
-
76
- throw new Error(`Unexpected positional argument: ${arg}`);
77
- }
78
-
79
- return { prompt, json };
80
- }
81
-
82
- // ---------------------------------------------------------------------------
83
- // Mode selection
84
- // ---------------------------------------------------------------------------
85
-
86
- /**
87
- * Return whether the current launch should run in headless mode.
88
- *
89
- * Headless mode is selected when a one-shot prompt was provided or when
90
- * either stdin or stdout is not attached to a TTY.
91
- *
92
- * @param options - Parsed CLI options.
93
- * @param tty - Current TTY availability.
94
- * @returns `true` when headless mode should be used.
95
- */
96
- export function shouldUseHeadlessMode(
97
- options: CliOptions,
98
- tty: TtyState,
99
- ): boolean {
100
- return options.prompt !== null || !tty.stdinIsTTY || !tty.stdoutIsTTY;
101
- }
102
-
103
- /**
104
- * Resolve the raw prompt text for headless mode.
105
- *
106
- * Prefers the explicit CLI prompt. Otherwise reads all of stdin. Empty or
107
- * whitespace-only input is rejected.
108
- *
109
- * @param options - Parsed CLI options.
110
- * @param tty - Current TTY availability.
111
- * @param readStdin - Callback that returns the full stdin contents.
112
- * @returns The raw prompt text to submit.
113
- */
114
- export async function resolveHeadlessPrompt(
115
- options: CliOptions,
116
- tty: TtyState,
117
- readStdin: () => Promise<string>,
118
- ): Promise<string> {
119
- const rawPrompt =
120
- options.prompt !== null
121
- ? options.prompt
122
- : tty.stdinIsTTY
123
- ? null
124
- : await readStdin();
125
-
126
- if (rawPrompt === null) {
127
- throw new Error("Headless mode requires -p/--prompt or piped stdin.");
128
- }
129
- if (rawPrompt.trim().length === 0) {
130
- throw new Error("Headless input is empty.");
131
- }
132
-
133
- return rawPrompt;
134
- }
package/src/errors.ts DELETED
@@ -1,15 +0,0 @@
1
- /**
2
- * Shared error-formatting helpers.
3
- *
4
- * @module
5
- */
6
-
7
- /**
8
- * Convert an unknown thrown value into a readable message string.
9
- *
10
- * @param error - The thrown value to format.
11
- * @returns The error message when available, otherwise the stringified value.
12
- */
13
- export function getErrorMessage(error: unknown): string {
14
- return error instanceof Error ? error.message : String(error);
15
- }
package/src/git.ts DELETED
@@ -1,247 +0,0 @@
1
- /**
2
- * Git state gathering.
3
- *
4
- * Runs fast git commands to collect branch name, working tree counts,
5
- * and ahead/behind status. Used by the system prompt footer and the
6
- * status bar to give the model and user situational awareness.
7
- *
8
- * @module
9
- */
10
-
11
- // ---------------------------------------------------------------------------
12
- // Types
13
- // ---------------------------------------------------------------------------
14
-
15
- /**
16
- * Snapshot of the current git repository state.
17
- *
18
- * All counts are non-negative integers. When there is no upstream
19
- * tracking branch, `ahead` and `behind` are both `0`.
20
- */
21
- export interface GitState {
22
- /** Absolute path to the repository root. */
23
- root: string;
24
- /** Current branch name (empty string for detached HEAD). */
25
- branch: string;
26
- /** Upstream tracking ref such as `origin/main`, or `null` when none exists. */
27
- upstream: string | null;
28
- /** Number of staged (index) changes. */
29
- staged: number;
30
- /** Number of unstaged working-tree modifications. */
31
- modified: number;
32
- /** Number of untracked files. */
33
- untracked: number;
34
- /** Commits ahead of the upstream tracking branch. */
35
- ahead: number;
36
- /** Commits behind the upstream tracking branch. */
37
- behind: number;
38
- }
39
-
40
- // ---------------------------------------------------------------------------
41
- // Helpers
42
- // ---------------------------------------------------------------------------
43
-
44
- /**
45
- * Run a git command and return its trimmed stdout.
46
- * Returns `null` if the command fails (non-zero exit).
47
- */
48
- async function run(
49
- args: string[],
50
- cwd: string,
51
- trim = true,
52
- ): Promise<string | null> {
53
- const proc = Bun.spawn(["git", ...args], {
54
- cwd,
55
- stdout: "pipe",
56
- stderr: "pipe",
57
- });
58
- const out = await new Response(proc.stdout as ReadableStream).text();
59
- const code = await proc.exited;
60
- if (code !== 0) return null;
61
- return trim ? out.trim() : out;
62
- }
63
-
64
- function getErrorStringProperty(
65
- error: unknown,
66
- key: string,
67
- ): string | undefined {
68
- if (typeof error !== "object" || error === null) {
69
- return undefined;
70
- }
71
-
72
- const value = Reflect.get(error, key);
73
- return typeof value === "string" ? value : undefined;
74
- }
75
-
76
- function isMissingGitError(error: unknown): boolean {
77
- const code = getErrorStringProperty(error, "code");
78
- if (code !== "ENOENT") {
79
- return false;
80
- }
81
-
82
- const message = getErrorStringProperty(error, "message");
83
- return (
84
- typeof message === "string" &&
85
- message.includes('Executable not found in $PATH: "git"')
86
- );
87
- }
88
-
89
- async function safeRun(
90
- runGit: (
91
- args: string[],
92
- cwd: string,
93
- trim?: boolean,
94
- ) => Promise<string | null>,
95
- args: string[],
96
- cwd: string,
97
- trim = true,
98
- ): Promise<string | null> {
99
- try {
100
- return await runGit(args, cwd, trim);
101
- } catch (error) {
102
- if (isMissingGitError(error)) {
103
- return null;
104
- }
105
- throw error;
106
- }
107
- }
108
-
109
- function isUntrackedStatus(
110
- indexStatus: string,
111
- workingTreeStatus: string,
112
- ): boolean {
113
- return indexStatus === "?" && workingTreeStatus === "?";
114
- }
115
-
116
- function hasTrackedChange(status: string): boolean {
117
- return status !== " " && status !== "?";
118
- }
119
-
120
- /**
121
- * Parse `git status --porcelain` output into staged, modified, and untracked counts.
122
- *
123
- * Porcelain v1 format: two-character status code per line.
124
- * - Column 1 = index (staged) status
125
- * - Column 2 = working tree status
126
- * - `?` in both columns = untracked
127
- *
128
- * @param output - Raw `git status --porcelain` output.
129
- * @returns Counts of staged, modified, and untracked files.
130
- */
131
- export function parseGitStatus(output: string): {
132
- staged: number;
133
- modified: number;
134
- untracked: number;
135
- } {
136
- let staged = 0;
137
- let modified = 0;
138
- let untracked = 0;
139
-
140
- for (const line of output.split("\n")) {
141
- if (line.length < 2) {
142
- continue;
143
- }
144
-
145
- const indexStatus = line[0];
146
- const workingTreeStatus = line[1];
147
- if (!indexStatus || !workingTreeStatus) {
148
- continue;
149
- }
150
- if (isUntrackedStatus(indexStatus, workingTreeStatus)) {
151
- untracked++;
152
- continue;
153
- }
154
- if (hasTrackedChange(indexStatus)) {
155
- staged++;
156
- }
157
- if (hasTrackedChange(workingTreeStatus)) {
158
- modified++;
159
- }
160
- }
161
-
162
- return { staged, modified, untracked };
163
- }
164
-
165
- /**
166
- * Parse `git rev-list --left-right --count HEAD...@{upstream}` output.
167
- *
168
- * The command returns two whitespace-separated integers: ahead then behind.
169
- * Invalid or missing values are treated as `0`.
170
- *
171
- * @param output - Raw `git rev-list --left-right --count` output.
172
- * @returns Parsed ahead and behind counts.
173
- */
174
- export function parseGitAheadBehind(output: string): {
175
- ahead: number;
176
- behind: number;
177
- } {
178
- const parts = output.trim().split(/\s+/);
179
- return {
180
- ahead: parseInt(parts[0] ?? "0", 10) || 0,
181
- behind: parseInt(parts[1] ?? "0", 10) || 0,
182
- };
183
- }
184
-
185
- // ---------------------------------------------------------------------------
186
- // Public API
187
- // ---------------------------------------------------------------------------
188
-
189
- /**
190
- * Gather the current git state for a directory.
191
- *
192
- * Runs several fast git commands in parallel to collect branch, working
193
- * tree status, and ahead/behind counts. Returns `null` if git is not
194
- * installed or the directory is not inside a git repository.
195
- *
196
- * @param cwd - The directory to query (can be a subdirectory of the repo).
197
- * @param opts - Optional runtime overrides used by tests.
198
- * @returns A {@link GitState} snapshot, or `null` if not in a git repo.
199
- */
200
- export async function getGitState(
201
- cwd: string,
202
- opts?: {
203
- run?: (
204
- args: string[],
205
- cwd: string,
206
- trim?: boolean,
207
- ) => Promise<string | null>;
208
- },
209
- ): Promise<GitState | null> {
210
- const exec = opts?.run ?? run;
211
-
212
- // Check if we're in a repo and get the root
213
- const root = await safeRun(exec, ["rev-parse", "--show-toplevel"], cwd);
214
- if (root === null) return null;
215
-
216
- // Run remaining commands in parallel
217
- const [branch, upstream, status, revList] = await Promise.all([
218
- safeRun(exec, ["branch", "--show-current"], cwd),
219
- safeRun(
220
- exec,
221
- ["rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{upstream}"],
222
- cwd,
223
- ),
224
- safeRun(exec, ["status", "--porcelain"], cwd, false),
225
- safeRun(
226
- exec,
227
- ["rev-list", "--left-right", "--count", "HEAD...@{upstream}"],
228
- cwd,
229
- ),
230
- ]);
231
-
232
- const { staged, modified, untracked } = parseGitStatus(status ?? "");
233
- const { ahead, behind } = revList
234
- ? parseGitAheadBehind(revList)
235
- : { ahead: 0, behind: 0 };
236
-
237
- return {
238
- root,
239
- branch: branch ?? "",
240
- upstream,
241
- staged,
242
- modified,
243
- untracked,
244
- ahead,
245
- behind,
246
- };
247
- }