vg-coder-cli 2.0.59 → 2.0.61

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.59",
3
+ "version": "2.0.61",
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": {
@@ -163,7 +163,13 @@ class TaskQueue {
163
163
  if (wasUnknown && email !== existing.email) {
164
164
  // shouldn't happen — kept for clarity (email already assigned above)
165
165
  }
166
- console.log(chalk.green(`[TaskQueue] Worker re-register: ${socket.id} (${email})`));
166
+ // Re-establish pin từ URL hiện tại của tab worker. Khắc phục race khi
167
+ // open-tab handler set _pinnedModelByEmail nhưng launcher email lúc đó
168
+ // null (chưa scrape) → pin bị mất → recycle reopen với default.
169
+ if (meta?.pinnedModel && !email.startsWith('unknown:')) {
170
+ this._pinnedModelByEmail.set(email, meta.pinnedModel);
171
+ }
172
+ console.log(chalk.green(`[TaskQueue] Worker re-register: ${socket.id} (${email})${meta?.pinnedModel ? ` pinned=${meta.pinnedModel}` : ''}`));
167
173
  setImmediate(() => this._drain());
168
174
  return true;
169
175
  }
@@ -184,7 +190,11 @@ class TaskQueue {
184
190
  if (meta?.chromeId && email && !email.startsWith('unknown:')) {
185
191
  this._bindChromeIdToEmail(meta.chromeId, email);
186
192
  }
187
- console.log(chalk.green(`[TaskQueue] Worker registered: ${socket.id} (${email})`));
193
+ // Re-establish pin từ URL hiện tại (xem comment re-register branch).
194
+ if (meta?.pinnedModel && !email.startsWith('unknown:')) {
195
+ this._pinnedModelByEmail.set(email, meta.pinnedModel);
196
+ }
197
+ console.log(chalk.green(`[TaskQueue] Worker registered: ${socket.id} (${email})${meta?.pinnedModel ? ` pinned=${meta.pinnedModel}` : ''}`));
188
198
  setImmediate(() => this._drain());
189
199
  return true;
190
200
  }
@@ -199,7 +199,7 @@ function throwIfRateLimited(stage = '') {
199
199
  }
200
200
 
201
201
  // Đọc model ID thật từ AI Studio sidebar — bắt được redirect AI Studio làm khi
202
- // account thiếu access tới preview model (vd request gemini-3-pro-preview, run
202
+ // account thiếu access tới preview model (vd request gemini-3.1-pro-preview, run
203
203
  // thật trên gemini-3-flash-preview). URL param không reliable vì AI Studio
204
204
  // không update URL khi fallback. Sidebar `<ms-model-selector>` mới là source-
205
205
  // of-truth.
@@ -256,6 +256,18 @@ async function handleTaskExecute(payload) {
256
256
  }
257
257
  await new Promise(r => setTimeout(r, 600)); // settle after navigation
258
258
 
259
+ // 1b. Pre-flight model check: AI Studio có thể fallback sang paid agent
260
+ // (vd "deep-research-preview-04-2026") khi pin model không có access.
261
+ // Submit task lên Deep Research → rate limit ngay (paid quota), URL không
262
+ // có ?model= để recycle pin lại → loop fail. Fail-fast nếu detect agent
263
+ // không phải gemini.
264
+ const preFlightModel = await readActualModel();
265
+ if (preFlightModel && !/^gemini[-.]/i.test(preFlightModel)) {
266
+ const e = new Error(`Worker tab loaded non-Gemini model: ${preFlightModel}. Pin model unavailable for this account.`);
267
+ e.code = 'model_unavailable';
268
+ throw e;
269
+ }
270
+
259
271
  if (cancelFlags.has(taskId)) {
260
272
  cancelFlags.delete(taskId);
261
273
  console.log(`[TaskWorker] ${taskId} canceled before send — skipping`);
@@ -347,12 +359,20 @@ function connect() {
347
359
  // Register with whatever email we have right now (may be null on cold load).
348
360
  const initialEmail = extractEmail();
349
361
  const chromeId = (window.vetgo && window.vetgo.chromeId) || null;
362
+ // pinnedModel: lấy từ URL ?model=X — server dùng để re-establish pin
363
+ // sau khi worker register với email thật (không lúc open-tab vì lúc đó
364
+ // launcher có thể chưa scrape email).
365
+ const pinnedModel = (() => {
366
+ try { return new URLSearchParams(location.search).get('model') || null; }
367
+ catch (_) { return null; }
368
+ })();
350
369
  socket.emit('worker:register', {
351
370
  domain: location.hostname,
352
371
  chatId: window.AIChat?.getChatIdFromUrl?.() || null,
353
372
  userAgent: navigator.userAgent,
354
373
  email: initialEmail,
355
- chromeId
374
+ chromeId,
375
+ pinnedModel
356
376
  });
357
377
  console.log(`[TaskWorker] Initial email: ${initialEmail || '(pending)'}, chromeId: ${chromeId || '(none)'}`);
358
378
 
@@ -368,14 +388,19 @@ function connect() {
368
388
  try {
369
389
  const resolved = await resolveEmail(3000, emailAbort?.signal);
370
390
  if (!resolved || !socket.connected) return;
391
+ const pm = (() => {
392
+ try { return new URLSearchParams(location.search).get('model') || null; }
393
+ catch (_) { return null; }
394
+ })();
371
395
  socket.emit('worker:register', {
372
396
  domain: location.hostname,
373
397
  chatId: window.AIChat?.getChatIdFromUrl?.() || null,
374
398
  userAgent: navigator.userAgent,
375
399
  email: resolved,
376
- chromeId: (window.vetgo && window.vetgo.chromeId) || null
400
+ chromeId: (window.vetgo && window.vetgo.chromeId) || null,
401
+ pinnedModel: pm
377
402
  });
378
- console.log(`[TaskWorker] Re-registered with email: ${resolved}`);
403
+ console.log(`[TaskWorker] Re-registered with email: ${resolved} (pinnedModel=${pm || 'none'})`);
379
404
  } catch (err) {
380
405
  console.error('[TaskWorker] Email retry failed:', err);
381
406
  }