agent-rev 0.2.9 → 0.3.1
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/dist/commands/repl.js +39 -2
- package/dist/core/engine.d.ts +4 -0
- package/dist/core/engine.js +133 -7
- package/dist/utils/qwen-auth.d.ts +2 -0
- package/dist/utils/qwen-auth.js +37 -7
- package/package.json +1 -1
package/dist/commands/repl.js
CHANGED
|
@@ -7,7 +7,7 @@ import chalk from 'chalk';
|
|
|
7
7
|
import { execSync } from 'child_process';
|
|
8
8
|
import { CLI_REGISTRY } from '../types.js';
|
|
9
9
|
import { writeJson, ensureDir, readJson, listDir, fileExists } from '../utils/fs.js';
|
|
10
|
-
import { loadAuth, saveAuth, loadCliConfig, saveCliConfig, loadProjectConfig } from '../utils/config.js';
|
|
10
|
+
import { loadAuth, saveAuth, loadCliConfig, saveCliConfig, loadProjectConfig, PKG_NAME } from '../utils/config.js';
|
|
11
11
|
import { log } from '../utils/logger.js';
|
|
12
12
|
import { AgentEngine, ExitError } from '../core/engine.js';
|
|
13
13
|
import { qwenAuthStatus, QWEN_AGENT_HOME, fetchQwenModels } from '../utils/qwen-auth.js';
|
|
@@ -716,10 +716,12 @@ function cmdHelp(fi) {
|
|
|
716
716
|
{ key: '/setup explorer', value: 'Reconfigure explorer only' },
|
|
717
717
|
{ key: '/config-multi', value: 'Reconfigure all agents at once' },
|
|
718
718
|
{ key: '/status', value: 'Show current configuration and tasks' },
|
|
719
|
+
{ key: '/explorer <task>', value: 'Run explorer agent on a task/question' },
|
|
719
720
|
{ key: '/run <task>', value: 'Full cycle: orchestrator → implementor → reviewer' },
|
|
720
721
|
{ key: '/run orch <task>', value: 'Run only orchestrator' },
|
|
721
722
|
{ key: '/run impl <id>', value: 'Run only implementor' },
|
|
722
723
|
{ key: '/run rev <id>', value: 'Run only reviewer' },
|
|
724
|
+
{ key: '/run explorer <task>', value: 'Run only explorer' },
|
|
723
725
|
{ key: '/models', value: 'List models for all installed CLIs' },
|
|
724
726
|
{ key: '/models <cli>', value: 'List models for a specific CLI' },
|
|
725
727
|
{ key: '/login', value: 'Login (Qwen OAuth or CLI auth)' },
|
|
@@ -1035,6 +1037,12 @@ export async function runRepl(resumeSession) {
|
|
|
1035
1037
|
const progress = await readJson(path.join(taskDir, 'progress.json'));
|
|
1036
1038
|
await engine.runReviewer(taskId, plan, progress);
|
|
1037
1039
|
}
|
|
1040
|
+
else if (args[0] === 'explorer' || args[0] === 'exp') {
|
|
1041
|
+
const task = args.slice(1).join(' ') || undefined;
|
|
1042
|
+
const engine = new AgentEngine(config, dir, gCoordinatorCmd, rl, fi, handleCmd);
|
|
1043
|
+
const result = await engine.runExplorer(task);
|
|
1044
|
+
fi.println(result);
|
|
1045
|
+
}
|
|
1038
1046
|
else {
|
|
1039
1047
|
const task = args.join(' ');
|
|
1040
1048
|
const engine = new AgentEngine(config, dir, gCoordinatorCmd, rl, fi, handleCmd);
|
|
@@ -1042,6 +1050,20 @@ export async function runRepl(resumeSession) {
|
|
|
1042
1050
|
}
|
|
1043
1051
|
break;
|
|
1044
1052
|
}
|
|
1053
|
+
case 'explorer': {
|
|
1054
|
+
const task = args.join(' ') || undefined;
|
|
1055
|
+
try {
|
|
1056
|
+
const dir = process.cwd();
|
|
1057
|
+
const config = await loadProjectConfig(dir);
|
|
1058
|
+
const engine = new AgentEngine(config, dir, gCoordinatorCmd, rl, fi, handleCmd);
|
|
1059
|
+
const result = await engine.runExplorer(task);
|
|
1060
|
+
fi.println(result);
|
|
1061
|
+
}
|
|
1062
|
+
catch (err) {
|
|
1063
|
+
fi.println(chalk.red(` Explorer error: ${err.message}`));
|
|
1064
|
+
}
|
|
1065
|
+
break;
|
|
1066
|
+
}
|
|
1045
1067
|
case 'models':
|
|
1046
1068
|
case 'model':
|
|
1047
1069
|
await withRl((rl) => cmdModels(args[0], fi, rl));
|
|
@@ -1203,6 +1225,21 @@ export async function runRole(role, arg, model) {
|
|
|
1203
1225
|
await engine.runReviewer(arg, plan, progress);
|
|
1204
1226
|
break;
|
|
1205
1227
|
}
|
|
1228
|
+
case 'explorer':
|
|
1229
|
+
case 'exp': {
|
|
1230
|
+
const explorerCli = config.roles.explorer?.cli;
|
|
1231
|
+
if (explorerCli && explorerCli === PKG_NAME) {
|
|
1232
|
+
// This binary IS the configured explorer CLI — avoid recursion.
|
|
1233
|
+
// Call Qwen API directly using own credentials.
|
|
1234
|
+
const result = await engine.runExplorerDirect(arg || undefined);
|
|
1235
|
+
console.log(result);
|
|
1236
|
+
}
|
|
1237
|
+
else {
|
|
1238
|
+
const result = await engine.runExplorer(arg || undefined);
|
|
1239
|
+
console.log(result);
|
|
1240
|
+
}
|
|
1241
|
+
break;
|
|
1242
|
+
}
|
|
1206
1243
|
case 'coordinator':
|
|
1207
1244
|
case 'coord': {
|
|
1208
1245
|
console.log(chalk.yellow(' Coordinator mode requires interactive REPL.'));
|
|
@@ -1210,7 +1247,7 @@ export async function runRole(role, arg, model) {
|
|
|
1210
1247
|
process.exit(1);
|
|
1211
1248
|
}
|
|
1212
1249
|
default:
|
|
1213
|
-
console.log(chalk.red(` Unknown role: ${role}. Use: orchestrator, implementor, reviewer`));
|
|
1250
|
+
console.log(chalk.red(` Unknown role: ${role}. Use: orchestrator, implementor, reviewer, explorer`));
|
|
1214
1251
|
process.exit(1);
|
|
1215
1252
|
}
|
|
1216
1253
|
}
|
package/dist/core/engine.d.ts
CHANGED
|
@@ -38,5 +38,9 @@ export declare class AgentEngine {
|
|
|
38
38
|
runReviewer(taskId: string, plan: TaskPlan, progress: TaskProgress): Promise<{
|
|
39
39
|
verdict: string;
|
|
40
40
|
}>;
|
|
41
|
+
runExplorer(task?: string): Promise<string>;
|
|
42
|
+
/** Called when the current binary IS the configured explorer CLI (prevents recursion).
|
|
43
|
+
* Builds the full exploration prompt and calls Qwen API using own credentials. */
|
|
44
|
+
runExplorerDirect(task?: string): Promise<string>;
|
|
41
45
|
runFullCycle(task: string): Promise<void>;
|
|
42
46
|
}
|
package/dist/core/engine.js
CHANGED
|
@@ -6,8 +6,7 @@ import { CLI_REGISTRY } from '../types.js';
|
|
|
6
6
|
import { writeJson, readJson, fileExists, writeFile, readFile } from '../utils/fs.js';
|
|
7
7
|
import { log } from '../utils/logger.js';
|
|
8
8
|
import chalk from 'chalk';
|
|
9
|
-
import { QWEN_AGENT_HOME } from '../utils/qwen-auth.js';
|
|
10
|
-
import { callQwenAPI } from '../utils/qwen-auth.js';
|
|
9
|
+
import { QWEN_AGENT_HOME, callQwenAPI } from '../utils/qwen-auth.js';
|
|
11
10
|
import * as fs from 'fs/promises';
|
|
12
11
|
/** Thrown when a slash command inside a conversation requests exit */
|
|
13
12
|
export class ExitError extends Error {
|
|
@@ -346,6 +345,7 @@ INSTRUCCIONES:
|
|
|
346
345
|
orchestrator: 'orchestrator',
|
|
347
346
|
implementor: 'implementor',
|
|
348
347
|
reviewer: 'reviewer',
|
|
348
|
+
explorer: 'explorer',
|
|
349
349
|
};
|
|
350
350
|
const key = roleMap[roleName];
|
|
351
351
|
const role = this.config.roles[key];
|
|
@@ -446,15 +446,24 @@ INSTRUCCIONES:
|
|
|
446
446
|
}
|
|
447
447
|
}
|
|
448
448
|
};
|
|
449
|
+
// Role binaries (agent-orch, agent-impl, etc.) are wrappers, not AI CLIs.
|
|
450
|
+
// runExplorer handles them separately by spawning with the short task.
|
|
451
|
+
// For orch/impl/rev the full cycle never spawns role binaries via runWithFallback.
|
|
452
|
+
const ROLE_BINARIES = new Set(['agent-orch', 'agent-impl', 'agent-rev', 'agent-explorer']);
|
|
449
453
|
// Try primary
|
|
450
454
|
log.info(`Launching ${roleName}: ${role.cli} (${role.model})`);
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
+
if (ROLE_BINARIES.has(role.cli)) {
|
|
456
|
+
log.warn(`${role.cli} is a role binary — skipping to fallback`);
|
|
457
|
+
}
|
|
458
|
+
else {
|
|
459
|
+
const primaryResult = await tryWithAutoRepair(role.cli, role.model, role.cmd);
|
|
460
|
+
if (primaryResult !== null) {
|
|
461
|
+
trackTokens(primaryResult, role.cli, role.model);
|
|
462
|
+
return primaryResult;
|
|
463
|
+
}
|
|
455
464
|
}
|
|
456
465
|
// Try individual fallback
|
|
457
|
-
if (role.fallback) {
|
|
466
|
+
if (role.fallback && !ROLE_BINARIES.has(role.fallback.cli)) {
|
|
458
467
|
log.warn(`Trying individual fallback for ${roleName}: ${role.fallback.cli} (${role.fallback.model})`);
|
|
459
468
|
const fallbackResult = await tryWithAutoRepair(role.fallback.cli, role.fallback.model, role.fallback.cmd);
|
|
460
469
|
if (fallbackResult !== null) {
|
|
@@ -489,6 +498,10 @@ REGLA: Al terminar, responde SOLO con el JSON de progreso indicado.`,
|
|
|
489
498
|
REGLA: Usa tus herramientas (read_file, grep_search, etc.) para leer los archivos y verificar criterios.
|
|
490
499
|
REGLA: NO modifiques archivos. NO implementes correcciones.
|
|
491
500
|
REGLA: Al terminar, responde SOLO con el JSON de resultado indicado.`,
|
|
501
|
+
explorer: `ROL: EXPLORER — solo explora y reporta, nunca modifica archivos.
|
|
502
|
+
REGLA: Usa tus herramientas (read_file, grep_search, list_directory, etc.) para explorar el proyecto.
|
|
503
|
+
REGLA: NO modifiques archivos. NO ejecutes comandos que cambien estado.
|
|
504
|
+
REGLA: Al terminar, reporta todo lo que encontraste de forma clara y estructurada.`,
|
|
492
505
|
};
|
|
493
506
|
const preamble = preambles[roleName] || '';
|
|
494
507
|
return preamble ? `${preamble}\n\n${taskPrompt}` : taskPrompt;
|
|
@@ -726,6 +739,119 @@ INSTRUCCIONES:
|
|
|
726
739
|
log.verdict(verdict);
|
|
727
740
|
return { verdict };
|
|
728
741
|
}
|
|
742
|
+
async runExplorer(task) {
|
|
743
|
+
if (!this.config.roles.explorer) {
|
|
744
|
+
if (!this.config.fallback_global) {
|
|
745
|
+
throw new Error('Explorer not configured and no fallback available. Run /setup explorer first.');
|
|
746
|
+
}
|
|
747
|
+
log.warn(`Explorer role not configured — using fallback: ${this.config.fallback_global.cli} (${this.config.fallback_global.model})`);
|
|
748
|
+
this.config.roles.explorer = { ...this.config.fallback_global };
|
|
749
|
+
}
|
|
750
|
+
log.phase(0, 'Exploracion', this.config.roles.explorer.cli, this.config.roles.explorer.model);
|
|
751
|
+
// Ensure .agent/ structure exists
|
|
752
|
+
const agentDir = path.join(this.projectDir, '.agent');
|
|
753
|
+
const contextDir = path.join(agentDir, 'context');
|
|
754
|
+
await fs.mkdir(contextDir, { recursive: true });
|
|
755
|
+
await fs.mkdir(path.join(agentDir, 'rules'), { recursive: true });
|
|
756
|
+
// Read existing architecture doc if any
|
|
757
|
+
const archPath = path.join(contextDir, 'architecture.md');
|
|
758
|
+
let existingArch = '';
|
|
759
|
+
try {
|
|
760
|
+
existingArch = await readFile(archPath);
|
|
761
|
+
}
|
|
762
|
+
catch { /* new project */ }
|
|
763
|
+
const effectiveTask = task || 'Explorar y documentar todas las aplicaciones y servicios del proyecto';
|
|
764
|
+
const prompt = `TAREA DE EXPLORACION: ${effectiveTask}
|
|
765
|
+
DIRECTORIO_TRABAJO: ${this.projectDir}
|
|
766
|
+
PROYECTO: ${this.config.project}
|
|
767
|
+
STACK: ${this.config.stack}
|
|
768
|
+
|
|
769
|
+
${existingArch ? `DOCUMENTACION EXISTENTE (actualizar si hay cambios):\n${existingArch.slice(0, 3000)}\n` : 'DOCUMENTACION EXISTENTE: ninguna — crear desde cero.\n'}
|
|
770
|
+
INSTRUCCIONES:
|
|
771
|
+
1. Lista el directorio raiz para identificar todos los servicios/aplicaciones.
|
|
772
|
+
2. Para cada servicio/app: lee su package.json / requirements.txt / pyproject.toml para obtener nombre, stack y dependencias clave.
|
|
773
|
+
3. Explora src/ o app/ de cada servicio: identifica entry point, modulos principales, rutas/endpoints expuestos, puerto configurado.
|
|
774
|
+
4. Identifica dependencias ENTRE servicios (llamadas HTTP, variables de entorno compartidas, bases de datos comunes).
|
|
775
|
+
5. Crea o actualiza el archivo ${archPath} con:
|
|
776
|
+
- Tabla resumen: | Servicio | Stack | Puerto | Proposito | Entry Point |
|
|
777
|
+
- Por cada servicio: modulos principales, rutas API clave, dependencias externas
|
|
778
|
+
- Mapa de dependencias entre servicios
|
|
779
|
+
6. Crea o actualiza archivos individuales en ${contextDir}/<servicio>/architecture.md para cada servicio.
|
|
780
|
+
7. Al terminar lista todos los archivos creados/actualizados.
|
|
781
|
+
|
|
782
|
+
REGLAS:
|
|
783
|
+
- NO modifiques archivos de aplicacion (solo .agent/context/)
|
|
784
|
+
- NO ejecutes comandos que cambien estado (npm install, migraciones, etc.)
|
|
785
|
+
- Si un directorio esta en node_modules, dist, .git: ignoralo`;
|
|
786
|
+
const ROLE_BINS = new Set(['agent-orch', 'agent-impl', 'agent-rev', 'agent-explorer']);
|
|
787
|
+
let res;
|
|
788
|
+
if (ROLE_BINS.has(this.config.roles.explorer.cli)) {
|
|
789
|
+
// Spawn the role binary as a separate process with its own credentials.
|
|
790
|
+
// Pass only the short task — the binary builds its own full prompt internally.
|
|
791
|
+
const explorerRole = this.config.roles.explorer;
|
|
792
|
+
const spawnCmd = `${explorerRole.cli} --model ${explorerRole.model}`;
|
|
793
|
+
log.info(`Spawning ${explorerRole.cli} (${explorerRole.model}) as separate process`);
|
|
794
|
+
const result = await runCli(spawnCmd, effectiveTask);
|
|
795
|
+
if (result.exitCode !== 0) {
|
|
796
|
+
log.warn(`${explorerRole.cli} exited with code ${result.exitCode} — trying fallback`);
|
|
797
|
+
res = await this.runWithFallback('explorer', prompt, 'Exploracion');
|
|
798
|
+
}
|
|
799
|
+
else {
|
|
800
|
+
res = result.output;
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
else {
|
|
804
|
+
res = await this.runWithFallback('explorer', prompt, 'Exploracion');
|
|
805
|
+
}
|
|
806
|
+
const text = extractCliText(res);
|
|
807
|
+
// Always save a timestamped explorer report
|
|
808
|
+
try {
|
|
809
|
+
const ts = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
|
|
810
|
+
await writeFile(path.join(contextDir, `explorer-${ts}.md`), `# Explorer Report\n\nTask: ${effectiveTask}\nDate: ${new Date().toISOString()}\n\n${text}\n`);
|
|
811
|
+
log.ok(`Saved to .agent/context/explorer-${ts}.md`);
|
|
812
|
+
}
|
|
813
|
+
catch { /* don't fail if save fails */ }
|
|
814
|
+
return text;
|
|
815
|
+
}
|
|
816
|
+
/** Called when the current binary IS the configured explorer CLI (prevents recursion).
|
|
817
|
+
* Builds the full exploration prompt and calls Qwen API using own credentials. */
|
|
818
|
+
async runExplorerDirect(task) {
|
|
819
|
+
const role = this.config.roles.explorer;
|
|
820
|
+
if (!role)
|
|
821
|
+
throw new Error('Explorer role not configured.');
|
|
822
|
+
const agentDir = path.join(this.projectDir, '.agent');
|
|
823
|
+
const contextDir = path.join(agentDir, 'context');
|
|
824
|
+
await fs.mkdir(contextDir, { recursive: true });
|
|
825
|
+
const archPath = path.join(contextDir, 'architecture.md');
|
|
826
|
+
let existingArch = '';
|
|
827
|
+
try {
|
|
828
|
+
existingArch = await readFile(archPath);
|
|
829
|
+
}
|
|
830
|
+
catch { /* new */ }
|
|
831
|
+
const effectiveTask = task || 'Explorar y documentar todas las aplicaciones y servicios del proyecto';
|
|
832
|
+
const context = await this.buildOrchestratorContext();
|
|
833
|
+
const prompt = this.buildRolePrompt('explorer', `TAREA DE EXPLORACION: ${effectiveTask}
|
|
834
|
+
DIRECTORIO_TRABAJO: ${this.projectDir}
|
|
835
|
+
PROYECTO: ${this.config.project}
|
|
836
|
+
|
|
837
|
+
${existingArch ? `DOCUMENTACION EXISTENTE:\n${existingArch.slice(0, 3000)}\n` : 'Sin documentacion previa.\n'}
|
|
838
|
+
CONTEXTO: ${context.slice(0, 2000)}
|
|
839
|
+
|
|
840
|
+
INSTRUCCIONES:
|
|
841
|
+
1. Lista el directorio raiz e identifica todos los servicios/apps.
|
|
842
|
+
2. Para cada uno: lee package.json/requirements.txt, explora src/, identifica entry point, rutas/endpoints, puerto.
|
|
843
|
+
3. Identifica dependencias entre servicios.
|
|
844
|
+
4. Crea/actualiza ${archPath} con tabla resumen y detalle por servicio.
|
|
845
|
+
5. Crea/actualiza ${contextDir}/<servicio>/architecture.md para cada servicio.`);
|
|
846
|
+
const result = await callQwenAPI(prompt, role.model);
|
|
847
|
+
try {
|
|
848
|
+
const ts = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
|
|
849
|
+
await writeFile(path.join(contextDir, `explorer-${ts}.md`), `# Explorer Report\n\nTask: ${effectiveTask}\n\n${result}\n`);
|
|
850
|
+
log.ok(`Saved to .agent/context/explorer-${ts}.md`);
|
|
851
|
+
}
|
|
852
|
+
catch { /* ignore */ }
|
|
853
|
+
return result;
|
|
854
|
+
}
|
|
729
855
|
async runFullCycle(task) {
|
|
730
856
|
// Header is now shown by the REPL before the first user message
|
|
731
857
|
// ══════════════════════════════════════════════════
|
|
@@ -11,3 +11,5 @@ export declare function qwenAuthStatus(): Promise<{
|
|
|
11
11
|
export declare function fetchQwenModels(): Promise<string[]>;
|
|
12
12
|
export declare function getQwenAccessToken(): Promise<string | null>;
|
|
13
13
|
export declare function callQwenAPI(prompt: string, model?: string): Promise<string>;
|
|
14
|
+
/** Call Qwen API using credentials from a specific file path (for role binaries) */
|
|
15
|
+
export declare function callQwenAPIFromCreds(prompt: string, model: string, credsPath: string): Promise<string>;
|
package/dist/utils/qwen-auth.js
CHANGED
|
@@ -237,12 +237,7 @@ export async function getQwenAccessToken() {
|
|
|
237
237
|
const token = await loadToken();
|
|
238
238
|
return token?.accessToken || null;
|
|
239
239
|
}
|
|
240
|
-
|
|
241
|
-
const token = await loadToken();
|
|
242
|
-
if (!token) {
|
|
243
|
-
throw new Error('No hay token de Qwen. Ejecutá /login primero.');
|
|
244
|
-
}
|
|
245
|
-
// Qwen OAuth tokens work with chat.qwen.ai API
|
|
240
|
+
async function callQwenAPIWithToken(token, prompt, model) {
|
|
246
241
|
const baseUrl = 'https://chat.qwen.ai/api/v1';
|
|
247
242
|
const response = await fetch(`${baseUrl}/chat/completions`, {
|
|
248
243
|
method: 'POST',
|
|
@@ -253,7 +248,6 @@ export async function callQwenAPI(prompt, model = 'coder-model') {
|
|
|
253
248
|
body: JSON.stringify({
|
|
254
249
|
model: model || 'coder-model',
|
|
255
250
|
messages: [
|
|
256
|
-
{ role: 'system', content: 'Sos el COORDINADOR de un equipo multi-agente de desarrollo. Tu trabajo es ENTENDER lo que el programador necesita haciendo PREGUNTAS si es necesario. Habla de forma NATURAL, como un compañero de equipo. Sé breve y directo.' },
|
|
257
251
|
{ role: 'user', content: prompt },
|
|
258
252
|
],
|
|
259
253
|
}),
|
|
@@ -265,3 +259,39 @@ export async function callQwenAPI(prompt, model = 'coder-model') {
|
|
|
265
259
|
const data = await response.json();
|
|
266
260
|
return data.choices?.[0]?.message?.content || '';
|
|
267
261
|
}
|
|
262
|
+
export async function callQwenAPI(prompt, model = 'coder-model') {
|
|
263
|
+
const token = await loadToken();
|
|
264
|
+
if (!token) {
|
|
265
|
+
throw new Error('No hay token de Qwen. Ejecutá /login primero.');
|
|
266
|
+
}
|
|
267
|
+
return callQwenAPIWithToken(token, prompt, model);
|
|
268
|
+
}
|
|
269
|
+
/** Call Qwen API using credentials from a specific file path (for role binaries) */
|
|
270
|
+
export async function callQwenAPIFromCreds(prompt, model, credsPath) {
|
|
271
|
+
let raw;
|
|
272
|
+
try {
|
|
273
|
+
raw = JSON.parse(await fs.readFile(credsPath, 'utf-8'));
|
|
274
|
+
}
|
|
275
|
+
catch {
|
|
276
|
+
throw new Error(`No credentials found at ${credsPath}. Run the role binary with --login first.`);
|
|
277
|
+
}
|
|
278
|
+
let token = {
|
|
279
|
+
accessToken: raw.accessToken || raw.access_token || '',
|
|
280
|
+
refreshToken: raw.refreshToken || raw.refresh_token || '',
|
|
281
|
+
expiresAt: raw.expiresAt || raw.expiry_date || 0,
|
|
282
|
+
idToken: raw.idToken || raw.id_token,
|
|
283
|
+
resourceUrl: raw.resourceUrl || raw.resource_url,
|
|
284
|
+
};
|
|
285
|
+
if (!token.accessToken) {
|
|
286
|
+
throw new Error(`Invalid credentials at ${credsPath}. Run the role binary with --login first.`);
|
|
287
|
+
}
|
|
288
|
+
// Refresh if expired
|
|
289
|
+
if (token.expiresAt <= Date.now() && token.refreshToken) {
|
|
290
|
+
const refreshed = await refreshAccessToken(token.refreshToken);
|
|
291
|
+
if (refreshed) {
|
|
292
|
+
token = refreshed;
|
|
293
|
+
await fs.writeFile(credsPath, JSON.stringify(token, null, 2), 'utf-8');
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
return callQwenAPIWithToken(token, prompt, model);
|
|
297
|
+
}
|
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"agent-rev","version":"0.
|
|
1
|
+
{"name":"agent-rev","version":"0.3.1","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"}}
|