agent-rev 0.2.8 → 0.3.0

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.
@@ -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,12 @@ 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 result = await engine.runExplorer(arg || undefined);
1231
+ console.log(result);
1232
+ break;
1233
+ }
1206
1234
  case 'coordinator':
1207
1235
  case 'coord': {
1208
1236
  console.log(chalk.yellow(' Coordinator mode requires interactive REPL.'));
@@ -1210,7 +1238,7 @@ export async function runRole(role, arg, model) {
1210
1238
  process.exit(1);
1211
1239
  }
1212
1240
  default:
1213
- console.log(chalk.red(` Unknown role: ${role}. Use: orchestrator, implementor, reviewer`));
1241
+ console.log(chalk.red(` Unknown role: ${role}. Use: orchestrator, implementor, reviewer, explorer`));
1214
1242
  process.exit(1);
1215
1243
  }
1216
1244
  }
@@ -38,5 +38,6 @@ 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>;
41
42
  runFullCycle(task: string): Promise<void>;
42
43
  }
@@ -346,6 +346,7 @@ INSTRUCCIONES:
346
346
  orchestrator: 'orchestrator',
347
347
  implementor: 'implementor',
348
348
  reviewer: 'reviewer',
349
+ explorer: 'explorer',
349
350
  };
350
351
  const key = roleMap[roleName];
351
352
  const role = this.config.roles[key];
@@ -446,15 +447,23 @@ INSTRUCCIONES:
446
447
  }
447
448
  }
448
449
  };
450
+ // Role binaries (agent-orch, agent-impl, etc.) are wrappers, not AI CLIs.
451
+ // Calling them with a full prompt causes recursion or ENAMETOOLONG errors.
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
- const primaryResult = await tryWithAutoRepair(role.cli, role.model, role.cmd);
452
- if (primaryResult !== null) {
453
- trackTokens(primaryResult, role.cli, role.model);
454
- return primaryResult;
455
+ if (ROLE_BINARIES.has(role.cli)) {
456
+ log.warn(`${role.cli} is a role binary — skipping to fallback to avoid recursion`);
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,61 @@ 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 res = await this.runWithFallback('explorer', prompt, 'Exploracion');
787
+ const text = extractCliText(res);
788
+ // Always save a timestamped explorer report
789
+ try {
790
+ const ts = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
791
+ await writeFile(path.join(contextDir, `explorer-${ts}.md`), `# Explorer Report\n\nTask: ${effectiveTask}\nDate: ${new Date().toISOString()}\n\n${text}\n`);
792
+ log.ok(`Saved to .agent/context/explorer-${ts}.md`);
793
+ }
794
+ catch { /* don't fail if save fails */ }
795
+ return text;
796
+ }
729
797
  async runFullCycle(task) {
730
798
  // Header is now shown by the REPL before the first user message
731
799
  // ══════════════════════════════════════════════════
package/dist/index.js CHANGED
@@ -85,6 +85,20 @@ const ROLE_BINS = {
85
85
  const nativeRole = ROLE_BINS[PKG_NAME];
86
86
  if (nativeRole) {
87
87
  const args = process.argv.slice(2);
88
+ // --version / -V
89
+ if (args.includes('--version') || args.includes('-V')) {
90
+ console.log(readVersion());
91
+ process.exit(0);
92
+ }
93
+ // --help / -h
94
+ if (args.includes('--help') || args.includes('-h')) {
95
+ console.log(chalk.bold.cyan(`\n ${PKG_NAME} v${readVersion()} — ${nativeRole} agent\n`));
96
+ console.log(chalk.dim(` Usage: ${PKG_NAME} [--model <model>] "<task>"`));
97
+ console.log(chalk.dim(` Login: ${PKG_NAME} --login`));
98
+ console.log(chalk.dim(` Status: ${PKG_NAME} --status`));
99
+ console.log(chalk.dim(` Version: ${PKG_NAME} --version\n`));
100
+ process.exit(0);
101
+ }
88
102
  // --login: OAuth login for this role's account
89
103
  if (args.includes('--login') || args.includes('login')) {
90
104
  const { qwenLogin, fetchQwenModels } = await import('./utils/qwen-auth.js');
package/package.json CHANGED
@@ -1 +1,23 @@
1
- {"name":"agent-rev","version":"0.2.8","description":"agent-rev agent","type":"module","main":"./dist/index.js","files":["dist/"],"bin":{"agent-rev":"dist/index.js"},"scripts":{"build":"tsc && echo '#!/usr/bin/env node' | cat - dist/index.js > dist/index.tmp && mv dist/index.tmp dist/index.js && chmod +x dist/index.js","dev":"tsx src/index.ts","prepublishOnly":"npm run build"},"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"},"devDependencies":{"@types/node":"^22.13.0","@types/open":"^6.1.0","tsx":"^4.19.3","typescript":"^5.7.3"},"engines":{"node":">=18.0.0"}}
1
+ {
2
+ "name": "agent-rev",
3
+ "version": "0.3.0",
4
+ "description": "agent-rev agent",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "files": ["dist/"],
8
+ "bin": { "agent-rev": "dist/index.js" },
9
+ "scripts": {
10
+ "build": "tsc && echo '#!/usr/bin/env node' | cat - dist/index.js > dist/index.tmp && mv dist/index.tmp dist/index.js && chmod +x dist/index.js"
11
+ },
12
+ "keywords": ["ai", "agent", "cli"],
13
+ "license": "MIT",
14
+ "dependencies": {
15
+ "@anthropic-ai/sdk": "^0.39.0",
16
+ "@google/generative-ai": "^0.24.0",
17
+ "chalk": "^5.4.1",
18
+ "commander": "^13.1.0",
19
+ "open": "^11.0.0",
20
+ "openai": "^4.91.0"
21
+ },
22
+ "engines": { "node": ">=18.0.0" }
23
+ }