opencode-miniterm 1.0.3 ā 1.0.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.
- package/package.json +1 -1
- package/src/commands/page.ts +2 -6
- package/src/render.ts +26 -4
- package/test/render.test.ts +52 -13
package/package.json
CHANGED
package/src/commands/page.ts
CHANGED
|
@@ -25,13 +25,9 @@ function run(client: OpencodeClient, state: State): void {
|
|
|
25
25
|
if (!part || !part.text.trim()) continue;
|
|
26
26
|
|
|
27
27
|
if (part.title === "thinking") {
|
|
28
|
-
pages.push(
|
|
29
|
-
`${ansi.BOLD_BRIGHT_BLACK}~${ansi.RESET} ${ansi.BRIGHT_BLACK}${part.text.trimStart()}${ansi.RESET}`,
|
|
30
|
-
);
|
|
28
|
+
pages.push(`š ${ansi.BRIGHT_BLACK}${part.text.trimStart()}${ansi.RESET}`);
|
|
31
29
|
} else if (part.title === "response") {
|
|
32
|
-
pages.push(
|
|
33
|
-
`${ansi.WHITE_BACKGROUND}${ansi.BOLD_BLACK}*${ansi.RESET} ${part.text.trimStart()}`,
|
|
34
|
-
);
|
|
30
|
+
pages.push(`š ${part.text.trimStart()}`);
|
|
35
31
|
} else {
|
|
36
32
|
pages.push(part.text);
|
|
37
33
|
}
|
package/src/render.ts
CHANGED
|
@@ -23,6 +23,7 @@ export function render(state: State, details = false): void {
|
|
|
23
23
|
|
|
24
24
|
if (part.title === "thinking") {
|
|
25
25
|
if (part.active === false) {
|
|
26
|
+
// We've already checked all the parts before here
|
|
26
27
|
break;
|
|
27
28
|
}
|
|
28
29
|
part.active = !foundPart;
|
|
@@ -35,6 +36,7 @@ export function render(state: State, details = false): void {
|
|
|
35
36
|
}
|
|
36
37
|
}
|
|
37
38
|
|
|
39
|
+
let lastPartWasTool = false;
|
|
38
40
|
for (let i = 0; i < state.accumulatedResponse.length; i++) {
|
|
39
41
|
const part = state.accumulatedResponse[i];
|
|
40
42
|
if (!part || !part.active) continue;
|
|
@@ -43,19 +45,29 @@ export function render(state: State, details = false): void {
|
|
|
43
45
|
if (part.title === "thinking") {
|
|
44
46
|
// Show max 10 thinking lines
|
|
45
47
|
const partText = details ? part.text.trimStart() : lastThinkingLines(part.text.trimStart());
|
|
46
|
-
output +=
|
|
48
|
+
output += "<ocmt-thinking>\n";
|
|
49
|
+
output += `š ${partText}\n\n`;
|
|
50
|
+
output += "</ocmt-thinking>\n";
|
|
47
51
|
} else if (part.title === "response") {
|
|
48
52
|
// Show all response lines
|
|
49
53
|
const doc = parse(part.text.trimStart(), gfm);
|
|
50
54
|
const partText = renderToConsole(doc);
|
|
51
|
-
output +=
|
|
52
|
-
} else if (part.title === "tool"
|
|
55
|
+
output += `š¬ ${partText}\n\n`;
|
|
56
|
+
} else if (part.title === "tool") {
|
|
57
|
+
// TODO: Show max 10 tool/file lines?
|
|
58
|
+
if (lastPartWasTool && output.endsWith("\n\n")) {
|
|
59
|
+
output = output.substring(0, output.length - 1);
|
|
60
|
+
}
|
|
61
|
+
output += part.text + "\n\n";
|
|
62
|
+
} else if (part.title === "files") {
|
|
53
63
|
// TODO: Show max 10 tool/file lines?
|
|
54
64
|
output += part.text + "\n\n";
|
|
55
65
|
} else if (part.title === "todo") {
|
|
56
66
|
// Show the whole todo list
|
|
57
67
|
output += part.text + "\n\n";
|
|
58
68
|
}
|
|
69
|
+
|
|
70
|
+
lastPartWasTool = part.title === "tool";
|
|
59
71
|
}
|
|
60
72
|
|
|
61
73
|
if (output) {
|
|
@@ -135,8 +147,18 @@ export function wrapText(text: string, width: number): string[] {
|
|
|
135
147
|
let visibleLength = indentLength;
|
|
136
148
|
let i = 0;
|
|
137
149
|
|
|
150
|
+
let inThinking = false;
|
|
151
|
+
|
|
138
152
|
const pushLine = () => {
|
|
139
|
-
|
|
153
|
+
if (currentLine === " <ocmt-thinking>") {
|
|
154
|
+
inThinking = true;
|
|
155
|
+
} else if (currentLine === " </ocmt-thinking>") {
|
|
156
|
+
inThinking = false;
|
|
157
|
+
} else {
|
|
158
|
+
let text = inThinking ? `${ansi.BRIGHT_BLACK}${currentLine}${ansi.RESET}` : currentLine;
|
|
159
|
+
lines.push(text);
|
|
160
|
+
}
|
|
161
|
+
|
|
140
162
|
currentLine = INDENT;
|
|
141
163
|
visibleLength = indentLength;
|
|
142
164
|
};
|
package/test/render.test.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { stripANSI } from "bun";
|
|
1
2
|
import { describe, expect, it, vi } from "bun:test";
|
|
2
3
|
import { type State } from "../src";
|
|
3
4
|
import * as ansi from "../src/ansi";
|
|
@@ -62,7 +63,7 @@ describe("render", () => {
|
|
|
62
63
|
const calls = write.mock.calls.map((c) => c[0]);
|
|
63
64
|
expect(calls.some((c) => c.includes("\u001B[2A"))).toBe(true);
|
|
64
65
|
const outputCall = calls.find((c) => c.includes("i've done it"));
|
|
65
|
-
expect(outputCall).toContain(
|
|
66
|
+
expect(outputCall).toContain(`š¬`);
|
|
66
67
|
});
|
|
67
68
|
});
|
|
68
69
|
|
|
@@ -77,9 +78,7 @@ describe("render", () => {
|
|
|
77
78
|
render(state);
|
|
78
79
|
|
|
79
80
|
const output = write.mock.calls.map((c) => c[0]).join("");
|
|
80
|
-
expect(output).toContain(
|
|
81
|
-
`${ansi.BOLD_BRIGHT_BLACK}~${ansi.RESET} ${ansi.BRIGHT_BLACK}åęé®é¢${ansi.RESET}`,
|
|
82
|
-
);
|
|
81
|
+
expect(output).toContain(`${ansi.BRIGHT_BLACK} š åęé®é¢${ansi.RESET}`);
|
|
83
82
|
});
|
|
84
83
|
|
|
85
84
|
it("should only show thinking indicator for last thinking part", () => {
|
|
@@ -95,9 +94,7 @@ describe("render", () => {
|
|
|
95
94
|
render(state);
|
|
96
95
|
|
|
97
96
|
const output = write.mock.calls.map((c) => c[0]).join("");
|
|
98
|
-
expect(output).toContain(
|
|
99
|
-
`${ansi.BOLD_BRIGHT_BLACK}~${ansi.RESET} ${ansi.BRIGHT_BLACK}second${ansi.RESET}`,
|
|
100
|
-
);
|
|
97
|
+
expect(output).toContain(`${ansi.BRIGHT_BLACK} š second${ansi.RESET}`);
|
|
101
98
|
expect(output).not.toContain("first");
|
|
102
99
|
});
|
|
103
100
|
|
|
@@ -124,6 +121,31 @@ describe("render", () => {
|
|
|
124
121
|
|
|
125
122
|
expect(write).toHaveBeenCalled();
|
|
126
123
|
});
|
|
124
|
+
|
|
125
|
+
it("all thinking lines should be gray", () => {
|
|
126
|
+
const write = vi.fn();
|
|
127
|
+
const state = createMockState({
|
|
128
|
+
accumulatedResponse: [
|
|
129
|
+
{
|
|
130
|
+
key: "xxx",
|
|
131
|
+
title: "thinking",
|
|
132
|
+
text: "Cookware and bakeware is food preparation equipment, such as cooking pots, pans, baking sheets etc. used in kitchens. Cookware is used on a stove or range cooktop, while bakeware is used in an oven. Some utensils are considered both cookware and bakeware.",
|
|
133
|
+
},
|
|
134
|
+
],
|
|
135
|
+
write,
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
render(state);
|
|
139
|
+
|
|
140
|
+
const output = write.mock.calls.map((c) => c[0]).join("");
|
|
141
|
+
expect(output).toContain(
|
|
142
|
+
`${ansi.BRIGHT_BLACK} š Cookware and bakeware is food preparation equipment, such as cooking pots, pans, baking sheets etc. used in kitchens. Cookware is used on a stove${ansi.RESET}`,
|
|
143
|
+
);
|
|
144
|
+
expect(output).toContain(
|
|
145
|
+
`${ansi.BRIGHT_BLACK} or range cooktop, while bakeware is used in an oven. Some utensils are considered both cookware and bakeware.${ansi.RESET}`,
|
|
146
|
+
);
|
|
147
|
+
expect(output).not.toContain("first");
|
|
148
|
+
});
|
|
127
149
|
});
|
|
128
150
|
|
|
129
151
|
describe("response parts", () => {
|
|
@@ -137,9 +159,7 @@ describe("render", () => {
|
|
|
137
159
|
render(state);
|
|
138
160
|
|
|
139
161
|
const output = write.mock.calls.map((c) => c[0]).join("");
|
|
140
|
-
expect(output).toContain(
|
|
141
|
-
`${ansi.WHITE_BACKGROUND}${ansi.BOLD_BLACK}*${ansi.RESET} Hello world`,
|
|
142
|
-
);
|
|
162
|
+
expect(output).toContain(`š¬ Hello world`);
|
|
143
163
|
});
|
|
144
164
|
});
|
|
145
165
|
|
|
@@ -156,6 +176,27 @@ describe("render", () => {
|
|
|
156
176
|
const output = write.mock.calls.map((c) => c[0]).join("");
|
|
157
177
|
expect(output).toContain("bash: ls -la");
|
|
158
178
|
});
|
|
179
|
+
|
|
180
|
+
it("multiple tool parts separated by inactive parts shouldn't have a blank line", () => {
|
|
181
|
+
const write = vi.fn();
|
|
182
|
+
const state = createMockState({
|
|
183
|
+
accumulatedResponse: [
|
|
184
|
+
{ key: "xxx", title: "tool", text: "foo" },
|
|
185
|
+
{ key: "xxx", title: "thinking", text: "need to do the stuff" },
|
|
186
|
+
{ key: "xxx", title: "tool", text: "bar" },
|
|
187
|
+
{ key: "xxx", title: "thinking", text: "ok, more stuff" },
|
|
188
|
+
{ key: "xxx", title: "tool", text: "baz" },
|
|
189
|
+
],
|
|
190
|
+
write,
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
render(state);
|
|
194
|
+
|
|
195
|
+
const output = stripANSI(write.mock.calls.map((c) => c[0]).join("")).replaceAll(" ", "");
|
|
196
|
+
console.log(output);
|
|
197
|
+
expect(output).toContain("foo\nbar\n\nš ok");
|
|
198
|
+
expect(output).toContain("stuff\n\nbaz");
|
|
199
|
+
});
|
|
159
200
|
});
|
|
160
201
|
|
|
161
202
|
describe("files parts", () => {
|
|
@@ -253,9 +294,7 @@ describe("render", () => {
|
|
|
253
294
|
const output = write.mock.calls.map((c) => c[0]).join("");
|
|
254
295
|
expect(output).not.toContain(`åęäø`);
|
|
255
296
|
expect(output).toContain(`bash: npm test`);
|
|
256
|
-
expect(output).toContain(
|
|
257
|
-
`${ansi.WHITE_BACKGROUND}${ansi.BOLD_BLACK}*${ansi.RESET} Test results: 5 passed`,
|
|
258
|
-
);
|
|
297
|
+
expect(output).toContain(`š¬ Test results: 5 passed`);
|
|
259
298
|
});
|
|
260
299
|
});
|
|
261
300
|
});
|