opencode-miniterm 1.0.11 → 1.0.13

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/bun.lock CHANGED
@@ -5,7 +5,7 @@
5
5
  "": {
6
6
  "name": "opencode-miniterm",
7
7
  "dependencies": {
8
- "@opencode-ai/sdk": "^1.2.15",
8
+ "@opencode-ai/sdk": "^1.2.24",
9
9
  "allmark": "^1.0.2",
10
10
  },
11
11
  "devDependencies": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-miniterm",
3
- "version": "1.0.11",
3
+ "version": "1.0.13",
4
4
  "description": "A small front-end terminal UI for OpenCode",
5
5
  "main": "src/index.ts",
6
6
  "bin": {
package/src/ansi.ts CHANGED
@@ -5,7 +5,6 @@ export const CLEAR_SCREEN_UP = "\x1b[2A";
5
5
  export const CURSOR_HOME = "\x1b[0G";
6
6
  export const CURSOR_HIDE = "\x1b[?25l";
7
7
  export const CURSOR_SHOW = "\x1b[?25h";
8
- export const CURSOR_UP = (lines: number) => `\x1b[${lines}A`;
9
8
  export const DISABLE_LINE_WRAP = "\x1b[?7l";
10
9
  export const ENABLE_LINE_WRAP = "\x1b[?7h";
11
10
  export const RESET = "\x1b[0m";
package/src/index.ts CHANGED
@@ -182,34 +182,50 @@ let completionCycling = false;
182
182
  let lastSpaceTime = 0;
183
183
  let currentInputBuffer: string | null = null;
184
184
 
185
- let count = 0;
185
+ let oldInputBuffer = "";
186
186
  let oldWrappedRows = 0;
187
187
  let oldCursorRow = 0;
188
188
  function renderLine(): void {
189
189
  const consoleWidth = process.stdout.columns || 80;
190
190
 
191
+ // Move to the start of the line (i.e. the prompt position)
191
192
  readline.cursorTo(process.stdout, 0);
192
-
193
- // Ensure the cursor is at the end of the old input
194
- if (cursorPosition < inputBuffer.length) {
195
- readline.moveCursor(process.stdout, 0, oldWrappedRows - oldCursorRow);
196
- }
197
-
198
- // Clear the old input
199
193
  if (oldWrappedRows > 0) {
194
+ if (cursorPosition < inputBuffer.length) {
195
+ readline.moveCursor(process.stdout, 0, oldWrappedRows - oldCursorRow);
196
+ }
200
197
  readline.moveCursor(process.stdout, 0, -oldWrappedRows);
201
198
  }
199
+
200
+ // Find the position where the input has changed (i.e. where the user has
201
+ // typed something)
202
+ let start = 0;
203
+ let currentCol = 2;
204
+ let newWrappedRows = 0;
205
+ for (let i = 0; i < Math.min(oldInputBuffer.length, inputBuffer.length); i++) {
206
+ if (oldInputBuffer[i] !== inputBuffer[i]) {
207
+ break;
208
+ }
209
+ if (currentCol >= consoleWidth) {
210
+ readline.moveCursor(process.stdout, 0, 1);
211
+ currentCol = 0;
212
+ newWrappedRows++;
213
+ }
214
+ currentCol++;
215
+ start++;
216
+ }
217
+
218
+ // Clear the old, changed, input
219
+ readline.moveCursor(process.stdout, currentCol, 0);
202
220
  readline.clearScreenDown(process.stdout);
203
- readline.cursorTo(process.stdout, 2);
204
221
 
205
- // Write the prompt
206
- writePrompt();
222
+ if (start === 0) {
223
+ writePrompt();
224
+ }
207
225
 
208
- // Write the new input buffer
226
+ // Write the changes from the new input buffer
209
227
  let renderExtent = Math.max(cursorPosition + 1, inputBuffer.length);
210
- let currentCol = 2;
211
- let newWrappedRows = 0;
212
- for (let i = 0; i < renderExtent; i++) {
228
+ for (let i = start; i < renderExtent; i++) {
213
229
  if (currentCol >= consoleWidth) {
214
230
  process.stdout.write("\n");
215
231
  currentCol = 0;
@@ -221,14 +237,15 @@ function renderLine(): void {
221
237
  currentCol++;
222
238
  }
223
239
 
240
+ // Calculate and move to the cursor's position
224
241
  let absolutePos = 2 + cursorPosition;
225
242
  let newCursorRow = Math.floor(absolutePos / consoleWidth);
226
243
  let newCursorCol = absolutePos % consoleWidth;
227
-
228
244
  readline.cursorTo(process.stdout, 0);
229
245
  readline.moveCursor(process.stdout, 0, -1 * (newWrappedRows - newCursorRow));
230
246
  readline.cursorTo(process.stdout, newCursorCol);
231
247
 
248
+ oldInputBuffer = inputBuffer;
232
249
  oldWrappedRows = newWrappedRows;
233
250
  oldCursorRow = newCursorRow;
234
251
  }
@@ -692,8 +709,8 @@ async function processEvent(event: Event): Promise<void> {
692
709
  const message = event.properties.status.message;
693
710
  const retryTime = event.properties.status.next;
694
711
  const sessionID = event.properties.sessionID;
695
- console.error(`\n${ansi.RED}Error:${ansi.RESET} ${message}`);
696
- console.error(`${ansi.BRIGHT_BLACK}Session:${ansi.RESET} ${sessionID}`);
712
+ console.error(`\n\n ${ansi.RED}Error:${ansi.RESET} ${message}`);
713
+ console.error(` ${ansi.BRIGHT_BLACK}Session:${ansi.RESET} ${sessionID}`);
697
714
  if (retryTime) {
698
715
  if (retryInterval) {
699
716
  clearInterval(retryInterval);
@@ -701,13 +718,13 @@ async function processEvent(event: Event): Promise<void> {
701
718
  const retryDate = new Date(retryTime);
702
719
 
703
720
  let lastSeconds = Math.max(0, Math.ceil((retryDate.getTime() - Date.now()) / 1000));
704
- console.error(`${ansi.BRIGHT_BLACK}Retrying in ${lastSeconds}s...${ansi.RESET}`);
721
+ console.error(` ${ansi.BRIGHT_BLACK}Retrying in ${lastSeconds}s...${ansi.RESET}`);
705
722
 
706
723
  retryInterval = setInterval(() => {
707
724
  const remaining = Math.max(0, Math.ceil((retryDate.getTime() - Date.now()) / 1000));
708
725
  if (remaining !== lastSeconds) {
709
726
  process.stdout.write(
710
- `\r${ansi.BRIGHT_BLACK}Retrying in ${remaining}s...${ansi.RESET}`,
727
+ `\r ${ansi.BRIGHT_BLACK}Retrying in ${remaining}s...${ansi.RESET}`,
711
728
  );
712
729
  lastSeconds = remaining;
713
730
  }
@@ -816,7 +833,9 @@ async function processToolUse(part: Part) {
816
833
  toolPart.state.input["description"] ||
817
834
  toolPart.state.input["filePath"] ||
818
835
  toolPart.state.input["path"] ||
819
- // TODO: more state.input props...
836
+ toolPart.state.input["include"] ||
837
+ toolPart.state.input["pattern"] ||
838
+ // TODO: more state.input props?
820
839
  "...";
821
840
  const toolText = `$ ${toolName}: ${ansi.BRIGHT_BLACK}${toolInput}${ansi.RESET}`;
822
841
 
package/src/render.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import type { OpencodeClient } from "@opencode-ai/sdk";
2
2
  import { gfm, parse, renderToConsole } from "allmark";
3
+ import readline from "node:readline";
3
4
  import * as ansi from "./ansi";
4
5
  import { config } from "./config";
5
6
  import type { State } from "./index";
@@ -138,9 +139,10 @@ function lastThinkingLines(text: string): string {
138
139
 
139
140
  function clearRenderedLines(state: State, linesToClear: number): void {
140
141
  if (linesToClear > 0) {
141
- state.write(`${ansi.CURSOR_UP(linesToClear)}\x1b[J`);
142
+ readline.moveCursor(process.stdout, 0, -1 * linesToClear);
143
+ readline.clearScreenDown(process.stdout);
142
144
  }
143
- state.write(ansi.CURSOR_HOME);
145
+ readline.cursorTo(process.stdout, 0);
144
146
  }
145
147
 
146
148
  export function wrapText(text: string, width: number): string[] {
@@ -301,7 +303,7 @@ export function startAnimation(startTime?: number): void {
301
303
  const elapsedText = formatDuration(elapsed);
302
304
 
303
305
  process.stdout.write(
304
- `\r${ansi.BOLD_MAGENTA}${ANIMATION_CHARS[index]} ${ansi.RESET}${ansi.BRIGHT_BLACK}Running for ${elapsedText}${ansi.RESET}`,
306
+ `\r${ansi.BOLD_MAGENTA}${ANIMATION_CHARS[index]} ${ansi.RESET}${ansi.BRIGHT_BLACK}Running for ${elapsedText}${ansi.RESET} `,
305
307
  );
306
308
  index = (index + 1) % ANIMATION_CHARS.length;
307
309
  }, 100);