agent-rev 0.3.2 → 0.3.4

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.
@@ -258,8 +258,13 @@ INSTRUCCIONES:
258
258
  return await callQwenAPI(prompt, model);
259
259
  }
260
260
  catch (err) {
261
- console.log(chalk.red(`\n ✗ Error de autenticación Qwen: ${err.message}`));
262
- console.log(chalk.yellow(' Ejecutá /login para autenticarte.\n'));
261
+ if (err.message?.startsWith('QWEN_AUTH_EXPIRED')) {
262
+ console.log(chalk.red('\n Sesión Qwen expirada.'));
263
+ console.log(chalk.yellow(' Ejecutá: /login para re-autenticarte.\n'));
264
+ }
265
+ else {
266
+ console.log(chalk.red(`\n ✗ Error Qwen: ${err.message}`));
267
+ }
263
268
  return '';
264
269
  }
265
270
  }
@@ -452,6 +457,11 @@ INSTRUCCIONES:
452
457
  return await callQwenAPIFromCreds(rolePrompt, model, credsPath);
453
458
  }
454
459
  catch (err) {
460
+ if (err.message?.startsWith('QWEN_AUTH_EXPIRED')) {
461
+ console.log(chalk.red(`\n ✗ Sesión expirada para ${cliName}.`));
462
+ console.log(chalk.yellow(` Ejecutá: ${cliName} --login\n`));
463
+ return null;
464
+ }
455
465
  log.warn(`${cliName} direct API call failed: ${err.message}`);
456
466
  return null;
457
467
  }
@@ -843,7 +853,18 @@ INSTRUCCIONES:
843
853
  3. Identifica dependencias entre servicios.
844
854
  4. Crea/actualiza ${archPath} con tabla resumen y detalle por servicio.
845
855
  5. Crea/actualiza ${contextDir}/<servicio>/architecture.md para cada servicio.`);
846
- const result = await callQwenAPI(prompt, role.model);
856
+ let result;
857
+ try {
858
+ result = await callQwenAPI(prompt, role.model);
859
+ }
860
+ catch (err) {
861
+ if (err.message?.startsWith('QWEN_AUTH_EXPIRED')) {
862
+ console.log(chalk.red('\n ✗ Sesión Qwen expirada.'));
863
+ console.log(chalk.yellow(' Ejecutá: agent-mp --login (o agent-explorer --login)\n'));
864
+ return '';
865
+ }
866
+ throw err;
867
+ }
847
868
  try {
848
869
  const ts = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
849
870
  await writeFile(path.join(contextDir, `explorer-${ts}.md`), `# Explorer Report\n\nTask: ${effectiveTask}\n\n${result}\n`);
@@ -59,7 +59,8 @@ async function saveToken(token) {
59
59
  const tokenPath = await getTokenPath();
60
60
  await fs.writeFile(tokenPath, JSON.stringify(token, null, 2), 'utf-8');
61
61
  }
62
- async function refreshAccessToken(refreshToken) {
62
+ /** Calls the refresh endpoint and returns the new token (does NOT save). */
63
+ async function doRefreshToken(refreshToken) {
63
64
  try {
64
65
  const response = await fetch(QWEN_OAUTH_TOKEN_ENDPOINT, {
65
66
  method: 'POST',
@@ -70,25 +71,29 @@ async function refreshAccessToken(refreshToken) {
70
71
  client_id: QWEN_OAUTH_CLIENT_ID,
71
72
  }),
72
73
  });
73
- if (!response.ok) {
74
- throw new Error(`Token refresh failed: ${response.status}`);
75
- }
74
+ if (!response.ok)
75
+ return null;
76
76
  const data = await response.json();
77
- const token = {
77
+ if (!data.access_token)
78
+ return null;
79
+ return {
78
80
  accessToken: data.access_token,
79
81
  refreshToken: data.refresh_token || refreshToken,
80
82
  expiresAt: Date.now() + (data.expires_in || 3600) * 1000,
81
83
  idToken: data.id_token,
82
84
  resourceUrl: data.resource_url,
83
85
  };
84
- await saveToken(token);
85
- return token;
86
86
  }
87
- catch (error) {
88
- console.error('Error refreshing token:', error);
87
+ catch {
89
88
  return null;
90
89
  }
91
90
  }
91
+ async function refreshAccessToken(refreshToken) {
92
+ const token = await doRefreshToken(refreshToken);
93
+ if (token)
94
+ await saveToken(token);
95
+ return token;
96
+ }
92
97
  // Generate PKCE code verifier and challenge
93
98
  function generatePKCE() {
94
99
  const codeVerifier = crypto.randomBytes(32).toString('base64url');
@@ -254,17 +259,35 @@ async function callQwenAPIWithToken(token, prompt, model) {
254
259
  });
255
260
  if (!response.ok) {
256
261
  const errorText = await response.text();
262
+ if (response.status === 401) {
263
+ throw new Error(`QWEN_AUTH_EXPIRED: ${errorText}`);
264
+ }
257
265
  throw new Error(`Qwen API error: ${response.status} - ${errorText}`);
258
266
  }
259
267
  const data = await response.json();
260
268
  return data.choices?.[0]?.message?.content || '';
261
269
  }
262
270
  export async function callQwenAPI(prompt, model = 'coder-model') {
263
- const token = await loadToken();
271
+ let token = await loadToken();
264
272
  if (!token) {
265
- throw new Error('No hay token de Qwen. Ejecutá /login primero.');
273
+ throw new Error('QWEN_AUTH_EXPIRED: No hay token de Qwen. Ejecutá --login primero.');
274
+ }
275
+ try {
276
+ return await callQwenAPIWithToken(token, prompt, model);
277
+ }
278
+ catch (err) {
279
+ if (!err.message?.startsWith('QWEN_AUTH_EXPIRED'))
280
+ throw err;
281
+ // 401 — intentar refresh antes de rendirse
282
+ if (token.refreshToken) {
283
+ const refreshed = await doRefreshToken(token.refreshToken);
284
+ if (refreshed) {
285
+ await saveToken(refreshed);
286
+ return callQwenAPIWithToken(refreshed, prompt, model);
287
+ }
288
+ }
289
+ throw new Error('QWEN_AUTH_EXPIRED: Sesión expirada. Ejecutá: agent-mp --login');
266
290
  }
267
- return callQwenAPIWithToken(token, prompt, model);
268
291
  }
269
292
  /** Call Qwen API using credentials from a specific file path (for role binaries) */
270
293
  export async function callQwenAPIFromCreds(prompt, model, credsPath) {
@@ -285,13 +308,29 @@ export async function callQwenAPIFromCreds(prompt, model, credsPath) {
285
308
  if (!token.accessToken) {
286
309
  throw new Error(`Invalid credentials at ${credsPath}. Run the role binary with --login first.`);
287
310
  }
288
- // Refresh if expired
311
+ // Refresh if expired by timestamp
289
312
  if (token.expiresAt <= Date.now() && token.refreshToken) {
290
- const refreshed = await refreshAccessToken(token.refreshToken);
313
+ const refreshed = await doRefreshToken(token.refreshToken);
291
314
  if (refreshed) {
292
315
  token = refreshed;
293
316
  await fs.writeFile(credsPath, JSON.stringify(token, null, 2), 'utf-8');
294
317
  }
295
318
  }
296
- return callQwenAPIWithToken(token, prompt, model);
319
+ try {
320
+ return await callQwenAPIWithToken(token, prompt, model);
321
+ }
322
+ catch (err) {
323
+ if (!err.message?.startsWith('QWEN_AUTH_EXPIRED'))
324
+ throw err;
325
+ // 401 server-side — intentar refresh aunque expiresAt no haya vencido
326
+ if (token.refreshToken) {
327
+ const refreshed = await doRefreshToken(token.refreshToken);
328
+ if (refreshed) {
329
+ await fs.writeFile(credsPath, JSON.stringify(refreshed, null, 2), 'utf-8');
330
+ return callQwenAPIWithToken(refreshed, prompt, model);
331
+ }
332
+ }
333
+ const cliName = path.basename(path.dirname(credsPath)).replace(/^\./, '');
334
+ throw new Error(`QWEN_AUTH_EXPIRED: Sesión expirada. Ejecutá: ${cliName} --login`);
335
+ }
297
336
  }
package/package.json CHANGED
@@ -1 +1 @@
1
- {"name":"agent-rev","version":"0.3.2","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.4","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"}}