vg-coder-cli 2.0.62 → 2.0.63

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.62",
3
+ "version": "2.0.63",
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": {
@@ -668,6 +668,25 @@ class ApiServer {
668
668
  res.json({ workers: taskQueue.listWorkers() });
669
669
  });
670
670
 
671
+ // Reset cooldown manually. Useful khi operator chắc chắn AI Studio đã hết
672
+ // rate-limit (vd quan sát qua noVNC submit prompt được) nhưng server timer
673
+ // 30 phút chưa expire. Body: { email: "alice@gmail.com" } hoặc {} cho tất cả.
674
+ this.app.post('/api/workers/reset-cooldown', (req, res) => {
675
+ const targetEmail = (req.body?.email || '').toString().toLowerCase().trim();
676
+ const reset = [];
677
+ for (const w of taskQueue.workers.values()) {
678
+ if (w.status !== 'rate_limited') continue;
679
+ if (targetEmail && w.email !== targetEmail) continue;
680
+ w.status = 'idle';
681
+ w.cooldownUntil = 0;
682
+ w.lastFailureCode = null;
683
+ w.lastFailureMessage = null;
684
+ reset.push({ id: w.id, email: w.email });
685
+ }
686
+ if (reset.length) setImmediate(() => taskQueue._drain());
687
+ res.json({ ok: true, reset, count: reset.length });
688
+ });
689
+
671
690
  this.app.get('/api/launchers', (req, res) => {
672
691
  res.json({ launchers: taskQueue.listLaunchers() });
673
692
  });
@@ -109,13 +109,21 @@ class TaskQueue {
109
109
 
110
110
  listWorkers() {
111
111
  const out = [];
112
+ const now = Date.now();
112
113
  for (const w of this.workers.values()) {
114
+ const cd = w.cooldownUntil || 0;
115
+ const remainingMs = cd > now ? cd - now : 0;
113
116
  out.push({
114
117
  id: w.id,
115
118
  email: w.email,
116
119
  status: w.status,
117
120
  currentTaskId: w.currentTaskId,
118
- cooldownUntil: w.cooldownUntil || 0,
121
+ cooldownUntil: cd,
122
+ cooldownUntilISO: cd ? new Date(cd).toISOString() : null,
123
+ cooldownRemainingMs: remainingMs,
124
+ cooldownRemainingMinutes: Math.ceil(remainingMs / 60_000),
125
+ lastFailureCode: w.lastFailureCode || null,
126
+ lastFailureMessage: w.lastFailureMessage || null,
119
127
  lastSeen: w.lastSeen,
120
128
  meta: { domain: w.meta?.domain, chatId: w.meta?.chatId, registeredAt: w.meta?.registeredAt }
121
129
  });
@@ -616,10 +624,14 @@ class TaskQueue {
616
624
  if (RL_CODES.has(code)) {
617
625
  worker.status = 'rate_limited';
618
626
  worker.cooldownUntil = Date.now() + RATE_LIMIT_COOLDOWN_MS;
627
+ worker.lastFailureCode = code;
628
+ worker.lastFailureMessage = message.slice(0, 300);
619
629
  worker.currentTaskId = null;
620
630
  console.log(chalk.yellow(`[TaskQueue] Worker ${worker.email} rate-limited until ${new Date(worker.cooldownUntil).toLocaleTimeString()}`));
621
631
  } else {
622
632
  // Plain failure — worker becomes idle again
633
+ worker.lastFailureCode = code;
634
+ worker.lastFailureMessage = message.slice(0, 300);
623
635
  worker.currentTaskId = null;
624
636
  worker.status = 'idle';
625
637
  }