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
package/src/ui/status.ts DELETED
@@ -1,220 +0,0 @@
1
- /**
2
- * Status-bar formatting and rendering for the terminal UI.
3
- *
4
- * Computes the cumulative usage pill, abbreviates the working directory, and
5
- * formats the cached current-context estimate maintained on application state.
6
- *
7
- * @module
8
- */
9
-
10
- import { homedir } from "node:os";
11
- import { Spacer } from "@cel-tui/components";
12
- import { HStack, Text, visibleWidth } from "@cel-tui/core";
13
- import type { Node } from "@cel-tui/types";
14
- import type { AppState } from "../index.ts";
15
- import type { StatusTone, Theme } from "../theme.ts";
16
-
17
- /**
18
- * Abbreviate a path with `~` for the home directory.
19
- *
20
- * @param path - Absolute path to abbreviate.
21
- * @returns The abbreviated display path.
22
- */
23
- export function abbreviatePath(path: string): string {
24
- const home = homedir();
25
- if (path === home) {
26
- return "~";
27
- }
28
- if (path.startsWith(`${home}/`)) {
29
- return `~${path.slice(home.length)}`;
30
- }
31
- return path;
32
- }
33
-
34
- /** Format a token count with human-friendly units (1.2k, 45k, 1.2M). */
35
- function formatTokens(n: number): string {
36
- if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;
37
- if (n >= 1_000) return `${(n / 1_000).toFixed(1)}k`;
38
- return String(n);
39
- }
40
-
41
- /** Format a token capacity, trimming unnecessary trailing `.0`. */
42
- function formatTokenCapacity(n: number): string {
43
- return formatTokens(n).replace(/\.0([kM])$/, "$1");
44
- }
45
-
46
- /** Format a dollar cost. */
47
- function formatCost(cost: number): string {
48
- return `$${cost.toFixed(2)}`;
49
- }
50
-
51
- /** Format the effort level for display. */
52
- function formatEffort(effort: string): string {
53
- const map: Record<string, string> = {
54
- minimal: "min",
55
- low: "low",
56
- medium: "med",
57
- high: "high",
58
- xhigh: "xhigh",
59
- };
60
- return map[effort] ?? effort;
61
- }
62
-
63
- /** Format git status for the status bar right side. */
64
- function formatGitStatus(state: AppState): string {
65
- if (!state.git) return "";
66
- const parts: string[] = [state.git.branch];
67
- if (state.git.staged > 0) parts.push(`+${state.git.staged}`);
68
- if (state.git.modified > 0) parts.push(`~${state.git.modified}`);
69
- if (state.git.untracked > 0) parts.push(`?${state.git.untracked}`);
70
- if (state.git.ahead > 0) parts.push(`▲ ${state.git.ahead}`);
71
- if (state.git.behind > 0) parts.push(`▼ ${state.git.behind}`);
72
- return parts.join(" ");
73
- }
74
-
75
- /** Format model info for the status bar left side. */
76
- function formatModelInfo(state: AppState): string {
77
- if (!state.model) return "no model";
78
- return `${state.model.provider}/${state.model.id} · ${formatEffort(state.effort)}`;
79
- }
80
-
81
- /** Estimate current context usage as a percentage of the active model window. */
82
- function getContextPercentage(state: AppState): number {
83
- if (!state.model || state.model.contextWindow <= 0) {
84
- return 0;
85
- }
86
- return (state.contextTokens / state.model.contextWindow) * 100;
87
- }
88
-
89
- /** Format cumulative session totals plus estimated current context usage for the status bar. */
90
- function formatUsage(state: AppState, contextPct: number): string {
91
- if (!state.model) return "";
92
- const input = formatTokens(state.stats.totalInput);
93
- const output = formatTokens(state.stats.totalOutput);
94
- const contextWindow = formatTokenCapacity(state.model.contextWindow);
95
- return `in:${input} out:${output} · ${contextPct.toFixed(1)}%/${contextWindow} · ${formatCost(state.stats.totalCost)}`;
96
- }
97
-
98
- /** Select the model/effort pill tone for the current reasoning effort. */
99
- function getEffortTone(theme: Theme, effort: string): StatusTone {
100
- switch (effort) {
101
- case "xhigh":
102
- return theme.statusEffortScale[3];
103
- case "high":
104
- return theme.statusEffortScale[2];
105
- case "medium":
106
- return theme.statusEffortScale[1];
107
- default:
108
- return theme.statusEffortScale[0];
109
- }
110
- }
111
-
112
- /** Select the usage/context pill tone for the current context pressure. */
113
- function getContextTone(theme: Theme, contextPct: number): StatusTone {
114
- if (contextPct >= 90) {
115
- return theme.statusContextScale[4];
116
- }
117
- if (contextPct >= 75) {
118
- return theme.statusContextScale[3];
119
- }
120
- if (contextPct >= 50) {
121
- return theme.statusContextScale[2];
122
- }
123
- if (contextPct >= 25) {
124
- return theme.statusContextScale[1];
125
- }
126
- return theme.statusContextScale[0];
127
- }
128
-
129
- /** Render a single compact status pill. */
130
- function renderStatusPill(text: string, tone: StatusTone): Node {
131
- return HStack({ bgColor: tone.bg, padding: { x: 1 } }, [
132
- Text(text, { fgColor: tone.fg }),
133
- ]);
134
- }
135
-
136
- function measureStatusPill(text: string): number {
137
- return visibleWidth(text) + 2;
138
- }
139
-
140
- function leftTruncate(text: string, maxWidth: number): string {
141
- if (maxWidth <= 0) {
142
- return "";
143
- }
144
- if (visibleWidth(text) <= maxWidth) {
145
- return text;
146
- }
147
- if (maxWidth === 1) {
148
- return "…";
149
- }
150
-
151
- for (let i = text.lastIndexOf("/"); i > 0; i = text.lastIndexOf("/", i - 1)) {
152
- const candidate = text.slice(i);
153
- if (visibleWidth(candidate) <= maxWidth - 1) {
154
- return `…${candidate}`;
155
- }
156
- }
157
-
158
- let suffix = "";
159
- for (const char of Array.from(text).reverse()) {
160
- const next = `${char}${suffix}`;
161
- if (visibleWidth(next) > maxWidth - 1) {
162
- break;
163
- }
164
- suffix = next;
165
- }
166
-
167
- return `…${suffix}`;
168
- }
169
-
170
- /**
171
- * Render the one-line status bar as compact padded pills.
172
- *
173
- * The inner pills use the neutral secondary tone. The model pill uses a
174
- * reasoning-effort tone scale, and the usage pill uses an independent
175
- * context-pressure tone scale. The git pill is omitted outside repositories.
176
- *
177
- * @param state - Application state.
178
- * @param cols - Current terminal width in columns.
179
- * @returns The rendered status bar node.
180
- */
181
- export function renderStatusBar(
182
- state: AppState,
183
- cols = Number.POSITIVE_INFINITY,
184
- ): Node {
185
- const fullCwd = abbreviatePath(state.cwd);
186
- const gitStatus = formatGitStatus(state);
187
- const modelInfo = formatModelInfo(state);
188
- const contextPct = getContextPercentage(state);
189
- const usage = formatUsage(state, contextPct);
190
- const reservedWidth =
191
- 2 +
192
- measureStatusPill(modelInfo) +
193
- measureStatusPill(usage) +
194
- (gitStatus ? measureStatusPill(gitStatus) : 0) +
195
- 2;
196
- const cwd = Number.isFinite(cols)
197
- ? leftTruncate(fullCwd, Math.max(Math.floor(cols) - reservedWidth, 1))
198
- : fullCwd;
199
-
200
- const secondaryTone = state.theme.statusSecondary;
201
- const children: Node[] = [
202
- renderStatusPill(modelInfo, getEffortTone(state.theme, state.effort)),
203
- renderStatusPill(cwd, secondaryTone),
204
- Spacer(),
205
- ];
206
- if (gitStatus) {
207
- children.push(renderStatusPill(gitStatus, secondaryTone));
208
- }
209
- children.push(
210
- renderStatusPill(usage, getContextTone(state.theme, contextPct)),
211
- );
212
-
213
- return HStack(
214
- {
215
- height: 1,
216
- padding: { x: 1 },
217
- },
218
- children,
219
- );
220
- }