vg-coder-cli 2.0.54 → 2.0.56

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vg-coder-cli",
3
- "version": "2.0.54",
3
+ "version": "2.0.56",
4
4
  "description": "🚀 CLI tool to analyze projects, concatenate source files, count tokens, and export HTML with syntax highlighting and copy functionality",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -699,6 +699,19 @@ class ApiServer {
699
699
  const body = req.body || {};
700
700
  const opts = body.workerLabel ? { workerLabel: body.workerLabel } : {};
701
701
  const payload = { url: body.url, model: body.model, active: body.active };
702
+ // Pin model cho worker (theo email) — _recycleWorkerTab sau task done
703
+ // sẽ reopen tab với cùng model, giữ lock qua nhiều task. Nếu caller
704
+ // không truyền workerLabel, pin cho TẤT CẢ launcher email hiện tại
705
+ // (single-tenant case phổ biến: 1 container = 1 worker).
706
+ if (body.model) {
707
+ if (body.workerLabel) {
708
+ taskQueue._pinnedModelByEmail.set(body.workerLabel, body.model);
709
+ } else {
710
+ for (const l of taskQueue.launchers.values()) {
711
+ if (l.email) taskQueue._pinnedModelByEmail.set(l.email, body.model);
712
+ }
713
+ }
714
+ }
702
715
  // Timeout 15s vì worker đợi tab status="complete" + 1.5s render delay
703
716
  // để bắt AI Studio fallback. Worker-side timeout cũng là 8s — server
704
717
  // phải lớn hơn để có response thay vì error.
@@ -38,6 +38,10 @@ class TaskQueue {
38
38
  // AI Studio tab (free CPU). Cancelled when a new task arrives or a worker
39
39
  // recycles for that email.
40
40
  this._idleCloseTimers = new Map();
41
+ // workerEmail → model string. Set qua /api/launcher/open-tab body.model;
42
+ // recycle dùng để reopen tab với cùng model (giữ pin qua nhiều task).
43
+ // Default null → recycle dùng AISTUDIO_DEFAULT_MODEL của extension.
44
+ this._pinnedModelByEmail = new Map();
41
45
  }
42
46
 
43
47
  attachIO(io) {
@@ -488,8 +492,10 @@ class TaskQueue {
488
492
  return;
489
493
  }
490
494
  await new Promise(r => setTimeout(r, 400));
491
- await this.requestLauncher('launcher:open_tab', {}, { workerLabel: workerEmail }, 8_000);
492
- console.log(chalk.cyan(`[TaskQueue] Recycled tab for ${workerEmail}`));
495
+ const pinned = this._pinnedModelByEmail.get(workerEmail);
496
+ const openPayload = pinned ? { model: pinned } : {};
497
+ await this.requestLauncher('launcher:open_tab', openPayload, { workerLabel: workerEmail }, 8_000);
498
+ console.log(chalk.cyan(`[TaskQueue] Recycled tab for ${workerEmail}${pinned ? ` (model=${pinned})` : ''}`));
493
499
  // Schedule idle close. If new task arrives before TTL, enqueue() will
494
500
  // cancel this timer.
495
501
  this._scheduleIdleClose(workerEmail);
@@ -209,21 +209,32 @@ function throwIfRateLimited(stage = '') {
209
209
  // đầu. Không throw — fail thì return null, caller chấp nhận `actualModel: null`.
210
210
  async function readActualModel() {
211
211
  try {
212
+ const url0 = location.href;
212
213
  // Fast path: panel đã mở (worker tab đã chạy task → AI Studio thường giữ panel open)
213
214
  let selector = document.querySelector('ms-model-selector');
214
215
  if (selector) {
215
216
  const name = selector.querySelector('[data-test-id="model-name"]')?.innerText?.trim();
216
- if (name) return name;
217
+ if (name) {
218
+ console.log('[ReadModel] FAST', { url: url0, name });
219
+ return name;
220
+ }
221
+ }
222
+ // Panel đóng — toggle mở (aria-label sẽ là "Toggle run settings panel" khi đóng,
223
+ // "Close run settings panel" khi mở. Match cả 2 để robust).
224
+ const toggle = document.querySelector('[aria-label="Toggle run settings panel"]')
225
+ || document.querySelector('[aria-label="Open run settings panel"]');
226
+ if (!toggle) {
227
+ console.warn('[ReadModel] NO_TOGGLE', { url: url0 });
228
+ return null;
217
229
  }
218
- // Slow path: toggle panel mở. Lưu state để restore sau khi đọc xong.
219
- const toggle = document.querySelector('[aria-label="Toggle run settings panel"]');
220
- if (!toggle) return null;
221
230
  toggle.click();
222
- await new Promise(r => setTimeout(r, 800));
231
+ await new Promise(r => setTimeout(r, 1200));
223
232
  selector = document.querySelector('ms-model-selector');
224
233
  const name = selector?.querySelector('[data-test-id="model-name"]')?.innerText?.trim() || null;
225
- // Đóng panel lại để không thay đổi UX (panel mở/đóng visible qua noVNC).
226
- toggle.click();
234
+ console.log('[ReadModel] SLOW', { url: url0, urlNow: location.href, name });
235
+ // Đóng panel lại để không thay đổi UX (label sau khi mở thành "Close...")
236
+ const closeBtn = document.querySelector('[aria-label="Close run settings panel"]');
237
+ if (closeBtn) closeBtn.click();
227
238
  return name;
228
239
  } catch (err) {
229
240
  console.warn('[TaskWorker] readActualModel failed:', err?.message);