agent-rev 0.1.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.
- package/dist/api/qwen.d.ts +12 -0
- package/dist/api/qwen.js +150 -0
- package/dist/commands/auth.d.ts +31 -0
- package/dist/commands/auth.js +255 -0
- package/dist/commands/config.d.ts +2 -0
- package/dist/commands/config.js +42 -0
- package/dist/commands/models.d.ts +2 -0
- package/dist/commands/models.js +27 -0
- package/dist/commands/repl.d.ts +29 -0
- package/dist/commands/repl.js +1167 -0
- package/dist/commands/run.d.ts +2 -0
- package/dist/commands/run.js +52 -0
- package/dist/commands/setup.d.ts +2 -0
- package/dist/commands/setup.js +353 -0
- package/dist/commands/status.d.ts +2 -0
- package/dist/commands/status.js +46 -0
- package/dist/core/engine.d.ts +36 -0
- package/dist/core/engine.js +905 -0
- package/dist/core/prompts.d.ts +11 -0
- package/dist/core/prompts.js +126 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +171 -0
- package/dist/providers/index.d.ts +2 -0
- package/dist/providers/index.js +120 -0
- package/dist/types.d.ts +73 -0
- package/dist/types.js +58 -0
- package/dist/ui/input.d.ts +24 -0
- package/dist/ui/input.js +244 -0
- package/dist/ui/theme.d.ts +99 -0
- package/dist/ui/theme.js +307 -0
- package/dist/utils/config.d.ts +38 -0
- package/dist/utils/config.js +40 -0
- package/dist/utils/fs.d.ts +7 -0
- package/dist/utils/fs.js +37 -0
- package/dist/utils/logger.d.ts +13 -0
- package/dist/utils/logger.js +46 -0
- package/dist/utils/qwen-auth.d.ts +12 -0
- package/dist/utils/qwen-auth.js +250 -0
- package/dist/utils/sessions.d.ts +17 -0
- package/dist/utils/sessions.js +46 -0
- package/package.json +44 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { TaskPlan } from '../types.js';
|
|
2
|
+
export declare function orchestratorSystem(): string;
|
|
3
|
+
export declare function orchestratorUser(taskId: string, task: string, context: string): string;
|
|
4
|
+
export declare function implementorSystem(approved: string[], forbidden: string[]): string;
|
|
5
|
+
export declare function implementorUser(taskId: string, plan: TaskPlan): string;
|
|
6
|
+
export declare function reviewerSystem(): string;
|
|
7
|
+
export declare function reviewerUser(taskId: string, plan: TaskPlan, progressSummary: string): string;
|
|
8
|
+
export declare function proposerSystem(): string;
|
|
9
|
+
export declare function proposerUser(task: string, question: string, prevRounds: string): string;
|
|
10
|
+
export declare function criticSystem(): string;
|
|
11
|
+
export declare function criticUser(task: string, question: string, proposal: string, prevCritiques: string): string;
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
export function orchestratorSystem() {
|
|
2
|
+
return `Sos el ORCHESTRATOR de un sistema multi-agente. Tu UNICO trabajo es planificar.
|
|
3
|
+
|
|
4
|
+
REGLAS:
|
|
5
|
+
- NO ejecutar codigo
|
|
6
|
+
- NO crear archivos fuera de .agent/tasks/
|
|
7
|
+
- NO instalar dependencias
|
|
8
|
+
- NO modificar archivos existentes
|
|
9
|
+
- Solo planificar y escribir JSON
|
|
10
|
+
|
|
11
|
+
Tu output debe ser SOLO JSON valido, sin markdown, sin explicaciones.`;
|
|
12
|
+
}
|
|
13
|
+
export function orchestratorUser(taskId, task, context) {
|
|
14
|
+
return `TAREA: ${task}
|
|
15
|
+
ID: ${taskId}
|
|
16
|
+
|
|
17
|
+
CONTEXTO:
|
|
18
|
+
${context}
|
|
19
|
+
|
|
20
|
+
Responde SOLO con este JSON:
|
|
21
|
+
{
|
|
22
|
+
"plan": {
|
|
23
|
+
"task_id": "${taskId}",
|
|
24
|
+
"description": "${task}",
|
|
25
|
+
"steps": [
|
|
26
|
+
{"num": 1, "description": "paso detallado", "files": ["ruta/archivo"], "status": "pending"}
|
|
27
|
+
],
|
|
28
|
+
"acceptance_criteria": ["criterio verificable 1", "criterio verificable 2"],
|
|
29
|
+
"deliberation": {"needed": false, "question": ""}
|
|
30
|
+
},
|
|
31
|
+
"progress": {
|
|
32
|
+
"task_id": "${taskId}",
|
|
33
|
+
"created_at": "${new Date().toISOString()}",
|
|
34
|
+
"steps": [],
|
|
35
|
+
"status": "planned"
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
Cada step debe ser atomico. Los criterios deben ser verificables.`;
|
|
40
|
+
}
|
|
41
|
+
export function implementorSystem(approved, forbidden) {
|
|
42
|
+
return `Sos el IMPLEMENTOR. Tu UNICO trabajo es ejecutar el plan.
|
|
43
|
+
|
|
44
|
+
REGLAS:
|
|
45
|
+
- NO modificar plan.json
|
|
46
|
+
- NO crear archivos no contemplados en el plan
|
|
47
|
+
- Seguir el plan exactamente
|
|
48
|
+
- Actualizar progress.json con timestamps
|
|
49
|
+
|
|
50
|
+
APROBADOS: ${approved.join(', ')}
|
|
51
|
+
PROHIBIDOS: ${forbidden.join(', ')}
|
|
52
|
+
|
|
53
|
+
Tu output debe ser SOLO JSON valido con el progress actualizado.`;
|
|
54
|
+
}
|
|
55
|
+
export function implementorUser(taskId, plan) {
|
|
56
|
+
return `EJECUTA ESTE PLAN:
|
|
57
|
+
Task: ${taskId}
|
|
58
|
+
${JSON.stringify(plan, null, 2)}
|
|
59
|
+
|
|
60
|
+
Por cada step completado, cambia status a "completed" y agrega completed_at.
|
|
61
|
+
Al terminar todos los steps, status = "completed".
|
|
62
|
+
|
|
63
|
+
Responde SOLO con el JSON de progress actualizado.`;
|
|
64
|
+
}
|
|
65
|
+
export function reviewerSystem() {
|
|
66
|
+
return `Sos el REVIEWER. Tu UNICO trabajo es validar.
|
|
67
|
+
|
|
68
|
+
REGLAS:
|
|
69
|
+
- NO modificar codigo
|
|
70
|
+
- NO implementar correcciones
|
|
71
|
+
- Solo validar y reportar
|
|
72
|
+
|
|
73
|
+
Tu output debe ser SOLO JSON valido.`;
|
|
74
|
+
}
|
|
75
|
+
export function reviewerUser(taskId, plan, progressSummary) {
|
|
76
|
+
return `VALIDA ESTA TAREA:
|
|
77
|
+
Task: ${taskId}
|
|
78
|
+
|
|
79
|
+
PLAN:
|
|
80
|
+
${JSON.stringify({ description: plan.description, criteria: plan.acceptance_criteria }, null, 2)}
|
|
81
|
+
|
|
82
|
+
PROGRESO:
|
|
83
|
+
${progressSummary}
|
|
84
|
+
|
|
85
|
+
Responde SOLO con:
|
|
86
|
+
{
|
|
87
|
+
"result": {
|
|
88
|
+
"task_id": "${taskId}",
|
|
89
|
+
"criteria": [{"criterion": "...", "status": "PASS", "notes": "..."}],
|
|
90
|
+
"verdict": "PASS",
|
|
91
|
+
"explanation": "..."
|
|
92
|
+
},
|
|
93
|
+
"validation": {
|
|
94
|
+
"status": "PASS",
|
|
95
|
+
"reviewed_at": "${new Date().toISOString()}",
|
|
96
|
+
"reviewer": "reviewer"
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
Verdict = "PASS" si TODOS los criterios se cumplen, "FAIL" si alguno falla.`;
|
|
101
|
+
}
|
|
102
|
+
export function proposerSystem() {
|
|
103
|
+
return `Sos el PROPOSER en un debate tecnico. Generas propuestas con justificacion tecnica.
|
|
104
|
+
Responde SOLO con JSON valido.`;
|
|
105
|
+
}
|
|
106
|
+
export function proposerUser(task, question, prevRounds) {
|
|
107
|
+
return `TAREA: ${task}
|
|
108
|
+
PREGUNTA: ${question}
|
|
109
|
+
${prevRounds ? 'RONDAS ANTERIORES:\n' + prevRounds : 'Primera ronda.'}
|
|
110
|
+
|
|
111
|
+
Responde SOLO con:
|
|
112
|
+
{"proposal": "...", "justification": "...", "trade_offs": ["..."], "accept": false}`;
|
|
113
|
+
}
|
|
114
|
+
export function criticSystem() {
|
|
115
|
+
return `Sos el CRITIC en un debate tecnico. Buscas debilidades, edge cases y errores.
|
|
116
|
+
Responde SOLO con JSON valido.`;
|
|
117
|
+
}
|
|
118
|
+
export function criticUser(task, question, proposal, prevCritiques) {
|
|
119
|
+
return `TAREA: ${task}
|
|
120
|
+
PREGUNTA: ${question}
|
|
121
|
+
PROPUESTA: ${proposal}
|
|
122
|
+
${prevCritiques ? 'CRITICAS ANTERIORES:\n' + prevCritiques : ''}
|
|
123
|
+
|
|
124
|
+
Responde SOLO con:
|
|
125
|
+
{"analysis": "...", "weaknesses": ["..."], "edge_cases": ["..."], "suggestions": ["..."], "verdict": "ACCEPT"}`;
|
|
126
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import * as path from 'path';
|
|
4
|
+
import * as os from 'os';
|
|
5
|
+
import * as fs from 'fs/promises';
|
|
6
|
+
import * as readline from 'readline';
|
|
7
|
+
import chalk from 'chalk';
|
|
8
|
+
import { AGENT_HOME } from './utils/config.js';
|
|
9
|
+
import { runRepl, runRole } from './commands/repl.js';
|
|
10
|
+
import { setupCommand } from './commands/setup.js';
|
|
11
|
+
import { getLastSessionForDir, listSessions, loadSession } from './utils/sessions.js';
|
|
12
|
+
const program = new Command();
|
|
13
|
+
program
|
|
14
|
+
.name('agent-mp')
|
|
15
|
+
.description('Deterministic multi-agent CLI orchestrator')
|
|
16
|
+
.version('0.1.0')
|
|
17
|
+
.argument('[task...]', 'Task description or arguments')
|
|
18
|
+
.option('--continue', 'Resume the last session in the current directory')
|
|
19
|
+
.option('--resume [id]', 'Resume any saved session by ID (omit ID to pick from list)')
|
|
20
|
+
.option('--rol <role>', 'Run a specific role directly: orchestrator | implementor | reviewer | coordinator')
|
|
21
|
+
.option('--reset-coordinator', 'Clear coordinator selection (re-pick on next run)')
|
|
22
|
+
.option('--reset-auth', 'Wipe all auth credentials and start fresh')
|
|
23
|
+
.addHelpText('after', `
|
|
24
|
+
Setup subcommands:
|
|
25
|
+
agent-mp setup init Full interactive wizard (login + roles + project)
|
|
26
|
+
agent-mp setup config-multi Reconfigure all roles at once
|
|
27
|
+
agent-mp setup orch Reconfigure orchestrator only
|
|
28
|
+
agent-mp setup impl Reconfigure implementor only
|
|
29
|
+
agent-mp setup rev Reconfigure reviewer only
|
|
30
|
+
agent-mp setup explorer Reconfigure explorer only
|
|
31
|
+
agent-mp setup proposer Reconfigure proposer (deliberation)
|
|
32
|
+
agent-mp setup critic Reconfigure critic (deliberation)
|
|
33
|
+
agent-mp setup status Show current configuration
|
|
34
|
+
|
|
35
|
+
REPL commands (type inside the session):
|
|
36
|
+
/help Show all REPL commands
|
|
37
|
+
/status Show roles, auth, and tasks
|
|
38
|
+
/auth-status Show login status
|
|
39
|
+
/setup orch|impl|rev|explorer Reconfigure a role without leaving the REPL
|
|
40
|
+
/config-multi Reconfigure all roles at once
|
|
41
|
+
/run <task> Full cycle: orchestrator → implementor → reviewer
|
|
42
|
+
/run orch <task> Run only orchestrator
|
|
43
|
+
/run impl <id> Run only implementor
|
|
44
|
+
/run rev <id> Run only reviewer
|
|
45
|
+
/login Login (OAuth)
|
|
46
|
+
/logout Logout and clear credentials
|
|
47
|
+
/models [cli] List available models
|
|
48
|
+
/tasks List all tasks
|
|
49
|
+
/clear Clear screen
|
|
50
|
+
/exit Exit
|
|
51
|
+
|
|
52
|
+
Examples:
|
|
53
|
+
agent-mp Start interactive REPL
|
|
54
|
+
agent-mp --continue Resume last session in this directory
|
|
55
|
+
agent-mp --resume Pick a saved session from a list
|
|
56
|
+
agent-mp --resume 2026-04-07_14-30-00 Resume a specific session
|
|
57
|
+
agent-mp --rol orchestrator "build login system"
|
|
58
|
+
agent-mp setup orch Change the orchestrator CLI/model
|
|
59
|
+
`);
|
|
60
|
+
// ── Role-specific binary detection ───────────────────────────────────────────
|
|
61
|
+
const ROLE_BINS = {
|
|
62
|
+
'agent-orch': 'orchestrator',
|
|
63
|
+
'agent-impl': 'implementor',
|
|
64
|
+
'agent-rev': 'reviewer',
|
|
65
|
+
'agent-explorer': 'explorer',
|
|
66
|
+
};
|
|
67
|
+
const binName = path.basename(process.argv[1]).replace(/\.(js|ts|mjs)$/, '');
|
|
68
|
+
const nativeRole = ROLE_BINS[binName];
|
|
69
|
+
if (nativeRole) {
|
|
70
|
+
// Role-specific CLI: accept task as positional arg or prompt for it
|
|
71
|
+
const taskArg = process.argv.slice(2).filter(a => !a.startsWith('-')).join(' ').trim();
|
|
72
|
+
if (!taskArg) {
|
|
73
|
+
console.error(chalk.red(` Usage: ${binName} "<task description or task-id>"`));
|
|
74
|
+
process.exit(1);
|
|
75
|
+
}
|
|
76
|
+
await runRole(nativeRole, taskArg);
|
|
77
|
+
process.exit(0);
|
|
78
|
+
}
|
|
79
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
80
|
+
program.action(async (task, options) => {
|
|
81
|
+
if (options.resetCoordinator || options.resetAuth) {
|
|
82
|
+
const authFile = path.join(AGENT_HOME, 'auth.json');
|
|
83
|
+
const qwenCreds = path.join(AGENT_HOME, 'oauth_creds.json');
|
|
84
|
+
try {
|
|
85
|
+
if (options.resetCoordinator) {
|
|
86
|
+
await fs.unlink(authFile).catch(() => { });
|
|
87
|
+
await fs.unlink(qwenCreds).catch(() => { });
|
|
88
|
+
console.log('✓ Coordinator reset. Run agent-mp to select a coordinator.');
|
|
89
|
+
}
|
|
90
|
+
if (options.resetAuth) {
|
|
91
|
+
await fs.rm(AGENT_HOME, { recursive: true, force: true });
|
|
92
|
+
await fs.rm(path.join(os.homedir(), '.qwen-agent'), { recursive: true, force: true }).catch(() => { });
|
|
93
|
+
console.log('✓ All authentication data cleared. Run agent-mp to start fresh.');
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
catch (err) {
|
|
97
|
+
console.error('Error resetting:', err.message);
|
|
98
|
+
process.exit(1);
|
|
99
|
+
}
|
|
100
|
+
process.exit(0);
|
|
101
|
+
}
|
|
102
|
+
// --continue: resume last session for current dir
|
|
103
|
+
if (options.continue) {
|
|
104
|
+
const session = await getLastSessionForDir(process.cwd());
|
|
105
|
+
if (!session) {
|
|
106
|
+
console.log(chalk.yellow(' No previous session found for this directory. Starting fresh.'));
|
|
107
|
+
runRepl();
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
const date = new Date(session.updatedAt).toLocaleString();
|
|
111
|
+
console.log(chalk.dim(` Resuming last session: ${session.id} (${date}, ${session.messages.length} messages)`));
|
|
112
|
+
runRepl(session);
|
|
113
|
+
}
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
// --resume [id]: pick or load a specific session
|
|
117
|
+
if (options.resume !== undefined) {
|
|
118
|
+
const id = typeof options.resume === 'string' ? options.resume : '';
|
|
119
|
+
if (id) {
|
|
120
|
+
const session = await loadSession(id);
|
|
121
|
+
if (!session) {
|
|
122
|
+
console.log(chalk.red(` Session not found: ${id}`));
|
|
123
|
+
process.exit(1);
|
|
124
|
+
}
|
|
125
|
+
runRepl(session);
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
// Show picker
|
|
129
|
+
const sessions = await listSessions();
|
|
130
|
+
if (sessions.length === 0) {
|
|
131
|
+
console.log(chalk.yellow(' No sessions saved yet. Starting fresh.'));
|
|
132
|
+
runRepl();
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
console.log(chalk.bold.cyan('\n Saved Sessions\n'));
|
|
136
|
+
sessions.slice(0, 20).forEach((s, i) => {
|
|
137
|
+
const date = new Date(s.updatedAt).toLocaleString();
|
|
138
|
+
const msgs = s.messages.length;
|
|
139
|
+
const dir = s.dir.replace(os.homedir(), '~');
|
|
140
|
+
console.log(chalk.dim(` ${String(i + 1).padStart(2)}. [${date}] ${dir} — ${msgs} messages (${s.id})`));
|
|
141
|
+
});
|
|
142
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
143
|
+
const answer = await new Promise((resolve) => rl.question(chalk.bold('\n Pick session #: '), resolve));
|
|
144
|
+
rl.close();
|
|
145
|
+
const num = parseInt(answer.trim());
|
|
146
|
+
if (isNaN(num) || num < 1 || num > sessions.length) {
|
|
147
|
+
console.log(chalk.red(' Invalid selection. Starting fresh.'));
|
|
148
|
+
runRepl();
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
const chosen = sessions[num - 1];
|
|
152
|
+
console.log(chalk.dim(` Resuming: ${chosen.id}`));
|
|
153
|
+
runRepl(chosen);
|
|
154
|
+
}
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
// --rol flag: run specific role directly
|
|
158
|
+
if (options.rol) {
|
|
159
|
+
if (!task || task.length === 0) {
|
|
160
|
+
console.error('Error: --rol requires an argument (task description or task ID)');
|
|
161
|
+
process.exit(1);
|
|
162
|
+
}
|
|
163
|
+
const arg = task.join(' ');
|
|
164
|
+
await runRole(options.rol, arg);
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
// Default: start fresh REPL
|
|
168
|
+
runRepl();
|
|
169
|
+
});
|
|
170
|
+
setupCommand(program);
|
|
171
|
+
program.parse();
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import OpenAI from 'openai';
|
|
2
|
+
import { Anthropic } from '@anthropic-ai/sdk';
|
|
3
|
+
import { GoogleGenerativeAI } from '@google/generative-ai';
|
|
4
|
+
import { loadAuth } from '../commands/auth.js';
|
|
5
|
+
function detectProvider(model) {
|
|
6
|
+
const m = model.toLowerCase();
|
|
7
|
+
if (m.startsWith('gpt') || m.startsWith('o1') || m.startsWith('o3') || m.startsWith('o4'))
|
|
8
|
+
return 'openai';
|
|
9
|
+
if (m.startsWith('claude'))
|
|
10
|
+
return 'anthropic';
|
|
11
|
+
if (m.startsWith('gemini'))
|
|
12
|
+
return 'google';
|
|
13
|
+
if (m.includes('/'))
|
|
14
|
+
return 'opencode';
|
|
15
|
+
return 'openai';
|
|
16
|
+
}
|
|
17
|
+
async function getAuthToken(provider) {
|
|
18
|
+
// 1. Check env vars
|
|
19
|
+
const envKey = process.env[`${provider.toUpperCase()}_API_KEY`];
|
|
20
|
+
if (envKey)
|
|
21
|
+
return envKey;
|
|
22
|
+
// 2. Check OAuth auth store
|
|
23
|
+
try {
|
|
24
|
+
const auth = await loadAuth();
|
|
25
|
+
const entry = auth.entries.find((e) => e.provider === provider) ||
|
|
26
|
+
auth.entries.find((e) => e.provider === auth.activeProvider);
|
|
27
|
+
if (entry?.accessToken)
|
|
28
|
+
return entry.accessToken;
|
|
29
|
+
if (entry?.apiKey)
|
|
30
|
+
return entry.apiKey;
|
|
31
|
+
}
|
|
32
|
+
catch { }
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
async function buildClient(role) {
|
|
36
|
+
const provider = role.provider || detectProvider(role.model);
|
|
37
|
+
const token = await getAuthToken(provider);
|
|
38
|
+
switch (provider) {
|
|
39
|
+
case 'openai':
|
|
40
|
+
return { type: 'openai', client: new OpenAI({ apiKey: token }) };
|
|
41
|
+
case 'anthropic':
|
|
42
|
+
return { type: 'anthropic', client: new Anthropic({ apiKey: token }) };
|
|
43
|
+
case 'google':
|
|
44
|
+
return { type: 'google', client: new GoogleGenerativeAI(token || '') };
|
|
45
|
+
case 'opencode': {
|
|
46
|
+
// Opencode uses an OpenAI-compatible API
|
|
47
|
+
const baseURL = process.env.OPENCODE_BASE_URL || 'https://api.opencode.ai/v1';
|
|
48
|
+
return { type: 'opencode', client: new OpenAI({ apiKey: token || '', baseURL }) };
|
|
49
|
+
}
|
|
50
|
+
default:
|
|
51
|
+
throw new Error(`Unknown provider: ${provider}`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
export async function chat(role, systemPrompt, userPrompt) {
|
|
55
|
+
const client = await buildClient(role);
|
|
56
|
+
switch (client.type) {
|
|
57
|
+
case 'openai':
|
|
58
|
+
case 'opencode':
|
|
59
|
+
return chatOpenai(client.client, role.model, systemPrompt, userPrompt);
|
|
60
|
+
case 'anthropic':
|
|
61
|
+
return chatAnthropic(client.client, role.model, systemPrompt, userPrompt);
|
|
62
|
+
case 'google':
|
|
63
|
+
return chatGoogle(client.client, role.model, systemPrompt, userPrompt);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
async function chatOpenai(client, model, system, user) {
|
|
67
|
+
const res = await client.chat.completions.create({
|
|
68
|
+
model,
|
|
69
|
+
messages: [
|
|
70
|
+
{ role: 'system', content: system },
|
|
71
|
+
{ role: 'user', content: user },
|
|
72
|
+
],
|
|
73
|
+
});
|
|
74
|
+
const content = res.choices[0]?.message?.content || '';
|
|
75
|
+
const usage = res.usage;
|
|
76
|
+
return {
|
|
77
|
+
content,
|
|
78
|
+
usage: {
|
|
79
|
+
input_tokens: usage?.prompt_tokens || 0,
|
|
80
|
+
output_tokens: usage?.completion_tokens || 0,
|
|
81
|
+
cache_read_input_tokens: 0,
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
async function chatAnthropic(client, model, system, user) {
|
|
86
|
+
const res = await client.messages.create({
|
|
87
|
+
model,
|
|
88
|
+
system,
|
|
89
|
+
max_tokens: 8192,
|
|
90
|
+
messages: [{ role: 'user', content: user }],
|
|
91
|
+
});
|
|
92
|
+
const content = res.content
|
|
93
|
+
.filter((b) => b.type === 'text')
|
|
94
|
+
.map((b) => b.text)
|
|
95
|
+
.join('\n');
|
|
96
|
+
return {
|
|
97
|
+
content,
|
|
98
|
+
usage: {
|
|
99
|
+
input_tokens: res.usage?.input_tokens || 0,
|
|
100
|
+
output_tokens: res.usage?.output_tokens || 0,
|
|
101
|
+
cache_read_input_tokens: res.usage?.cache_read_input_tokens || 0,
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
async function chatGoogle(client, model, system, user) {
|
|
106
|
+
const genModel = client.getGenerativeModel({ model });
|
|
107
|
+
const result = await genModel.generateContent({
|
|
108
|
+
contents: [{ role: 'user', parts: [{ text: `${system}\n\n---\n\n${user}` }] }],
|
|
109
|
+
});
|
|
110
|
+
const text = result.response.text();
|
|
111
|
+
const usageMetadata = result.response.usageMetadata;
|
|
112
|
+
return {
|
|
113
|
+
content: text,
|
|
114
|
+
usage: {
|
|
115
|
+
input_tokens: usageMetadata?.promptTokenCount || 0,
|
|
116
|
+
output_tokens: usageMetadata?.candidatesTokenCount || 0,
|
|
117
|
+
cache_read_input_tokens: 0,
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
export interface CliRole {
|
|
2
|
+
cli: string;
|
|
3
|
+
model: string;
|
|
4
|
+
cmd: string;
|
|
5
|
+
fallback?: CliRole;
|
|
6
|
+
}
|
|
7
|
+
export interface AgentConfig {
|
|
8
|
+
project: string;
|
|
9
|
+
description: string;
|
|
10
|
+
stack: string;
|
|
11
|
+
roles: {
|
|
12
|
+
orchestrator: CliRole;
|
|
13
|
+
implementor: CliRole;
|
|
14
|
+
reviewer: CliRole;
|
|
15
|
+
explorer?: CliRole;
|
|
16
|
+
};
|
|
17
|
+
deliberation?: {
|
|
18
|
+
proposer: CliRole;
|
|
19
|
+
critic: CliRole;
|
|
20
|
+
max_rounds: number;
|
|
21
|
+
stop_on: string;
|
|
22
|
+
output_dir: string;
|
|
23
|
+
};
|
|
24
|
+
fallback_global?: CliRole;
|
|
25
|
+
structure: {
|
|
26
|
+
approved_dirs: string[];
|
|
27
|
+
forbidden_dirs: string[];
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
export interface TaskPlan {
|
|
31
|
+
task_id: string;
|
|
32
|
+
description: string;
|
|
33
|
+
steps: TaskStep[];
|
|
34
|
+
acceptance_criteria: string[];
|
|
35
|
+
deliberation: {
|
|
36
|
+
needed: boolean;
|
|
37
|
+
question: string;
|
|
38
|
+
resolved?: boolean;
|
|
39
|
+
rounds?: number;
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
export interface TaskStep {
|
|
43
|
+
num: number;
|
|
44
|
+
description: string;
|
|
45
|
+
files: string[];
|
|
46
|
+
status: 'pending' | 'completed' | 'failed';
|
|
47
|
+
completed_at?: string;
|
|
48
|
+
}
|
|
49
|
+
export interface TaskProgress {
|
|
50
|
+
task_id: string;
|
|
51
|
+
created_at: string;
|
|
52
|
+
steps: TaskStep[];
|
|
53
|
+
status: string;
|
|
54
|
+
validation?: {
|
|
55
|
+
status: 'PASS' | 'FAIL';
|
|
56
|
+
reviewed_at: string;
|
|
57
|
+
reviewer: string;
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
export interface TokenUsage {
|
|
61
|
+
input_tokens: number;
|
|
62
|
+
output_tokens: number;
|
|
63
|
+
cache_read_input_tokens: number;
|
|
64
|
+
}
|
|
65
|
+
export interface CliInfo {
|
|
66
|
+
name: string;
|
|
67
|
+
command: string;
|
|
68
|
+
modelFlag: string;
|
|
69
|
+
extraFlags: string;
|
|
70
|
+
promptFlag: string;
|
|
71
|
+
promptPosition: 'flag' | 'arg';
|
|
72
|
+
}
|
|
73
|
+
export declare const CLI_REGISTRY: Record<string, CliInfo>;
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
export const CLI_REGISTRY = {
|
|
2
|
+
claude: {
|
|
3
|
+
name: 'Claude',
|
|
4
|
+
command: 'claude',
|
|
5
|
+
modelFlag: '--model',
|
|
6
|
+
extraFlags: '--dangerously-skip-permissions --output-format json',
|
|
7
|
+
promptFlag: '-p',
|
|
8
|
+
promptPosition: 'flag',
|
|
9
|
+
},
|
|
10
|
+
qwen: {
|
|
11
|
+
name: 'Qwen',
|
|
12
|
+
command: 'qwen',
|
|
13
|
+
modelFlag: '-m',
|
|
14
|
+
extraFlags: '-y -o json',
|
|
15
|
+
promptFlag: '-p',
|
|
16
|
+
promptPosition: 'flag',
|
|
17
|
+
},
|
|
18
|
+
gemini: {
|
|
19
|
+
name: 'Gemini',
|
|
20
|
+
command: 'gemini',
|
|
21
|
+
modelFlag: '-m',
|
|
22
|
+
extraFlags: '-y -o json',
|
|
23
|
+
promptFlag: '-p',
|
|
24
|
+
promptPosition: 'flag',
|
|
25
|
+
},
|
|
26
|
+
codex: {
|
|
27
|
+
name: 'Codex',
|
|
28
|
+
command: 'codex',
|
|
29
|
+
modelFlag: '-m',
|
|
30
|
+
extraFlags: 'exec',
|
|
31
|
+
promptFlag: '',
|
|
32
|
+
promptPosition: 'arg',
|
|
33
|
+
},
|
|
34
|
+
cn: {
|
|
35
|
+
name: 'CN',
|
|
36
|
+
command: 'cn',
|
|
37
|
+
modelFlag: '--model',
|
|
38
|
+
extraFlags: '--auto',
|
|
39
|
+
promptFlag: '-p',
|
|
40
|
+
promptPosition: 'flag',
|
|
41
|
+
},
|
|
42
|
+
opencode: {
|
|
43
|
+
name: 'Opencode',
|
|
44
|
+
command: 'opencode',
|
|
45
|
+
modelFlag: '-m',
|
|
46
|
+
extraFlags: '',
|
|
47
|
+
promptFlag: '',
|
|
48
|
+
promptPosition: 'arg',
|
|
49
|
+
},
|
|
50
|
+
aider: {
|
|
51
|
+
name: 'Aider',
|
|
52
|
+
command: 'aider',
|
|
53
|
+
modelFlag: '--model',
|
|
54
|
+
extraFlags: '--yes',
|
|
55
|
+
promptFlag: '-p',
|
|
56
|
+
promptPosition: 'flag',
|
|
57
|
+
},
|
|
58
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export declare class FixedInput {
|
|
2
|
+
private buf;
|
|
3
|
+
private history;
|
|
4
|
+
private histIdx;
|
|
5
|
+
private origLog;
|
|
6
|
+
private get rows();
|
|
7
|
+
get cols(): number;
|
|
8
|
+
private get scrollBottom();
|
|
9
|
+
private _contentRows;
|
|
10
|
+
setup(): void;
|
|
11
|
+
teardown(): void;
|
|
12
|
+
redrawBox(): void;
|
|
13
|
+
suspend(): () => void;
|
|
14
|
+
readLine(): Promise<string>;
|
|
15
|
+
println(text: string): void;
|
|
16
|
+
printSeparator(): void;
|
|
17
|
+
/** Set DECSTBM once — only called in setup() and on resize, never during typing. */
|
|
18
|
+
private _setScrollRegion;
|
|
19
|
+
/** Blank every row in the reserved area. */
|
|
20
|
+
private _clearReserved;
|
|
21
|
+
private _drawBox;
|
|
22
|
+
/** Split text into visual lines: split on \n, then wrap each segment. */
|
|
23
|
+
private _wrapText;
|
|
24
|
+
}
|