@autonsh/cli 0.16.5 → 0.17.2
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/chat.d.ts +3 -0
- package/dist/chat.js +350 -0
- package/dist/chat.js.map +1 -0
- package/dist/config.d.ts +25 -0
- package/dist/config.js +104 -0
- package/dist/config.js.map +1 -0
- package/dist/index.js +579 -106
- package/dist/index.js.map +1 -1
- package/dist/login.d.ts +4 -11
- package/dist/login.js +47 -40
- package/dist/login.js.map +1 -1
- package/dist/model.d.ts +24 -0
- package/dist/model.js +195 -0
- package/dist/model.js.map +1 -0
- package/dist/picker.d.ts +8 -0
- package/dist/picker.js +52 -0
- package/dist/picker.js.map +1 -0
- package/dist/prompts.d.ts +8 -1
- package/dist/prompts.js +51 -1
- package/dist/prompts.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -15,7 +15,11 @@ import { SingleBar, Presets } from "cli-progress";
|
|
|
15
15
|
import pc from "picocolors";
|
|
16
16
|
import { ok, fail, info, dim, bold, url, spinner, logo, tagLine, statusColor, table, box, isTTY, } from "./ui.js";
|
|
17
17
|
import { cmdLogin as loginCmd, cmdLogout as logoutCmd, credentialEnv } from "./login.js";
|
|
18
|
-
import {
|
|
18
|
+
import { cmdModel, modelLs, modelSet, modelTest } from "./model.js";
|
|
19
|
+
import { cmdChat } from "./chat.js";
|
|
20
|
+
import { resolveAgent } from "./picker.js";
|
|
21
|
+
import { getDefaultModel, getActiveProvider } from "./config.js";
|
|
22
|
+
import { TEMPLATES, promptInit, promptConfirmUndeploy, promptGateApproval, promptGateQuestion, parseGateLine, } from "./prompts.js";
|
|
19
23
|
import { loadTaskManifest, MODES, SKILLS, EXIT, ExitError, } from "./task.js";
|
|
20
24
|
import { runVerify } from "./verify.js";
|
|
21
25
|
const SRC = dirname(fileURLToPath(import.meta.url));
|
|
@@ -45,8 +49,8 @@ function ensureRuntimeLink(dir) {
|
|
|
45
49
|
* TTY: barra de progresso com fases do npm. Pipe: silencioso, 1 linha. */
|
|
46
50
|
async function installRuntime(dir) {
|
|
47
51
|
const run = (onLine) => new Promise((resolveP, reject) => {
|
|
48
|
-
const
|
|
49
|
-
const child = spawn("npm",
|
|
52
|
+
const realArgs = ["install", "@autonsh/runtime", "--no-audit", "--no-fund", "--loglevel=info"];
|
|
53
|
+
const child = spawn("npm", realArgs, {
|
|
50
54
|
cwd: dir,
|
|
51
55
|
stdio: ["ignore", "ignore", "pipe"],
|
|
52
56
|
shell: process.platform === "win32",
|
|
@@ -157,10 +161,79 @@ async function cmdInit(name, template, opts = {}) {
|
|
|
157
161
|
if (isTTY)
|
|
158
162
|
console.log(logo());
|
|
159
163
|
console.log(ok(`${plain} (template: ${template}) em ${dim(dir)}`));
|
|
160
|
-
console.log(info(`próximo: ${bold(`
|
|
164
|
+
console.log(info(`próximo: ${bold(`cd ${plain} && auton run "<objetivo>"`)}`));
|
|
161
165
|
}
|
|
162
166
|
const VERSION = JSON.parse(readFileSync(resolve(SRC, "../package.json"), "utf8")).version;
|
|
163
167
|
const API = process.env.AUTON_API ?? "http://localhost:8080";
|
|
168
|
+
let cpStarted = false;
|
|
169
|
+
/** G3: auto-start control plane se não estiver rodando (single-command UX). */
|
|
170
|
+
async function ensureCPRunning() {
|
|
171
|
+
if (cpStarted)
|
|
172
|
+
return;
|
|
173
|
+
try {
|
|
174
|
+
const res = await fetch(`${API}/v1/agents`, {
|
|
175
|
+
method: "GET",
|
|
176
|
+
headers: authHeaders(),
|
|
177
|
+
signal: AbortSignal.timeout(1000),
|
|
178
|
+
});
|
|
179
|
+
if (res.ok) {
|
|
180
|
+
cpStarted = true;
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
catch {
|
|
185
|
+
// CP não responde — tenta iniciar
|
|
186
|
+
}
|
|
187
|
+
// Tenta achar binário do control-plane
|
|
188
|
+
const candidates = [
|
|
189
|
+
// monorepo dev
|
|
190
|
+
resolve(SRC, "../../control-plane/bin/control-plane"),
|
|
191
|
+
// npm install global (se publicado)
|
|
192
|
+
resolve(process.execPath, "../../lib/node_modules/@autonsh/server/bin/control-plane"),
|
|
193
|
+
// fallback PATH
|
|
194
|
+
"control-plane",
|
|
195
|
+
];
|
|
196
|
+
let cpBin = null;
|
|
197
|
+
for (const c of candidates) {
|
|
198
|
+
try {
|
|
199
|
+
await import("node:fs/promises").then((fs) => fs.access(c, fs.constants.X_OK));
|
|
200
|
+
cpBin = c;
|
|
201
|
+
break;
|
|
202
|
+
}
|
|
203
|
+
catch {
|
|
204
|
+
// não existe ou não executável
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
if (!cpBin) {
|
|
208
|
+
console.log(dim("aviso: control-plane não encontrado — assumindo externo"));
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
console.log(info(`iniciando control-plane (${cpBin})...`));
|
|
212
|
+
const child = spawn(cpBin, {
|
|
213
|
+
detached: true,
|
|
214
|
+
stdio: ["ignore", "ignore", "ignore"],
|
|
215
|
+
});
|
|
216
|
+
child.unref();
|
|
217
|
+
// Aguarda CP subir (max 5s)
|
|
218
|
+
for (let i = 0; i < 50; i++) {
|
|
219
|
+
await new Promise((r) => setTimeout(r, 100));
|
|
220
|
+
try {
|
|
221
|
+
const res = await fetch(`${API}/v1/agents`, {
|
|
222
|
+
headers: authHeaders(),
|
|
223
|
+
signal: AbortSignal.timeout(500),
|
|
224
|
+
});
|
|
225
|
+
if (res.ok) {
|
|
226
|
+
cpStarted = true;
|
|
227
|
+
console.log(ok("control-plane iniciado"));
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
catch {
|
|
232
|
+
// ainda subindo
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
console.log(dim("aviso: control-plane pode não ter subido a tempo"));
|
|
236
|
+
}
|
|
164
237
|
function authHeaders(extra) {
|
|
165
238
|
const h = { ...extra };
|
|
166
239
|
const token = process.env.AUTON_TOKEN;
|
|
@@ -168,37 +241,74 @@ function authHeaders(extra) {
|
|
|
168
241
|
h.Authorization = `Bearer ${token}`;
|
|
169
242
|
return h;
|
|
170
243
|
}
|
|
244
|
+
/** Nomes dos agentes deployados (0.17.0 — `auton <nome>` abre sessão). */
|
|
245
|
+
async function listAgentNames() {
|
|
246
|
+
try {
|
|
247
|
+
const res = await fetch(`${API}/v1/agents`, { headers: authHeaders() });
|
|
248
|
+
if (!res.ok)
|
|
249
|
+
return [];
|
|
250
|
+
return (await res.json()).map((a) => a.name);
|
|
251
|
+
}
|
|
252
|
+
catch {
|
|
253
|
+
return [];
|
|
254
|
+
}
|
|
255
|
+
}
|
|
171
256
|
const USAGE = `
|
|
172
257
|
auton — Tasks that start themselves
|
|
173
258
|
|
|
174
259
|
Usage:
|
|
175
|
-
auton
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
auton
|
|
181
|
-
auton
|
|
182
|
-
auton
|
|
183
|
-
auton
|
|
184
|
-
|
|
185
|
-
auton
|
|
260
|
+
auton <comando> [argumentos]
|
|
261
|
+
|
|
262
|
+
Modelos:
|
|
263
|
+
auton model Seletor interativo do modelo default
|
|
264
|
+
(local ollama + providers configurados)
|
|
265
|
+
auton model ls [--json] Lista modelos locais + providers
|
|
266
|
+
auton model set <spec> Define default (ex: ollama:qwen3)
|
|
267
|
+
auton model test Testa latência dos providers
|
|
268
|
+
auton login [provider] [--apikey X]
|
|
269
|
+
Conecta provider (gemini/groq/ollama)
|
|
270
|
+
auton logout [id] Remove provider configurado
|
|
271
|
+
|
|
272
|
+
Agentes:
|
|
273
|
+
auton [nome] Sessão de trabalho (estilo opencode): dá
|
|
274
|
+
tasks, acompanha o agente ao vivo, gates
|
|
275
|
+
inline. Sem nome: cwd/picker.
|
|
276
|
+
auton chat [name] Alias da sessão de trabalho
|
|
277
|
+
auton agent [dir] Deploy do agente no diretório
|
|
278
|
+
auton ps Lista agentes + status
|
|
279
|
+
auton logs [name] [--tail N] [--follow] [--since X] [--turn N]
|
|
280
|
+
Stream de logs do agente (SSE)
|
|
281
|
+
auton status [name] Status do agente
|
|
282
|
+
auton restart [name] Reinicia o agente
|
|
186
283
|
auton invoke [name] [--stream] [-- prompt]
|
|
187
|
-
|
|
188
|
-
auton kv get|set|ls [name] [key] [value]
|
|
189
|
-
Inspeciona o storage KV
|
|
190
|
-
auton context [name] Lista work context: decisions/findings/artifacts
|
|
284
|
+
Roda 1 turno (legado v0)
|
|
191
285
|
auton approve|reject [name] [-- razão]
|
|
192
|
-
|
|
193
|
-
auton
|
|
194
|
-
auton
|
|
286
|
+
Decide o gate de aprovação
|
|
287
|
+
auton answer [name] [-- texto] Responde pergunta pendente (ctx.ask)
|
|
288
|
+
auton context [name] Work context: decisions/findings/artifacts
|
|
289
|
+
auton undeploy [name] Remove o agente (--all remove tudo)
|
|
290
|
+
|
|
291
|
+
Tasks:
|
|
292
|
+
auton run [goal] [--model X] [--skip-verify] [--async]
|
|
293
|
+
Roda a task do diretório atual (--async = fire-and-forget)
|
|
294
|
+
auton wait <task-id> Aguarda task async terminar (poll logs)
|
|
295
|
+
auton result <task-id> Busca resultado final de task async
|
|
296
|
+
auton verify [dir] [--json] Roda gates mecânicos do verify
|
|
297
|
+
auton inspect [dir] [--json] Inspeciona task + evidência
|
|
298
|
+
auton continue [name] [goal] Retoma a última task (sem redeploy)
|
|
299
|
+
auton init [nome] [template] Scaffold de task (support|with-approval|...)
|
|
300
|
+
|
|
301
|
+
Infra:
|
|
302
|
+
auton kv get|set|ls [name] [key] [value]
|
|
303
|
+
Inspeciona o storage KV
|
|
304
|
+
auton env set|get|ls [name] [key] [value]
|
|
305
|
+
Env vars por agente
|
|
195
306
|
|
|
196
307
|
Options:
|
|
197
308
|
--help, -h Mostra ajuda
|
|
198
|
-
--version, -v Mostra versão
|
|
309
|
+
--version, -v Mostra versão + modelo default
|
|
199
310
|
AUTON_API=http://... Base do control plane (default localhost:8080)
|
|
200
|
-
|
|
201
|
-
Nota: commandos legado v0 (deploy agent . / deploy invoke) continuam funcionando.
|
|
311
|
+
--no-auto-cp Desliga auto-start do control plane
|
|
202
312
|
|
|
203
313
|
Exit codes (0.14):
|
|
204
314
|
0 ok · 1 erro genérico · 2 uso inválido · 3 verificação falhou
|
|
@@ -414,24 +524,190 @@ async function cmdRun(dir, goalArg, skipVerify, model) {
|
|
|
414
524
|
const manifest = await loadTaskManifest(dir);
|
|
415
525
|
if (!skipVerify)
|
|
416
526
|
await verifyPreFlight(dir, manifest);
|
|
417
|
-
|
|
527
|
+
let goal = goalArg ?? manifest.goal;
|
|
418
528
|
if (!goal) {
|
|
419
|
-
|
|
529
|
+
if (isTTY) {
|
|
530
|
+
// 0.17: run sem goal pergunta (estilo `ollama run` sem modelo)
|
|
531
|
+
const { text, isCancel } = await import("@clack/prompts");
|
|
532
|
+
const answered = (await text({
|
|
533
|
+
message: `qual o objetivo da task ${manifest.name}?`,
|
|
534
|
+
validate: (v) => (!v || v.trim() === "" ? "objetivo não pode ser vazio" : undefined),
|
|
535
|
+
}));
|
|
536
|
+
if (isCancel(answered)) {
|
|
537
|
+
console.log(dim("cancelado"));
|
|
538
|
+
return;
|
|
539
|
+
}
|
|
540
|
+
goal = answered.trim();
|
|
541
|
+
}
|
|
542
|
+
else {
|
|
543
|
+
throw new Error(`task ${manifest.name} sem objetivo — passe "${bold('auton run "<objetivo>"')}" ou defina 'goal' no task.yaml`);
|
|
544
|
+
}
|
|
420
545
|
}
|
|
421
|
-
// 0.
|
|
422
|
-
|
|
546
|
+
// 0.17: modelo efetivo = --model > task.yaml > env > config default (auton model)
|
|
547
|
+
const defaultModel = getDefaultModel();
|
|
548
|
+
await precheckModel(model ?? manifest.models ?? process.env.AUTON_MODEL ?? defaultModel);
|
|
423
549
|
// 0.15.1: credencial do `auton login` injetada no deploy (key/base);
|
|
424
550
|
// --model (0.14.3) sobrescreve models: do task.yaml
|
|
425
551
|
await cmdDeploy(dir, { ...credentialEnv(), ...(model ? { AUTON_MODEL: model } : {}) });
|
|
426
552
|
const lines = await runWithGates(manifest.name, goal);
|
|
427
553
|
await printTaskDone(manifest.name, goal, lines);
|
|
428
554
|
}
|
|
555
|
+
/** G2: auton run --async — dispara task e retorna task-id imediatamente. */
|
|
556
|
+
async function cmdRunAsync(dir, goalArg, skipVerify, model) {
|
|
557
|
+
const manifest = await loadTaskManifest(dir);
|
|
558
|
+
if (!skipVerify)
|
|
559
|
+
await verifyPreFlight(dir, manifest);
|
|
560
|
+
let goal = goalArg ?? manifest.goal;
|
|
561
|
+
if (!goal) {
|
|
562
|
+
throw new Error(`task ${manifest.name} sem objetivo — passe "auton run \"<objetivo>\" --async" ou defina 'goal' no task.yaml`);
|
|
563
|
+
}
|
|
564
|
+
const defaultModel = getDefaultModel();
|
|
565
|
+
await precheckModel(model ?? manifest.models ?? process.env.AUTON_MODEL ?? defaultModel);
|
|
566
|
+
await cmdDeploy(dir, { ...credentialEnv(), ...(model ? { AUTON_MODEL: model } : {}) });
|
|
567
|
+
// Gera task-id único: agent-name + timestamp + random
|
|
568
|
+
const taskId = `${manifest.name}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
569
|
+
// Dispara invoke sem aguardar (fire-and-forget)
|
|
570
|
+
const body = { prompt: goal };
|
|
571
|
+
const res = await fetch(`${API}/v1/agents/${manifest.name}/invoke`, {
|
|
572
|
+
method: "POST",
|
|
573
|
+
headers: authHeaders({ "Content-Type": "application/json" }),
|
|
574
|
+
body: JSON.stringify(body),
|
|
575
|
+
});
|
|
576
|
+
if (!res.ok) {
|
|
577
|
+
throw new Error(`control plane ${res.status}: ${await res.text()}`);
|
|
578
|
+
}
|
|
579
|
+
// Salva mapping task-id -> agent name para wait/result
|
|
580
|
+
const taskMapKey = `task-map:${taskId}`;
|
|
581
|
+
await fetch(`${API}/v1/agents/${manifest.name}/kv/${taskMapKey}`, {
|
|
582
|
+
method: "PUT",
|
|
583
|
+
headers: authHeaders({ "Content-Type": "application/json" }),
|
|
584
|
+
body: JSON.stringify({ agent: manifest.name, goal, startedAt: new Date().toISOString() }),
|
|
585
|
+
});
|
|
586
|
+
console.log(ok(`task iniciada (async): ${bold(taskId)}`));
|
|
587
|
+
console.log(info(` agente: ${manifest.name}`));
|
|
588
|
+
console.log(info(` objetivo: ${goal}`));
|
|
589
|
+
console.log(info(` acompanhe: ${bold(`auton wait ${taskId}`)} | resultado: ${bold(`auton result ${taskId}`)}`));
|
|
590
|
+
}
|
|
591
|
+
/** G2: auton wait <task-id> — aguarda task terminar (poll logs até TASK:DONE/ERR). */
|
|
592
|
+
async function cmdWait(taskId) {
|
|
593
|
+
if (!taskId)
|
|
594
|
+
throw new ExitError(EXIT.USAGE, "uso: auton wait <task-id>");
|
|
595
|
+
// Busca agent name do task-id via KV de qualquer agente (precisa listar agentes)
|
|
596
|
+
const agentsRes = await fetch(`${API}/v1/agents`, { headers: authHeaders() });
|
|
597
|
+
if (!agentsRes.ok)
|
|
598
|
+
throw new Error(`control plane ${agentsRes.status}: ${await agentsRes.text()}`);
|
|
599
|
+
const agents = (await agentsRes.json());
|
|
600
|
+
let agentName;
|
|
601
|
+
let taskInfo;
|
|
602
|
+
for (const a of agents) {
|
|
603
|
+
const taskMapKey = `task-map:${taskId}`;
|
|
604
|
+
const res = await fetch(`${API}/v1/agents/${a.name}/kv/${taskMapKey}`, { headers: authHeaders() });
|
|
605
|
+
if (res.ok) {
|
|
606
|
+
taskInfo = (await res.json());
|
|
607
|
+
agentName = taskInfo.agent;
|
|
608
|
+
break;
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
if (!agentName || !taskInfo) {
|
|
612
|
+
throw new Error(`task-id ${taskId} não encontrado`);
|
|
613
|
+
}
|
|
614
|
+
console.log(info(`aguardando task ${bold(taskId)} (agente: ${agentName})...`));
|
|
615
|
+
const deadline = Date.now() + 30 * 60 * 1000; // 30 min max
|
|
616
|
+
let lastLineCount = 0;
|
|
617
|
+
while (Date.now() < deadline) {
|
|
618
|
+
await new Promise((r) => setTimeout(r, 2000));
|
|
619
|
+
const res = await fetch(`${API}/v1/agents/${agentName}/logs?tail=50`, {
|
|
620
|
+
headers: authHeaders({ Accept: "application/json" }),
|
|
621
|
+
});
|
|
622
|
+
if (!res.ok)
|
|
623
|
+
continue;
|
|
624
|
+
const entries = (await res.json());
|
|
625
|
+
const lines = entries.map((e) => e.line);
|
|
626
|
+
// Verifica se terminou
|
|
627
|
+
const doneLine = lines.find((l) => l.startsWith("[TASK:DONE]"));
|
|
628
|
+
const errLine = lines.find((l) => l.startsWith("[TASK:ERR]"));
|
|
629
|
+
if (doneLine || errLine) {
|
|
630
|
+
console.log(ok(`task ${bold(taskId)} concluída`));
|
|
631
|
+
if (doneLine) {
|
|
632
|
+
const ev = JSON.parse(doneLine.slice("[TASK:DONE]".length).trim());
|
|
633
|
+
if (ev.result)
|
|
634
|
+
console.log(dim(`resultado: ${ev.result}`));
|
|
635
|
+
}
|
|
636
|
+
else {
|
|
637
|
+
console.log(fail(`task falhou: ${errLine.slice("[TASK:ERR]".length).trim()}`));
|
|
638
|
+
process.exitCode = EXIT.ERR;
|
|
639
|
+
}
|
|
640
|
+
return;
|
|
641
|
+
}
|
|
642
|
+
// Progress: mostra novas linhas se houver
|
|
643
|
+
if (lines.length > lastLineCount) {
|
|
644
|
+
for (let i = lastLineCount; i < lines.length; i++) {
|
|
645
|
+
const line = lines[i];
|
|
646
|
+
if (line)
|
|
647
|
+
console.log(tagLine(line));
|
|
648
|
+
}
|
|
649
|
+
lastLineCount = lines.length;
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
console.log(info(`timeout aguardando task — veja ${bold(`auton logs ${agentName}`)} ou ${bold(`auton result ${taskId}`)}`));
|
|
653
|
+
process.exitCode = EXIT.TIMEOUT;
|
|
654
|
+
}
|
|
655
|
+
/** G2: auton result <task-id> — busca resultado final da task (sem aguardar). */
|
|
656
|
+
async function cmdResult(taskId) {
|
|
657
|
+
if (!taskId)
|
|
658
|
+
throw new ExitError(EXIT.USAGE, "uso: auton result <task-id>");
|
|
659
|
+
const agentsRes = await fetch(`${API}/v1/agents`, { headers: authHeaders() });
|
|
660
|
+
if (!agentsRes.ok)
|
|
661
|
+
throw new Error(`control plane ${agentsRes.status}: ${await agentsRes.text()}`);
|
|
662
|
+
const agents = (await agentsRes.json());
|
|
663
|
+
let agentName;
|
|
664
|
+
for (const a of agents) {
|
|
665
|
+
const taskMapKey = `task-map:${taskId}`;
|
|
666
|
+
const res = await fetch(`${API}/v1/agents/${a.name}/kv/${taskMapKey}`, { headers: authHeaders() });
|
|
667
|
+
if (res.ok) {
|
|
668
|
+
const info = (await res.json());
|
|
669
|
+
agentName = info.agent;
|
|
670
|
+
break;
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
if (!agentName) {
|
|
674
|
+
throw new Error(`task-id ${taskId} não encontrado`);
|
|
675
|
+
}
|
|
676
|
+
// Busca última evidência TASK:DONE nos logs
|
|
677
|
+
const res = await fetch(`${API}/v1/agents/${agentName}/logs?tail=100`, {
|
|
678
|
+
headers: authHeaders({ Accept: "application/json" }),
|
|
679
|
+
});
|
|
680
|
+
if (!res.ok)
|
|
681
|
+
throw new Error(`control plane ${res.status}: ${await res.text()}`);
|
|
682
|
+
const entries = (await res.json());
|
|
683
|
+
const lines = entries.map((e) => e.line);
|
|
684
|
+
const doneLine = [...lines].reverse().find((l) => l.startsWith("[TASK:DONE]"));
|
|
685
|
+
const errLine = [...lines].reverse().find((l) => l.startsWith("[TASK:ERR]"));
|
|
686
|
+
if (doneLine) {
|
|
687
|
+
const ev = JSON.parse(doneLine.slice("[TASK:DONE]".length).trim());
|
|
688
|
+
console.log(ok(`task ${bold(taskId)} concluída`));
|
|
689
|
+
console.log(`resultado: ${ev.result ?? "?"}`);
|
|
690
|
+
if (ev.evidence)
|
|
691
|
+
console.log(dim(`evidência: ${JSON.stringify(ev.evidence)}`));
|
|
692
|
+
return;
|
|
693
|
+
}
|
|
694
|
+
if (errLine) {
|
|
695
|
+
console.log(fail(`task ${bold(taskId)} falhou`));
|
|
696
|
+
console.log(`erro: ${errLine.slice("[TASK:ERR]".length).trim()}`);
|
|
697
|
+
process.exitCode = EXIT.ERR;
|
|
698
|
+
return;
|
|
699
|
+
}
|
|
700
|
+
console.log(info(`task ${bold(taskId)} ainda em andamento — use ${bold(`auton wait ${taskId}`)} para aguardar`));
|
|
701
|
+
}
|
|
429
702
|
/** 0.16.13 — valida modelo no provider antes do turno (ollama /api/tags; openai-compat /models).
|
|
430
703
|
* Falha dura só quando o provider respondeu e o modelo não existe; endpoint fora → aviso. */
|
|
431
704
|
async function precheckModel(model) {
|
|
432
705
|
if (!model)
|
|
433
706
|
return;
|
|
434
|
-
|
|
707
|
+
// 0.17.1 — separa provider do nome SEM cortar a tag (ollama:deepseek-coder:1.3b)
|
|
708
|
+
const sep = model.indexOf(":");
|
|
709
|
+
const provider = sep === -1 ? model : model.slice(0, sep);
|
|
710
|
+
const name = sep === -1 ? undefined : model.slice(sep + 1);
|
|
435
711
|
if (!name)
|
|
436
712
|
return;
|
|
437
713
|
if (provider === "ollama") {
|
|
@@ -462,30 +738,37 @@ async function precheckModel(model) {
|
|
|
462
738
|
return;
|
|
463
739
|
}
|
|
464
740
|
}
|
|
465
|
-
/** Roda o turno resolvendo gates pendentes em linha (TTY pergunta; pipe reporta).
|
|
741
|
+
/** Roda o turno resolvendo gates pendentes em linha (TTY pergunta; pipe reporta).
|
|
742
|
+
* 0.17.0: além de aprovação, resolve perguntas de clarificação (ctx.ask). */
|
|
466
743
|
async function runWithGates(name, goal) {
|
|
467
744
|
let lines = await cmdInvoke(name, goal, false);
|
|
468
745
|
for (let i = 0; i < 10; i++) {
|
|
469
|
-
const gate = lines.find((l) => l.startsWith("[APPROVAL:REQ]"));
|
|
746
|
+
const gate = lines.find((l) => l.startsWith("[APPROVAL:REQ]") || l.startsWith("[QUESTION:REQ]"));
|
|
470
747
|
if (!gate)
|
|
471
748
|
return lines;
|
|
749
|
+
const g = parseGateLine(gate);
|
|
750
|
+
if (!g)
|
|
751
|
+
return lines;
|
|
752
|
+
if (g.kind === "question") {
|
|
753
|
+
if (!isTTY) {
|
|
754
|
+
console.log(info("pergunta pendente — rode `auton answer <nome> -- \"resposta\"`"));
|
|
755
|
+
return lines;
|
|
756
|
+
}
|
|
757
|
+
const answer = await promptGateQuestion(String(g.payload?.question ?? "pergunta"));
|
|
758
|
+
if (answer === undefined)
|
|
759
|
+
return lines;
|
|
760
|
+
lines = await answerPost(name, answer);
|
|
761
|
+
continue;
|
|
762
|
+
}
|
|
472
763
|
if (!isTTY) {
|
|
473
764
|
console.log(info("aprovação pendente — rode `auton approve` ou `auton reject`"));
|
|
474
765
|
return lines;
|
|
475
766
|
}
|
|
476
|
-
|
|
477
|
-
try {
|
|
478
|
-
payload = gate.slice("[APPROVAL:REQ]".length).trim();
|
|
479
|
-
JSON.parse(payload);
|
|
480
|
-
}
|
|
481
|
-
catch {
|
|
482
|
-
payload = "{}";
|
|
483
|
-
}
|
|
484
|
-
const reason = JSON.parse(payload).reason ?? "ação";
|
|
767
|
+
const reason = g.payload?.reason ?? "ação";
|
|
485
768
|
const approved = await promptGateApproval(reason);
|
|
486
769
|
lines = await cmdInvokeApproval(name, approved, undefined);
|
|
487
770
|
}
|
|
488
|
-
throw new Error(`loop de
|
|
771
|
+
throw new Error(`loop de gates não convergiu (10)`);
|
|
489
772
|
}
|
|
490
773
|
/** POST de controle: resolve o gate pendente no worker (sem novo trigger). */
|
|
491
774
|
async function cmdInvokeApproval(name, approved, reason) {
|
|
@@ -506,6 +789,62 @@ async function cmdInvokeApproval(name, approved, reason) {
|
|
|
506
789
|
console.log(line);
|
|
507
790
|
return out.lines;
|
|
508
791
|
}
|
|
792
|
+
/** 0.17.0 — POST de controle de pergunta: resolve ctx.ask no worker (sem trigger novo). */
|
|
793
|
+
async function answerPost(name, answer) {
|
|
794
|
+
const res = await fetch(`${API}/v1/agents/${name}/invoke`, {
|
|
795
|
+
method: "POST",
|
|
796
|
+
headers: authHeaders({ "Content-Type": "application/json" }),
|
|
797
|
+
body: JSON.stringify({ question: { answer } }),
|
|
798
|
+
});
|
|
799
|
+
if (!res.ok) {
|
|
800
|
+
const body = await res.text();
|
|
801
|
+
if (res.status === 409 && body.includes("sem pergunta pendente")) {
|
|
802
|
+
throw new Error(`task ${name} sem pergunta pendente`);
|
|
803
|
+
}
|
|
804
|
+
throw new Error(`control plane ${res.status}: ${body}`);
|
|
805
|
+
}
|
|
806
|
+
const out = (await res.json());
|
|
807
|
+
return out.lines;
|
|
808
|
+
}
|
|
809
|
+
/** auton answer [name] [-- texto] — responde pergunta de clarificação pendente. */
|
|
810
|
+
async function cmdAnswer(name, answer) {
|
|
811
|
+
const agent = await resolveAgent("answer", name);
|
|
812
|
+
if (answer === undefined) {
|
|
813
|
+
if (!isTTY) {
|
|
814
|
+
throw new ExitError(EXIT.USAGE, `uso: auton answer <nome> -- "resposta" (pipe)`);
|
|
815
|
+
}
|
|
816
|
+
// mostra a pergunta pendente (logs recentes) e pede a resposta
|
|
817
|
+
let question = "pergunta pendente — responda:";
|
|
818
|
+
const logs = await fetch(`${API}/v1/agents/${agent}/logs?tail=30`, {
|
|
819
|
+
headers: authHeaders({ Accept: "application/json" }),
|
|
820
|
+
});
|
|
821
|
+
if (logs.ok) {
|
|
822
|
+
const entries = (await logs.json());
|
|
823
|
+
const qline = [...entries].reverse().find((e) => e.line.startsWith("[QUESTION:REQ]"));
|
|
824
|
+
if (qline) {
|
|
825
|
+
const g = parseGateLine(qline.line);
|
|
826
|
+
if (g)
|
|
827
|
+
question = String(g.payload?.question ?? question);
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
answer = await promptGateQuestion(question);
|
|
831
|
+
if (answer === undefined) {
|
|
832
|
+
console.log(dim("cancelado — agente segue pausado"));
|
|
833
|
+
return;
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
const lines = await answerPost(agent, answer);
|
|
837
|
+
console.log(ok(`resposta entregue — task ${bold(agent)} segue.`));
|
|
838
|
+
const done = lines.find((l) => l.startsWith("[TASK:DONE]"));
|
|
839
|
+
if (done) {
|
|
840
|
+
const ev = JSON.parse(done.slice("[TASK:DONE]".length).trim());
|
|
841
|
+
if (ev.result)
|
|
842
|
+
console.log(dim(`resultado: ${ev.result}`));
|
|
843
|
+
}
|
|
844
|
+
else if (lines.some((l) => l.startsWith("[QUESTION:REQ]"))) {
|
|
845
|
+
console.log(info("nova pergunta pendente — `auton answer` de novo."));
|
|
846
|
+
}
|
|
847
|
+
}
|
|
509
848
|
/** auton continue — retoma a última task sem re-passar o objetivo.
|
|
510
849
|
* O harness guarda o último input no KV ("ultima-task"); aqui só busca e
|
|
511
850
|
* invoca de novo (worker dormindo → cold start; KV persiste). */
|
|
@@ -531,15 +870,7 @@ async function cmdContinue(dir, nameArg, goalArg) {
|
|
|
531
870
|
* 0.12: vira POST de CONTROLE (resolve gate pendente no worker vivo);
|
|
532
871
|
* gate de legado (template com approval:) também é resolvido assim. */
|
|
533
872
|
async function cmdApproval(name, approved, reason) {
|
|
534
|
-
|
|
535
|
-
if (!agent) {
|
|
536
|
-
try {
|
|
537
|
-
agent = (await loadTaskManifest(process.cwd())).name;
|
|
538
|
-
}
|
|
539
|
-
catch {
|
|
540
|
-
throw new Error(`${approved ? "approve" : "reject"}: nenhum nome passado e cwd não é um agente — rode \`auton ${approved ? "approve" : "reject"} <nome>\``);
|
|
541
|
-
}
|
|
542
|
-
}
|
|
873
|
+
const agent = await resolveAgent(approved ? "approve" : "reject", name);
|
|
543
874
|
const lines = await cmdInvokeApproval(agent, approved, reason);
|
|
544
875
|
const done = lines.find((l) => l.startsWith("[TASK:DONE]"));
|
|
545
876
|
if (done) {
|
|
@@ -562,7 +893,7 @@ async function cmdApproval(name, approved, reason) {
|
|
|
562
893
|
/** 0.16.14: snapshot JSON c/ timestamp + filtro por turno (--turn N = últimos N turnos);
|
|
563
894
|
* --follow mantém SSE ao vivo (sem ts, como antes). */
|
|
564
895
|
async function cmdLogs(name, tail, since, follow = false, turn) {
|
|
565
|
-
const agent = name ?? (await
|
|
896
|
+
const agent = name ?? (await resolveAgent("logs", undefined));
|
|
566
897
|
const params = new URLSearchParams();
|
|
567
898
|
if (tail !== undefined)
|
|
568
899
|
params.set("tail", String(tail));
|
|
@@ -597,6 +928,7 @@ async function cmdLogs(name, tail, since, follow = false, turn) {
|
|
|
597
928
|
}
|
|
598
929
|
if (!res.body)
|
|
599
930
|
throw new Error("resposta sem body");
|
|
931
|
+
console.log(dim(`— seguindo ${agent} — Ctrl+C sai —`));
|
|
600
932
|
const reader = res.body.getReader();
|
|
601
933
|
const decoder = new TextDecoder();
|
|
602
934
|
let buf = "";
|
|
@@ -619,7 +951,7 @@ async function cmdLogs(name, tail, since, follow = false, turn) {
|
|
|
619
951
|
}
|
|
620
952
|
}
|
|
621
953
|
async function cmdStatus(name) {
|
|
622
|
-
const agent =
|
|
954
|
+
const agent = await resolveAgent("status", name);
|
|
623
955
|
const res = await fetch(`${API}/v1/agents/${agent}`, {
|
|
624
956
|
headers: authHeaders(),
|
|
625
957
|
});
|
|
@@ -630,7 +962,7 @@ async function cmdStatus(name) {
|
|
|
630
962
|
}
|
|
631
963
|
async function cmdRestart(name) {
|
|
632
964
|
// 0.1.1 — reinicia o agente (SIGTERM + respawn, state preservado)
|
|
633
|
-
const agent =
|
|
965
|
+
const agent = await resolveAgent("restart", name);
|
|
634
966
|
const res = await fetch(`${API}/v1/agents/${agent}/restart`, {
|
|
635
967
|
method: "POST",
|
|
636
968
|
headers: authHeaders(),
|
|
@@ -661,7 +993,7 @@ async function cmdUndeploy(name) {
|
|
|
661
993
|
console.log(dim("(nada pra remover)"));
|
|
662
994
|
return;
|
|
663
995
|
}
|
|
664
|
-
const agent =
|
|
996
|
+
const agent = await resolveAgent("undeploy", name);
|
|
665
997
|
if (isTTY && !(await promptConfirmUndeploy(agent)))
|
|
666
998
|
return;
|
|
667
999
|
const res = await fetch(`${API}/v1/agents/${agent}`, {
|
|
@@ -819,7 +1151,7 @@ async function cmdInvoke(name, prompt, stream) {
|
|
|
819
1151
|
/** autonomous context [name] — imprime a memória do trabalho da task:
|
|
820
1152
|
* decisions/findings/artifacts gravadas via ctx.work (KV "work:*"). */
|
|
821
1153
|
async function cmdContext(name) {
|
|
822
|
-
const agent =
|
|
1154
|
+
const agent = await resolveAgent("context", name);
|
|
823
1155
|
const res = await fetch(`${API}/v1/agents/${agent}/kv`, { headers: authHeaders() });
|
|
824
1156
|
if (!res.ok)
|
|
825
1157
|
throw new Error(`control plane ${res.status}: ${await res.text()}`);
|
|
@@ -916,8 +1248,9 @@ async function cmdPs(json) {
|
|
|
916
1248
|
a.cron ? "sim" : "-",
|
|
917
1249
|
String(a.logs),
|
|
918
1250
|
String(a.kv),
|
|
1251
|
+
a.model ? String(a.model) : "-",
|
|
919
1252
|
]);
|
|
920
|
-
console.log(table(["AGENTE", "STATUS", "CRON", "LOGS", "KV"], rows));
|
|
1253
|
+
console.log(table(["AGENTE", "STATUS", "CRON", "LOGS", "KV", "MODEL"], rows));
|
|
921
1254
|
}
|
|
922
1255
|
async function cmdKv(op, name, key, value) {
|
|
923
1256
|
const agent = name ?? (await loadTaskManifest(process.cwd())).name;
|
|
@@ -958,40 +1291,101 @@ async function cmdKv(op, name, key, value) {
|
|
|
958
1291
|
throw new Error(`control plane ${res.status}: ${await res.text()}`);
|
|
959
1292
|
console.log(ok(`${key} = ${bold(value)}`));
|
|
960
1293
|
}
|
|
961
|
-
async function cmdLogin(
|
|
1294
|
+
async function cmdLogin(realArgs) {
|
|
962
1295
|
// 0.15.1 — auton login [provider] [--apikey X] / auton logout
|
|
963
|
-
const keyIdx =
|
|
964
|
-
const apiKey = keyIdx !== -1 ?
|
|
965
|
-
const provider =
|
|
966
|
-
.filter((a, i) => a !== "--apikey" &&
|
|
1296
|
+
const keyIdx = realArgs.indexOf("--apikey");
|
|
1297
|
+
const apiKey = keyIdx !== -1 ? realArgs[keyIdx + 1] : undefined;
|
|
1298
|
+
const provider = realArgs
|
|
1299
|
+
.filter((a, i) => a !== "--apikey" && realArgs[i - 1] !== "--apikey" && !a.startsWith("-"))
|
|
967
1300
|
.find(() => true);
|
|
968
1301
|
await loginCmd(provider, apiKey);
|
|
969
1302
|
}
|
|
970
|
-
async function cmdLogout() {
|
|
971
|
-
await logoutCmd();
|
|
1303
|
+
async function cmdLogout(providerId) {
|
|
1304
|
+
await logoutCmd(providerId);
|
|
972
1305
|
}
|
|
973
1306
|
async function main() {
|
|
974
|
-
|
|
975
|
-
|
|
1307
|
+
let realArgs = process.argv.slice(2);
|
|
1308
|
+
// G3: auto-start CP para comandos que precisam dele (--no-auto-cp desliga)
|
|
1309
|
+
const noAutoCP = realArgs.includes("--no-auto-cp");
|
|
1310
|
+
const noCP = new Set(["login", "logout", "model", "--help", "-h", "--version", "-v", "init"]);
|
|
1311
|
+
const cmd = realArgs[0];
|
|
1312
|
+
if (!noAutoCP && cmd && !noCP.has(cmd)) {
|
|
1313
|
+
await ensureCPRunning();
|
|
1314
|
+
}
|
|
1315
|
+
// Remove --no-auto-cp dos realArgs antes do switch
|
|
1316
|
+
realArgs = realArgs.filter((a) => a !== "--no-auto-cp");
|
|
1317
|
+
if (realArgs.length === 0) {
|
|
1318
|
+
// 0.17.0 — `auton` bare: abre sessão de trabalho (estilo opencode):
|
|
1319
|
+
// cwd é agente → sessão nele; senão picker. Pipe: mosta ajuda.
|
|
1320
|
+
if (isTTY) {
|
|
1321
|
+
await cmdChat(undefined);
|
|
1322
|
+
return;
|
|
1323
|
+
}
|
|
1324
|
+
console.log(USAGE);
|
|
1325
|
+
return;
|
|
1326
|
+
}
|
|
1327
|
+
if (realArgs[0] === "--help" || realArgs[0] === "-h") {
|
|
976
1328
|
console.log(USAGE);
|
|
977
1329
|
return;
|
|
978
1330
|
}
|
|
979
|
-
if (
|
|
1331
|
+
if (realArgs[0] === "--version" || realArgs[0] === "-v") {
|
|
980
1332
|
if (isTTY)
|
|
981
1333
|
console.log(logo());
|
|
982
1334
|
console.log(bold(`auton v${VERSION}`));
|
|
1335
|
+
const d = getDefaultModel();
|
|
1336
|
+
const active = getActiveProvider();
|
|
1337
|
+
if (d)
|
|
1338
|
+
console.log(dim(` modelo default: ${d}`));
|
|
1339
|
+
if (active)
|
|
1340
|
+
console.log(dim(` provider: ${active.id} (${active.quando.slice(0, 10)})`));
|
|
983
1341
|
return;
|
|
984
1342
|
}
|
|
985
|
-
|
|
1343
|
+
// 0.17.0 — `auton <nome-de-agente-deployado>` abre sessão (comandos têm prioridade).
|
|
1344
|
+
const KNOWN = new Set([
|
|
1345
|
+
"login", "logout", "model", "agent", "logs", "status", "restart", "run",
|
|
1346
|
+
"verify", "inspect", "continue", "invoke", "undeploy", "approve", "reject",
|
|
1347
|
+
"ps", "context", "env", "init", "kv", "chat", "answer", "wait", "result",
|
|
1348
|
+
]);
|
|
1349
|
+
if (!KNOWN.has(realArgs[0]) && isTTY) {
|
|
1350
|
+
const deployed = await listAgentNames();
|
|
1351
|
+
if (deployed.includes(realArgs[0])) {
|
|
1352
|
+
await cmdChat(realArgs[0]);
|
|
1353
|
+
return;
|
|
1354
|
+
}
|
|
1355
|
+
}
|
|
1356
|
+
switch (realArgs[0]) {
|
|
986
1357
|
case "login":
|
|
987
|
-
await cmdLogin(
|
|
1358
|
+
await cmdLogin(realArgs.slice(1));
|
|
988
1359
|
break;
|
|
989
1360
|
case "logout":
|
|
990
|
-
await cmdLogout();
|
|
1361
|
+
await cmdLogout(realArgs[1]);
|
|
1362
|
+
break;
|
|
1363
|
+
case "model": {
|
|
1364
|
+
// auton model [ls|set <spec>|test] — sem sub: seletor TTY
|
|
1365
|
+
const sub = realArgs[1];
|
|
1366
|
+
const json = realArgs.includes("--json");
|
|
1367
|
+
if (sub === "ls") {
|
|
1368
|
+
await modelLs(json);
|
|
1369
|
+
}
|
|
1370
|
+
else if (sub === "set") {
|
|
1371
|
+
if (!realArgs[2])
|
|
1372
|
+
throw new ExitError(EXIT.USAGE, "uso: auton model set <provider:modelo>");
|
|
1373
|
+
await modelSet(realArgs[2]);
|
|
1374
|
+
}
|
|
1375
|
+
else if (sub === "test") {
|
|
1376
|
+
await modelTest();
|
|
1377
|
+
}
|
|
1378
|
+
else if (sub === undefined || sub === "select") {
|
|
1379
|
+
await cmdModel();
|
|
1380
|
+
}
|
|
1381
|
+
else {
|
|
1382
|
+
throw new ExitError(EXIT.USAGE, `uso: auton model [ls|set <spec>|test] — subcomando desconhecido: ${sub}`);
|
|
1383
|
+
}
|
|
991
1384
|
break;
|
|
1385
|
+
}
|
|
992
1386
|
case "agent":
|
|
993
|
-
if (
|
|
994
|
-
const dir = resolve(
|
|
1387
|
+
if (realArgs[1]) {
|
|
1388
|
+
const dir = resolve(realArgs[1]);
|
|
995
1389
|
ensureRuntimeLink(dir);
|
|
996
1390
|
await cmdDeploy(dir);
|
|
997
1391
|
}
|
|
@@ -1001,8 +1395,8 @@ async function main() {
|
|
|
1001
1395
|
}
|
|
1002
1396
|
break;
|
|
1003
1397
|
case "logs":
|
|
1004
|
-
//
|
|
1005
|
-
const rest =
|
|
1398
|
+
// realArgs[1..]: [name] [--tail N] [--since RFC3339] [--follow] [--turn N]
|
|
1399
|
+
const rest = realArgs.slice(1);
|
|
1006
1400
|
const tailIdx = rest.indexOf("--tail");
|
|
1007
1401
|
const sinceIdx = rest.indexOf("--since");
|
|
1008
1402
|
let name;
|
|
@@ -1034,34 +1428,90 @@ async function main() {
|
|
|
1034
1428
|
await cmdLogs(name, tail, since, follow, turn);
|
|
1035
1429
|
break;
|
|
1036
1430
|
case "status":
|
|
1037
|
-
await cmdStatus(
|
|
1431
|
+
await cmdStatus(realArgs[1]);
|
|
1038
1432
|
break;
|
|
1039
1433
|
case "restart":
|
|
1040
|
-
await cmdRestart(
|
|
1434
|
+
await cmdRestart(realArgs[1]);
|
|
1041
1435
|
break;
|
|
1042
1436
|
case "run": {
|
|
1043
|
-
// auton run "<goal>" [--skip-verify] [--model X] (ou auton run
|
|
1044
|
-
const skipVerify =
|
|
1045
|
-
const
|
|
1046
|
-
const
|
|
1047
|
-
const
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1437
|
+
// auton run "<goal>" [--skip-verify] [--model X] [--async] [--dir DIR] [-d DIR] (ou auton run <agent-name> "goal")
|
|
1438
|
+
const skipVerify = realArgs.includes("--skip-verify");
|
|
1439
|
+
const isAsync = realArgs.includes("--async");
|
|
1440
|
+
const modelIdx = realArgs.indexOf("--model");
|
|
1441
|
+
const model = modelIdx !== -1 ? realArgs[modelIdx + 1] : undefined;
|
|
1442
|
+
// --dir / -d
|
|
1443
|
+
const dirIdx = realArgs.indexOf("--dir");
|
|
1444
|
+
const dirShortIdx = realArgs.indexOf("-d");
|
|
1445
|
+
const explicitDir = (dirIdx !== -1 ? realArgs[dirIdx + 1] : undefined) ??
|
|
1446
|
+
(dirShortIdx !== -1 ? realArgs[dirShortIdx + 1] : undefined);
|
|
1447
|
+
// resolve dir: --dir > agent name via CP > cwd
|
|
1448
|
+
let targetDir = explicitDir ? resolve(explicitDir) : process.cwd();
|
|
1449
|
+
let usedAgentName = false;
|
|
1450
|
+
let agentNameSliceIdx = -1; // index in realArgs.slice(1) of the agent name
|
|
1451
|
+
if (!explicitDir) {
|
|
1452
|
+
// Find first positional arg (not a flag) after "run"
|
|
1453
|
+
let firstPosArg;
|
|
1454
|
+
let firstPosArgIdx = -1;
|
|
1455
|
+
for (let i = 1; i < realArgs.length; i++) {
|
|
1456
|
+
const arg = realArgs[i];
|
|
1457
|
+
if (arg && !arg.startsWith("-")) {
|
|
1458
|
+
firstPosArg = arg;
|
|
1459
|
+
firstPosArgIdx = i;
|
|
1460
|
+
break;
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1463
|
+
if (firstPosArg) {
|
|
1464
|
+
const knownCmds = new Set([
|
|
1465
|
+
"login", "logout", "model", "agent", "logs", "status", "restart", "run",
|
|
1466
|
+
"verify", "inspect", "continue", "invoke", "undeploy", "approve", "reject",
|
|
1467
|
+
"ps", "context", "env", "init", "kv", "chat", "answer", "wait", "result",
|
|
1468
|
+
]);
|
|
1469
|
+
if (!knownCmds.has(firstPosArg)) {
|
|
1470
|
+
try {
|
|
1471
|
+
const agent = await resolveAgent("run", firstPosArg);
|
|
1472
|
+
const statusRes = await fetch(`${API}/v1/agents/${agent}`, { headers: authHeaders() });
|
|
1473
|
+
if (statusRes.ok) {
|
|
1474
|
+
const status = (await statusRes.json());
|
|
1475
|
+
if (status.dir) {
|
|
1476
|
+
targetDir = resolve(status.dir);
|
|
1477
|
+
usedAgentName = true;
|
|
1478
|
+
agentNameSliceIdx = firstPosArgIdx - 1; // index in realArgs.slice(1)
|
|
1479
|
+
}
|
|
1480
|
+
}
|
|
1481
|
+
}
|
|
1482
|
+
catch { /* ignora, usa cwd */ }
|
|
1483
|
+
}
|
|
1484
|
+
}
|
|
1485
|
+
}
|
|
1486
|
+
// build goal: exclude flags + agent name if used for resolution
|
|
1487
|
+
const goal = realArgs.slice(1).filter((a, i) => {
|
|
1488
|
+
const origIdx = i + 1; // index in realArgs
|
|
1489
|
+
if (a === "--skip-verify" || a === "--model" || realArgs[origIdx - 1] === "--model" ||
|
|
1490
|
+
a === "--async" || a === "--dir" || a === "-d" ||
|
|
1491
|
+
realArgs[origIdx - 1] === "--dir" || realArgs[origIdx - 1] === "-d")
|
|
1492
|
+
return false;
|
|
1493
|
+
if (usedAgentName && i === agentNameSliceIdx)
|
|
1494
|
+
return false; // exclude agent name from goal
|
|
1495
|
+
return true;
|
|
1496
|
+
}).join(" ").trim() || undefined;
|
|
1497
|
+
ensureRuntimeLink(targetDir);
|
|
1498
|
+
if (isAsync) {
|
|
1499
|
+
await cmdRunAsync(targetDir, goal, skipVerify, model);
|
|
1500
|
+
}
|
|
1501
|
+
else {
|
|
1502
|
+
await cmdRun(targetDir, goal, skipVerify, model);
|
|
1503
|
+
}
|
|
1054
1504
|
break;
|
|
1055
1505
|
}
|
|
1056
1506
|
case "verify": {
|
|
1057
|
-
const rest =
|
|
1507
|
+
const rest = realArgs.slice(1);
|
|
1058
1508
|
const json = rest.includes("--json");
|
|
1059
1509
|
const dirArg = rest.find((a) => !a.startsWith("-"));
|
|
1060
1510
|
await cmdVerify(resolve(dirArg ?? process.cwd()), json);
|
|
1061
1511
|
break;
|
|
1062
1512
|
}
|
|
1063
1513
|
case "inspect": {
|
|
1064
|
-
const rest =
|
|
1514
|
+
const rest = realArgs.slice(1);
|
|
1065
1515
|
const json = rest.includes("--json");
|
|
1066
1516
|
const dirArg = rest.find((a) => !a.startsWith("-"));
|
|
1067
1517
|
await cmdInspect(resolve(dirArg ?? process.cwd()), json);
|
|
@@ -1069,51 +1519,74 @@ async function main() {
|
|
|
1069
1519
|
}
|
|
1070
1520
|
case "continue": {
|
|
1071
1521
|
// auton continue [name] [goal...]
|
|
1072
|
-
const goal =
|
|
1073
|
-
const nameArg =
|
|
1522
|
+
const goal = realArgs.slice(2).filter((a) => !a.startsWith("-")).join(" ").trim() || undefined;
|
|
1523
|
+
const nameArg = realArgs[1] && !realArgs[1].startsWith("-") ? realArgs[1] : undefined;
|
|
1074
1524
|
ensureRuntimeLink(process.cwd());
|
|
1075
1525
|
await cmdContinue(process.cwd(), nameArg, goal);
|
|
1076
1526
|
break;
|
|
1077
1527
|
}
|
|
1078
1528
|
case "invoke": {
|
|
1079
1529
|
// deploy invoke [name] [-- prompt] [--stream]
|
|
1080
|
-
const rest =
|
|
1530
|
+
const rest = realArgs.slice(2);
|
|
1081
1531
|
const stream = rest.includes("--stream");
|
|
1082
1532
|
const promptIdx = rest.indexOf("--");
|
|
1083
1533
|
const prompt = promptIdx !== -1 ? rest.slice(promptIdx + 1).join(" ") : undefined;
|
|
1084
|
-
await cmdInvoke(
|
|
1534
|
+
await cmdInvoke(realArgs[1], prompt, stream);
|
|
1085
1535
|
break;
|
|
1086
1536
|
}
|
|
1087
1537
|
case "undeploy":
|
|
1088
|
-
await cmdUndeploy(
|
|
1538
|
+
await cmdUndeploy(realArgs[1]);
|
|
1539
|
+
break;
|
|
1540
|
+
case "wait":
|
|
1541
|
+
// auton wait <task-id> [--timeout Ms]
|
|
1542
|
+
if (!realArgs[1])
|
|
1543
|
+
throw new ExitError(EXIT.USAGE, "uso: auton wait <task-id>");
|
|
1544
|
+
await cmdWait(realArgs[1]);
|
|
1545
|
+
break;
|
|
1546
|
+
case "result":
|
|
1547
|
+
// auton result <task-id>
|
|
1548
|
+
if (!realArgs[1])
|
|
1549
|
+
throw new ExitError(EXIT.USAGE, "uso: auton result <task-id>");
|
|
1550
|
+
await cmdResult(realArgs[1]);
|
|
1089
1551
|
break;
|
|
1090
1552
|
case "approve":
|
|
1091
1553
|
case "reject": {
|
|
1092
|
-
const approved =
|
|
1554
|
+
const approved = realArgs[0] === "approve";
|
|
1093
1555
|
// auton approve [name] [-- razão]: -- na posição [1] = sem name
|
|
1094
|
-
const rest =
|
|
1556
|
+
const rest = realArgs.slice(1);
|
|
1095
1557
|
const dash = rest.indexOf("--");
|
|
1096
1558
|
const name = dash === -1 ? rest[0] : dash === 0 ? undefined : rest[0];
|
|
1097
1559
|
const reason = dash !== -1 ? rest.slice(dash + 1).join(" ") : undefined;
|
|
1098
1560
|
await cmdApproval(name, approved, reason);
|
|
1099
1561
|
break;
|
|
1100
1562
|
}
|
|
1563
|
+
case "chat":
|
|
1564
|
+
await cmdChat(realArgs[1]);
|
|
1565
|
+
break;
|
|
1566
|
+
case "answer": {
|
|
1567
|
+
const rest = realArgs.slice(1);
|
|
1568
|
+
const dash = rest.indexOf("--");
|
|
1569
|
+
const name = dash === -1 ? rest[0] : dash === 0 ? undefined : rest[0];
|
|
1570
|
+
const answer = dash !== -1 ? rest.slice(dash + 1).join(" ") : undefined;
|
|
1571
|
+
await cmdAnswer(name, answer);
|
|
1572
|
+
break;
|
|
1573
|
+
}
|
|
1101
1574
|
case "ps":
|
|
1102
|
-
await cmdPs(
|
|
1575
|
+
await cmdPs(realArgs[1] === "--json");
|
|
1103
1576
|
break;
|
|
1104
1577
|
case "context":
|
|
1105
|
-
await cmdContext(
|
|
1578
|
+
await cmdContext(realArgs[1]);
|
|
1106
1579
|
break;
|
|
1107
1580
|
case "env": {
|
|
1108
|
-
const sub =
|
|
1581
|
+
const sub = realArgs[1];
|
|
1109
1582
|
if (sub === "set") {
|
|
1110
|
-
await cmdEnvSet(
|
|
1583
|
+
await cmdEnvSet(realArgs[2], realArgs[3], realArgs[4]);
|
|
1111
1584
|
}
|
|
1112
1585
|
else if (sub === "get") {
|
|
1113
|
-
await cmdEnvGet(
|
|
1586
|
+
await cmdEnvGet(realArgs[2], realArgs[3]);
|
|
1114
1587
|
}
|
|
1115
1588
|
else if (sub === "ls") {
|
|
1116
|
-
await cmdEnvLs(
|
|
1589
|
+
await cmdEnvLs(realArgs[2]);
|
|
1117
1590
|
}
|
|
1118
1591
|
else {
|
|
1119
1592
|
console.log(USAGE);
|
|
@@ -1122,8 +1595,8 @@ async function main() {
|
|
|
1122
1595
|
}
|
|
1123
1596
|
case "init": {
|
|
1124
1597
|
// deploy init [nome] [template] [--mode=X] [--skills=a,b] — sem argumentos (TTY): pergunta interativo
|
|
1125
|
-
const initFlags =
|
|
1126
|
-
const initPos =
|
|
1598
|
+
const initFlags = realArgs.filter((a) => a.startsWith("--"));
|
|
1599
|
+
const initPos = realArgs.filter((a) => !a.startsWith("--"));
|
|
1127
1600
|
const initOpts = {
|
|
1128
1601
|
mode: initFlags.find((f) => f.startsWith("--mode="))?.slice(7),
|
|
1129
1602
|
skills: initFlags
|
|
@@ -1147,10 +1620,10 @@ async function main() {
|
|
|
1147
1620
|
}
|
|
1148
1621
|
case "kv":
|
|
1149
1622
|
// deploy kv get|set|ls <nome> [chave] [valor]
|
|
1150
|
-
await cmdKv(
|
|
1623
|
+
await cmdKv(realArgs[1], realArgs[2], realArgs[3], realArgs[4]);
|
|
1151
1624
|
break;
|
|
1152
1625
|
default: {
|
|
1153
|
-
console.error(fail(`comando desconhecido: ${
|
|
1626
|
+
console.error(fail(`comando desconhecido: ${realArgs[0]}`));
|
|
1154
1627
|
console.error(USAGE);
|
|
1155
1628
|
process.exit(EXIT.USAGE);
|
|
1156
1629
|
}
|