mini-coder 0.5.14 → 0.6.1

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 +26 -109
  2. package/bin/mc.ts +8 -11
  3. package/bun.lock +79 -269
  4. package/nono-mini-coder.json +42 -0
  5. package/package.json +17 -22
  6. package/src/agent.ts +243 -1403
  7. package/src/args.ts +289 -0
  8. package/src/headless.ts +41 -359
  9. package/src/index.ts +29 -1016
  10. package/src/oauth.ts +117 -0
  11. package/src/prompt.ts +219 -284
  12. package/src/session.ts +55 -1306
  13. package/src/shared.ts +117 -38
  14. package/src/tool-bash.ts +110 -0
  15. package/src/tool-edit.ts +133 -0
  16. package/src/tool-read.ts +80 -293
  17. package/src/tui-components.ts +150 -0
  18. package/src/tui-conversation.ts +271 -0
  19. package/src/tui-editor.ts +29 -0
  20. package/src/tui-overlay.ts +403 -0
  21. package/src/tui.ts +228 -0
  22. package/src/types.ts +164 -0
  23. package/tsconfig.json +17 -0
  24. package/BENCHMARK.md +0 -107
  25. package/LICENSE +0 -9
  26. package/PROGRESS.md +0 -5
  27. package/assets/icon-1-minimal.svg +0 -31
  28. package/assets/icon-2-dark-terminal.svg +0 -48
  29. package/assets/icon-3-gradient-modern.svg +0 -45
  30. package/assets/icon-4-filled-bold.svg +0 -54
  31. package/assets/icon-5-community-badge.svg +0 -63
  32. package/assets/mc-claude-smart.png +0 -0
  33. package/assets/mc-gpt-smart.png +0 -0
  34. package/assets/preview-0-5-0.png +0 -0
  35. package/assets/preview.gif +0 -0
  36. package/benchmark-baseline.sh +0 -15
  37. package/benchmark-loop.sh +0 -19
  38. package/skills-lock.json +0 -15
  39. package/src/assistant-output.ts +0 -73
  40. package/src/cli.ts +0 -134
  41. package/src/delegation.ts +0 -238
  42. package/src/errors.ts +0 -15
  43. package/src/git.ts +0 -247
  44. package/src/input.ts +0 -168
  45. package/src/mcp.ts +0 -609
  46. package/src/paths.ts +0 -37
  47. package/src/session-message.ts +0 -385
  48. package/src/settings.ts +0 -449
  49. package/src/skills.ts +0 -271
  50. package/src/submit.ts +0 -376
  51. package/src/text.ts +0 -71
  52. package/src/theme.ts +0 -330
  53. package/src/tool-common.ts +0 -93
  54. package/src/tool-delegate.ts +0 -125
  55. package/src/tool-grep.ts +0 -606
  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/agent.ts DELETED
@@ -1,320 +0,0 @@
1
- /**
2
- * Input parsing, message submission, and streaming agent-event handling for the terminal UI.
3
- *
4
- * This module builds the controller used by `ui.ts`. Each controller owns its
5
- * own transient streaming render state for the in-progress assistant response.
6
- * Persistent session and message state remain on {@link AppState}; transient UI
7
- * concerns are exposed through runtime hooks so `ui.ts` can stay a small
8
- * orchestrator.
9
- *
10
- * @module
11
- */
12
-
13
- import type { AssistantMessage } from "@mariozechner/pi-ai";
14
- import type { AgentEvent } from "../agent.ts";
15
- import { getErrorMessage } from "../errors.ts";
16
- import type { AppState } from "../index.ts";
17
- import {
18
- queueResolvedInput,
19
- resolveRawInput,
20
- submitResolvedInput,
21
- } from "../submit.ts";
22
- import type {
23
- PendingToolResult,
24
- StreamingConversationState,
25
- } from "./conversation.ts";
26
- import type { UiRenderPriority } from "./runtime.ts";
27
-
28
- export { isEmptyUserContent, stripSkillFrontmatter } from "../submit.ts";
29
-
30
- interface UiAgentRuntimeState {
31
- /** Whether a response is currently streaming. */
32
- isStreaming: boolean;
33
- /** Streaming assistant content for the current response. */
34
- content: AssistantMessage["content"];
35
- /** Tool results collected during the current streaming turn. */
36
- pendingToolResults: PendingToolResult[];
37
- }
38
-
39
- /** Hooks implemented by `ui.ts` to bridge controller logic with runtime UI state. */
40
- interface UiAgentRuntime {
41
- /** Append a UI-only informational message to the conversation log. */
42
- appendInfoMessage: (text: string, state: AppState) => void;
43
- /** Dispatch a parsed slash command. */
44
- handleCommand: (command: string, state: AppState) => boolean;
45
- /** Schedule a UI render. */
46
- requestRender: (priority?: UiRenderPriority) => void;
47
- /** Re-enable stick-to-bottom behavior for the conversation log. */
48
- scrollConversationToBottom: () => void;
49
- /** Clear the readonly queued-input draft after it is committed. */
50
- clearQueuedInputDraft: () => void;
51
- /** Start the active-turn divider animation. */
52
- startDividerAnimation: () => void;
53
- /** Stop the active-turn divider animation. */
54
- stopDividerAnimation: () => void;
55
- }
56
-
57
- /** Public controller API for raw input dispatch and streaming state. */
58
- interface UiAgentController {
59
- /** Route raw user input through parseInput and dispatch accordingly. */
60
- handleInput: (raw: string, state: AppState) => void;
61
- /** Read the current streaming tail state for conversation rendering. */
62
- getStreamingConversationState: () => StreamingConversationState;
63
- /** Reset the transient streaming state owned by this controller. */
64
- reset: () => void;
65
- }
66
-
67
- /**
68
- * Create the UI agent controller bound to runtime hooks supplied by `ui.ts`.
69
- *
70
- * @param runtime - Runtime hooks for rendering, scrolling, and command feedback.
71
- * @returns The controller used by the input layer and tests.
72
- */
73
- export function createUiAgentController(
74
- runtime: UiAgentRuntime,
75
- ): UiAgentController {
76
- const streamingState: UiAgentRuntimeState = {
77
- isStreaming: false,
78
- content: [],
79
- pendingToolResults: [],
80
- };
81
-
82
- const resetStreamingState = (): boolean => {
83
- const changed =
84
- streamingState.isStreaming ||
85
- streamingState.content.length > 0 ||
86
- streamingState.pendingToolResults.length > 0;
87
- streamingState.isStreaming = false;
88
- streamingState.content = [];
89
- streamingState.pendingToolResults = [];
90
- return changed;
91
- };
92
-
93
- const clearStreamingContent = (): boolean => {
94
- if (streamingState.content.length === 0) {
95
- return false;
96
- }
97
- streamingState.content = [];
98
- return true;
99
- };
100
-
101
- const setStreamingContent = (
102
- content: AssistantMessage["content"],
103
- ): boolean => {
104
- if (streamingState.content === content) {
105
- return false;
106
- }
107
- streamingState.content = content;
108
- return true;
109
- };
110
-
111
- const upsertPendingToolResult = (
112
- event: Extract<AgentEvent, { type: "tool_delta" | "tool_end" }>,
113
- ): boolean => {
114
- const pending = streamingState.pendingToolResults.find(
115
- (toolResult) => toolResult.toolCallId === event.toolCallId,
116
- );
117
- if (pending) {
118
- if (
119
- pending.toolName === event.name &&
120
- pending.content === event.result.content &&
121
- pending.details === event.result.details &&
122
- pending.isError === event.result.isError
123
- ) {
124
- return false;
125
- }
126
- pending.toolName = event.name;
127
- pending.content = event.result.content;
128
- pending.details = event.result.details;
129
- pending.isError = event.result.isError;
130
- return true;
131
- }
132
-
133
- streamingState.pendingToolResults.push({
134
- toolCallId: event.toolCallId,
135
- toolName: event.name,
136
- content: event.result.content,
137
- details: event.result.details,
138
- isError: event.result.isError,
139
- });
140
- return true;
141
- };
142
-
143
- const removePendingToolResult = (toolCallId: string): boolean => {
144
- const nextPendingToolResults = streamingState.pendingToolResults.filter(
145
- (toolResult) => toolResult.toolCallId !== toolCallId,
146
- );
147
- if (
148
- nextPendingToolResults.length === streamingState.pendingToolResults.length
149
- ) {
150
- return false;
151
- }
152
- streamingState.pendingToolResults = nextPendingToolResults;
153
- return true;
154
- };
155
-
156
- const isStreamingContentEvent = (
157
- event: AgentEvent,
158
- ): event is Extract<
159
- AgentEvent,
160
- {
161
- type:
162
- | "text_delta"
163
- | "thinking_delta"
164
- | "toolcall_start"
165
- | "toolcall_delta"
166
- | "toolcall_end";
167
- }
168
- > => {
169
- return (
170
- event.type === "text_delta" ||
171
- event.type === "thinking_delta" ||
172
- event.type === "toolcall_start" ||
173
- event.type === "toolcall_delta" ||
174
- event.type === "toolcall_end"
175
- );
176
- };
177
-
178
- const isPendingToolProgressEvent = (
179
- event: AgentEvent,
180
- ): event is Extract<AgentEvent, { type: "tool_delta" | "tool_end" }> => {
181
- return event.type === "tool_delta" || event.type === "tool_end";
182
- };
183
-
184
- const handleCommittedAgentEvent = (
185
- event: Exclude<
186
- AgentEvent,
187
- | Extract<
188
- AgentEvent,
189
- {
190
- type:
191
- | "text_delta"
192
- | "thinking_delta"
193
- | "toolcall_start"
194
- | "toolcall_delta"
195
- | "toolcall_end";
196
- }
197
- >
198
- | Extract<AgentEvent, { type: "tool_delta" | "tool_end" }>
199
- >,
200
- ): void => {
201
- switch (event.type) {
202
- case "user_message":
203
- runtime.clearQueuedInputDraft();
204
- runtime.scrollConversationToBottom();
205
- runtime.requestRender("normal");
206
- return;
207
- case "assistant_message":
208
- if (clearStreamingContent()) {
209
- runtime.requestRender("normal");
210
- }
211
- return;
212
- case "tool_result":
213
- if (removePendingToolResult(event.message.toolCallId)) {
214
- runtime.requestRender("normal");
215
- }
216
- return;
217
- case "done":
218
- case "error":
219
- case "aborted":
220
- if (resetStreamingState()) {
221
- runtime.requestRender("normal");
222
- }
223
- return;
224
- case "context_compacted":
225
- runtime.requestRender("normal");
226
- return;
227
- case "tool_start":
228
- return;
229
- }
230
- };
231
-
232
- const handleAgentEvent = (event: AgentEvent, _state: AppState): void => {
233
- if (isStreamingContentEvent(event)) {
234
- if (setStreamingContent(event.content)) {
235
- runtime.requestRender("stream");
236
- }
237
- return;
238
- }
239
-
240
- if (isPendingToolProgressEvent(event)) {
241
- if (upsertPendingToolResult(event)) {
242
- runtime.requestRender("stream");
243
- }
244
- return;
245
- }
246
-
247
- handleCommittedAgentEvent(event);
248
- };
249
-
250
- const submitMessageAsync = (rawInput: string, state: AppState): void => {
251
- const resolved = resolveRawInput(rawInput, state);
252
-
253
- switch (resolved.type) {
254
- case "empty":
255
- return;
256
- case "error":
257
- runtime.appendInfoMessage(resolved.message, state);
258
- return;
259
- case "command":
260
- if (!runtime.handleCommand(resolved.command, state)) {
261
- // Unimplemented command — ignore for now
262
- }
263
- return;
264
- case "message":
265
- break;
266
- }
267
-
268
- if (state.running) {
269
- queueResolvedInput(rawInput, resolved.content, state);
270
- return;
271
- }
272
-
273
- if (!state.model) {
274
- return;
275
- }
276
-
277
- let submitPromise: Promise<void>;
278
- submitPromise = submitResolvedInput(rawInput, resolved.content, state, {
279
- onUserMessage: () => {
280
- runtime.scrollConversationToBottom();
281
- runtime.requestRender("normal");
282
- },
283
- onTurnStart: () => {
284
- resetStreamingState();
285
- streamingState.isStreaming = true;
286
- runtime.startDividerAnimation();
287
- runtime.requestRender("normal");
288
- },
289
- onEvent: (event, currentState) => handleAgentEvent(event, currentState),
290
- onTurnEnd: () => {
291
- resetStreamingState();
292
- runtime.clearQueuedInputDraft();
293
- runtime.stopDividerAnimation();
294
- runtime.requestRender("normal");
295
- },
296
- })
297
- .then(() => undefined)
298
- .catch((err) => {
299
- runtime.appendInfoMessage(
300
- `Submit failed: ${getErrorMessage(err)}`,
301
- state,
302
- );
303
- })
304
- .finally(() => {
305
- if (state.activeTurnPromise === submitPromise) {
306
- state.activeTurnPromise = null;
307
- }
308
- });
309
-
310
- state.activeTurnPromise = submitPromise;
311
- };
312
-
313
- return {
314
- handleInput: (raw, state) => {
315
- submitMessageAsync(raw, state);
316
- },
317
- getStreamingConversationState: () => streamingState,
318
- reset: resetStreamingState,
319
- };
320
- }