zames_pro 2.82.141 → 2.82.142

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,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [2.82.142] - 2026-10-27
11
+
12
+ ### Fixed
13
+
14
+ - **release:** bump package-lock.json root versions too
15
+
10
16
  ## [2.82.141] - 2026-10-26
11
17
 
12
18
  ### Fixed
@@ -6,7 +6,7 @@ import { createHash } from 'crypto';
6
6
  import { execFileSync } from 'child_process';
7
7
  import { extractPathToken } from './path-token.js';
8
8
  export { extractPathToken };
9
- export const IMAGE_EXTS = [
9
+ const IMAGE_EXTS = [
10
10
  '.png',
11
11
  '.jpg',
12
12
  '.jpeg',
@@ -16,7 +16,7 @@ export const IMAGE_EXTS = [
16
16
  '.svg',
17
17
  '.ico',
18
18
  ];
19
- export const MAX_ATTACHMENT_BYTES = 20 * 1024 * 1024;
19
+ const MAX_ATTACHMENT_BYTES = 20 * 1024 * 1024;
20
20
  // Stable content hash for de-duplicating identical attachments (a pasted image
21
21
  // is saved to a NEW temp file every time, so its path is not a stable identity).
22
22
  export function contentHash(data) {
@@ -286,7 +286,7 @@ export function hasClipboardTool() {
286
286
  }
287
287
  // True when the Windows filesystem is visible from here, i.e. a
288
288
  // powershell.exe call can reach the Windows clipboard.
289
- export function windowsReachable() {
289
+ function windowsReachable() {
290
290
  if (process.platform === 'win32')
291
291
  return true;
292
292
  if (process.platform !== 'linux')
@@ -410,9 +410,6 @@ export async function readClipboardImageDetailed() {
410
410
  }
411
411
  return { data: null, via: 'unsupported-platform' };
412
412
  }
413
- export async function readClipboardImage() {
414
- return (await readClipboardImageDetailed()).data;
415
- }
416
413
  function tryCommand(bin, args) {
417
414
  try {
418
415
  const out = execFileSync(bin, args, {
@@ -501,7 +498,7 @@ export function winPathToWsl(winPath) {
501
498
  return '/mnt/' + drive + '/' + rest;
502
499
  }
503
500
  // Run the embedded PowerShell script and return the clipboard image bytes.
504
- export async function readWindowsClipboardImage() {
501
+ async function readWindowsClipboardImage() {
505
502
  if (!isWsl())
506
503
  return null;
507
504
  const out = tryCommand('powershell.exe', [
package/dist/backlog.js CHANGED
@@ -13,8 +13,8 @@ const NL = String.fromCharCode(10);
13
13
  const NEW_ITEM_PREFIX = 'N';
14
14
  // Past these thresholds BACKLOG.md costs more tokens (on /improve) than it is
15
15
  // worth, so the operator is nudged to collapse it.
16
- export const BACKLOG_WARN_LINES = 500;
17
- export const BACKLOG_WARN_CHARS = 60_000;
16
+ const BACKLOG_WARN_LINES = 500;
17
+ const BACKLOG_WARN_CHARS = 60_000;
18
18
  // Parse a `/backlog <text>` note into the shape appendBacklogItem() wants. An
19
19
  // optional leading `P0..P3` token sets the priority; the first line becomes the
20
20
  // title and the rest the body. PURE so the operator's note is placed exactly as
@@ -214,7 +214,7 @@ export function sanitizeHeadlessUA(ua) {
214
214
  // reported "no session" for whichever provider had signed in second. A legacy
215
215
  // record without `providers` still reads: `{provider:'qwen'}` means Qwen and a
216
216
  // bare `{at}` means DeepSeek (the only writer before the second backend).
217
- export const AUTH_MARKER_FILE = path.join(os.homedir(), '.zames', 'auth.json');
217
+ const AUTH_MARKER_FILE = path.join(os.homedir(), '.zames', 'auth.json');
218
218
  /**
219
219
  * PURE: does the marker text say `provider` has a stored session? Legacy
220
220
  * shapes are honored (see the comment above AUTH_MARKER_FILE).
@@ -269,7 +269,7 @@ export function mergeAuthMarker(raw, provider, at) {
269
269
  return JSON.stringify({ providers }, null, 2);
270
270
  }
271
271
  // Best-effort: read the marker text from disk ('' when absent/unreadable).
272
- export async function readAuthMarker() {
272
+ async function readAuthMarker() {
273
273
  try {
274
274
  return await fs.readFile(AUTH_MARKER_FILE, 'utf-8');
275
275
  }
package/dist/commands.js CHANGED
@@ -161,7 +161,7 @@ export function parseTranscript(body) {
161
161
  }
162
162
  return out;
163
163
  }
164
- export const EN_DURATION_UNITS = { h: 'h', m: 'm', s: 's' };
164
+ const EN_DURATION_UNITS = { h: 'h', m: 'm', s: 's' };
165
165
  // Human-readable duration: "8s", "5m 12s", "1h 01m 01s". Seconds are padded
166
166
  // only when a larger unit is present, so a lone "45s" is not "45s" padded.
167
167
  export function formatDuration(ms, units = EN_DURATION_UNITS) {
@@ -421,7 +421,7 @@ export const RESTORED_HISTORY_LIMIT = 20;
421
421
  * history) is far bigger and is filtered by the noise checks below; a real
422
422
  * answer above this size is shortened instead of being dropped.
423
423
  */
424
- export const RESTORED_MESSAGE_MAX = 100_000;
424
+ const RESTORED_MESSAGE_MAX = 100_000;
425
425
  /**
426
426
  * DeepSeek stores the assistant turn VERBATIM: either a raw tool-call JSON
427
427
  * ({"tool":"Read","args":{...}}, frequently dirty/truncated) or a `respond`
package/dist/compact.js CHANGED
@@ -3,7 +3,7 @@ import { buildCompactPrompt, buildCompactCarryover, isUsableCompactSummary, trim
3
3
  import { loadHooks, runLifecycleHooks } from './hooks.js';
4
4
  const NL = String.fromCharCode(10);
5
5
  /** How many times the summary call is retried before the local fallback. */
6
- export const COMPACT_SUMMARY_ATTEMPTS = 3;
6
+ const COMPACT_SUMMARY_ATTEMPTS = 3;
7
7
  /** How many restored messages the local fallback keeps. */
8
8
  export const COMPACT_FALLBACK_LIMIT = 40;
9
9
  /**
package/dist/config.js CHANGED
@@ -748,7 +748,7 @@ function parseConfigValue(field, raw) {
748
748
  export function validateConfigValue(field, raw) {
749
749
  return parseConfigValue(field, raw);
750
750
  }
751
- export function configPathFor(scope) {
751
+ function configPathFor(scope) {
752
752
  return scope === 'project' ? projectConfigPath() : HOME_CONFIG;
753
753
  }
754
754
  /**
@@ -33,7 +33,7 @@ import { extractAnswer, extractTokenUsage, isFinishedWithoutAnswer, isRateLimitT
33
33
  import { SendRuntime } from './send-runtime.js';
34
34
  import { readGlmBodyFeatures, unsafeGlmModes, glmFlagsMismatch, } from './glm-flags.js';
35
35
  import { interactiveBrowserLogin, loginIsInteractive, canShowWindow, } from './browser-login.js';
36
- export const GLM_USER_DATA_DIR = path.join(os.homedir(), '.zames', 'glm-profile');
36
+ const GLM_USER_DATA_DIR = path.join(os.homedir(), '.zames', 'glm-profile');
37
37
  const MAX_NET_BODY = 64 * 1024;
38
38
  function capNetBody(body) {
39
39
  if (body.length <= MAX_NET_BODY)
@@ -224,7 +224,7 @@ export function extractTokenUsage(body) {
224
224
  return null;
225
225
  }
226
226
  /** True when a chunk marks the end of the stream (`done: true`). */
227
- export function isDoneChunk(obj) {
227
+ function isDoneChunk(obj) {
228
228
  const d = completionData(obj);
229
229
  if (!d)
230
230
  return false;
package/dist/glm-ui.js CHANGED
@@ -49,8 +49,6 @@ export function chatHistoryUrl(chatId) {
49
49
  }
50
50
  /** GET - the current user (or guest) record. */
51
51
  export const AUTH_URL = 'https://chat.z.ai/api/v1/auths/';
52
- /** POST - creates a chat and returns { id }. */
53
- export const NEW_CHAT_URL = 'https://chat.z.ai/api/v1/chats/new';
54
52
  /** POST - the SSE completion endpoint (the answer stream). */
55
53
  export const ANSWER_URL_RE = /\/api\/v2\/chat\/completions/i;
56
54
  // ---------- input ----------
@@ -142,30 +140,12 @@ export function glmContextWindow(model) {
142
140
  return null;
143
141
  }
144
142
  // ---------- service statuses / errors ----------
145
- // A placeholder that must never be taken for an answer.
146
- export const STATUS_RE = /^(thinking|generating|thinking\s+process|thought\s+process)[\s.…]*$/i;
147
- // z.ai's captcha gate (an Aliyun slider). Visible text on the modal.
148
- export const CAPTCHA_RE = /security verification|drag the slider/i;
149
- export const CAPTCHA_SELECTORS = [
150
- '.aliyun-captcha',
151
- '[class*="aliyunCaptcha"]',
152
- '[id*="aliyunCaptcha"]',
153
- ];
154
143
  // Rate limit / busy notices. Kept NARROW: the classifier additionally requires
155
144
  // an error payload or an answer-less body (same rule as qwen-net-capture.ts),
156
145
  // so a normal answer that merely mentions "try again" is not mistaken for a
157
146
  // limit.
158
147
  export const RATE_LIMIT_RE = /too many requests|rate limit|too frequent|please try again later|слишком часто/i;
159
148
  export const SERVER_BUSY_RE = /server is busy|service unavailable|try again later|high demand/i;
160
- export const GUEST_LIMIT_RE = /guest.*limit|log ?in to continue|sign ?in to continue|гостевой лимит/i;
161
- // ---------- mode flags ----------
162
- // The completion body carries the mode flags. `preview_mode` and the
163
- // `general_agent` flag change the ANSWER FORMAT (they enable z.ai's own agent
164
- // runtime, which emits its own tool calls), and that would break the zames
165
- // tool-call protocol. The request body is rewritten before the send and then
166
- // verified (glm-browser's _installRuntimeRewrite/_verifyModes + glm-flags).
167
- export const SAFE_PREVIEW_MODE = false;
168
- export const SAFE_ENABLE_THINKING = true;
169
149
  // ---------- attachments ----------
170
150
  // The observed upload control (a real filechooser on click).
171
151
  export const UPLOAD_BUTTON_SELECTOR = '#upload-file-button, button[class*="upload"]';
package/dist/hooks.js CHANGED
@@ -31,7 +31,7 @@ function cutHookText(s, max) {
31
31
  cut--;
32
32
  return s.slice(0, cut);
33
33
  }
34
- export function hooksConfigPath(workdir) {
34
+ function hooksConfigPath(workdir) {
35
35
  return path.join(workdir, '.zames', 'hooks.json');
36
36
  }
37
37
  /**
package/dist/mcp.js CHANGED
@@ -110,7 +110,7 @@ export function normalizeServerConfig(raw) {
110
110
  return out;
111
111
  }
112
112
  /** Candidate config paths, ordered from global to project-local. */
113
- export async function discoverConfigFiles(workdir) {
113
+ async function discoverConfigFiles(workdir) {
114
114
  const path = await import('path');
115
115
  const os = await import('os');
116
116
  const fsMod = await import('fs/promises');
@@ -127,7 +127,7 @@ export async function discoverConfigFiles(workdir) {
127
127
  return out;
128
128
  }
129
129
  /** Read and merge every config file. Later files override earlier ones. */
130
- export async function loadConfigFiles(files) {
130
+ async function loadConfigFiles(files) {
131
131
  const merged = {};
132
132
  const fsMod = await import('fs/promises');
133
133
  for (const f of files) {
@@ -35,7 +35,7 @@ import { extractAnswer, extractTokenUsage, isFinishedWithoutAnswer, isRateLimitT
35
35
  // contexts on ONE --user-data-dir cannot coexist (SingletonLock), and keeping
36
36
  // Qwen's cookies apart also means switching providers never logs the other
37
37
  // one out.
38
- export const QWEN_USER_DATA_DIR = path.join(os.homedir(), '.zames', 'qwen-profile');
38
+ const QWEN_USER_DATA_DIR = path.join(os.homedir(), '.zames', 'qwen-profile');
39
39
  // Escape a string for use inside a RegExp (the model id may carry dots).
40
40
  function escapeRegExp(s) {
41
41
  return String(s).replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
package/dist/qwen-ui.js CHANGED
@@ -169,8 +169,6 @@ export const LOGIN_SELECTORS = [
169
169
  'input[autocomplete="username"]',
170
170
  ];
171
171
  // ---------- service statuses / errors ----------
172
- // A generic "generating" label that must never be taken for an answer.
173
- export const STATUS_RE = /^(thinking|searching|generating|thinking completed|остановить|stop)[\s.…]*$/i;
174
172
  // Qwen's rate-limit / busy notices (best-effort; the toast may be short-lived).
175
173
  export const RATE_LIMIT_RE = /too many requests|rate limit|too frequent|please try again later|слишком часто/i;
176
174
  export const SERVER_BUSY_RE = /server is busy|service unavailable|try again later/i;
package/dist/run-task.js CHANGED
@@ -123,7 +123,7 @@ async function promptOnce(question) {
123
123
  // Enter sends the buffer to onQueue; an empty Enter is ignored. Backspace,
124
124
  // Ctrl+U, Esc sequences (arrows/Home/End/Delete are ignored) and bracketed
125
125
  // paste are supported. Returns a cleanup function.
126
- export function watchInput({ onEscape, onChange, onQueue, } = {}) {
126
+ function watchInput({ onEscape, onChange, onQueue, } = {}) {
127
127
  const stdin = process.stdin;
128
128
  if (!stdin.isTTY || !stdin.setRawMode)
129
129
  return () => { };
package/dist/scheduler.js CHANGED
@@ -26,7 +26,7 @@ export function parseInterval(text) {
26
26
  return ms;
27
27
  }
28
28
  /** Largest delay setInterval accepts (32-bit signed milliseconds). */
29
- export const MAX_TIMER_MS = 2_147_483_647;
29
+ const MAX_TIMER_MS = 2_147_483_647;
30
30
  // Render an interval back to the shortest human form (used in listings).
31
31
  // Non-finite input (a cron job whose next fire could not be computed sets
32
32
  // nextAt to Infinity) renders as "-" instead of "Infinityh".
package/dist/sessions.js CHANGED
@@ -68,7 +68,7 @@ function safeName(id) {
68
68
  // Save/update a session. workdir is needed so that when launched from the same
69
69
  // project we restore exactly its last chat.
70
70
  /** Hard cap on the todo checklist stored with a session. */
71
- export const SESSION_TODOS_CAP = 1000;
71
+ const SESSION_TODOS_CAP = 1000;
72
72
  export function saveSession({ id, title = '', workdir = '', todos, provider, }) {
73
73
  if (!id)
74
74
  return null;
package/dist/spinner.js CHANGED
@@ -22,7 +22,7 @@ export function stripEllipsis(phrase) {
22
22
  // (3 dots) so the trailing hint does not "jump" when the phase changes. Kept in
23
23
  // one place so the two status lines animate identically.
24
24
  export const DOTS = ['', '.', '..', '...'];
25
- export const DOTS_PAD = ' ';
25
+ const DOTS_PAD = ' ';
26
26
  // The colored dot string for a phase (brown, matching the base text).
27
27
  export function renderDots(n) {
28
28
  const d = DOTS[n] ?? '';
@@ -9,10 +9,10 @@ import { spawn } from 'node:child_process';
9
9
  // hidden), never an error in the UI.
10
10
  // Longest status text that still fits a typical terminal row together with
11
11
  // the rest of the status bar.
12
- export const STATUS_BADGE_MAX = 80;
12
+ const STATUS_BADGE_MAX = 80;
13
13
  /** Clip a status badge to STATUS_BADGE_MAX with an ellipsis (never splits a
14
14
  * surrogate pair). */
15
- export function clipBadge(text, max = STATUS_BADGE_MAX) {
15
+ function clipBadge(text, max = STATUS_BADGE_MAX) {
16
16
  const s = String(text ?? '');
17
17
  if (s.length <= max)
18
18
  return s;
package/dist/subagent.js CHANGED
@@ -14,11 +14,11 @@ import { markInternalChat } from './sessions.js';
14
14
  // subagents would need a second page and a shared send scheduler (a change to
15
15
  // browser.ts, which owns the live Playwright context) — out of scope here.
16
16
  /** Hard cap on iterations for one subagent run. */
17
- export const SUBAGENT_MAX_ITER = 30;
17
+ const SUBAGENT_MAX_ITER = 30;
18
18
  // The report is fed back into the PARENT chat as a tool result, so a runaway
19
19
  // subagent must not be able to blow up the parent's context with one answer.
20
20
  // The tail is trimmed with a marker, not silently dropped.
21
- export const SUBAGENT_REPORT_CAP = 20_000;
21
+ const SUBAGENT_REPORT_CAP = 20_000;
22
22
  /** Cap a subagent report before it becomes a parent-context tool result. */
23
23
  export function capReport(text, cap = SUBAGENT_REPORT_CAP) {
24
24
  if (text.length <= cap)
@@ -41,7 +41,7 @@ export function capReport(text, cap = SUBAGENT_REPORT_CAP) {
41
41
  * standard system prompt itself (tool list + call format), and the model needs
42
42
  * exactly that to work. The persona only adds role + output contract.
43
43
  */
44
- export function subagentPersona(type) {
44
+ function subagentPersona(type) {
45
45
  const base = 'You are a SUBAGENT launched by a main coding agent to complete ONE ' +
46
46
  'self-contained sub-task in an ISOLATED chat. You do NOT see the main ' +
47
47
  "conversation's history, so rely only on the instructions below and on " +
@@ -199,7 +199,7 @@ export function renderContextSection(context) {
199
199
  // of truth for `### <Tool>` blocks; the prose that cannot be derived
200
200
  // ("Choosing the right tool", the call formats) stays hard-coded below.
201
201
  // Guarded by test/system-prompt-tools.test.ts.
202
- export function renderToolSection(tools) {
202
+ function renderToolSection(tools) {
203
203
  return tools
204
204
  .map((t2) => `### ${t2.name}\n${t2.description}\nParameters: ${JSON.stringify(t2.parameters)}`)
205
205
  .join('\n\n');
@@ -12,10 +12,9 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
12
12
  import { useSyncExternalStore } from 'react';
13
13
  import { Box, Text, useWindowSize, useInput } from 'ink';
14
14
  import { LogList } from './LogView.js';
15
- import { windowByRows, totalRows, entryRows } from './log-window.js';
15
+ import { windowByRows, totalRows } from './log-window.js';
16
16
  import { StatusBar } from './StatusBar.js';
17
17
  import { InputLine } from './InputLine.js';
18
- import { contentWidth } from '../width.js';
19
18
  import { translate } from '../i18n.js';
20
19
  import { suggestRowCount } from '../input/suggest.js';
21
20
  import { truncateToWidth, visLen } from '../input/layout.js';
@@ -69,22 +68,13 @@ export function FullScreenApp({ store, inputProps, }) {
69
68
  // it half empty. `scroll` is measured in ROWS here (0 = newest at the
70
69
  // bottom).
71
70
  const all = state.log;
72
- // The viewport height is RESERVED with the floor (never more rows than the
73
- // pane can hold) and the box is allowed to take the slack: rounding the
74
- // reservation UP on every entry made the panel taller than the terminal on a
75
- // short window, so the input rows fell below the last screen row and the
76
- // caret drifted under the box while a long multi-line buffer was typed.
77
- const totalFloor = totalRows(all, cols, 'floor');
71
+ // The scroll bound uses the EXACT row count: it is what the content really
72
+ // renders, so the newest row stays reachable. (Reserving the viewport with
73
+ // the floor is a separate concern, handled in `fullScreenLayout`.)
78
74
  const total = totalRows(all, cols);
79
75
  const maxScroll = Math.max(0, total - logHeight);
80
76
  const scroll = Math.max(0, Math.min(state.scroll, maxScroll));
81
77
  const visible = windowByRows(all, logHeight, scroll, cols);
82
- // Rows the WINDOWED content really needs. The reservation above rounds DOWN
83
- // per entry (floor), so the difference is the slack the content needs. The
84
- // box takes at most `logHeight` and at least one row; never more, because
85
- // that is exactly what pushed the input rows off a short screen.
86
- const filledRows = visible.reduce((n, e) => n + entryRows(e, cols), 0);
87
- const logBoxHeight = Math.max(1, Math.min(logHeight, Math.max(filledRows, 1)));
88
78
  // Scroll the log with PgUp/PgDn; Home/End jump to the very top/bottom. The
89
79
  // input line OWNS Home/End while its buffer is non-empty (they move the
90
80
  // caret), so the jump only applies to an EMPTY buffer — which is exactly
@@ -126,4 +116,3 @@ export function FullScreenApp({ store, inputProps, }) {
126
116
  cursorTop: fsLayout.cursorTop, prompt: state.prompt, locale: state.locale, commands: state.commands, locked: state.locked }), _jsx(Text, { color: "#5b616e", wrap: "truncate", children: ' ' +
127
117
  translate(state.locale)(state.mouseScroll ? 'editor.keys_hint' : 'editor.keys_hint_select') })] }));
128
118
  }
129
- void contentWidth;
@@ -3,7 +3,7 @@ import { Static, Box, Text } from 'ink';
3
3
  import { theme } from '../theme.js';
4
4
  /** One log entry. `raw` items already carry ANSI colors and are printed
5
5
  * verbatim; structured items get a themed prefix. */
6
- export function LogRow({ entry }) {
6
+ function LogRow({ entry }) {
7
7
  if (entry.raw) {
8
8
  // Pre-rendered (markdown answer, tool preview). Print as-is; Ink passes
9
9
  // embedded ANSI escape sequences through to the terminal.
package/dist/tui/edit.js CHANGED
@@ -292,7 +292,7 @@ export function searchStart(s) {
292
292
  };
293
293
  return searchRefresh(st, true);
294
294
  }
295
- export function searchRefresh(s, resetToNewest) {
295
+ function searchRefresh(s, resetToNewest) {
296
296
  const q = s.searchQuery;
297
297
  const index = resetToNewest ? s.history.length - 1 : s.searchIndex;
298
298
  for (let i = index; i >= 0; i--) {
@@ -7,7 +7,7 @@ import { inputBoxRows } from '../input/layout.js';
7
7
  /** Rows of the fixed header: the title row + the divider. */
8
8
  export const HEADER_ROWS = 2;
9
9
  /** Rows of the status bar above the input box. */
10
- export const STATUS_ROWS = 1;
10
+ const STATUS_ROWS = 1;
11
11
  /** Rows of the key hint UNDER the input box. */
12
12
  export const HINT_ROWS = 1;
13
13
  export function fullScreenLayout(input) {
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Box, Text } from 'ink';
2
+ import { Text } from 'ink';
3
3
  export const UI = {
4
4
  accent: '#c8b06a',
5
5
  accentDim: '#7a6b45',
@@ -23,33 +23,7 @@ export function Checkbox({ checked, focused, }) {
23
23
  export function Select({ value, focused, }) {
24
24
  return (_jsxs(Text, { children: [_jsx(Text, { color: UI.off, children: '‹ ' }), _jsx(Text, { color: focused ? UI.accent : UI.text, bold: focused, children: value }), _jsx(Text, { color: UI.off, children: ' ›' })] }));
25
25
  }
26
- /** A framed panel (rounded border) with an optional title bar and footer. */
27
- export function Panel({ title, subtitle, footer, width, children, }) {
28
- return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: UI.border, paddingX: 1, width: width, children: [title ? (_jsxs(Box, { justifyContent: "space-between", children: [_jsx(Text, { color: UI.title, bold: true, children: title }), subtitle ? _jsx(Text, { color: UI.dim, children: subtitle }) : null] })) : null, title ? (_jsx(Text, { color: "#3a3f4b", children: '─'.repeat(panelInnerCols(width)) })) : null, children, footer ? footer : null] }));
29
- }
30
- /** Inner width (minus border + paddingX) the panel divider should span. */
31
- function panelInnerCols(width) {
32
- const cols = width || process.stdout.columns || 80;
33
- return Math.max(1, cols - 6);
34
- }
35
- /** A single hint chip: `↑/↓ select`. */
36
- export function Hint({ keys, label, }) {
37
- return (_jsxs(Text, { children: [_jsx(Text, { color: UI.accent, children: keys }), _jsx(Text, { color: UI.dim, children: ' ' + label })] }));
38
- }
39
26
  /** A row of hint chips separated by ` · `. */
40
27
  export function HintBar({ hints, }) {
41
28
  return (_jsx(Text, { children: hints.map(([k, l], i) => (_jsxs(Text, { children: [i > 0 ? _jsx(Text, { color: UI.dim, children: ' · ' }) : null, _jsx(Text, { color: UI.accent, children: k }), _jsx(Text, { color: UI.dim, children: ' ' + l })] }, i))) }));
42
29
  }
43
- /**
44
- * A CODE BLOCK with a syntax-highlighted body and an optional title label.
45
- *
46
- * The agent's answers are printed as pre-rendered ANSI (markdown.ts already
47
- * highlights with cli-highlight), so the live log does NOT use this component —
48
- * it exists for menus/panels that show a snippet inline. No call site today:
49
- * the Ctrl+Y / `/copy-code` feature that used it was removed, and plain `/copy`
50
- * copies the whole answer, so `extractCodeBlocks` (src/code-blocks.ts) is only
51
- * reached from its own tests.
52
- */
53
- export function CodeBlock({ code, lang, highlighted, width, hint, focused, }) {
54
- return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: focused ? UI.accent : UI.border, paddingX: 1, width: width, children: [_jsxs(Box, { justifyContent: "space-between", children: [_jsx(Text, { color: UI.dim, children: lang || 'code' }), hint ? _jsx(Text, { color: UI.accent, children: hint }) : null] }), (highlighted || code).split(String.fromCharCode(10)).map((line, i) => (_jsx(Text, { children: line || ' ' }, i)))] }));
55
- }
package/dist/web.js CHANGED
@@ -97,7 +97,7 @@ export function htmlToText(html) {
97
97
  // accept) into a uint32, or null when it is not one. Rules: 1-4 parts; each
98
98
  // part may be hex (0x…), octal (leading 0) or decimal; the LAST part fills all
99
99
  // remaining bytes, so `127.1` == 127.0.0.1 and `2130706433` == 127.0.0.1.
100
- export function parseLegacyIpv4(host) {
100
+ function parseLegacyIpv4(host) {
101
101
  const h = String(host || '').trim();
102
102
  if (!h)
103
103
  return null;
package/dist/width.js CHANGED
@@ -8,7 +8,7 @@
8
8
  // A longer line is harder to read and the eye loses the start of the next
9
9
  // line on a wide terminal, so there is a cap.
10
10
  // > 0 = an explicit cap (still never wider than the terminal).
11
- export const DEFAULT_CONTENT_WIDTH = 100;
11
+ const DEFAULT_CONTENT_WIDTH = 100;
12
12
  let configured = 0;
13
13
  /** Set the configured content width (0 or a non-positive value = auto). */
14
14
  export function setContentWidth(width) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zames_pro",
3
- "version": "2.82.141",
3
+ "version": "2.82.142",
4
4
  "description": "Terminal coding agent that drives a real browser to chat with DeepSeek, Qwen or GLM — 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": {
@@ -1,54 +0,0 @@
1
- // PURE extraction of fenced code blocks from a Markdown answer. It returns the
2
- // RAW fenced text: the highlighted render is full of ANSI and must never be
3
- // what gets copied out of the TUI.
4
- /**
5
- * Extract every fenced code block (``` or ~~~) from `md`, in order. Handles a
6
- * longer closing fence than the opening one and an unterminated final block
7
- * (the answer was truncated) — a half block is still copyable.
8
- */
9
- export function extractCodeBlocks(md) {
10
- const lines = String(md ?? '').split(String.fromCharCode(10));
11
- const out = [];
12
- let i = 0;
13
- let n = 0;
14
- while (i < lines.length) {
15
- // The info string may contain a BACKTICK (CommonMark forbids it, models
16
- // write it anyway: ```` ```ts` ````, ```` ```c++ `std::vector` ````). The
17
- // old `[^`]*` rejected such a line, so the block's own CLOSING fence was
18
- // read as an OPENING one and the following prose became a bogus block.
19
- const m = /^(\s*)(`{3,}|~{3,})\s*(.*)$/.exec(lines[i]);
20
- if (!m) {
21
- i++;
22
- continue;
23
- }
24
- // A BACKTICK fence cannot carry a backtick in its info (that is what makes
25
- // it unparseable for CommonMark); treat the trailing text as prose after a
26
- // plain fence only when the line is exactly a fence. For our purpose the
27
- // pragmatic rule is: any trailing text is the language label, backticks
28
- // stripped.
29
- const fence = m[2];
30
- const marker = fence[0];
31
- const minLen = fence.length;
32
- const lang = (m[3] || '').replace(/`/g, '').trim();
33
- i++;
34
- const body = [];
35
- let closed = false;
36
- while (i < lines.length) {
37
- // A closing fence is the SAME marker, at least as long, with nothing
38
- // else on the line (whitespace allowed).
39
- const c = new RegExp('^\\s*' + marker + '{' + minLen + ',}\\s*$');
40
- if (c.test(lines[i])) {
41
- closed = true;
42
- i++;
43
- break;
44
- }
45
- body.push(lines[i]);
46
- i++;
47
- }
48
- if (body.length === 0 && closed)
49
- continue;
50
- n++;
51
- out.push({ lang, text: body.join(String.fromCharCode(10)), index: n });
52
- }
53
- return out;
54
- }