zames_pro 2.82.51 → 2.82.52

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,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [2.82.52] - 2026-10-23
11
+
12
+ ### Fixed
13
+
14
+ - **config:** tolerate an unparsable config file when writing
15
+ - **tui:** use the shared width table when estimating log rows
16
+
17
+ ### Changed
18
+
19
+ - **tui:** derive the input box width from the shared helper
20
+
10
21
  ## [2.82.51] - 2026-10-23
11
22
 
12
23
  ### Added
package/dist/config.js CHANGED
@@ -696,19 +696,47 @@ export function configPathFor(scope) {
696
696
  * writing does not "freeze" all defaults into the user's file.
697
697
  */
698
698
  export function readConfigFile(file) {
699
+ let raw;
699
700
  try {
700
- const data = JSON.parse(fs.readFileSync(file, 'utf-8'));
701
- if (data && typeof data === 'object' && !Array.isArray(data)) {
702
- return data;
703
- }
701
+ raw = fs.readFileSync(file, 'utf-8');
704
702
  }
705
703
  catch (e) {
706
704
  const err = e;
705
+ // A MISSING file is the normal first-write case. Anything else (EACCES,
706
+ // EISDIR) is reported — the caller must know the write cannot land.
707
707
  if (err.code !== 'ENOENT') {
708
708
  throw new Error(`failed to read ${file}: ${err.message}`);
709
709
  }
710
+ return {};
711
+ }
712
+ try {
713
+ const data = JSON.parse(raw);
714
+ if (data && typeof data === 'object' && !Array.isArray(data)) {
715
+ return data;
716
+ }
717
+ return {};
718
+ }
719
+ catch (e) {
720
+ // A file that does not PARSE (a hand edit with a trailing comma, a
721
+ // merge-conflict marker, a bare-word value) is NOT a reason to fail the
722
+ // write: loadConfig() already tolerates it with a warning. Failing here
723
+ // made /config set useless on such a project, and a caller that ignored
724
+ // the error overwrote the WHOLE file with the single edited key.
725
+ //
726
+ // The unparsable text is backed up beside the file first, so the operator's
727
+ // other settings are recoverable by hand; the warning goes to stderr, the
728
+ // same channel loadConfig() uses.
729
+ const backup = file + '.broken-' + Date.now();
730
+ try {
731
+ fs.copyFileSync(file, backup);
732
+ console.error(`config: ${file} is not valid JSON (${e.message});` +
733
+ ` its content was kept in ${backup} and the write starts a fresh file`);
734
+ }
735
+ catch {
736
+ // Best-effort: an unreadable backup must not block the write either.
737
+ }
738
+ return {};
710
739
  }
711
- return {};
712
740
  }
713
741
  /**
714
742
  * Write a setting value to the file. Returns the final object that was
@@ -11,7 +11,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
11
11
  import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
12
12
  import { Box, Text, useInput, usePaste, useCursor, useWindowSize, useStdin, } from 'ink';
13
13
  import { translate } from '../i18n.js';
14
- import { layoutInput, SUGGEST_PAGE, } from '../input/layout.js';
14
+ import { inputInnerCols, layoutInput, SUGGEST_PAGE, } from '../input/layout.js';
15
15
  import { insertText, insertPaste, insertNewline, backspace, del, moveLeft, moveRight, moveHome, moveEnd, wordLeft, wordRight, deleteWordLeft, deleteWordRight, killToLineEnd, moveVisualRows, pushUndo, undoEdit, historyUp, historyDown, searchStart, searchNext, searchAccept, searchCancel, searchInput, searchBackspace, recordHistory, afterSubmit, } from './edit.js';
16
16
  import { dispatchKey, parseCsiU } from './keys.js';
17
17
  import { useSyncExternalStore } from 'react';
@@ -42,9 +42,13 @@ export function InputLine(props) {
42
42
  }));
43
43
  }, [props.store]);
44
44
  // The input lives inside a rounded box: 2 columns of border (left/right) plus
45
- // 1 column of inner padding on each side. The layout must wrap to the INNER
46
- // width, or a long line would overflow the frame.
47
- const innerCols = Math.max(4, cols - 4);
45
+ // 1 column of inner padding on each side, so the CONTENT width is `cols - 4`.
46
+ // Use the SHARED helper: `inputBoxRows()` — the height the full-screen layout
47
+ // reserves — is computed from the SAME function, and a hand-written
48
+ // `Math.max(4, cols - 4)` here was one independent copy that could drift from
49
+ // the reservation (the box then rendered more rows than were reserved and the
50
+ // input rows overprinted the status bar).
51
+ const innerCols = inputInnerCols(cols);
48
52
  // Mirror the state into a ref so the useInput callback (a stable closure Ink
49
53
  // calls for every key) always sees the latest values.
50
54
  const stRef = useRef(st);
@@ -7,6 +7,7 @@
7
7
  // purpose: measuring the real Yoga layout per entry would need a ref per row
8
8
  // and a re-render, while counting wrapped lines is exact enough for a log and
9
9
  // costs nothing.
10
+ import { charWidth } from '../input/layout.js';
10
11
  /** Visible width of a line without ANSI escapes (wide chars count 2). */
11
12
  function visWidth(s) {
12
13
  let w = 0;
@@ -43,16 +44,14 @@ function visWidth(s) {
43
44
  continue;
44
45
  }
45
46
  const cp = s.codePointAt(i);
46
- // Wide ranges (CJK/emoji) count 2; combining marks 0. Approximate — a log
47
- // windowing error of one cell is invisible.
48
- if (cp >= 0x1f300 && cp <= 0x1faff)
49
- w += 2;
50
- else if (cp >= 0x1100 && cp <= 0x9fff)
51
- w += 2;
52
- else if ((cp >= 0x300 && cp <= 0x36f) || cp === 0x200d)
53
- w += 0;
54
- else
55
- w += 1;
47
+ // Use the SAME width rule as the input/status layout (charWidth in
48
+ // src/input/layout.ts). The old table here counted EVERYTHING up to
49
+ // U+9FFF as two cells, so a line of box arrows (`→`, U+2192), the
50
+ // hourglass `⧗` (U+29D7) or Cyrillic/Greek letters over-estimated its
51
+ // rows; at a narrow width that reserves an extra row per entry and the
52
+ // pane believes it is full, stopping the scroll early. Sharing ONE table
53
+ // keeps the viewport and the rest of the TUI from disagreeing.
54
+ w += charWidth(cp);
56
55
  i += cp > 0xffff ? 2 : 1;
57
56
  }
58
57
  return w;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zames_pro",
3
- "version": "2.82.51",
3
+ "version": "2.82.52",
4
4
  "description": "Terminal coding agent that drives a real browser to chat with DeepSeek, Qwen and other web LLMs — 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": {