@autonsh/cli 0.17.1 → 0.18.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/config.js +14 -0
- package/dist/config.js.map +1 -1
- package/dist/index.js +607 -124
- package/dist/index.js.map +1 -1
- package/dist/prompts.d.ts +34 -8
- package/dist/prompts.js +186 -8
- package/dist/prompts.js.map +1 -1
- package/dist/task.d.ts +9 -1
- package/dist/task.js +21 -0
- package/dist/task.js.map +1 -1
- package/dist/template-engine.d.ts +19 -0
- package/dist/template-engine.js +187 -0
- package/dist/template-engine.js.map +1 -0
- package/dist/template-registry.d.ts +36 -0
- package/dist/template-registry.js +294 -0
- package/dist/template-registry.js.map +1 -0
- package/package.json +2 -1
- package/templates/coding/agent.md +39 -0
- package/templates/coding/agent.ts +83 -0
- package/templates/coding/task.yaml +36 -0
- package/templates/harness/agent.md +43 -0
- package/templates/harness/harness.ts +145 -0
- package/templates/harness/task.yaml +15 -0
- package/templates/research/task.yaml +32 -0
package/dist/index.js
CHANGED
|
@@ -19,7 +19,9 @@ import { cmdModel, modelLs, modelSet, modelTest } from "./model.js";
|
|
|
19
19
|
import { cmdChat } from "./chat.js";
|
|
20
20
|
import { resolveAgent } from "./picker.js";
|
|
21
21
|
import { getDefaultModel, getActiveProvider } from "./config.js";
|
|
22
|
-
import {
|
|
22
|
+
import { promptInit, promptConfirmUndeploy, promptGateApproval, promptGateQuestion, parseGateLine, listTemplatesForDisplay, } from "./prompts.js";
|
|
23
|
+
import { getTemplateRegistry } from "./template-registry.js";
|
|
24
|
+
import { renderTemplate } from "./template-engine.js";
|
|
23
25
|
import { loadTaskManifest, MODES, SKILLS, EXIT, ExitError, } from "./task.js";
|
|
24
26
|
import { runVerify } from "./verify.js";
|
|
25
27
|
const SRC = dirname(fileURLToPath(import.meta.url));
|
|
@@ -49,8 +51,8 @@ function ensureRuntimeLink(dir) {
|
|
|
49
51
|
* TTY: barra de progresso com fases do npm. Pipe: silencioso, 1 linha. */
|
|
50
52
|
async function installRuntime(dir) {
|
|
51
53
|
const run = (onLine) => new Promise((resolveP, reject) => {
|
|
52
|
-
const
|
|
53
|
-
const child = spawn("npm",
|
|
54
|
+
const realArgs = ["install", "@autonsh/runtime", "--no-audit", "--no-fund", "--loglevel=info"];
|
|
55
|
+
const child = spawn("npm", realArgs, {
|
|
54
56
|
cwd: dir,
|
|
55
57
|
stdio: ["ignore", "ignore", "pipe"],
|
|
56
58
|
shell: process.platform === "win32",
|
|
@@ -109,62 +111,185 @@ async function installRuntime(dir) {
|
|
|
109
111
|
bar.stop();
|
|
110
112
|
}
|
|
111
113
|
}
|
|
112
|
-
async function cmdInit(name,
|
|
114
|
+
async function cmdInit(name, templateId, opts = {}) {
|
|
115
|
+
const registry = await getTemplateRegistry();
|
|
116
|
+
const template = await registry.get(templateId);
|
|
117
|
+
if (!template) {
|
|
118
|
+
throw new ExitError(EXIT.USAGE, `template não encontrado: ${templateId}. Rode 'auton template list' para ver disponíveis.`);
|
|
119
|
+
}
|
|
113
120
|
const plain = name === "." ? basename(process.cwd()) : name;
|
|
114
121
|
const dir = resolve(name === "." ? process.cwd() : join(process.cwd(), name));
|
|
115
122
|
if (existsSync(dir) && readdirSync(dir).length > 0) {
|
|
116
123
|
throw new ExitError(EXIT.USAGE, `diretório não vazio: ${dir}`);
|
|
117
124
|
}
|
|
125
|
+
// Prepara contexto de renderização
|
|
126
|
+
const context = {
|
|
127
|
+
name: plain,
|
|
128
|
+
...opts.variables,
|
|
129
|
+
};
|
|
130
|
+
if (opts.dryRun) {
|
|
131
|
+
console.log(info(`[dry-run] Scaffold seria criado em: ${dir}`));
|
|
132
|
+
console.log(info(`[dry-run] Template: ${template.name} (${template.id})`));
|
|
133
|
+
console.log(info(`[dry-run] Variáveis: ${JSON.stringify(context, null, 2)}`));
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
118
136
|
mkdirSync(dir, { recursive: true });
|
|
119
|
-
|
|
120
|
-
|
|
137
|
+
// Renderiza template via engine (Handlebars)
|
|
138
|
+
const result = await renderTemplate(template, context, dir);
|
|
139
|
+
// Substitui name no task.yaml (backward compat: templates built-in têm name hardcoded)
|
|
121
140
|
const yamlPath = join(dir, "task.yaml");
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
141
|
+
if (existsSync(yamlPath)) {
|
|
142
|
+
let yaml = await readFile(yamlPath, "utf8");
|
|
143
|
+
yaml = yaml.replace(/^name: .*$/m, `name: ${plain}`);
|
|
144
|
+
await writeFile(yamlPath, yaml);
|
|
145
|
+
}
|
|
146
|
+
// Garante package.json (pode vir do template ou ser gerado)
|
|
147
|
+
const pkgPath = join(dir, "package.json");
|
|
148
|
+
if (!existsSync(pkgPath)) {
|
|
149
|
+
const pkgName = plain.toLowerCase().replace(/[^a-z0-9._-]/g, "-");
|
|
150
|
+
await writeFile(pkgPath, JSON.stringify({
|
|
151
|
+
name: pkgName || "agent",
|
|
152
|
+
version: "0.0.0",
|
|
153
|
+
private: true,
|
|
154
|
+
type: "module",
|
|
155
|
+
dependencies: { "@autonsh/runtime": "^0.11.0" },
|
|
156
|
+
}, null, 2) + "\n");
|
|
157
|
+
}
|
|
158
|
+
// Genesis custom (se fornecido via --genesis ou prompt)
|
|
159
|
+
if (opts.genesis) {
|
|
160
|
+
const yamlPath = join(dir, "task.yaml");
|
|
161
|
+
let yaml = await readFile(yamlPath, "utf8");
|
|
162
|
+
// Substitui ou adiciona bloco genesis
|
|
163
|
+
if (yaml.includes("genesis:")) {
|
|
164
|
+
yaml = yaml.replace(/^genesis:[\s\S]*?(?=\n\S|\n*$)/m, `genesis: |\n ${opts.genesis.replace(/\n/g, "\n ")}\n`);
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
yaml += `\ngenesis: |\n ${opts.genesis.replace(/\n/g, "\n ")}\n`;
|
|
168
|
+
}
|
|
169
|
+
await writeFile(yamlPath, yaml);
|
|
170
|
+
}
|
|
171
|
+
// Mode + skills do template (podem ser sobrescritos por opts)
|
|
125
172
|
const mode = opts.mode && MODES.includes(opts.mode)
|
|
126
173
|
? opts.mode
|
|
127
|
-
:
|
|
174
|
+
: template.defaultMode;
|
|
175
|
+
const skills = (opts.skills ?? template.skills).filter((s) => SKILLS.includes(s));
|
|
176
|
+
// Atualiza task.yaml com mode/skills apenas se override explícito
|
|
177
|
+
if (opts.mode || opts.skills) {
|
|
178
|
+
const yamlPath2 = join(dir, "task.yaml");
|
|
179
|
+
let yaml = await readFile(yamlPath2, "utf8");
|
|
180
|
+
yaml = yaml
|
|
181
|
+
.split("\n")
|
|
182
|
+
.filter((line) => !/^(mode|skills):/m.test(line) && !/^\s*-\s/.test(line))
|
|
183
|
+
.join("\n")
|
|
184
|
+
.trimEnd()
|
|
185
|
+
.concat("\n", `mode: ${mode}`, skills.length > 0
|
|
186
|
+
? `\nskills:\n${skills.map((s) => ` - ${s}`).join("\n")}`
|
|
187
|
+
: "")
|
|
188
|
+
.concat("\n");
|
|
189
|
+
await writeFile(yamlPath2, yaml);
|
|
190
|
+
}
|
|
191
|
+
// Copia agent.md do modo se não existir
|
|
128
192
|
const modeDoc = join(TEMPLATES_SRC, "modes", mode, "agent.md");
|
|
129
|
-
if (existsSync(modeDoc)) {
|
|
193
|
+
if (existsSync(modeDoc) && !existsSync(join(dir, "agent.md"))) {
|
|
130
194
|
cpSync(modeDoc, join(dir, "agent.md"));
|
|
131
195
|
}
|
|
132
|
-
|
|
196
|
+
// Skills built-in
|
|
133
197
|
for (const s of skills) {
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
198
|
+
try {
|
|
199
|
+
cpSync(join(TEMPLATES_SRC, "skills", s, "SKILL.md"), join(dir, "skills", s, "SKILL.md"), {
|
|
200
|
+
recursive: true,
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
catch {
|
|
204
|
+
// skill não existe — ignora
|
|
205
|
+
}
|
|
137
206
|
}
|
|
138
|
-
await writeFile(yamlPath, yaml
|
|
139
|
-
.split("\n")
|
|
140
|
-
.filter((line) => !/^(mode|skills):/m.test(line))
|
|
141
|
-
.join("\n")
|
|
142
|
-
.trimEnd()
|
|
143
|
-
.concat("\n", `mode: ${mode}`, skills.length > 0
|
|
144
|
-
? `\nskills:\n${skills.map((s) => ` - ${s}`).join("\n")}`
|
|
145
|
-
: "")
|
|
146
|
-
.concat("\n"));
|
|
147
|
-
// package.json do projeto (0.0.7): remove o passo manual de criar pacote.
|
|
148
|
-
// `npm install` abaixo salva/adiciona a dep se preciso; aqui o pacote já existe.
|
|
149
|
-
const pkgName = plain.toLowerCase().replace(/[^a-z0-9._-]/g, "-");
|
|
150
|
-
await writeFile(join(dir, "package.json"), JSON.stringify({
|
|
151
|
-
name: pkgName || "agent",
|
|
152
|
-
version: "0.0.0",
|
|
153
|
-
private: true,
|
|
154
|
-
type: "module",
|
|
155
|
-
dependencies: { "@autonsh/runtime": "^0.11.0" },
|
|
156
|
-
}, null, 2) + "\n");
|
|
157
207
|
ensureRuntimeLink(dir);
|
|
158
208
|
if (!HAS_LOCAL_RUNTIME) {
|
|
159
209
|
await installRuntime(dir);
|
|
160
210
|
}
|
|
161
211
|
if (isTTY)
|
|
162
212
|
console.log(logo());
|
|
163
|
-
console.log(ok(`${plain} (template: ${template}) em ${dim(dir)}`));
|
|
164
|
-
console.log(info(`próximo: ${bold(`
|
|
213
|
+
console.log(ok(`${plain} (template: ${template.name}) em ${dim(dir)}`));
|
|
214
|
+
console.log(info(`próximo: ${bold(`cd ${plain} && auton run "<objetivo>"`)}`));
|
|
215
|
+
// Deploy opcional
|
|
216
|
+
if (opts.deploy) {
|
|
217
|
+
console.log(info(`deployando ${bold(plain)}...`));
|
|
218
|
+
await cmdDeploy(dir);
|
|
219
|
+
console.log(ok(`${plain} deployado`));
|
|
220
|
+
}
|
|
165
221
|
}
|
|
166
222
|
const VERSION = JSON.parse(readFileSync(resolve(SRC, "../package.json"), "utf8")).version;
|
|
167
223
|
const API = process.env.AUTON_API ?? "http://localhost:8080";
|
|
224
|
+
let cpStarted = false;
|
|
225
|
+
/** G3: auto-start control plane se não estiver rodando (single-command UX). */
|
|
226
|
+
async function ensureCPRunning() {
|
|
227
|
+
if (cpStarted)
|
|
228
|
+
return;
|
|
229
|
+
try {
|
|
230
|
+
const res = await fetch(`${API}/v1/agents`, {
|
|
231
|
+
method: "GET",
|
|
232
|
+
headers: authHeaders(),
|
|
233
|
+
signal: AbortSignal.timeout(1000),
|
|
234
|
+
});
|
|
235
|
+
if (res.ok) {
|
|
236
|
+
cpStarted = true;
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
catch {
|
|
241
|
+
// CP não responde — tenta iniciar
|
|
242
|
+
}
|
|
243
|
+
// Tenta achar binário do control-plane
|
|
244
|
+
const candidates = [
|
|
245
|
+
// monorepo dev
|
|
246
|
+
resolve(SRC, "../../control-plane/bin/control-plane"),
|
|
247
|
+
// npm install global (se publicado)
|
|
248
|
+
resolve(process.execPath, "../../lib/node_modules/@autonsh/server/bin/control-plane"),
|
|
249
|
+
// fallback PATH
|
|
250
|
+
"control-plane",
|
|
251
|
+
];
|
|
252
|
+
let cpBin = null;
|
|
253
|
+
for (const c of candidates) {
|
|
254
|
+
try {
|
|
255
|
+
await import("node:fs/promises").then((fs) => fs.access(c, fs.constants.X_OK));
|
|
256
|
+
cpBin = c;
|
|
257
|
+
break;
|
|
258
|
+
}
|
|
259
|
+
catch {
|
|
260
|
+
// não existe ou não executável
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
if (!cpBin) {
|
|
264
|
+
console.log(dim("aviso: control-plane não encontrado — assumindo externo"));
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
console.log(info(`iniciando control-plane (${cpBin})...`));
|
|
268
|
+
const child = spawn(cpBin, {
|
|
269
|
+
detached: true,
|
|
270
|
+
stdio: ["ignore", "ignore", "ignore"],
|
|
271
|
+
});
|
|
272
|
+
child.unref();
|
|
273
|
+
// Aguarda CP subir (max 5s)
|
|
274
|
+
for (let i = 0; i < 50; i++) {
|
|
275
|
+
await new Promise((r) => setTimeout(r, 100));
|
|
276
|
+
try {
|
|
277
|
+
const res = await fetch(`${API}/v1/agents`, {
|
|
278
|
+
headers: authHeaders(),
|
|
279
|
+
signal: AbortSignal.timeout(500),
|
|
280
|
+
});
|
|
281
|
+
if (res.ok) {
|
|
282
|
+
cpStarted = true;
|
|
283
|
+
console.log(ok("control-plane iniciado"));
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
catch {
|
|
288
|
+
// ainda subindo
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
console.log(dim("aviso: control-plane pode não ter subido a tempo"));
|
|
292
|
+
}
|
|
168
293
|
function authHeaders(extra) {
|
|
169
294
|
const h = { ...extra };
|
|
170
295
|
const token = process.env.AUTON_TOKEN;
|
|
@@ -192,51 +317,59 @@ Usage:
|
|
|
192
317
|
|
|
193
318
|
Modelos:
|
|
194
319
|
auton model Seletor interativo do modelo default
|
|
195
|
-
|
|
320
|
+
(local ollama + providers configurados)
|
|
196
321
|
auton model ls [--json] Lista modelos locais + providers
|
|
197
322
|
auton model set <spec> Define default (ex: ollama:qwen3)
|
|
198
323
|
auton model test Testa latência dos providers
|
|
199
324
|
auton login [provider] [--apikey X]
|
|
200
|
-
|
|
325
|
+
Conecta provider (gemini/groq/ollama)
|
|
201
326
|
auton logout [id] Remove provider configurado
|
|
202
327
|
|
|
203
328
|
Agentes:
|
|
204
329
|
auton [nome] Sessão de trabalho (estilo opencode): dá
|
|
205
|
-
|
|
206
|
-
|
|
330
|
+
tasks, acompanha o agente ao vivo, gates
|
|
331
|
+
inline. Sem nome: cwd/picker.
|
|
207
332
|
auton chat [name] Alias da sessão de trabalho
|
|
208
333
|
auton agent [dir] Deploy do agente no diretório
|
|
209
334
|
auton ps Lista agentes + status
|
|
210
335
|
auton logs [name] [--tail N] [--follow] [--since X] [--turn N]
|
|
211
|
-
|
|
336
|
+
Stream de logs do agente (SSE)
|
|
212
337
|
auton status [name] Status do agente
|
|
213
338
|
auton restart [name] Reinicia o agente
|
|
214
339
|
auton invoke [name] [--stream] [-- prompt]
|
|
215
|
-
|
|
340
|
+
Roda 1 turno (legado v0)
|
|
216
341
|
auton approve|reject [name] [-- razão]
|
|
217
|
-
|
|
342
|
+
Decide o gate de aprovação
|
|
218
343
|
auton answer [name] [-- texto] Responde pergunta pendente (ctx.ask)
|
|
219
344
|
auton context [name] Work context: decisions/findings/artifacts
|
|
220
345
|
auton undeploy [name] Remove o agente (--all remove tudo)
|
|
221
346
|
|
|
222
347
|
Tasks:
|
|
223
|
-
auton run [goal] [--model X] [--skip-verify]
|
|
224
|
-
|
|
225
|
-
auton
|
|
226
|
-
auton
|
|
227
|
-
auton
|
|
228
|
-
auton
|
|
348
|
+
auton run [goal] [--model X] [--skip-verify] [--async]
|
|
349
|
+
Roda a task do diretório atual (--async = fire-and-forget)
|
|
350
|
+
auton wait <task-id> Aguarda task async terminar (poll logs)
|
|
351
|
+
auton result <task-id> Busca resultado final de task async
|
|
352
|
+
auton verify [dir] [--json] Roda gates mecânicos do verify
|
|
353
|
+
auton inspect [dir] [--json] Inspeciona task + evidência
|
|
354
|
+
auton continue [name] [goal] Retoma a última task (sem redeploy)
|
|
355
|
+
auton init [nome] [template] [--mode=X] [--skills=a,b] [--deploy] [--dry-run] [--genesis] [--var key=value]
|
|
356
|
+
Scaffold de task (templates built-in + custom)
|
|
357
|
+
|
|
358
|
+
Templates:
|
|
359
|
+
auton template list [--json] Lista templates (built-in + custom)
|
|
360
|
+
auton template create <id> Cria template custom (futuro)
|
|
229
361
|
|
|
230
362
|
Infra:
|
|
231
363
|
auton kv get|set|ls [name] [key] [value]
|
|
232
|
-
|
|
364
|
+
Inspeciona o storage KV
|
|
233
365
|
auton env set|get|ls [name] [key] [value]
|
|
234
|
-
|
|
366
|
+
Env vars por agente
|
|
235
367
|
|
|
236
368
|
Options:
|
|
237
369
|
--help, -h Mostra ajuda
|
|
238
370
|
--version, -v Mostra versão + modelo default
|
|
239
371
|
AUTON_API=http://... Base do control plane (default localhost:8080)
|
|
372
|
+
--no-auto-cp Desliga auto-start do control plane
|
|
240
373
|
|
|
241
374
|
Exit codes (0.14):
|
|
242
375
|
0 ok · 1 erro genérico · 2 uso inválido · 3 verificação falhou
|
|
@@ -480,6 +613,153 @@ async function cmdRun(dir, goalArg, skipVerify, model) {
|
|
|
480
613
|
const lines = await runWithGates(manifest.name, goal);
|
|
481
614
|
await printTaskDone(manifest.name, goal, lines);
|
|
482
615
|
}
|
|
616
|
+
/** G2: auton run --async — dispara task e retorna task-id imediatamente. */
|
|
617
|
+
async function cmdRunAsync(dir, goalArg, skipVerify, model) {
|
|
618
|
+
const manifest = await loadTaskManifest(dir);
|
|
619
|
+
if (!skipVerify)
|
|
620
|
+
await verifyPreFlight(dir, manifest);
|
|
621
|
+
let goal = goalArg ?? manifest.goal;
|
|
622
|
+
if (!goal) {
|
|
623
|
+
throw new Error(`task ${manifest.name} sem objetivo — passe "auton run \"<objetivo>\" --async" ou defina 'goal' no task.yaml`);
|
|
624
|
+
}
|
|
625
|
+
const defaultModel = getDefaultModel();
|
|
626
|
+
await precheckModel(model ?? manifest.models ?? process.env.AUTON_MODEL ?? defaultModel);
|
|
627
|
+
await cmdDeploy(dir, { ...credentialEnv(), ...(model ? { AUTON_MODEL: model } : {}) });
|
|
628
|
+
// Gera task-id único: agent-name + timestamp + random
|
|
629
|
+
const taskId = `${manifest.name}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
630
|
+
// Dispara invoke sem aguardar (fire-and-forget)
|
|
631
|
+
const body = { prompt: goal };
|
|
632
|
+
const res = await fetch(`${API}/v1/agents/${manifest.name}/invoke`, {
|
|
633
|
+
method: "POST",
|
|
634
|
+
headers: authHeaders({ "Content-Type": "application/json" }),
|
|
635
|
+
body: JSON.stringify(body),
|
|
636
|
+
});
|
|
637
|
+
if (!res.ok) {
|
|
638
|
+
throw new Error(`control plane ${res.status}: ${await res.text()}`);
|
|
639
|
+
}
|
|
640
|
+
// Salva mapping task-id -> agent name para wait/result
|
|
641
|
+
const taskMapKey = `task-map:${taskId}`;
|
|
642
|
+
await fetch(`${API}/v1/agents/${manifest.name}/kv/${taskMapKey}`, {
|
|
643
|
+
method: "PUT",
|
|
644
|
+
headers: authHeaders({ "Content-Type": "application/json" }),
|
|
645
|
+
body: JSON.stringify({ agent: manifest.name, goal, startedAt: new Date().toISOString() }),
|
|
646
|
+
});
|
|
647
|
+
console.log(ok(`task iniciada (async): ${bold(taskId)}`));
|
|
648
|
+
console.log(info(` agente: ${manifest.name}`));
|
|
649
|
+
console.log(info(` objetivo: ${goal}`));
|
|
650
|
+
console.log(info(` acompanhe: ${bold(`auton wait ${taskId}`)} | resultado: ${bold(`auton result ${taskId}`)}`));
|
|
651
|
+
}
|
|
652
|
+
/** G2: auton wait <task-id> — aguarda task terminar (poll logs até TASK:DONE/ERR). */
|
|
653
|
+
async function cmdWait(taskId) {
|
|
654
|
+
if (!taskId)
|
|
655
|
+
throw new ExitError(EXIT.USAGE, "uso: auton wait <task-id>");
|
|
656
|
+
// Busca agent name do task-id via KV de qualquer agente (precisa listar agentes)
|
|
657
|
+
const agentsRes = await fetch(`${API}/v1/agents`, { headers: authHeaders() });
|
|
658
|
+
if (!agentsRes.ok)
|
|
659
|
+
throw new Error(`control plane ${agentsRes.status}: ${await agentsRes.text()}`);
|
|
660
|
+
const agents = (await agentsRes.json());
|
|
661
|
+
let agentName;
|
|
662
|
+
let taskInfo;
|
|
663
|
+
for (const a of agents) {
|
|
664
|
+
const taskMapKey = `task-map:${taskId}`;
|
|
665
|
+
const res = await fetch(`${API}/v1/agents/${a.name}/kv/${taskMapKey}`, { headers: authHeaders() });
|
|
666
|
+
if (res.ok) {
|
|
667
|
+
taskInfo = (await res.json());
|
|
668
|
+
agentName = taskInfo.agent;
|
|
669
|
+
break;
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
if (!agentName || !taskInfo) {
|
|
673
|
+
throw new Error(`task-id ${taskId} não encontrado`);
|
|
674
|
+
}
|
|
675
|
+
console.log(info(`aguardando task ${bold(taskId)} (agente: ${agentName})...`));
|
|
676
|
+
const deadline = Date.now() + 30 * 60 * 1000; // 30 min max
|
|
677
|
+
let lastLineCount = 0;
|
|
678
|
+
while (Date.now() < deadline) {
|
|
679
|
+
await new Promise((r) => setTimeout(r, 2000));
|
|
680
|
+
const res = await fetch(`${API}/v1/agents/${agentName}/logs?tail=50`, {
|
|
681
|
+
headers: authHeaders({ Accept: "application/json" }),
|
|
682
|
+
});
|
|
683
|
+
if (!res.ok)
|
|
684
|
+
continue;
|
|
685
|
+
const entries = (await res.json());
|
|
686
|
+
const lines = entries.map((e) => e.line);
|
|
687
|
+
// Verifica se terminou
|
|
688
|
+
const doneLine = lines.find((l) => l.startsWith("[TASK:DONE]"));
|
|
689
|
+
const errLine = lines.find((l) => l.startsWith("[TASK:ERR]"));
|
|
690
|
+
if (doneLine || errLine) {
|
|
691
|
+
console.log(ok(`task ${bold(taskId)} concluída`));
|
|
692
|
+
if (doneLine) {
|
|
693
|
+
const ev = JSON.parse(doneLine.slice("[TASK:DONE]".length).trim());
|
|
694
|
+
if (ev.result)
|
|
695
|
+
console.log(dim(`resultado: ${ev.result}`));
|
|
696
|
+
}
|
|
697
|
+
else {
|
|
698
|
+
console.log(fail(`task falhou: ${errLine.slice("[TASK:ERR]".length).trim()}`));
|
|
699
|
+
process.exitCode = EXIT.ERR;
|
|
700
|
+
}
|
|
701
|
+
return;
|
|
702
|
+
}
|
|
703
|
+
// Progress: mostra novas linhas se houver
|
|
704
|
+
if (lines.length > lastLineCount) {
|
|
705
|
+
for (let i = lastLineCount; i < lines.length; i++) {
|
|
706
|
+
const line = lines[i];
|
|
707
|
+
if (line)
|
|
708
|
+
console.log(tagLine(line));
|
|
709
|
+
}
|
|
710
|
+
lastLineCount = lines.length;
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
console.log(info(`timeout aguardando task — veja ${bold(`auton logs ${agentName}`)} ou ${bold(`auton result ${taskId}`)}`));
|
|
714
|
+
process.exitCode = EXIT.TIMEOUT;
|
|
715
|
+
}
|
|
716
|
+
/** G2: auton result <task-id> — busca resultado final da task (sem aguardar). */
|
|
717
|
+
async function cmdResult(taskId) {
|
|
718
|
+
if (!taskId)
|
|
719
|
+
throw new ExitError(EXIT.USAGE, "uso: auton result <task-id>");
|
|
720
|
+
const agentsRes = await fetch(`${API}/v1/agents`, { headers: authHeaders() });
|
|
721
|
+
if (!agentsRes.ok)
|
|
722
|
+
throw new Error(`control plane ${agentsRes.status}: ${await agentsRes.text()}`);
|
|
723
|
+
const agents = (await agentsRes.json());
|
|
724
|
+
let agentName;
|
|
725
|
+
for (const a of agents) {
|
|
726
|
+
const taskMapKey = `task-map:${taskId}`;
|
|
727
|
+
const res = await fetch(`${API}/v1/agents/${a.name}/kv/${taskMapKey}`, { headers: authHeaders() });
|
|
728
|
+
if (res.ok) {
|
|
729
|
+
const info = (await res.json());
|
|
730
|
+
agentName = info.agent;
|
|
731
|
+
break;
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
if (!agentName) {
|
|
735
|
+
throw new Error(`task-id ${taskId} não encontrado`);
|
|
736
|
+
}
|
|
737
|
+
// Busca última evidência TASK:DONE nos logs
|
|
738
|
+
const res = await fetch(`${API}/v1/agents/${agentName}/logs?tail=100`, {
|
|
739
|
+
headers: authHeaders({ Accept: "application/json" }),
|
|
740
|
+
});
|
|
741
|
+
if (!res.ok)
|
|
742
|
+
throw new Error(`control plane ${res.status}: ${await res.text()}`);
|
|
743
|
+
const entries = (await res.json());
|
|
744
|
+
const lines = entries.map((e) => e.line);
|
|
745
|
+
const doneLine = [...lines].reverse().find((l) => l.startsWith("[TASK:DONE]"));
|
|
746
|
+
const errLine = [...lines].reverse().find((l) => l.startsWith("[TASK:ERR]"));
|
|
747
|
+
if (doneLine) {
|
|
748
|
+
const ev = JSON.parse(doneLine.slice("[TASK:DONE]".length).trim());
|
|
749
|
+
console.log(ok(`task ${bold(taskId)} concluída`));
|
|
750
|
+
console.log(`resultado: ${ev.result ?? "?"}`);
|
|
751
|
+
if (ev.evidence)
|
|
752
|
+
console.log(dim(`evidência: ${JSON.stringify(ev.evidence)}`));
|
|
753
|
+
return;
|
|
754
|
+
}
|
|
755
|
+
if (errLine) {
|
|
756
|
+
console.log(fail(`task ${bold(taskId)} falhou`));
|
|
757
|
+
console.log(`erro: ${errLine.slice("[TASK:ERR]".length).trim()}`);
|
|
758
|
+
process.exitCode = EXIT.ERR;
|
|
759
|
+
return;
|
|
760
|
+
}
|
|
761
|
+
console.log(info(`task ${bold(taskId)} ainda em andamento — use ${bold(`auton wait ${taskId}`)} para aguardar`));
|
|
762
|
+
}
|
|
483
763
|
/** 0.16.13 — valida modelo no provider antes do turno (ollama /api/tags; openai-compat /models).
|
|
484
764
|
* Falha dura só quando o provider respondeu e o modelo não existe; endpoint fora → aviso. */
|
|
485
765
|
async function precheckModel(model) {
|
|
@@ -1072,35 +1352,108 @@ async function cmdKv(op, name, key, value) {
|
|
|
1072
1352
|
throw new Error(`control plane ${res.status}: ${await res.text()}`);
|
|
1073
1353
|
console.log(ok(`${key} = ${bold(value)}`));
|
|
1074
1354
|
}
|
|
1075
|
-
async function cmdLogin(
|
|
1355
|
+
async function cmdLogin(realArgs) {
|
|
1076
1356
|
// 0.15.1 — auton login [provider] [--apikey X] / auton logout
|
|
1077
|
-
const keyIdx =
|
|
1078
|
-
const apiKey = keyIdx !== -1 ?
|
|
1079
|
-
const provider =
|
|
1080
|
-
.filter((a, i) => a !== "--apikey" &&
|
|
1357
|
+
const keyIdx = realArgs.indexOf("--apikey");
|
|
1358
|
+
const apiKey = keyIdx !== -1 ? realArgs[keyIdx + 1] : undefined;
|
|
1359
|
+
const provider = realArgs
|
|
1360
|
+
.filter((a, i) => a !== "--apikey" && realArgs[i - 1] !== "--apikey" && !a.startsWith("-"))
|
|
1081
1361
|
.find(() => true);
|
|
1082
1362
|
await loginCmd(provider, apiKey);
|
|
1083
1363
|
}
|
|
1084
1364
|
async function cmdLogout(providerId) {
|
|
1085
1365
|
await logoutCmd(providerId);
|
|
1086
1366
|
}
|
|
1367
|
+
/** Project mode: `auton` bare — se não há agente, cria + deploya + entra no chat. */
|
|
1368
|
+
async function cmdProject() {
|
|
1369
|
+
// 1. Tenta achar agente no cwd (task.yaml)
|
|
1370
|
+
let agentName;
|
|
1371
|
+
try {
|
|
1372
|
+
const { loadTaskManifest } = await import("./task.js");
|
|
1373
|
+
const manifest = await loadTaskManifest(process.cwd());
|
|
1374
|
+
if (manifest?.name)
|
|
1375
|
+
agentName = manifest.name;
|
|
1376
|
+
}
|
|
1377
|
+
catch {
|
|
1378
|
+
// sem task.yaml
|
|
1379
|
+
}
|
|
1380
|
+
// 2. Se não há no cwd, tenta deployed agents
|
|
1381
|
+
if (!agentName) {
|
|
1382
|
+
const deployed = await listAgentNames();
|
|
1383
|
+
if (deployed.length === 1) {
|
|
1384
|
+
agentName = deployed[0];
|
|
1385
|
+
}
|
|
1386
|
+
else if (deployed.length > 1) {
|
|
1387
|
+
// Múltiplos deployados — usa picker (cmdChat já faz isso)
|
|
1388
|
+
await cmdChat(undefined);
|
|
1389
|
+
return;
|
|
1390
|
+
}
|
|
1391
|
+
}
|
|
1392
|
+
// 3. Tem agente (cwd ou único deployado) → entra no chat
|
|
1393
|
+
if (agentName) {
|
|
1394
|
+
console.log(info(`entrando no agente ${bold(agentName)}...`));
|
|
1395
|
+
await cmdChat(agentName);
|
|
1396
|
+
return;
|
|
1397
|
+
}
|
|
1398
|
+
// 4. Nenhum agente — oferece init interativo
|
|
1399
|
+
console.log(box("auton — nenhum agente encontrado", [
|
|
1400
|
+
"Este diretório não tem task.yaml e não há agentes deployados.",
|
|
1401
|
+
"Quer criar um novo agente aqui?",
|
|
1402
|
+
]));
|
|
1403
|
+
const { confirm } = await import("@clack/prompts");
|
|
1404
|
+
const create = await confirm({
|
|
1405
|
+
message: "criar novo agente neste diretório?",
|
|
1406
|
+
active: "sim",
|
|
1407
|
+
inactive: "não",
|
|
1408
|
+
});
|
|
1409
|
+
if (!create) {
|
|
1410
|
+
console.log(dim("até logo."));
|
|
1411
|
+
return;
|
|
1412
|
+
}
|
|
1413
|
+
// Init interativo
|
|
1414
|
+
const { promptInit } = await import("./prompts.js");
|
|
1415
|
+
const p = await promptInit();
|
|
1416
|
+
// Deploy automático
|
|
1417
|
+
console.log(info(`criando e deployando ${bold(p.name)}...`));
|
|
1418
|
+
await cmdInit(p.name, p.templateId, {
|
|
1419
|
+
mode: p.mode,
|
|
1420
|
+
skills: p.skills,
|
|
1421
|
+
genesis: p.genesis,
|
|
1422
|
+
deploy: true,
|
|
1423
|
+
dryRun: false,
|
|
1424
|
+
variables: p.variables,
|
|
1425
|
+
});
|
|
1426
|
+
// Entra no chat
|
|
1427
|
+
console.log(info(`entrando no agente ${bold(p.name)}...`));
|
|
1428
|
+
await cmdChat(p.name);
|
|
1429
|
+
}
|
|
1087
1430
|
async function main() {
|
|
1088
|
-
|
|
1089
|
-
|
|
1431
|
+
let realArgs = process.argv.slice(2);
|
|
1432
|
+
// G3: auto-start CP para comandos que precisam dele (--no-auto-cp desliga)
|
|
1433
|
+
const noAutoCP = realArgs.includes("--no-auto-cp");
|
|
1434
|
+
const noCP = new Set(["login", "logout", "model", "--help", "-h", "--version", "-v", "init"]);
|
|
1435
|
+
const cmd = realArgs[0];
|
|
1436
|
+
if (!noAutoCP && cmd && !noCP.has(cmd)) {
|
|
1437
|
+
await ensureCPRunning();
|
|
1438
|
+
}
|
|
1439
|
+
// Remove --no-auto-cp dos realArgs antes do switch
|
|
1440
|
+
realArgs = realArgs.filter((a) => a !== "--no-auto-cp");
|
|
1441
|
+
if (realArgs.length === 0) {
|
|
1090
1442
|
// 0.17.0 — `auton` bare: abre sessão de trabalho (estilo opencode):
|
|
1091
1443
|
// cwd é agente → sessão nele; senão picker. Pipe: mosta ajuda.
|
|
1444
|
+
// NOVO: project mode — se não há agente, oferece init + deploy + chat
|
|
1092
1445
|
if (isTTY) {
|
|
1093
|
-
await
|
|
1446
|
+
await cmdProject();
|
|
1094
1447
|
return;
|
|
1095
1448
|
}
|
|
1096
1449
|
console.log(USAGE);
|
|
1097
1450
|
return;
|
|
1098
1451
|
}
|
|
1099
|
-
if (
|
|
1452
|
+
if (realArgs[0] === "--help" || realArgs[0] === "-h") {
|
|
1100
1453
|
console.log(USAGE);
|
|
1101
1454
|
return;
|
|
1102
1455
|
}
|
|
1103
|
-
if (
|
|
1456
|
+
if (realArgs[0] === "--version" || realArgs[0] === "-v") {
|
|
1104
1457
|
if (isTTY)
|
|
1105
1458
|
console.log(logo());
|
|
1106
1459
|
console.log(bold(`auton v${VERSION}`));
|
|
@@ -1116,33 +1469,34 @@ async function main() {
|
|
|
1116
1469
|
const KNOWN = new Set([
|
|
1117
1470
|
"login", "logout", "model", "agent", "logs", "status", "restart", "run",
|
|
1118
1471
|
"verify", "inspect", "continue", "invoke", "undeploy", "approve", "reject",
|
|
1119
|
-
"ps", "context", "env", "init", "kv", "chat", "answer",
|
|
1472
|
+
"ps", "context", "env", "init", "kv", "chat", "answer", "wait", "result",
|
|
1473
|
+
"template",
|
|
1120
1474
|
]);
|
|
1121
|
-
if (!KNOWN.has(
|
|
1475
|
+
if (!KNOWN.has(realArgs[0]) && isTTY) {
|
|
1122
1476
|
const deployed = await listAgentNames();
|
|
1123
|
-
if (deployed.includes(
|
|
1124
|
-
await cmdChat(
|
|
1477
|
+
if (deployed.includes(realArgs[0])) {
|
|
1478
|
+
await cmdChat(realArgs[0]);
|
|
1125
1479
|
return;
|
|
1126
1480
|
}
|
|
1127
1481
|
}
|
|
1128
|
-
switch (
|
|
1482
|
+
switch (realArgs[0]) {
|
|
1129
1483
|
case "login":
|
|
1130
|
-
await cmdLogin(
|
|
1484
|
+
await cmdLogin(realArgs.slice(1));
|
|
1131
1485
|
break;
|
|
1132
1486
|
case "logout":
|
|
1133
|
-
await cmdLogout(
|
|
1487
|
+
await cmdLogout(realArgs[1]);
|
|
1134
1488
|
break;
|
|
1135
1489
|
case "model": {
|
|
1136
1490
|
// auton model [ls|set <spec>|test] — sem sub: seletor TTY
|
|
1137
|
-
const sub =
|
|
1138
|
-
const json =
|
|
1491
|
+
const sub = realArgs[1];
|
|
1492
|
+
const json = realArgs.includes("--json");
|
|
1139
1493
|
if (sub === "ls") {
|
|
1140
1494
|
await modelLs(json);
|
|
1141
1495
|
}
|
|
1142
1496
|
else if (sub === "set") {
|
|
1143
|
-
if (!
|
|
1497
|
+
if (!realArgs[2])
|
|
1144
1498
|
throw new ExitError(EXIT.USAGE, "uso: auton model set <provider:modelo>");
|
|
1145
|
-
await modelSet(
|
|
1499
|
+
await modelSet(realArgs[2]);
|
|
1146
1500
|
}
|
|
1147
1501
|
else if (sub === "test") {
|
|
1148
1502
|
await modelTest();
|
|
@@ -1156,8 +1510,8 @@ async function main() {
|
|
|
1156
1510
|
break;
|
|
1157
1511
|
}
|
|
1158
1512
|
case "agent":
|
|
1159
|
-
if (
|
|
1160
|
-
const dir = resolve(
|
|
1513
|
+
if (realArgs[1]) {
|
|
1514
|
+
const dir = resolve(realArgs[1]);
|
|
1161
1515
|
ensureRuntimeLink(dir);
|
|
1162
1516
|
await cmdDeploy(dir);
|
|
1163
1517
|
}
|
|
@@ -1167,8 +1521,8 @@ async function main() {
|
|
|
1167
1521
|
}
|
|
1168
1522
|
break;
|
|
1169
1523
|
case "logs":
|
|
1170
|
-
//
|
|
1171
|
-
const rest =
|
|
1524
|
+
// realArgs[1..]: [name] [--tail N] [--since RFC3339] [--follow] [--turn N]
|
|
1525
|
+
const rest = realArgs.slice(1);
|
|
1172
1526
|
const tailIdx = rest.indexOf("--tail");
|
|
1173
1527
|
const sinceIdx = rest.indexOf("--since");
|
|
1174
1528
|
let name;
|
|
@@ -1200,34 +1554,90 @@ async function main() {
|
|
|
1200
1554
|
await cmdLogs(name, tail, since, follow, turn);
|
|
1201
1555
|
break;
|
|
1202
1556
|
case "status":
|
|
1203
|
-
await cmdStatus(
|
|
1557
|
+
await cmdStatus(realArgs[1]);
|
|
1204
1558
|
break;
|
|
1205
1559
|
case "restart":
|
|
1206
|
-
await cmdRestart(
|
|
1560
|
+
await cmdRestart(realArgs[1]);
|
|
1207
1561
|
break;
|
|
1208
1562
|
case "run": {
|
|
1209
|
-
// auton run "<goal>" [--skip-verify] [--model X] (ou auton run
|
|
1210
|
-
const skipVerify =
|
|
1211
|
-
const
|
|
1212
|
-
const
|
|
1213
|
-
const
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1563
|
+
// auton run "<goal>" [--skip-verify] [--model X] [--async] [--dir DIR] [-d DIR] (ou auton run <agent-name> "goal")
|
|
1564
|
+
const skipVerify = realArgs.includes("--skip-verify");
|
|
1565
|
+
const isAsync = realArgs.includes("--async");
|
|
1566
|
+
const modelIdx = realArgs.indexOf("--model");
|
|
1567
|
+
const model = modelIdx !== -1 ? realArgs[modelIdx + 1] : undefined;
|
|
1568
|
+
// --dir / -d
|
|
1569
|
+
const dirIdx = realArgs.indexOf("--dir");
|
|
1570
|
+
const dirShortIdx = realArgs.indexOf("-d");
|
|
1571
|
+
const explicitDir = (dirIdx !== -1 ? realArgs[dirIdx + 1] : undefined) ??
|
|
1572
|
+
(dirShortIdx !== -1 ? realArgs[dirShortIdx + 1] : undefined);
|
|
1573
|
+
// resolve dir: --dir > agent name via CP > cwd
|
|
1574
|
+
let targetDir = explicitDir ? resolve(explicitDir) : process.cwd();
|
|
1575
|
+
let usedAgentName = false;
|
|
1576
|
+
let agentNameSliceIdx = -1; // index in realArgs.slice(1) of the agent name
|
|
1577
|
+
if (!explicitDir) {
|
|
1578
|
+
// Find first positional arg (not a flag) after "run"
|
|
1579
|
+
let firstPosArg;
|
|
1580
|
+
let firstPosArgIdx = -1;
|
|
1581
|
+
for (let i = 1; i < realArgs.length; i++) {
|
|
1582
|
+
const arg = realArgs[i];
|
|
1583
|
+
if (arg && !arg.startsWith("-")) {
|
|
1584
|
+
firstPosArg = arg;
|
|
1585
|
+
firstPosArgIdx = i;
|
|
1586
|
+
break;
|
|
1587
|
+
}
|
|
1588
|
+
}
|
|
1589
|
+
if (firstPosArg) {
|
|
1590
|
+
const knownCmds = new Set([
|
|
1591
|
+
"login", "logout", "model", "agent", "logs", "status", "restart", "run",
|
|
1592
|
+
"verify", "inspect", "continue", "invoke", "undeploy", "approve", "reject",
|
|
1593
|
+
"ps", "context", "env", "init", "kv", "chat", "answer", "wait", "result",
|
|
1594
|
+
]);
|
|
1595
|
+
if (!knownCmds.has(firstPosArg)) {
|
|
1596
|
+
try {
|
|
1597
|
+
const agent = await resolveAgent("run", firstPosArg);
|
|
1598
|
+
const statusRes = await fetch(`${API}/v1/agents/${agent}`, { headers: authHeaders() });
|
|
1599
|
+
if (statusRes.ok) {
|
|
1600
|
+
const status = (await statusRes.json());
|
|
1601
|
+
if (status.dir) {
|
|
1602
|
+
targetDir = resolve(status.dir);
|
|
1603
|
+
usedAgentName = true;
|
|
1604
|
+
agentNameSliceIdx = firstPosArgIdx - 1; // index in realArgs.slice(1)
|
|
1605
|
+
}
|
|
1606
|
+
}
|
|
1607
|
+
}
|
|
1608
|
+
catch { /* ignora, usa cwd */ }
|
|
1609
|
+
}
|
|
1610
|
+
}
|
|
1611
|
+
}
|
|
1612
|
+
// build goal: exclude flags + agent name if used for resolution
|
|
1613
|
+
const goal = realArgs.slice(1).filter((a, i) => {
|
|
1614
|
+
const origIdx = i + 1; // index in realArgs
|
|
1615
|
+
if (a === "--skip-verify" || a === "--model" || realArgs[origIdx - 1] === "--model" ||
|
|
1616
|
+
a === "--async" || a === "--dir" || a === "-d" ||
|
|
1617
|
+
realArgs[origIdx - 1] === "--dir" || realArgs[origIdx - 1] === "-d")
|
|
1618
|
+
return false;
|
|
1619
|
+
if (usedAgentName && i === agentNameSliceIdx)
|
|
1620
|
+
return false; // exclude agent name from goal
|
|
1621
|
+
return true;
|
|
1622
|
+
}).join(" ").trim() || undefined;
|
|
1623
|
+
ensureRuntimeLink(targetDir);
|
|
1624
|
+
if (isAsync) {
|
|
1625
|
+
await cmdRunAsync(targetDir, goal, skipVerify, model);
|
|
1626
|
+
}
|
|
1627
|
+
else {
|
|
1628
|
+
await cmdRun(targetDir, goal, skipVerify, model);
|
|
1629
|
+
}
|
|
1220
1630
|
break;
|
|
1221
1631
|
}
|
|
1222
1632
|
case "verify": {
|
|
1223
|
-
const rest =
|
|
1633
|
+
const rest = realArgs.slice(1);
|
|
1224
1634
|
const json = rest.includes("--json");
|
|
1225
1635
|
const dirArg = rest.find((a) => !a.startsWith("-"));
|
|
1226
1636
|
await cmdVerify(resolve(dirArg ?? process.cwd()), json);
|
|
1227
1637
|
break;
|
|
1228
1638
|
}
|
|
1229
1639
|
case "inspect": {
|
|
1230
|
-
const rest =
|
|
1640
|
+
const rest = realArgs.slice(1);
|
|
1231
1641
|
const json = rest.includes("--json");
|
|
1232
1642
|
const dirArg = rest.find((a) => !a.startsWith("-"));
|
|
1233
1643
|
await cmdInspect(resolve(dirArg ?? process.cwd()), json);
|
|
@@ -1235,29 +1645,41 @@ async function main() {
|
|
|
1235
1645
|
}
|
|
1236
1646
|
case "continue": {
|
|
1237
1647
|
// auton continue [name] [goal...]
|
|
1238
|
-
const goal =
|
|
1239
|
-
const nameArg =
|
|
1648
|
+
const goal = realArgs.slice(2).filter((a) => !a.startsWith("-")).join(" ").trim() || undefined;
|
|
1649
|
+
const nameArg = realArgs[1] && !realArgs[1].startsWith("-") ? realArgs[1] : undefined;
|
|
1240
1650
|
ensureRuntimeLink(process.cwd());
|
|
1241
1651
|
await cmdContinue(process.cwd(), nameArg, goal);
|
|
1242
1652
|
break;
|
|
1243
1653
|
}
|
|
1244
1654
|
case "invoke": {
|
|
1245
1655
|
// deploy invoke [name] [-- prompt] [--stream]
|
|
1246
|
-
const rest =
|
|
1656
|
+
const rest = realArgs.slice(2);
|
|
1247
1657
|
const stream = rest.includes("--stream");
|
|
1248
1658
|
const promptIdx = rest.indexOf("--");
|
|
1249
1659
|
const prompt = promptIdx !== -1 ? rest.slice(promptIdx + 1).join(" ") : undefined;
|
|
1250
|
-
await cmdInvoke(
|
|
1660
|
+
await cmdInvoke(realArgs[1], prompt, stream);
|
|
1251
1661
|
break;
|
|
1252
1662
|
}
|
|
1253
1663
|
case "undeploy":
|
|
1254
|
-
await cmdUndeploy(
|
|
1664
|
+
await cmdUndeploy(realArgs[1]);
|
|
1665
|
+
break;
|
|
1666
|
+
case "wait":
|
|
1667
|
+
// auton wait <task-id> [--timeout Ms]
|
|
1668
|
+
if (!realArgs[1])
|
|
1669
|
+
throw new ExitError(EXIT.USAGE, "uso: auton wait <task-id>");
|
|
1670
|
+
await cmdWait(realArgs[1]);
|
|
1671
|
+
break;
|
|
1672
|
+
case "result":
|
|
1673
|
+
// auton result <task-id>
|
|
1674
|
+
if (!realArgs[1])
|
|
1675
|
+
throw new ExitError(EXIT.USAGE, "uso: auton result <task-id>");
|
|
1676
|
+
await cmdResult(realArgs[1]);
|
|
1255
1677
|
break;
|
|
1256
1678
|
case "approve":
|
|
1257
1679
|
case "reject": {
|
|
1258
|
-
const approved =
|
|
1680
|
+
const approved = realArgs[0] === "approve";
|
|
1259
1681
|
// auton approve [name] [-- razão]: -- na posição [1] = sem name
|
|
1260
|
-
const rest =
|
|
1682
|
+
const rest = realArgs.slice(1);
|
|
1261
1683
|
const dash = rest.indexOf("--");
|
|
1262
1684
|
const name = dash === -1 ? rest[0] : dash === 0 ? undefined : rest[0];
|
|
1263
1685
|
const reason = dash !== -1 ? rest.slice(dash + 1).join(" ") : undefined;
|
|
@@ -1265,10 +1687,10 @@ async function main() {
|
|
|
1265
1687
|
break;
|
|
1266
1688
|
}
|
|
1267
1689
|
case "chat":
|
|
1268
|
-
await cmdChat(
|
|
1690
|
+
await cmdChat(realArgs[1]);
|
|
1269
1691
|
break;
|
|
1270
1692
|
case "answer": {
|
|
1271
|
-
const rest =
|
|
1693
|
+
const rest = realArgs.slice(1);
|
|
1272
1694
|
const dash = rest.indexOf("--");
|
|
1273
1695
|
const name = dash === -1 ? rest[0] : dash === 0 ? undefined : rest[0];
|
|
1274
1696
|
const answer = dash !== -1 ? rest.slice(dash + 1).join(" ") : undefined;
|
|
@@ -1276,21 +1698,21 @@ async function main() {
|
|
|
1276
1698
|
break;
|
|
1277
1699
|
}
|
|
1278
1700
|
case "ps":
|
|
1279
|
-
await cmdPs(
|
|
1701
|
+
await cmdPs(realArgs[1] === "--json");
|
|
1280
1702
|
break;
|
|
1281
1703
|
case "context":
|
|
1282
|
-
await cmdContext(
|
|
1704
|
+
await cmdContext(realArgs[1]);
|
|
1283
1705
|
break;
|
|
1284
1706
|
case "env": {
|
|
1285
|
-
const sub =
|
|
1707
|
+
const sub = realArgs[1];
|
|
1286
1708
|
if (sub === "set") {
|
|
1287
|
-
await cmdEnvSet(
|
|
1709
|
+
await cmdEnvSet(realArgs[2], realArgs[3], realArgs[4]);
|
|
1288
1710
|
}
|
|
1289
1711
|
else if (sub === "get") {
|
|
1290
|
-
await cmdEnvGet(
|
|
1712
|
+
await cmdEnvGet(realArgs[2], realArgs[3]);
|
|
1291
1713
|
}
|
|
1292
1714
|
else if (sub === "ls") {
|
|
1293
|
-
await cmdEnvLs(
|
|
1715
|
+
await cmdEnvLs(realArgs[2]);
|
|
1294
1716
|
}
|
|
1295
1717
|
else {
|
|
1296
1718
|
console.log(USAGE);
|
|
@@ -1298,36 +1720,97 @@ async function main() {
|
|
|
1298
1720
|
break;
|
|
1299
1721
|
}
|
|
1300
1722
|
case "init": {
|
|
1301
|
-
//
|
|
1302
|
-
const initFlags =
|
|
1303
|
-
const initPos =
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1723
|
+
// auton init [nome] [template] [--mode=X] [--skills=a,b] [--deploy] [--dry-run] [--genesis] [--var key=value]
|
|
1724
|
+
const initFlags = realArgs.filter((a) => a.startsWith("--"));
|
|
1725
|
+
const initPos = realArgs.filter((a) => !a.startsWith("--"));
|
|
1726
|
+
// Parse flags
|
|
1727
|
+
const deploy = initFlags.includes("--deploy");
|
|
1728
|
+
const dryRun = initFlags.includes("--dry-run");
|
|
1729
|
+
const mode = initFlags.find((f) => f.startsWith("--mode="))?.slice(7);
|
|
1730
|
+
const skills = initFlags
|
|
1731
|
+
.find((f) => f.startsWith("--skills="))
|
|
1732
|
+
?.slice(9)
|
|
1733
|
+
.split(",")
|
|
1734
|
+
.filter(Boolean);
|
|
1735
|
+
const genesis = initFlags.find((f) => f.startsWith("--genesis="))?.slice(10);
|
|
1736
|
+
// Parse --var key=value
|
|
1737
|
+
const variables = {};
|
|
1738
|
+
for (const f of initFlags) {
|
|
1739
|
+
if (f.startsWith("--var=")) {
|
|
1740
|
+
const rest = f.slice(6); // remove "--var="
|
|
1741
|
+
const eqIdx = rest.indexOf("=");
|
|
1742
|
+
if (eqIdx > 0) {
|
|
1743
|
+
const key = rest.slice(0, eqIdx);
|
|
1744
|
+
const val = rest.slice(eqIdx + 1);
|
|
1745
|
+
variables[key] = val === "true" ? true : val === "false" ? false : val;
|
|
1746
|
+
}
|
|
1747
|
+
}
|
|
1748
|
+
}
|
|
1312
1749
|
if (isTTY && !initPos[1] && !initPos[2]) {
|
|
1313
1750
|
const p = await promptInit();
|
|
1314
|
-
await cmdInit(p.name, p.
|
|
1751
|
+
await cmdInit(p.name, p.templateId, {
|
|
1752
|
+
mode: p.mode ?? mode,
|
|
1753
|
+
skills: p.skills ?? skills,
|
|
1754
|
+
genesis: p.genesis ?? genesis,
|
|
1755
|
+
deploy,
|
|
1756
|
+
dryRun,
|
|
1757
|
+
variables,
|
|
1758
|
+
});
|
|
1315
1759
|
}
|
|
1316
1760
|
else {
|
|
1317
|
-
const
|
|
1318
|
-
|
|
1319
|
-
|
|
1761
|
+
const name = initPos[1] ?? ".";
|
|
1762
|
+
const templateId = initPos[2];
|
|
1763
|
+
if (!templateId) {
|
|
1764
|
+
throw new ExitError(EXIT.USAGE, "uso: auton init <nome> <template-id> [--deploy] [--dry-run] ...");
|
|
1765
|
+
}
|
|
1766
|
+
// Valida template existe
|
|
1767
|
+
const registry = await getTemplateRegistry();
|
|
1768
|
+
const tpl = await registry.get(templateId);
|
|
1769
|
+
if (!tpl) {
|
|
1770
|
+
const list = await listTemplatesForDisplay();
|
|
1771
|
+
throw new ExitError(EXIT.USAGE, `template desconhecido: ${templateId}\nDisponíveis: ${list.map(t => `${t.id} (${t.category})`).join(", ")}`);
|
|
1772
|
+
}
|
|
1773
|
+
await cmdInit(name, templateId, {
|
|
1774
|
+
mode,
|
|
1775
|
+
skills,
|
|
1776
|
+
genesis,
|
|
1777
|
+
deploy,
|
|
1778
|
+
dryRun,
|
|
1779
|
+
variables,
|
|
1780
|
+
});
|
|
1781
|
+
}
|
|
1782
|
+
break;
|
|
1783
|
+
}
|
|
1784
|
+
case "template": {
|
|
1785
|
+
const sub = realArgs[1];
|
|
1786
|
+
if (sub === "list" || sub === "ls" || !sub) {
|
|
1787
|
+
const list = await listTemplatesForDisplay();
|
|
1788
|
+
if (realArgs.includes("--json")) {
|
|
1789
|
+
console.log(JSON.stringify(list, null, 2));
|
|
1790
|
+
}
|
|
1791
|
+
else {
|
|
1792
|
+
console.log(bold("Templates disponíveis:"));
|
|
1793
|
+
for (const t of list) {
|
|
1794
|
+
const srcTag = t.source === "custom" ? pc.cyan("(custom)") : pc.dim("(builtin)");
|
|
1795
|
+
console.log(` ${bold(t.id)} ${srcTag} — ${t.name} [${t.category}]`);
|
|
1796
|
+
console.log(` ${dim(t.description)}`);
|
|
1797
|
+
}
|
|
1320
1798
|
}
|
|
1321
|
-
|
|
1799
|
+
}
|
|
1800
|
+
else if (sub === "create") {
|
|
1801
|
+
console.log(info("Use 'auton init' com template custom — criação de template virá em versão futura"));
|
|
1802
|
+
}
|
|
1803
|
+
else {
|
|
1804
|
+
console.log(USAGE);
|
|
1322
1805
|
}
|
|
1323
1806
|
break;
|
|
1324
1807
|
}
|
|
1325
1808
|
case "kv":
|
|
1326
1809
|
// deploy kv get|set|ls <nome> [chave] [valor]
|
|
1327
|
-
await cmdKv(
|
|
1810
|
+
await cmdKv(realArgs[1], realArgs[2], realArgs[3], realArgs[4]);
|
|
1328
1811
|
break;
|
|
1329
1812
|
default: {
|
|
1330
|
-
console.error(fail(`comando desconhecido: ${
|
|
1813
|
+
console.error(fail(`comando desconhecido: ${realArgs[0]}`));
|
|
1331
1814
|
console.error(USAGE);
|
|
1332
1815
|
process.exit(EXIT.USAGE);
|
|
1333
1816
|
}
|