agent-rev 0.3.3 → 0.3.5

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.
@@ -42,14 +42,20 @@ async function loadToken() {
42
42
  };
43
43
  if (!token.accessToken)
44
44
  return null;
45
- if (token.expiresAt > Date.now()) {
46
- return token;
47
- }
48
- // Token expirado intentar refresh
49
- if (token.refreshToken) {
50
- return refreshAccessToken(token.refreshToken);
45
+ // Refresh proactivo: si vence en menos de 2 minutos (o ya venció)
46
+ const TWO_MIN = 2 * 60 * 1000;
47
+ if (token.expiresAt - Date.now() < TWO_MIN && token.refreshToken) {
48
+ const refreshed = await doRefreshToken(token.refreshToken);
49
+ if (refreshed) {
50
+ await saveToken(refreshed);
51
+ return refreshed;
52
+ }
53
+ // Si el refresh falla pero el token aún no venció del todo, seguir con él
54
+ if (token.expiresAt > Date.now())
55
+ return token;
56
+ return null;
51
57
  }
52
- return null;
58
+ return token;
53
59
  }
54
60
  catch {
55
61
  return null;
@@ -59,7 +65,8 @@ async function saveToken(token) {
59
65
  const tokenPath = await getTokenPath();
60
66
  await fs.writeFile(tokenPath, JSON.stringify(token, null, 2), 'utf-8');
61
67
  }
62
- async function refreshAccessToken(refreshToken) {
68
+ /** Calls the refresh endpoint and returns the new token (does NOT save). */
69
+ async function doRefreshToken(refreshToken) {
63
70
  try {
64
71
  const response = await fetch(QWEN_OAUTH_TOKEN_ENDPOINT, {
65
72
  method: 'POST',
@@ -70,25 +77,29 @@ async function refreshAccessToken(refreshToken) {
70
77
  client_id: QWEN_OAUTH_CLIENT_ID,
71
78
  }),
72
79
  });
73
- if (!response.ok) {
74
- throw new Error(`Token refresh failed: ${response.status}`);
75
- }
80
+ if (!response.ok)
81
+ return null;
76
82
  const data = await response.json();
77
- const token = {
83
+ if (!data.access_token)
84
+ return null;
85
+ return {
78
86
  accessToken: data.access_token,
79
87
  refreshToken: data.refresh_token || refreshToken,
80
88
  expiresAt: Date.now() + (data.expires_in || 3600) * 1000,
81
89
  idToken: data.id_token,
82
90
  resourceUrl: data.resource_url,
83
91
  };
84
- await saveToken(token);
85
- return token;
86
92
  }
87
- catch (error) {
88
- console.error('Error refreshing token:', error);
93
+ catch {
89
94
  return null;
90
95
  }
91
96
  }
97
+ async function refreshAccessToken(refreshToken) {
98
+ const token = await doRefreshToken(refreshToken);
99
+ if (token)
100
+ await saveToken(token);
101
+ return token;
102
+ }
92
103
  // Generate PKCE code verifier and challenge
93
104
  function generatePKCE() {
94
105
  const codeVerifier = crypto.randomBytes(32).toString('base64url');
@@ -263,7 +274,7 @@ async function callQwenAPIWithToken(token, prompt, model) {
263
274
  return data.choices?.[0]?.message?.content || '';
264
275
  }
265
276
  export async function callQwenAPI(prompt, model = 'coder-model') {
266
- const token = await loadToken();
277
+ let token = await loadToken();
267
278
  if (!token) {
268
279
  throw new Error('QWEN_AUTH_EXPIRED: No hay token de Qwen. Ejecutá --login primero.');
269
280
  }
@@ -271,10 +282,17 @@ export async function callQwenAPI(prompt, model = 'coder-model') {
271
282
  return await callQwenAPIWithToken(token, prompt, model);
272
283
  }
273
284
  catch (err) {
274
- if (err.message?.startsWith('QWEN_AUTH_EXPIRED')) {
275
- throw new Error('QWEN_AUTH_EXPIRED: Sesión expirada. Ejecutá: agent-mp --login');
285
+ if (!err.message?.startsWith('QWEN_AUTH_EXPIRED'))
286
+ throw err;
287
+ // 401 — intentar refresh antes de rendirse
288
+ if (token.refreshToken) {
289
+ const refreshed = await doRefreshToken(token.refreshToken);
290
+ if (refreshed) {
291
+ await saveToken(refreshed);
292
+ return callQwenAPIWithToken(refreshed, prompt, model);
293
+ }
276
294
  }
277
- throw err;
295
+ throw new Error('QWEN_AUTH_EXPIRED: Sesión expirada. Ejecutá: agent-mp --login');
278
296
  }
279
297
  }
280
298
  /** Call Qwen API using credentials from a specific file path (for role binaries) */
@@ -296,9 +314,10 @@ export async function callQwenAPIFromCreds(prompt, model, credsPath) {
296
314
  if (!token.accessToken) {
297
315
  throw new Error(`Invalid credentials at ${credsPath}. Run the role binary with --login first.`);
298
316
  }
299
- // Refresh if expired
300
- if (token.expiresAt <= Date.now() && token.refreshToken) {
301
- const refreshed = await refreshAccessToken(token.refreshToken);
317
+ // Refresh proactivo: si vence en menos de 2 minutos (o ya venció)
318
+ const TWO_MIN = 2 * 60 * 1000;
319
+ if (token.expiresAt - Date.now() < TWO_MIN && token.refreshToken) {
320
+ const refreshed = await doRefreshToken(token.refreshToken);
302
321
  if (refreshed) {
303
322
  token = refreshed;
304
323
  await fs.writeFile(credsPath, JSON.stringify(token, null, 2), 'utf-8');
@@ -308,10 +327,17 @@ export async function callQwenAPIFromCreds(prompt, model, credsPath) {
308
327
  return await callQwenAPIWithToken(token, prompt, model);
309
328
  }
310
329
  catch (err) {
311
- if (err.message?.startsWith('QWEN_AUTH_EXPIRED')) {
312
- const cliName = path.basename(path.dirname(credsPath)).replace(/^\./, '');
313
- throw new Error(`QWEN_AUTH_EXPIRED: Sesión expirada. Ejecutá: ${cliName} --login`);
330
+ if (!err.message?.startsWith('QWEN_AUTH_EXPIRED'))
331
+ throw err;
332
+ // 401 server-side intentar refresh aunque expiresAt no haya vencido
333
+ if (token.refreshToken) {
334
+ const refreshed = await doRefreshToken(token.refreshToken);
335
+ if (refreshed) {
336
+ await fs.writeFile(credsPath, JSON.stringify(refreshed, null, 2), 'utf-8');
337
+ return callQwenAPIWithToken(refreshed, prompt, model);
338
+ }
314
339
  }
315
- throw err;
340
+ const cliName = path.basename(path.dirname(credsPath)).replace(/^\./, '');
341
+ throw new Error(`QWEN_AUTH_EXPIRED: Sesión expirada. Ejecutá: ${cliName} --login`);
316
342
  }
317
343
  }
package/package.json CHANGED
@@ -1 +1 @@
1
- {"name":"agent-rev","version":"0.3.3","description":"agent-rev agent","type":"module","main":"./dist/index.js","files":["dist/"],"bin":{"agent-rev":"dist/index.js"},"scripts":{"build":"tsc"},"keywords":["ai","agent","cli"],"license":"MIT","dependencies":{"@anthropic-ai/sdk":"^0.39.0","@google/generative-ai":"^0.24.0","chalk":"^5.4.1","commander":"^13.1.0","open":"^11.0.0","openai":"^4.91.0"},"engines":{"node":">=18.0.0"}}
1
+ {"name":"agent-rev","version":"0.3.5","description":"agent-rev agent","type":"module","main":"./dist/index.js","files":["dist/"],"bin":{"agent-rev":"dist/index.js"},"scripts":{"build":"tsc"},"keywords":["ai","agent","cli"],"license":"MIT","dependencies":{"@anthropic-ai/sdk":"^0.39.0","@google/generative-ai":"^0.24.0","chalk":"^5.4.1","commander":"^13.1.0","open":"^11.0.0","openai":"^4.91.0"},"engines":{"node":">=18.0.0"}}