vg-coder-cli 2.0.60 → 2.0.62

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.60",
3
+ "version": "2.0.62",
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": {
@@ -133,12 +133,15 @@ async function fetchAsFile(url, name, mime) {
133
133
  async function waitForNewAssistantTurn(baselineCount, timeoutMs = 90_000) {
134
134
  const start = Date.now();
135
135
  while (Date.now() - start < timeoutMs) {
136
- // Surface rate-limit / quota errors early no point waiting for a turn
137
- // that will never appear.
138
- const rl = detectRateLimit();
139
- if (rl) { const e = new Error(rl.message); e.code = rl.code; throw e; }
140
-
136
+ // Chỉ surface rate-limit/quota khi turn count đã vượt baseline. Trước
137
+ // đó turn cuối vẫn là turn cũ (có thể là error từ session restore) —
138
+ // detectRateLimit match phải khớp với turn MỚI.
141
139
  const turns = document.querySelectorAll('ms-chat-turn');
140
+ if (turns.length > baselineCount) {
141
+ // Turn mới đã render — bây giờ mới check (toast vẫn check global ok)
142
+ const rl = detectRateLimit();
143
+ if (rl) { const e = new Error(rl.message); e.code = rl.code; throw e; }
144
+ }
142
145
  if (turns.length >= baselineCount + 2) {
143
146
  const last = turns[turns.length - 1];
144
147
  const role = last.querySelector('[data-turn-role]')?.getAttribute('data-turn-role');
@@ -164,8 +167,15 @@ function detectRateLimit() {
164
167
  if (/failed to generate/i.test(t)) return { code: 'generation_failed', message: t.slice(0, 500) };
165
168
  }
166
169
 
167
- // Inline model-error inside the last assistant turn
168
- const modelErr = document.querySelector('.model-error');
170
+ // Inline model-error CHỈ check trong turn CUỐI (response cho prompt vừa
171
+ // submit). AI Studio restore chat session từ cookies → turn cũ với
172
+ // .model-error rate-limit có thể vẫn trong DOM dù limit đã hết.
173
+ // Global querySelector('.model-error') match turn cũ → mark cooldown
174
+ // infinite loop. Scope theo last ms-chat-turn để chỉ trigger trên response
175
+ // mới.
176
+ const turns = document.querySelectorAll('ms-chat-turn');
177
+ const lastTurn = turns[turns.length - 1];
178
+ const modelErr = lastTurn?.querySelector('.model-error');
169
179
  if (modelErr) {
170
180
  const text = (modelErr.textContent || '').trim();
171
181
  if (/rate limit/i.test(text)) return { code: 'rate_limit_exceeded', message: text };
@@ -199,7 +209,7 @@ function throwIfRateLimited(stage = '') {
199
209
  }
200
210
 
201
211
  // Đọ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
212
+ // account thiếu access tới preview model (vd request gemini-3.1-pro-preview, run
203
213
  // thật trên gemini-3-flash-preview). URL param không reliable vì AI Studio
204
214
  // không update URL khi fallback. Sidebar `<ms-model-selector>` mới là source-
205
215
  // of-truth.
@@ -256,6 +266,18 @@ async function handleTaskExecute(payload) {
256
266
  }
257
267
  await new Promise(r => setTimeout(r, 600)); // settle after navigation
258
268
 
269
+ // 1b. Pre-flight model check: AI Studio có thể fallback sang paid agent
270
+ // (vd "deep-research-preview-04-2026") khi pin model không có access.
271
+ // Submit task lên Deep Research → rate limit ngay (paid quota), URL không
272
+ // có ?model= để recycle pin lại → loop fail. Fail-fast nếu detect agent
273
+ // không phải gemini.
274
+ const preFlightModel = await readActualModel();
275
+ if (preFlightModel && !/^gemini[-.]/i.test(preFlightModel)) {
276
+ const e = new Error(`Worker tab loaded non-Gemini model: ${preFlightModel}. Pin model unavailable for this account.`);
277
+ e.code = 'model_unavailable';
278
+ throw e;
279
+ }
280
+
259
281
  if (cancelFlags.has(taskId)) {
260
282
  cancelFlags.delete(taskId);
261
283
  console.log(`[TaskWorker] ${taskId} canceled before send — skipping`);