mini-coder 0.5.14 → 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 (70) hide show
  1. package/README.md +25 -109
  2. package/bin/mc.ts +8 -11
  3. package/bun.lock +79 -269
  4. package/package.json +17 -22
  5. package/src/agent.ts +237 -1403
  6. package/src/args.ts +289 -0
  7. package/src/headless.ts +43 -358
  8. package/src/index.ts +29 -1016
  9. package/src/oauth.ts +117 -0
  10. package/src/prompt.ts +227 -284
  11. package/src/session.ts +55 -1306
  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 -5
  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/assistant-output.ts +0 -73
  39. package/src/cli.ts +0 -134
  40. package/src/delegation.ts +0 -238
  41. package/src/errors.ts +0 -15
  42. package/src/git.ts +0 -247
  43. package/src/input.ts +0 -168
  44. package/src/mcp.ts +0 -609
  45. package/src/paths.ts +0 -37
  46. package/src/session-message.ts +0 -385
  47. package/src/settings.ts +0 -449
  48. package/src/skills.ts +0 -271
  49. package/src/submit.ts +0 -376
  50. package/src/text.ts +0 -71
  51. package/src/theme.ts +0 -330
  52. package/src/tool-common.ts +0 -93
  53. package/src/tool-delegate.ts +0 -125
  54. package/src/tool-grep.ts +0 -606
  55. package/src/tool-read.ts +0 -313
  56. package/src/tool-shell.ts +0 -1051
  57. package/src/tools.ts +0 -1179
  58. package/src/ui/agent.ts +0 -320
  59. package/src/ui/commands.test.ts +0 -957
  60. package/src/ui/commands.ts +0 -848
  61. package/src/ui/conversation.test.ts +0 -585
  62. package/src/ui/conversation.ts +0 -1836
  63. package/src/ui/help.ts +0 -158
  64. package/src/ui/input.test.ts +0 -64
  65. package/src/ui/input.ts +0 -138
  66. package/src/ui/overlay.ts +0 -59
  67. package/src/ui/runtime.ts +0 -69
  68. package/src/ui/status.ts +0 -220
  69. package/src/ui.ts +0 -1190
  70. 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
- }