@oh-my-pi/pi-tui 18.2.7 → 18.2.8

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/CHANGELOG.md CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [18.2.8] - 2026-09-21
6
+
7
+ ### Changed
8
+
9
+ - Improved Bash tool background-task notices by providing completed output as a follow-up and discouraging unnecessary polling.
10
+
5
11
  ## [18.2.7] - 2026-09-21
6
12
 
7
13
  ### Breaking Changes
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@oh-my-pi/pi-tui",
4
- "version": "18.2.7",
4
+ "version": "18.2.8",
5
5
  "description": "Terminal User Interface library with differential rendering for efficient text-based applications",
6
6
  "homepage": "https://omp.sh",
7
7
  "author": "Stencil Labs, Inc.",
@@ -37,14 +37,14 @@
37
37
  "fmt": "oxfmt --no-error-on-unmatched-pattern 'src/**/*.{ts,tsx}' '{test,bench,examples,scripts}/**/*.ts' '*.ts'"
38
38
  },
39
39
  "dependencies": {
40
- "@oh-my-pi/omptype": "18.2.7",
41
- "@oh-my-pi/pi-agent-core": "18.2.7",
42
- "@oh-my-pi/pi-ai": "18.2.7",
43
- "@oh-my-pi/pi-catalog": "18.2.7",
44
- "@oh-my-pi/pi-natives": "18.2.7",
45
- "@oh-my-pi/pi-utils": "18.2.7",
46
- "@oh-my-pi/pi-wire": "18.2.7",
47
- "@oh-my-pi/snapcompact": "18.2.7"
40
+ "@oh-my-pi/omptype": "18.2.8",
41
+ "@oh-my-pi/pi-agent-core": "18.2.8",
42
+ "@oh-my-pi/pi-ai": "18.2.8",
43
+ "@oh-my-pi/pi-catalog": "18.2.8",
44
+ "@oh-my-pi/pi-natives": "18.2.8",
45
+ "@oh-my-pi/pi-utils": "18.2.8",
46
+ "@oh-my-pi/pi-wire": "18.2.8",
47
+ "@oh-my-pi/snapcompact": "18.2.8"
48
48
  },
49
49
  "devDependencies": {
50
50
  "kitty-vt-wasm": "^0.2.0"
@@ -1114,8 +1114,12 @@ export class Editor implements Component, Focusable {
1114
1114
  const lastGrapheme = beforeGraphemes[beforeGraphemes.length - 1]?.segment;
1115
1115
  const lastGraphemeWidth = lastGrapheme ? visibleWidth(lastGrapheme) : 0;
1116
1116
  const builtInCursor = this.#getStyledInputCursor();
1117
+ // The end-of-line cursor borrows the last grapheme's cell, which the
1118
+ // on-character cursor also highlights with reverse video. Underline the
1119
+ // borrowed cell instead so insertion after the last character stays
1120
+ // visually distinct from insertion before it.
1117
1121
  const fallbackReplacement = lastGrapheme
1118
- ? { text: this.#cursorCell(lastGrapheme), width: lastGraphemeWidth }
1122
+ ? { text: `\x1b[4m${lastGrapheme}\x1b[0m`, width: lastGraphemeWidth }
1119
1123
  : builtInCursor;
1120
1124
  const clampReplacement = (candidate: { text: string; width: number }): { text: string; width: number } => {
1121
1125
  let text = sliceByColumn(candidate.text, 0, maxWidth, true);
@@ -1136,7 +1140,6 @@ export class Editor implements Component, Focusable {
1136
1140
  // If even the highlighted trailing grapheme cannot fit, show the built-in single-column cursor.
1137
1141
  clampedReplacement = clampReplacement(builtInCursor);
1138
1142
  }
1139
-
1140
1143
  const replacedSpanWidth = Math.min(maxWidth, Math.max(lastGraphemeWidth, clampedReplacement.width));
1141
1144
  const prefixWidth = Math.max(0, maxWidth - replacedSpanWidth);
1142
1145
  const beforePrefix = sliceByColumn(before, 0, prefixWidth, true);
@@ -1152,17 +1155,14 @@ export class Editor implements Component, Focusable {
1152
1155
  if (visibleWidth(text) < maxWidth) {
1153
1156
  return text + marker;
1154
1157
  }
1155
-
1156
- let insertAt = text.length;
1157
- let offset = 0;
1158
- for (const seg of segmenter.segment(text)) {
1159
- if (visibleWidth(seg.segment) > 0) {
1160
- insertAt = offset;
1161
- }
1162
- offset += seg.segment.length;
1163
- }
1164
-
1165
- return `${text.slice(0, insertAt)}${marker}${text.slice(insertAt)}`;
1158
+ // The row is exactly full, so the marker lands before the last visible
1159
+ // grapheme instead of after it. The mirrored on-character position renders
1160
+ // the identical string; underline the final grapheme at end-of-line so the
1161
+ // two insertion points stay visually distinct.
1162
+ const graphemes = [...segmenter.segment(text)];
1163
+ const lastGrapheme = graphemes[graphemes.length - 1]?.segment;
1164
+ if (lastGrapheme === undefined) return text + marker;
1165
+ return `${text.slice(0, text.length - lastGrapheme.length)}\x1b[4m${lastGrapheme}\x1b[0m${marker}`;
1166
1166
  }
1167
1167
 
1168
1168
  #getPageScrollStep(totalVisualLines: number): number {
package/src/tools/bash.ts CHANGED
@@ -25,7 +25,7 @@ export const BASH_DEFAULT_PREVIEW_LINES = DEFAULT_TERMINAL_PREVIEW_LINES;
25
25
 
26
26
  /** LLM-facing footer appended when a tool call becomes a background job. */
27
27
  export function formatBackgroundNotice(jobId: string): string {
28
- return `Backgrounded as job ${jobId}; result will be delivered automatically.`;
28
+ return `Backgrounded as job ${jobId}; its output is injected into the conversation as a follow-up the moment it finishes. Do NOT poll for it (no \`sleep\`, \`ps\`, \`pgrep\`, \`top\`, \`pidwait\`, log tailing): every poll is a wasted turn. Do other work, or end your reply and wait to be woken.`;
29
29
  }
30
30
 
31
31
  /** Shell execution metadata used by transcript rendering. */