little-coder 1.9.3 → 1.9.4
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.
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
type SubCoderResult,
|
|
9
9
|
} from "./spawn.ts";
|
|
10
10
|
import { SubCoderTracker } from "./tracker.ts";
|
|
11
|
+
import { truncateLineToWidth } from "../_shared/width.ts";
|
|
11
12
|
|
|
12
13
|
// The `dispatch` tool: the main little-coder spawns isolated child little-coder
|
|
13
14
|
// sessions ("sub-coders") to research a focused question — they read the repo
|
|
@@ -190,11 +191,22 @@ export default function (pi: ExtensionAPI) {
|
|
|
190
191
|
});
|
|
191
192
|
}
|
|
192
193
|
|
|
193
|
-
/** A minimal pi-tui Component backed by precomputed lines.
|
|
194
|
-
|
|
194
|
+
/** A minimal pi-tui Component backed by precomputed lines.
|
|
195
|
+
*
|
|
196
|
+
* pi paints custom tool-result panels with a 1-char left margin + background-
|
|
197
|
+
* frame fill, so any line we hand back that's wider than `width - 1` overflows
|
|
198
|
+
* the terminal and crashes pi-tui (issue #51 / reopen of #48 — the dispatch
|
|
199
|
+
* renderer fed an unbounded sub-coder report sentence into the panel, and on
|
|
200
|
+
* `--resume` the same renderer paints session history, so the crash recurred
|
|
201
|
+
* even after v1.9.2 capped the *live* tracker). We respect the pi-supplied
|
|
202
|
+
* `width` here and truncate every line to `width - 2`, leaving a 2-char
|
|
203
|
+
* safety margin so wide unicode chars in the report can't sneak past our
|
|
204
|
+
* char-count-based visibleWidth approximation. */
|
|
205
|
+
export function makeComponent(lines: string[]) {
|
|
195
206
|
return {
|
|
196
|
-
render(
|
|
197
|
-
|
|
207
|
+
render(width: number): string[] {
|
|
208
|
+
const cap = Math.max(1, width - 2);
|
|
209
|
+
return lines.map((l) => truncateLineToWidth(l, cap));
|
|
198
210
|
},
|
|
199
211
|
invalidate() {},
|
|
200
212
|
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { makeComponent } from "./index.ts";
|
|
3
|
+
|
|
4
|
+
// Live regression for issue #51 (and the #48 reopen — same root cause from a
|
|
5
|
+
// different code path). pi paints the dispatch tool-result panel with a 1-char
|
|
6
|
+
// background-color left margin + fill; any line we return wider than
|
|
7
|
+
// `width - 1` overflows pi-tui and crashes the session, including on
|
|
8
|
+
// `--resume` because pi re-renders saved tool results from session history.
|
|
9
|
+
//
|
|
10
|
+
// The user's crash log showed a 134-char sub-coder report sentence rendered
|
|
11
|
+
// at terminal width 133 → 135 > 133. This test drives makeComponent at the
|
|
12
|
+
// same width with the same shape and asserts no emitted line exceeds.
|
|
13
|
+
|
|
14
|
+
const stripAnsi = (s: string) => s.replace(/\x1b\[[0-9;]*[a-zA-Z]/g, "");
|
|
15
|
+
const visibleWidth = (s: string) => stripAnsi(s).length;
|
|
16
|
+
|
|
17
|
+
describe("issue #51 — dispatch renderResult doesn't overflow", () => {
|
|
18
|
+
it("caps a wide sub-coder report line to fit the pi-supplied width", () => {
|
|
19
|
+
const wideSentence =
|
|
20
|
+
"There is **no `rate_limits` table**. The entire file defines a single class, `ConversationStore`, which manages only one SQLite table:";
|
|
21
|
+
// Sanity: this is the exact 134-char shape from the user's crash log.
|
|
22
|
+
expect(wideSentence.length).toBeGreaterThan(133);
|
|
23
|
+
const comp = makeComponent([
|
|
24
|
+
"✓ Storage schema",
|
|
25
|
+
"**Report: `bot/storage.py` Schema Analysis**",
|
|
26
|
+
"",
|
|
27
|
+
wideSentence,
|
|
28
|
+
"",
|
|
29
|
+
" …",
|
|
30
|
+
"(Ctrl+O to expand)",
|
|
31
|
+
]);
|
|
32
|
+
const out = comp.render(133);
|
|
33
|
+
const max = Math.max(...out.map((l) => visibleWidth(l)));
|
|
34
|
+
expect(max).toBeLessThanOrEqual(133);
|
|
35
|
+
// The truncated wide sentence keeps its prefix verbatim — it's not blanked
|
|
36
|
+
// out, just clipped with an ellipsis so the user can still read most of it.
|
|
37
|
+
const truncated = out[3];
|
|
38
|
+
expect(stripAnsi(truncated).startsWith("There is **no")).toBe(true);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it("survives a narrow terminal (40 cols) without throwing", () => {
|
|
42
|
+
const comp = makeComponent([
|
|
43
|
+
"very long content " + "x".repeat(500),
|
|
44
|
+
"another long line " + "y".repeat(200),
|
|
45
|
+
]);
|
|
46
|
+
const out = comp.render(40);
|
|
47
|
+
expect(Math.max(...out.map((l) => visibleWidth(l)))).toBeLessThanOrEqual(40);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("preserves short lines unchanged", () => {
|
|
51
|
+
const comp = makeComponent(["short", "tiny"]);
|
|
52
|
+
expect(comp.render(133)).toEqual(["short", "tiny"]);
|
|
53
|
+
});
|
|
54
|
+
});
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to little-coder are documented here. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and little-coder's public interface (CLI, providers, tools, skills) follows semver starting at `v0.0.1` post-rename.
|
|
4
4
|
|
|
5
|
+
## [v1.9.4] — 2026-06-18
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
- **Dispatch tool-result panel overflows the terminal on wide report lines** ([#51](https://github.com/itayinbarr/little-coder/issues/51), reopen of [#48](https://github.com/itayinbarr/little-coder/issues/48)). v1.9.2 capped every line the *live* sub-coder tracker emitted, but the **dispatch tool's result renderer** (`subagent/index.ts`'s `makeComponent`) was still ignoring the `width` arg pi passes to `render(width)` — it returned the precomputed lines verbatim. pi paints the tool-result panel with a 1-char background-color left margin, so any sub-coder report sentence wider than `terminal_width - 1` overflowed pi-tui. Crash log line 453 was a 134-char markdown sentence rendered at terminal width 133 → 135 > 133. The same path runs on **`--resume`** (pi re-paints saved tool results from session history), so v1.9.2 users still hit it after upgrading whenever they resumed a session with a wide dispatch report saved — that's why @steverhoades caught the regression. `makeComponent` now truncates every emitted line to `width - 2` using the existing `_shared/width.ts` utility (2-char safety margin for wide unicode under our char-count-based `visibleWidth` approximation), so the dispatch panel can no longer crash a session — live, on resume, or anywhere else. New `subagent/issue-51-repro.test.ts` drives `makeComponent` with the user's exact 134-char content shape at width 133 and asserts no emitted line exceeds, plus a narrow-terminal (40-col) survival check.
|
|
9
|
+
|
|
10
|
+
### Notes for upgraders
|
|
11
|
+
- No CLI-flag or public-API changes. If you saw `Rendered line N exceeds terminal width` on v1.9.2 / 1.9.3 — especially while *resuming* a session — 1.9.4 fixes it. If you still see it after upgrading, the offending line in `~/.pi/agent/pi-crash.log` should let us spot the source; reopen #51 or #48 with the log attached.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
5
15
|
## [v1.9.3] — 2026-06-18
|
|
6
16
|
|
|
7
17
|
### Added
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "little-coder",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.4",
|
|
4
4
|
"description": "A pi-based coding agent optimized for small local language models. Reproduces the whitepaper's scaffold-model-fit adaptations as pi extensions.",
|
|
5
5
|
"homepage": "https://github.com/itayinbarr/little-coder",
|
|
6
6
|
"repository": {
|