zames_pro 2.29.16 → 2.31.0
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/dist/agent-loop.js +138 -12
- package/dist/browser.js +422 -145
- package/dist/commands.js +69 -0
- package/dist/compact.js +178 -0
- package/dist/config-menu.js +22 -5
- package/dist/config.js +43 -0
- package/dist/confirm.js +30 -6
- package/dist/context.js +3 -2
- package/dist/gitTools.js +3 -2
- package/dist/i18n.js +94 -8
- package/dist/index.js +217 -174
- package/dist/input.js +86 -11
- package/package.json +1 -1
package/dist/input.js
CHANGED
|
@@ -260,6 +260,11 @@ export class LineEditor {
|
|
|
260
260
|
_lastStatusBlock;
|
|
261
261
|
_wasRaw;
|
|
262
262
|
_onData;
|
|
263
|
+
// On SIGWINCH we redraw the whole block so the layout follows the new
|
|
264
|
+
// terminal width. Debounced: a drag fires many resize events. `_onResize`
|
|
265
|
+
// is stored so it can be removed in dispose().
|
|
266
|
+
_onResize;
|
|
267
|
+
_resizeTimer;
|
|
263
268
|
// History of sent messages (for the up/down arrows).
|
|
264
269
|
history;
|
|
265
270
|
_histIndex;
|
|
@@ -304,6 +309,10 @@ export class LineEditor {
|
|
|
304
309
|
// A callback the editor calls to fetch the CURRENT token count before every
|
|
305
310
|
// status render, so the status line stays fresh without the caller polling.
|
|
306
311
|
onContextQuery;
|
|
312
|
+
// The context window size used for the fill percentage and its color. Kept
|
|
313
|
+
// as a mutable field (set from config.ui.contextLimit) so the status bar
|
|
314
|
+
// reflects the real limit instead of a hardcoded constant.
|
|
315
|
+
contextLimit;
|
|
307
316
|
constructor({ prompt = '> ', commands = [], locale = 'ru', } = {}) {
|
|
308
317
|
this.locale = locale;
|
|
309
318
|
this.promptStr = prompt;
|
|
@@ -327,6 +336,26 @@ export class LineEditor {
|
|
|
327
336
|
this._lastStatusBlock = '';
|
|
328
337
|
this._wasRaw = false;
|
|
329
338
|
this._onData = (b) => this._handle(b);
|
|
339
|
+
this._resizeTimer = null;
|
|
340
|
+
this._onResize = () => {
|
|
341
|
+
// Debounce: a window drag fires a burst of SIGWINCH events. We wait a
|
|
342
|
+
// short moment, then redraw the block at the NEW width.
|
|
343
|
+
if (this._resizeTimer)
|
|
344
|
+
clearTimeout(this._resizeTimer);
|
|
345
|
+
this._resizeTimer = setTimeout(() => {
|
|
346
|
+
this._resizeTimer = null;
|
|
347
|
+
// Repaint ONLY the status + input block. We deliberately do NOT clear
|
|
348
|
+
// the whole viewport here: the operator's scrollback (the tool-call
|
|
349
|
+
// lines and answers printed above the input) must stay on screen.
|
|
350
|
+
// `_eraseBlock` erases from the top of the block DOWN (CR + ESC[J),
|
|
351
|
+
// so everything above it is preserved; then _writeBlock redraws the
|
|
352
|
+
// block at the new width. A slight leftover is possible at extreme
|
|
353
|
+
// width changes, but losing the history is far worse.
|
|
354
|
+
this._render();
|
|
355
|
+
}, 120);
|
|
356
|
+
if (this._resizeTimer.unref)
|
|
357
|
+
this._resizeTimer.unref();
|
|
358
|
+
};
|
|
330
359
|
this.history = [];
|
|
331
360
|
this._histIndex = 0;
|
|
332
361
|
this._histDraft = '';
|
|
@@ -343,6 +372,7 @@ export class LineEditor {
|
|
|
343
372
|
this.contextTokens = null;
|
|
344
373
|
this.thinkingEnabled = false;
|
|
345
374
|
this.searchEnabled = false;
|
|
375
|
+
this.contextLimit = CONTEXT_LIMIT;
|
|
346
376
|
this.onToggleQuery = null;
|
|
347
377
|
this.onContextQuery = null;
|
|
348
378
|
}
|
|
@@ -370,7 +400,9 @@ export class LineEditor {
|
|
|
370
400
|
const n = this.onContextQuery();
|
|
371
401
|
this.contextTokens = typeof n === 'number' ? n : null;
|
|
372
402
|
this.contextStatus =
|
|
373
|
-
n === null || n === undefined
|
|
403
|
+
n === null || n === undefined
|
|
404
|
+
? null
|
|
405
|
+
: formatTokenStatus(n, this.contextLimit) || null;
|
|
374
406
|
}
|
|
375
407
|
catch {
|
|
376
408
|
// A broken callback must never break the render.
|
|
@@ -384,7 +416,7 @@ export class LineEditor {
|
|
|
384
416
|
const ctx = this._contextForRender();
|
|
385
417
|
if (!ctx)
|
|
386
418
|
return '';
|
|
387
|
-
const level = tokenStatusLevel(this.contextTokens);
|
|
419
|
+
const level = tokenStatusLevel(this.contextTokens, this.contextLimit);
|
|
388
420
|
if (level === 'high')
|
|
389
421
|
return theme.error(ctx);
|
|
390
422
|
if (level === 'warn')
|
|
@@ -392,11 +424,11 @@ export class LineEditor {
|
|
|
392
424
|
return theme.success(ctx);
|
|
393
425
|
}
|
|
394
426
|
// Icons for the DeepSeek toggles: 🧠 "Deep thinking" and 🌐 "Smart search",
|
|
395
|
-
// shown before the context counter. Only the ENABLED
|
|
396
|
-
//
|
|
397
|
-
//
|
|
398
|
-
//
|
|
399
|
-
//
|
|
427
|
+
// shown before the context counter. Only the ENABLED toggles are shown, so
|
|
428
|
+
// the state is unambiguous WITHOUT relying on the terminal coloring the
|
|
429
|
+
// emoji: an icon present = ON, absent = OFF. Emoji are (almost) never
|
|
430
|
+
// colored by ANSI, so a "dim" vs "green" pair of the SAME emoji would look
|
|
431
|
+
// identical — that is why the disabled icon is hidden instead.
|
|
400
432
|
_toggleIcons() {
|
|
401
433
|
const TEXT = '\uFE0E';
|
|
402
434
|
const parts = [];
|
|
@@ -466,12 +498,18 @@ export class LineEditor {
|
|
|
466
498
|
stdin.resume();
|
|
467
499
|
process.stdout.write(ESC + '[?2004h');
|
|
468
500
|
stdin.on('data', this._onData);
|
|
501
|
+
// Redraw on terminal resize so the layout follows the new width instead
|
|
502
|
+
// of leaving artifacts from the old one.
|
|
503
|
+
process.stdout.on('resize', this._onResize);
|
|
469
504
|
this._writeBlock();
|
|
470
505
|
return true;
|
|
471
506
|
}
|
|
472
507
|
dispose() {
|
|
473
508
|
const stdin = process.stdin;
|
|
474
509
|
stdin.removeListener('data', this._onData);
|
|
510
|
+
process.stdout.removeListener('resize', this._onResize);
|
|
511
|
+
if (this._resizeTimer)
|
|
512
|
+
clearTimeout(this._resizeTimer);
|
|
475
513
|
process.stdout.write(ESC + '[?2004l');
|
|
476
514
|
this._stopDots();
|
|
477
515
|
if (this.rendered)
|
|
@@ -529,9 +567,16 @@ export class LineEditor {
|
|
|
529
567
|
setContextStatus(tokens) {
|
|
530
568
|
this.contextTokens =
|
|
531
569
|
typeof tokens === 'number' && Number.isFinite(tokens) ? tokens : null;
|
|
532
|
-
this.contextStatus = formatTokenStatus(tokens) || null;
|
|
570
|
+
this.contextStatus = formatTokenStatus(tokens, this.contextLimit) || null;
|
|
533
571
|
this._render();
|
|
534
572
|
}
|
|
573
|
+
// Update the context window size (from config.ui.contextLimit). The next
|
|
574
|
+
// render recomputes the percentage and its color with the new limit.
|
|
575
|
+
setContextLimit(limit) {
|
|
576
|
+
if (typeof limit === 'number' && Number.isFinite(limit) && limit > 0) {
|
|
577
|
+
this.contextLimit = limit;
|
|
578
|
+
}
|
|
579
|
+
}
|
|
535
580
|
// Update the interface language (labels: hint, answer marker, pause).
|
|
536
581
|
setLocale(locale) {
|
|
537
582
|
this.locale = locale;
|
|
@@ -735,6 +780,17 @@ export class LineEditor {
|
|
|
735
780
|
this._eraseBlock();
|
|
736
781
|
this._writeBlock();
|
|
737
782
|
}
|
|
783
|
+
// Full-screen clear (like /clear in a shell) followed by a fresh repaint of
|
|
784
|
+
// the status + input block. Used by /new and /resume so a new/resumed chat
|
|
785
|
+
// starts on a clean terminal instead of under pages of the previous chat.
|
|
786
|
+
// We do NOT clear the scrollback here: the operator may still want it.
|
|
787
|
+
clearScreen() {
|
|
788
|
+
this._eraseBlock();
|
|
789
|
+
process.stdout.write(ESC + '[2J' + ESC + '[H');
|
|
790
|
+
this.rendered = false;
|
|
791
|
+
this._lastStatusBlock = '';
|
|
792
|
+
this._writeBlock();
|
|
793
|
+
}
|
|
738
794
|
// Repaint ONLY the input rows, leaving the status/spinner block untouched.
|
|
739
795
|
// Used for buffer/cursor changes (typing, arrows, backspace, …): the status
|
|
740
796
|
// line has its OWN animation timer, and repainting it on every keystroke
|
|
@@ -874,7 +930,8 @@ export class LineEditor {
|
|
|
874
930
|
this.setStatus('');
|
|
875
931
|
}
|
|
876
932
|
toolCall(name, args) {
|
|
877
|
-
const
|
|
933
|
+
const full = safeJson(args);
|
|
934
|
+
const preview = full.slice(0, 120) + (full.length > 120 ? ' …' : '');
|
|
878
935
|
this.printAbove(theme.tool('🔧 ' + name) + ' ' + theme.dim(preview));
|
|
879
936
|
// A tool may run for a long time (Bash, npm test, MCP). Without an active
|
|
880
937
|
// animation the operator sees a frozen screen and cannot tell work is in
|
|
@@ -887,18 +944,36 @@ export class LineEditor {
|
|
|
887
944
|
toolResult(result) {
|
|
888
945
|
this.stop();
|
|
889
946
|
const text = typeof result === 'string' ? result : safeJson(result);
|
|
890
|
-
const preview = text.slice(0, 200).split(NL).join(' ↵ ');
|
|
947
|
+
const preview = text.slice(0, 200).split(NL).join(' ↵ ') + (text.length > 200 ? ' …' : '');
|
|
891
948
|
this.printAbove(theme.toolResult(' → ' + preview));
|
|
892
949
|
}
|
|
893
950
|
assistant(msg) {
|
|
894
951
|
this.stop();
|
|
895
952
|
const rendered = renderMarkdown(msg);
|
|
953
|
+
// Show the used context size at the END of the answer too. During
|
|
954
|
+
// generation it lives in the status line, but ui.stop() clears that right
|
|
955
|
+
// before this call, so the operator lost the number exactly when the
|
|
956
|
+
// answer arrived. Read it fresh via onContextQuery and append it dimmed
|
|
957
|
+
// under the answer divider.
|
|
958
|
+
let ctxLine = '';
|
|
959
|
+
if (this.onContextQuery) {
|
|
960
|
+
try {
|
|
961
|
+
const n = this.onContextQuery();
|
|
962
|
+
const txt = formatTokenStatus(n, this.contextLimit);
|
|
963
|
+
if (txt)
|
|
964
|
+
ctxLine = NL + theme.dim(txt);
|
|
965
|
+
}
|
|
966
|
+
catch {
|
|
967
|
+
// never break the render
|
|
968
|
+
}
|
|
969
|
+
}
|
|
896
970
|
this.printAbove(NL +
|
|
897
971
|
theme.assistant(translate(this.locale)('editor.answer')) +
|
|
898
972
|
NL +
|
|
899
973
|
rendered +
|
|
900
974
|
NL +
|
|
901
|
-
theme.dim('─'.repeat(60))
|
|
975
|
+
theme.dim('─'.repeat(60)) +
|
|
976
|
+
ctxLine);
|
|
902
977
|
}
|
|
903
978
|
// Warning to the operator (e.g. the agent stopped suspiciously).
|
|
904
979
|
// Printed above the input line without overwriting it.
|