zames_pro 2.68.0 → 2.68.1

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
@@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [2.68.1] - 2026-10-08
11
+
12
+ ### Fixed
13
+
14
+ - **ui:** long service messages (send failures, rate limits) are now
15
+ word-wrapped to the same margin as the tool previews (`cols - 1`).
16
+ Before, they were printed at the full terminal width and the terminal
17
+ wrapped them mid-word, so some lines ran to the edge and some stopped
18
+ short. Applies to `LineEditor.warning()` and the non-TTY spinner.
19
+
10
20
  ## [2.68.0] - 2026-10-08
11
21
 
12
22
  ### Changed
@@ -154,6 +154,61 @@ export function charWidth(cp) {
154
154
  // appending an ellipsis when it was cut. Used for one-line previews (tool call
155
155
  // args, tool results) so a long argument cannot print a line wider than the
156
156
  // terminal — which made some terminals show a horizontal scrollbar.
157
+ // Word-wrap a PLAIN (no-ANSI) string to at most `maxCols` visible columns per
158
+ // line. Used for service messages printed above the input (warnings): the
159
+ // terminal's OWN wrap breaks at the full width and mid-word, while our previews
160
+ // stop at cols-1 — the mismatch looked ragged. Wrapping here keeps every line
161
+ // inside the same margin. A single word longer than the width is hard-split so
162
+ // it never overflows.
163
+ export function wrapToWidth(s, maxCols) {
164
+ const width = Math.max(1, Math.floor(maxCols));
165
+ const text = String(s ?? '');
166
+ const out = [];
167
+ for (const raw of text.split(NL)) {
168
+ if (raw === '') {
169
+ out.push('');
170
+ continue;
171
+ }
172
+ let line = '';
173
+ let lineW = 0;
174
+ for (const word of raw.split(' ')) {
175
+ const w = visLen(word);
176
+ // Hard-split a word longer than a whole line.
177
+ if (w > width) {
178
+ if (line) {
179
+ out.push(line);
180
+ }
181
+ let piece = '';
182
+ let pieceW = 0;
183
+ for (const ch of word) {
184
+ const cw = charWidth(ch.codePointAt(0));
185
+ if (pieceW + cw > width) {
186
+ out.push(piece);
187
+ piece = '';
188
+ pieceW = 0;
189
+ }
190
+ piece += ch;
191
+ pieceW += cw;
192
+ }
193
+ line = piece;
194
+ lineW = pieceW;
195
+ continue;
196
+ }
197
+ const sep = line ? 1 : 0;
198
+ if (lineW + sep + w > width) {
199
+ out.push(line);
200
+ line = word;
201
+ lineW = w;
202
+ }
203
+ else {
204
+ line = line ? line + ' ' + word : word;
205
+ lineW += sep + w;
206
+ }
207
+ }
208
+ out.push(line);
209
+ }
210
+ return out.join(NL);
211
+ }
157
212
  export function truncateToWidth(s, maxCols) {
158
213
  const width = Math.max(1, Math.floor(maxCols));
159
214
  const text = String(s ?? '');
package/dist/input.js CHANGED
@@ -3,12 +3,12 @@ import { renderMarkdown } from './markdown.js';
3
3
  import { randomThinkingPhrase, stripEllipsis, DOTS, renderDots, } from './spinner.js';
4
4
  import { translate } from './i18n.js';
5
5
  import { AttachmentStore, parseImagePaste, looksLikeFilePath, } from './attachments.js';
6
- import { NL, CR, ESC, PASTE_START, PASTE_END, SUGGEST_PAGE, isSubsequence, pasteReplacement, expandPastes, safeJson, visRows, visLen, charWidth, layoutInput, formatTokenStatus, tokenStatusLevel, truncateToWidth, CONTEXT_LIMIT, } from './input/layout.js';
6
+ import { NL, CR, ESC, PASTE_START, PASTE_END, SUGGEST_PAGE, isSubsequence, pasteReplacement, expandPastes, safeJson, visRows, visLen, charWidth, layoutInput, formatTokenStatus, tokenStatusLevel, truncateToWidth, wrapToWidth, CONTEXT_LIMIT, } from './input/layout.js';
7
7
  // The pure layout/formatting helpers (visual rows, cursor position, visible
8
8
  // width, paste markers, token formatting) live in ./input/layout.js. They are
9
9
  // re-exported here so every existing import from './input.js' keeps working,
10
10
  // and so tests can import them from either module (C3 step 3).
11
- export { PASTE_MIN_LINES, SUGGEST_PAGE, isSubsequence, countPasteLines, formatPasteMarker, pasteReplacement, expandPastes, visRows, visLen, charWidth, layoutInput, tokenStatusLevel, formatTokenStatus, formatCompactTokens, truncateToWidth, CONTEXT_LIMIT, CONTEXT_YELLOW_PCT, CONTEXT_RED_PCT, } from './input/layout.js';
11
+ export { PASTE_MIN_LINES, SUGGEST_PAGE, isSubsequence, countPasteLines, formatPasteMarker, pasteReplacement, expandPastes, visRows, visLen, charWidth, layoutInput, tokenStatusLevel, formatTokenStatus, formatCompactTokens, truncateToWidth, wrapToWidth, CONTEXT_LIMIT, CONTEXT_YELLOW_PCT, CONTEXT_RED_PCT, } from './input/layout.js';
12
12
  // How long a lone ESC is held before it is treated as the Escape key (and not
13
13
  // as the head of a control sequence split across two reads). 40ms is below a
14
14
  // human "two Escapes" interval but above typical chunk-split latency.
@@ -1115,7 +1115,12 @@ export class LineEditor {
1115
1115
  // Warning to the operator (e.g. the agent stopped suspiciously).
1116
1116
  // Printed above the input line without overwriting it.
1117
1117
  warning(msg) {
1118
- this.printAbove(NL + theme.warn('⚠ ' + msg));
1118
+ // Wrap long service messages (send failures, rate limits) to the same
1119
+ // margin the tool previews use, instead of letting the terminal wrap them
1120
+ // at the full width and mid-word — that mismatch looked ragged.
1121
+ const maxW = Math.max(20, (process.stdout.columns || 80) - 1);
1122
+ const wrapped = wrapToWidth('⚠ ' + msg, maxW);
1123
+ this.printAbove(NL + theme.warn(wrapped));
1119
1124
  }
1120
1125
  // ---------- input ----------
1121
1126
  _submit() {
package/dist/spinner.js CHANGED
@@ -2,7 +2,7 @@ import ora from 'ora';
2
2
  import { theme, divider } from './theme.js';
3
3
  import { renderMarkdown } from './markdown.js';
4
4
  import { translate } from './i18n.js';
5
- import { truncateToWidth } from './input/layout.js';
5
+ import { truncateToWidth, wrapToWidth } from './input/layout.js';
6
6
  // Phrases for the "agent is working" spinner. Chosen in random order.
7
7
  // The text comes from i18n via the key 'spinner.phrases' (strings separated by "|").
8
8
  export function randomThinkingPhrase(locale = 'ru') {
@@ -199,7 +199,8 @@ export function createSpinner(locale = 'ru') {
199
199
  },
200
200
  warning: (msg) => {
201
201
  stop();
202
- console.log(String.fromCharCode(10) + theme.warn('⚠ ' + msg));
202
+ const maxW = Math.max(20, (process.stdout.columns || 80) - 1);
203
+ console.log(String.fromCharCode(10) + theme.warn(wrapToWidth('⚠ ' + msg, maxW)));
203
204
  },
204
205
  stop,
205
206
  succeed: () => { },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zames_pro",
3
- "version": "2.68.0",
3
+ "version": "2.68.1",
4
4
  "description": "Terminal coding agent that drives chat.deepseek.com through Playwright — no API key required. Reads and edits files, runs commands, commits to git, like Claude Code / Codex CLI.",
5
5
  "type": "module",
6
6
  "bin": {