mini-coder 0.0.8 → 0.0.10
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.
- package/codex-lazy-fix.md +76 -0
- package/dist/mc.js +3960 -3554
- package/hanging-bug.md +79 -0
- package/package.json +1 -1
- package/plan-code-health.md +169 -0
package/hanging-bug.md
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# Hanging Bug Investigation
|
|
2
|
+
|
|
3
|
+
## Symptoms
|
|
4
|
+
|
|
5
|
+
After a shell tool call completes successfully, **SOMETIMES** the app hangs indefinitely instead of
|
|
6
|
+
returning to the prompt. Two observed states:
|
|
7
|
+
|
|
8
|
+
```
|
|
9
|
+
$ $ rm src/session/db.ts && bun run test
|
|
10
|
+
⠇ shell
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Stayed spinning with shell label for well over the timeout time. I had to kill the app.
|
|
14
|
+
|
|
15
|
+
Another example with a different shell command:
|
|
16
|
+
```
|
|
17
|
+
$ $ git diff
|
|
18
|
+
✔ 0
|
|
19
|
+
│ diff --git a/src/cli/tool-render.ts b/src/cli/tool-render.ts
|
|
20
|
+
│ index f8d33af..e224932 100644
|
|
21
|
+
│ --- a/src/cli/tool-render.ts
|
|
22
|
+
│ +++ b/src/cli/tool-render.ts
|
|
23
|
+
│ @@ -148,21 +148,25 @@ export function renderToolResultInline(
|
|
24
|
+
│ }
|
|
25
|
+
│
|
|
26
|
+
│ if (toolName === "glob") {
|
|
27
|
+
│ - const r = result as { files: string[]; truncated: boolean };
|
|
28
|
+
│ - const n = r.files.length;
|
|
29
|
+
│ - writeln(
|
|
30
|
+
│ - `${indent}${G.info} ${c.dim(n === 0 ? "no matches" : `${n} file${n === 1 ? "" : "s"}${r.truncated ? " (capped)" : ""}`)}`,
|
|
31
|
+
│ - );
|
|
32
|
+
│ - return;
|
|
33
|
+
│ + const r = result as { files?: string[]; truncated?: boolean };
|
|
34
|
+
│ + if (Array.isArray(r.files)) {
|
|
35
|
+
│ + const n = r.files.length;
|
|
36
|
+
│ + writeln(
|
|
37
|
+
│ + `${indent}${G.info} ${c.dim(n === 0 ? "no matches" : `${n} file${n === 1 ? "" : "s"}${r.truncated ? " (capped)" : ""}`)}`,
|
|
38
|
+
│ + );
|
|
39
|
+
│ … +150 lines
|
|
40
|
+
⠦ thinking
|
|
41
|
+
```
|
|
42
|
+
User also had to kill the app.
|
|
43
|
+
|
|
44
|
+
Only seen with Gemini/Google models.
|
|
45
|
+
Only happens after shell tool calls.
|
|
46
|
+
Other tools calls worked just fine during the same session with the same model and mini-coder version.
|
|
47
|
+
There are no shell tool related hooks configured anywhere.
|
|
48
|
+
|
|
49
|
+
The expectation was the turn to continue as normal since the tool calls succeded.
|
|
50
|
+
|
|
51
|
+
Find the root cause, show proof.
|
|
52
|
+
|
|
53
|
+
## Findings:
|
|
54
|
+
|
|
55
|
+
Here is the concrete proof I just ran, no edits:
|
|
56
|
+
- I executed renderTurn with an event stream that does:
|
|
57
|
+
1) tool-call-start(shell)
|
|
58
|
+
2) tool-result(shell success)
|
|
59
|
+
3) then never yields again
|
|
60
|
+
- Result: the promise did not resolve within 700ms (timed_out_700ms).
|
|
61
|
+
Then I ran the same sequence but added turn-complete:
|
|
62
|
+
- Result: it resolved immediately (resolved).
|
|
63
|
+
So this is now proven in your codepath:
|
|
64
|
+
- renderTurn waits forever when the upstream async stream goes silent after a shell tool result.
|
|
65
|
+
- This exactly matches the visible hang states.
|
|
66
|
+
|
|
67
|
+
### Root Cause 1: Hangs spinning on `"shell"`
|
|
68
|
+
**Proof in code:** `src/tools/shell.ts`
|
|
69
|
+
* When a command times out, `proc.kill("SIGTERM")` only kills the parent process (e.g., `bash`). Any child processes (e.g., `bun`) become orphaned but stay alive, holding the write end of the `stdout`/`stderr` pipes open.
|
|
70
|
+
* Because the pipe never closes, `await reader.read()` inside `collectStream()` hangs indefinitely.
|
|
71
|
+
* Because `collectStream()` never resolves, the tool execution never finishes, `tool-result` is never yielded, and the stream goes completely silent while the spinner stays stuck on "shell".
|
|
72
|
+
- **FIXED**
|
|
73
|
+
|
|
74
|
+
### Root Cause 2: Hangs spinning on `"thinking"`
|
|
75
|
+
**Proof in code:** `src/llm-api/turn.ts`
|
|
76
|
+
* After `git diff` completes, the tool resolves and `renderTurn` switches the spinner to `"thinking"`.
|
|
77
|
+
* The AI SDK automatically makes a new HTTP request to the Gemini API containing the tool result to generate the next step.
|
|
78
|
+
* Gemini's API occasionally hangs indefinitely or silently drops connections when receiving certain payloads (like large tool outputs or ANSI color codes, which `git diff` outputs).
|
|
79
|
+
* Because there is no timeout configured on the `streamText` call in `runTurn` (unless the user manually aborts), the underlying fetch request waits forever. The `result.fullStream` never yields the next chunk, but also never closes or errors.
|
package/package.json
CHANGED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# Code Health Remediation Plan
|
|
2
|
+
|
|
3
|
+
## Goal
|
|
4
|
+
Address maintainability and reliability issues identified in `code-health.md` with low-risk, incremental refactors that keep behavior stable.
|
|
5
|
+
|
|
6
|
+
## Constraints
|
|
7
|
+
- Keep `mini-coder-idea.md` and `README.md` unchanged.
|
|
8
|
+
- Prefer small PR-sized changes with passing tests after each step.
|
|
9
|
+
- Preserve current CLI behavior while improving structure.
|
|
10
|
+
|
|
11
|
+
## Workstreams
|
|
12
|
+
|
|
13
|
+
### 1) Decompose `src/agent/agent.ts` (High)
|
|
14
|
+
**Outcome:** `runAgent` remains orchestration entrypoint; responsibilities split into focused modules.
|
|
15
|
+
|
|
16
|
+
**Steps:**
|
|
17
|
+
1. Add `src/agent/reporter.ts` interface (narrow surface for output/status/tool events).
|
|
18
|
+
2. Extract session lifecycle + turn loop into `src/agent/session-runner.ts`.
|
|
19
|
+
3. Extract subagent execution into `src/agent/subagent-runner.ts`.
|
|
20
|
+
4. Extract snapshot/undo helpers into `src/agent/undo-snapshot.ts`.
|
|
21
|
+
5. Extract user input processing into `src/agent/input-loop.ts`.
|
|
22
|
+
6. Keep `agent.ts` as composition/wiring file only.
|
|
23
|
+
|
|
24
|
+
**Checks:**
|
|
25
|
+
- Add/adjust unit tests around orchestration boundaries.
|
|
26
|
+
- Ensure no behavior regressions in interrupts, resume, and tool-call flows.
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
### 2) Decompose `src/cli/output.ts` (High)
|
|
31
|
+
**Outcome:** Rendering responsibilities isolated and testable.
|
|
32
|
+
|
|
33
|
+
**Target modules:**
|
|
34
|
+
- `src/cli/spinner.ts`
|
|
35
|
+
- `src/cli/tool-render.ts`
|
|
36
|
+
- `src/cli/stream-render.ts`
|
|
37
|
+
- `src/cli/status-bar.ts`
|
|
38
|
+
- `src/cli/error-render.ts`
|
|
39
|
+
- `src/cli/output.ts` as facade
|
|
40
|
+
|
|
41
|
+
**Steps:**
|
|
42
|
+
1. Extract pure formatting helpers first (no IO).
|
|
43
|
+
2. Extract spinner lifecycle module.
|
|
44
|
+
3. Extract stream queue/tick/flush behavior.
|
|
45
|
+
4. Keep compatibility exports in `output.ts` to avoid broad callsite churn.
|
|
46
|
+
|
|
47
|
+
**Checks:**
|
|
48
|
+
- Add focused tests for formatting + stream behavior.
|
|
49
|
+
- Verify terminal rendering remains stable manually.
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
### 3) Introduce `TerminalIO` abstraction (Medium)
|
|
54
|
+
**Outcome:** Centralized process/TTY interactions and signal lifecycle.
|
|
55
|
+
|
|
56
|
+
**Steps:**
|
|
57
|
+
1. Create `src/cli/terminal-io.ts` with methods for stdout/stderr writes, raw mode, signal subscriptions.
|
|
58
|
+
2. Replace direct `process.*` use in output/input stack with injected `TerminalIO`.
|
|
59
|
+
3. Centralize signal registration/unregistration in one lifecycle owner.
|
|
60
|
+
|
|
61
|
+
**Checks:**
|
|
62
|
+
- Add unit tests for signal registration cleanup semantics.
|
|
63
|
+
- Confirm no stuck raw-mode edge cases.
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
### 4) Split DB layer by domain (Medium)
|
|
68
|
+
**Outcome:** Reduced blast radius and clearer data ownership.
|
|
69
|
+
|
|
70
|
+
**Target modules:**
|
|
71
|
+
- `src/session/db/connection.ts`
|
|
72
|
+
- `src/session/db/session-repo.ts`
|
|
73
|
+
- `src/session/db/message-repo.ts`
|
|
74
|
+
- `src/session/db/settings-repo.ts`
|
|
75
|
+
- `src/session/db/mcp-repo.ts`
|
|
76
|
+
- `src/session/db/snapshot-repo.ts`
|
|
77
|
+
- `src/session/db/index.ts` (facade exports)
|
|
78
|
+
|
|
79
|
+
**Steps:**
|
|
80
|
+
1. Move code without behavior changes.
|
|
81
|
+
2. Keep SQL and schema unchanged initially.
|
|
82
|
+
3. Replace direct `JSON.parse` in message loading with guarded parser:
|
|
83
|
+
- skip malformed rows
|
|
84
|
+
- emit diagnostic via logger/reporter
|
|
85
|
+
|
|
86
|
+
**Checks:**
|
|
87
|
+
- Add tests for malformed payload handling.
|
|
88
|
+
- Validate existing DB tests still pass.
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
### 5) Shared markdown config loader (Medium)
|
|
93
|
+
**Outcome:** Remove duplication across agents/skills/custom-commands.
|
|
94
|
+
|
|
95
|
+
**Steps:**
|
|
96
|
+
1. Create `src/cli/load-markdown-configs.ts` with parameterized layout strategy.
|
|
97
|
+
2. Migrate:
|
|
98
|
+
- `src/cli/agents.ts`
|
|
99
|
+
- `src/cli/skills.ts`
|
|
100
|
+
- `src/cli/custom-commands.ts`
|
|
101
|
+
3. Keep precedence rules identical (built-in/user/project).
|
|
102
|
+
4. Preserve existing frontmatter semantics.
|
|
103
|
+
|
|
104
|
+
**Checks:**
|
|
105
|
+
- Reuse/expand existing loader tests to cover parity.
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
### 6) Runtime/UI decoupling via reporter boundary (Medium)
|
|
110
|
+
**Outcome:** Core runtime no longer depends directly on terminal rendering.
|
|
111
|
+
|
|
112
|
+
**Steps:**
|
|
113
|
+
1. Define domain events or reporter interface in `src/agent/reporter.ts`.
|
|
114
|
+
2. Implement CLI reporter adapter in `src/cli/output-reporter.ts`.
|
|
115
|
+
3. Replace direct output calls in agent runtime with reporter calls.
|
|
116
|
+
|
|
117
|
+
**Checks:**
|
|
118
|
+
- Add tests using test reporter to assert emitted events.
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
### 7) Error observability and silent catches (Medium)
|
|
123
|
+
**Outcome:** Non-fatal failures become diagnosable without crashing.
|
|
124
|
+
|
|
125
|
+
**Steps:**
|
|
126
|
+
1. Find empty/broad catches in agent/output/loaders.
|
|
127
|
+
2. Add debug-level diagnostics with contextual metadata.
|
|
128
|
+
3. Keep user-facing behavior unchanged unless critical.
|
|
129
|
+
|
|
130
|
+
**Checks:**
|
|
131
|
+
- Validate noisy paths are still quiet at normal verbosity.
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
### 8) Startup FS sync usage (Low/Deferred)
|
|
136
|
+
**Outcome:** Optional responsiveness improvement if startup cost grows.
|
|
137
|
+
|
|
138
|
+
**Steps:**
|
|
139
|
+
1. Measure startup and config-loading time first.
|
|
140
|
+
2. If needed, move high-volume file scanning to async or cache results with invalidation.
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
### 9) Test hygiene cleanup (Low)
|
|
145
|
+
**Outcome:** Cleaner CI output.
|
|
146
|
+
|
|
147
|
+
**Steps:**
|
|
148
|
+
1. Remove `console.log` skip notices in `src/tools/shell.test.ts`.
|
|
149
|
+
2. Use test-framework-native skip annotations/helpers.
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## Execution Order (recommended)
|
|
154
|
+
1. Reporter interface (foundation for later decoupling).
|
|
155
|
+
2. `agent.ts` decomposition.
|
|
156
|
+
3. `output.ts` decomposition.
|
|
157
|
+
4. Shared config loader extraction.
|
|
158
|
+
5. DB module split + safe JSON parsing.
|
|
159
|
+
6. TerminalIO + centralized signals.
|
|
160
|
+
7. Silent catch diagnostics.
|
|
161
|
+
8. Test hygiene and any deferred FS optimization.
|
|
162
|
+
|
|
163
|
+
## Definition of Done
|
|
164
|
+
- `bun run typecheck && bun run format && bun run lint && bun test` passes.
|
|
165
|
+
- No behavior regressions in interactive CLI flows.
|
|
166
|
+
- `agent.ts` and `output.ts` materially reduced in size/responsibility.
|
|
167
|
+
- Config loader duplication removed.
|
|
168
|
+
- Message loading resilient to malformed JSON rows.
|
|
169
|
+
- New abstractions documented in code comments where non-obvious.
|