zames_pro 2.29.1 → 2.29.2

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/browser.js CHANGED
@@ -1063,6 +1063,35 @@ export class DeepSeekBrowser {
1063
1063
  async _isGenerating() {
1064
1064
  return await this._stopButtonVisible();
1065
1065
  }
1066
+ // Is DeepSeek's "Continue" button currently visible? Used to BLOCK the
1067
+ // "answer settled" early-return in the finish loop: while Continue is on
1068
+ // screen the generation is PAUSED, not finished, so returning the partial
1069
+ // text there is exactly the "agent stopped with a Continue button" bug.
1070
+ async _continueButtonVisible() {
1071
+ try {
1072
+ return await this.page.evaluate(() => {
1073
+ const labelOf = (b) => ((b.textContent || '') + ' ' + (b.getAttribute('aria-label') || ''))
1074
+ .replace(/\s+/g, ' ')
1075
+ .trim();
1076
+ const isExact = (t) => /^(continue|продолжить|продолжение)\s*[.!…]?$/i.test(t);
1077
+ const cands = Array.from(document.querySelectorAll('div[role="button"], button'));
1078
+ for (const e of cands) {
1079
+ if (!isExact(labelOf(e)))
1080
+ continue;
1081
+ const st = getComputedStyle(e);
1082
+ if (st.display === 'none' || st.visibility === 'hidden')
1083
+ continue;
1084
+ if (!e.offsetParent && st.position !== 'fixed')
1085
+ continue;
1086
+ return true;
1087
+ }
1088
+ return false;
1089
+ });
1090
+ }
1091
+ catch {
1092
+ return false;
1093
+ }
1094
+ }
1066
1095
  // Click the DeepSeek "Continue" button when it is visible (reasoning/answer
1067
1096
  // paused by the server). Returns true when a click happened.
1068
1097
  //
@@ -1091,6 +1120,27 @@ export class DeepSeekBrowser {
1091
1120
  continue;
1092
1121
  if (!e.offsetParent && st.position !== 'fixed')
1093
1122
  continue;
1123
+ // DeepSeek's button is a React component listening for POINTER/mouse
1124
+ // events, not just a bare click(). A plain e.click() sometimes does
1125
+ // nothing; dispatching the full sequence is what a real press does.
1126
+ const rect = e.getBoundingClientRect();
1127
+ const cx = rect.left + rect.width / 2;
1128
+ const cy = rect.top + rect.height / 2;
1129
+ const opts = {
1130
+ bubbles: true,
1131
+ cancelable: true,
1132
+ composed: true,
1133
+ clientX: cx,
1134
+ clientY: cy,
1135
+ button: 0,
1136
+ };
1137
+ try {
1138
+ e.dispatchEvent(new PointerEvent('pointerdown', opts));
1139
+ e.dispatchEvent(new MouseEvent('mousedown', opts));
1140
+ e.dispatchEvent(new PointerEvent('pointerup', opts));
1141
+ e.dispatchEvent(new MouseEvent('mouseup', opts));
1142
+ }
1143
+ catch { }
1094
1144
  e.click();
1095
1145
  return true;
1096
1146
  }
@@ -1688,7 +1738,10 @@ export class DeepSeekBrowser {
1688
1738
  // capture proves a new answer exists. If it stays equal, keep waiting.
1689
1739
  const notGenerating = !(await this._isGenerating());
1690
1740
  const differs = !!cur && normText(cur) !== normText(beforeText);
1691
- if (differs && cur === lastStartCur && notGenerating) {
1741
+ // Do NOT accept a "settled" answer while Continue is on screen — that
1742
+ // is a paused generation, not a finished one.
1743
+ const paused = this.autoContinue && (await this._continueButtonVisible());
1744
+ if (differs && cur === lastStartCur && notGenerating && !paused) {
1692
1745
  settledTicks++;
1693
1746
  if (settledTicks >= 2) {
1694
1747
  this._askDebug('SETTLED-differs return len=' + cur.length);
@@ -1829,7 +1882,17 @@ export class DeepSeekBrowser {
1829
1882
  // so the FIN-loop always cost ~1.6s per answer. Defaults are now
1830
1883
  // 2 checks x 400ms (~0.8s saved per turn) and the values are honored.
1831
1884
  if (stable >= Math.max(1, this.stabilityChecks - 1)) {
1832
- if (isNew || !(await this._isGenerating())) {
1885
+ // A PAUSED generation also looks "stable" (the text stops changing
1886
+ // while Continue is on screen), so the old check returned the
1887
+ // partial answer here — the "agent stopped with a Continue button"
1888
+ // symptom. Click Continue and keep waiting instead.
1889
+ if (this.autoContinue && (await this._continueButtonVisible())) {
1890
+ if (await this._clickContinueIfVisible()) {
1891
+ this._askDebug('CLICKED Continue (before early return)');
1892
+ }
1893
+ stable = 0;
1894
+ }
1895
+ else if (isNew || !(await this._isGenerating())) {
1833
1896
  this._askDebug('RETURN stable curLen=' + cur.length);
1834
1897
  return cur;
1835
1898
  }
@@ -1855,6 +1918,10 @@ export class DeepSeekBrowser {
1855
1918
  await this.page.waitForTimeout(Math.max(0, this.stabilityDelayMs));
1856
1919
  }
1857
1920
  if (last && (normText(last) !== normText(beforeText) || this._netCapture)) {
1921
+ // If Continue is STILL on screen, the turn is paused, not finished:
1922
+ // click once more and report what we have rather than silently stopping.
1923
+ if (this.autoContinue)
1924
+ await this._clickContinueIfVisible();
1858
1925
  this._askDebug('RETURN last len=' + last.length);
1859
1926
  return last;
1860
1927
  }
package/dist/input.js CHANGED
@@ -233,6 +233,10 @@ export class LineEditor {
233
233
  pendingText;
234
234
  rendered;
235
235
  cursorRowFromTop;
236
+ // Number of rows occupied by the status/spinner block above the input line,
237
+ // as computed by the last _writeBlock(). _renderInputOnly() uses it to keep
238
+ // cursorRowFromTop correct without repainting the status.
239
+ _statusTop;
236
240
  busy;
237
241
  onSubmit;
238
242
  onEscape;
@@ -309,6 +313,7 @@ export class LineEditor {
309
313
  this.pendingText = null;
310
314
  this.rendered = false;
311
315
  this.cursorRowFromTop = 0;
316
+ this._statusTop = 0;
312
317
  this.busy = false;
313
318
  this.onSubmit = null;
314
319
  this.onEscape = null;
@@ -642,6 +647,7 @@ export class LineEditor {
642
647
  // re-printing the whole block on every keystroke is what made the display
643
648
  // flicker on terminals like Tabby. `top` is recovered from the cache so the
644
649
  // cursor math stays correct.
650
+ this._statusTop = top;
645
651
  const statusBlock = statusOut;
646
652
  const statusUnchanged = this.rendered && statusBlock === this._lastStatusBlock;
647
653
  if (statusUnchanged) {
@@ -729,6 +735,52 @@ export class LineEditor {
729
735
  this._eraseBlock();
730
736
  this._writeBlock();
731
737
  }
738
+ // Repaint ONLY the input rows, leaving the status/spinner block untouched.
739
+ // Used for buffer/cursor changes (typing, arrows, backspace, …): the status
740
+ // line has its OWN animation timer, and repainting it on every keystroke
741
+ // made the whole block blink on terminals like Tabby. When nothing is drawn
742
+ // yet (rendered === false) fall back to a full render so the very first
743
+ // paint is correct.
744
+ _renderInputOnly() {
745
+ if (!this.rendered) {
746
+ this._render();
747
+ return;
748
+ }
749
+ const cols = process.stdout.columns || 80;
750
+ const lay = layoutInput(this.promptStr, this.buf, this.cursor, cols);
751
+ const inputRows = lay.rows.length;
752
+ const sugg = this._suggestions();
753
+ const shown = sugg.slice(0, 8);
754
+ this._suggestCount = shown.length;
755
+ const linesBelow = shown.length
756
+ ? shown.length + (sugg.length > shown.length ? 1 : 0)
757
+ : 0;
758
+ this._eraseInputOnly(inputRows + linesBelow);
759
+ let out = lay.rows.map((r) => r.prefix + r.text).join(NL);
760
+ if (shown.length) {
761
+ const maxName = Math.max(...shown.map((c) => c.name.length));
762
+ const lines = shown.map((c) => {
763
+ const name = theme.prompt(c.name.padEnd(maxName));
764
+ const desc = theme.dim(' ' + c.description);
765
+ return ' ' + name + desc;
766
+ });
767
+ out += NL + lines.join(NL);
768
+ const hidden = sugg.length - shown.length;
769
+ if (hidden > 0)
770
+ out +=
771
+ NL +
772
+ theme.dim(' ' + translate(this.locale)('editor.more', { n: hidden }));
773
+ }
774
+ process.stdout.write(out);
775
+ const up = lay.rows.length - 1 - lay.cursorRow + linesBelow;
776
+ if (up > 0)
777
+ process.stdout.write(ESC + '[' + up + 'A');
778
+ process.stdout.write(CR);
779
+ if (lay.cursorCol > 0)
780
+ process.stdout.write(ESC + '[' + lay.cursorCol + 'C');
781
+ this.rendered = true;
782
+ this.cursorRowFromTop = this._statusTop + lay.cursorRow;
783
+ }
732
784
  // Print a block ABOVE the input line and put the input line back.
733
785
  printAbove(text) {
734
786
  this._stopDots();
@@ -1185,7 +1237,7 @@ export class LineEditor {
1185
1237
  }
1186
1238
  this._pasteBuf = '';
1187
1239
  }
1188
- this._render();
1240
+ this._renderInputOnly();
1189
1241
  continue;
1190
1242
  }
1191
1243
  const pasteAt = s.indexOf(PASTE_START);
@@ -1196,7 +1248,7 @@ export class LineEditor {
1196
1248
  this._pasteBuf = '';
1197
1249
  if (before) {
1198
1250
  this._insert(before);
1199
- this._render();
1251
+ this._renderInputOnly();
1200
1252
  }
1201
1253
  continue;
1202
1254
  }
@@ -1205,31 +1257,31 @@ export class LineEditor {
1205
1257
  if (s.startsWith(ESC + '[13;2u')) {
1206
1258
  this._insertNewline();
1207
1259
  s = s.slice(7);
1208
- this._render();
1260
+ this._renderInputOnly();
1209
1261
  continue;
1210
1262
  }
1211
1263
  if (s.startsWith(ESC + '[13;5u')) {
1212
1264
  this._insertNewline();
1213
1265
  s = s.slice(7);
1214
- this._render();
1266
+ this._renderInputOnly();
1215
1267
  continue;
1216
1268
  }
1217
1269
  if (s.startsWith(ESC + '[27;2;13~')) {
1218
1270
  this._insertNewline();
1219
1271
  s = s.slice(10);
1220
- this._render();
1272
+ this._renderInputOnly();
1221
1273
  continue;
1222
1274
  }
1223
1275
  if (s.startsWith(ESC + '[27;5;13~')) {
1224
1276
  this._insertNewline();
1225
1277
  s = s.slice(10);
1226
- this._render();
1278
+ this._renderInputOnly();
1227
1279
  continue;
1228
1280
  }
1229
1281
  if (s.startsWith(ESC + NL)) {
1230
1282
  this._insertNewline();
1231
1283
  s = s.slice(2);
1232
- this._render();
1284
+ this._renderInputOnly();
1233
1285
  continue;
1234
1286
  }
1235
1287
  const ch = s[0];
@@ -1243,7 +1295,7 @@ export class LineEditor {
1243
1295
  const before = this.cursor > 0 ? Array.from(this.buf)[this.cursor - 1] : '';
1244
1296
  if (before === '\\') {
1245
1297
  this._insertNewline();
1246
- this._render();
1298
+ this._renderInputOnly();
1247
1299
  continue;
1248
1300
  }
1249
1301
  this._submit();
@@ -1251,7 +1303,7 @@ export class LineEditor {
1251
1303
  }
1252
1304
  if (code === 10) {
1253
1305
  this._insertNewline();
1254
- this._render();
1306
+ this._renderInputOnly();
1255
1307
  continue;
1256
1308
  }
1257
1309
  if (code === 3) {
@@ -1266,24 +1318,24 @@ export class LineEditor {
1266
1318
  }
1267
1319
  if (code === 1) {
1268
1320
  this._home();
1269
- this._render();
1321
+ this._renderInputOnly();
1270
1322
  continue;
1271
1323
  }
1272
1324
  if (code === 5) {
1273
1325
  this._end();
1274
- this._render();
1326
+ this._renderInputOnly();
1275
1327
  continue;
1276
1328
  }
1277
1329
  if (code === 9) {
1278
1330
  this._completeCommand();
1279
- this._render();
1331
+ this._renderInputOnly();
1280
1332
  continue;
1281
1333
  }
1282
1334
  if (code === 21) {
1283
1335
  this.buf = '';
1284
1336
  this.cursor = 0;
1285
1337
  this.pastes = [];
1286
- this._render();
1338
+ this._renderInputOnly();
1287
1339
  continue;
1288
1340
  }
1289
1341
  if (code === 22) {
@@ -1295,7 +1347,7 @@ export class LineEditor {
1295
1347
  }
1296
1348
  if (code === 23) {
1297
1349
  this._deleteWordLeft();
1298
- this._render();
1350
+ this._renderInputOnly();
1299
1351
  continue;
1300
1352
  }
1301
1353
  if (code === 11) {
@@ -1306,12 +1358,12 @@ export class LineEditor {
1306
1358
  e++;
1307
1359
  arr.splice(this.cursor, e - this.cursor);
1308
1360
  this.buf = arr.join('');
1309
- this._render();
1361
+ this._renderInputOnly();
1310
1362
  continue;
1311
1363
  }
1312
1364
  if (code === 127 || code === 8) {
1313
1365
  this._backspace();
1314
- this._render();
1366
+ this._renderInputOnly();
1315
1367
  continue;
1316
1368
  }
1317
1369
  if (code === 27) {
@@ -1320,25 +1372,25 @@ export class LineEditor {
1320
1372
  if (s.startsWith('[1;5D') || s.startsWith('[5D')) {
1321
1373
  this._wordLeft();
1322
1374
  s = s.slice(s.startsWith('[1;5D') ? 5 : 3);
1323
- this._render();
1375
+ this._renderInputOnly();
1324
1376
  continue;
1325
1377
  }
1326
1378
  if (s.startsWith('[1;5C') || s.startsWith('[5C')) {
1327
1379
  this._wordRight();
1328
1380
  s = s.slice(s.startsWith('[1;5C') ? 5 : 3);
1329
- this._render();
1381
+ this._renderInputOnly();
1330
1382
  continue;
1331
1383
  }
1332
1384
  if (s.startsWith('[D')) {
1333
1385
  this._left();
1334
1386
  s = s.slice(2);
1335
- this._render();
1387
+ this._renderInputOnly();
1336
1388
  continue;
1337
1389
  }
1338
1390
  if (s.startsWith('[C')) {
1339
1391
  this._right();
1340
1392
  s = s.slice(2);
1341
- this._render();
1393
+ this._renderInputOnly();
1342
1394
  continue;
1343
1395
  }
1344
1396
  if (s.startsWith('[A')) {
@@ -1348,7 +1400,7 @@ export class LineEditor {
1348
1400
  else
1349
1401
  this._up();
1350
1402
  s = s.slice(2);
1351
- this._render();
1403
+ this._renderInputOnly();
1352
1404
  continue;
1353
1405
  }
1354
1406
  if (s.startsWith('[B')) {
@@ -1357,38 +1409,38 @@ export class LineEditor {
1357
1409
  else
1358
1410
  this._down();
1359
1411
  s = s.slice(2);
1360
- this._render();
1412
+ this._renderInputOnly();
1361
1413
  continue;
1362
1414
  }
1363
1415
  if (s.startsWith('[H') || s.startsWith('[1~')) {
1364
1416
  this._home();
1365
1417
  s = s.slice(s.startsWith('[1~') ? 3 : 2);
1366
- this._render();
1418
+ this._renderInputOnly();
1367
1419
  continue;
1368
1420
  }
1369
1421
  if (s.startsWith('[F') || s.startsWith('[4~')) {
1370
1422
  this._end();
1371
1423
  s = s.slice(s.startsWith('[4~') ? 3 : 2);
1372
- this._render();
1424
+ this._renderInputOnly();
1373
1425
  continue;
1374
1426
  }
1375
1427
  if (s.startsWith('[3~')) {
1376
1428
  this._delete();
1377
1429
  s = s.slice(3);
1378
- this._render();
1430
+ this._renderInputOnly();
1379
1431
  continue;
1380
1432
  }
1381
1433
  // Alt+B / Alt+F — word movement.
1382
1434
  if (s.startsWith('b') || s.startsWith('B')) {
1383
1435
  this._wordLeft();
1384
1436
  s = s.slice(1);
1385
- this._render();
1437
+ this._renderInputOnly();
1386
1438
  continue;
1387
1439
  }
1388
1440
  if (s.startsWith('f') || s.startsWith('F')) {
1389
1441
  this._wordRight();
1390
1442
  s = s.slice(1);
1391
- this._render();
1443
+ this._renderInputOnly();
1392
1444
  continue;
1393
1445
  }
1394
1446
  let j = 0;
@@ -1400,7 +1452,7 @@ export class LineEditor {
1400
1452
  if (code < 32)
1401
1453
  continue;
1402
1454
  this._insert(ch);
1403
- this._render();
1455
+ this._renderInputOnly();
1404
1456
  }
1405
1457
  }
1406
1458
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zames_pro",
3
- "version": "2.29.1",
3
+ "version": "2.29.2",
4
4
  "description": "Terminal coding agent over chat.deepseek.com via Playwright",
5
5
  "type": "module",
6
6
  "bin": {