@autonsh/cli 0.17.2 → 0.19.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.
Files changed (136) hide show
  1. package/dist/chat.d.ts +1 -1
  2. package/dist/chat.js +166 -120
  3. package/dist/chat.js.map +1 -1
  4. package/dist/completion.d.ts +2 -0
  5. package/dist/completion.js +379 -0
  6. package/dist/completion.js.map +1 -0
  7. package/dist/config-validation.d.ts +10 -0
  8. package/dist/config-validation.js +101 -0
  9. package/dist/config-validation.js.map +1 -0
  10. package/dist/config.d.ts +9 -3
  11. package/dist/config.js +23 -11
  12. package/dist/config.js.map +1 -1
  13. package/dist/doctor.d.ts +18 -0
  14. package/dist/doctor.js +409 -0
  15. package/dist/doctor.js.map +1 -0
  16. package/dist/errors.d.ts +22 -0
  17. package/dist/errors.js +60 -0
  18. package/dist/errors.js.map +1 -0
  19. package/dist/index.js +304 -119
  20. package/dist/index.js.map +1 -1
  21. package/dist/input.d.ts +43 -0
  22. package/dist/input.js +288 -0
  23. package/dist/input.js.map +1 -0
  24. package/dist/llm/factory.d.ts +5 -0
  25. package/dist/llm/factory.js +54 -0
  26. package/dist/llm/factory.js.map +1 -0
  27. package/dist/llm/index.d.ts +9 -0
  28. package/dist/llm/index.js +11 -0
  29. package/dist/llm/index.js.map +1 -0
  30. package/dist/llm/provider.d.ts +27 -0
  31. package/dist/llm/provider.js +98 -0
  32. package/dist/llm/provider.js.map +1 -0
  33. package/dist/llm/providers/anthropic.d.ts +23 -0
  34. package/dist/llm/providers/anthropic.js +198 -0
  35. package/dist/llm/providers/anthropic.js.map +1 -0
  36. package/dist/llm/providers/google.d.ts +31 -0
  37. package/dist/llm/providers/google.js +190 -0
  38. package/dist/llm/providers/google.js.map +1 -0
  39. package/dist/llm/providers/ollama.d.ts +21 -0
  40. package/dist/llm/providers/ollama.js +157 -0
  41. package/dist/llm/providers/ollama.js.map +1 -0
  42. package/dist/llm/providers/openai-compatible.d.ts +22 -0
  43. package/dist/llm/providers/openai-compatible.js +175 -0
  44. package/dist/llm/providers/openai-compatible.js.map +1 -0
  45. package/dist/llm/providers/openai.d.ts +20 -0
  46. package/dist/llm/providers/openai.js +167 -0
  47. package/dist/llm/providers/openai.js.map +1 -0
  48. package/dist/llm/registry.d.ts +19 -0
  49. package/dist/llm/registry.js +421 -0
  50. package/dist/llm/registry.js.map +1 -0
  51. package/dist/llm/types.d.ts +174 -0
  52. package/dist/llm/types.js +3 -0
  53. package/dist/llm/types.js.map +1 -0
  54. package/dist/login.d.ts +1 -1
  55. package/dist/login.js +14 -14
  56. package/dist/login.js.map +1 -1
  57. package/dist/mcp/client.d.ts +36 -0
  58. package/dist/mcp/client.js +199 -0
  59. package/dist/mcp/client.js.map +1 -0
  60. package/dist/mcp/config.d.ts +10 -0
  61. package/dist/mcp/config.js +43 -0
  62. package/dist/mcp/config.js.map +1 -0
  63. package/dist/mcp/index.d.ts +4 -0
  64. package/dist/mcp/index.js +6 -0
  65. package/dist/mcp/index.js.map +1 -0
  66. package/dist/mcp/types.d.ts +104 -0
  67. package/dist/mcp/types.js +3 -0
  68. package/dist/mcp/types.js.map +1 -0
  69. package/dist/model.d.ts +3 -14
  70. package/dist/model.js +131 -91
  71. package/dist/model.js.map +1 -1
  72. package/dist/ollama.d.ts +10 -0
  73. package/dist/ollama.js +11 -0
  74. package/dist/ollama.js.map +1 -0
  75. package/dist/prompts.d.ts +34 -8
  76. package/dist/prompts.js +186 -8
  77. package/dist/prompts.js.map +1 -1
  78. package/dist/repomap.d.ts +37 -0
  79. package/dist/repomap.js +431 -0
  80. package/dist/repomap.js.map +1 -0
  81. package/dist/skills/index.d.ts +3 -0
  82. package/dist/skills/index.js +5 -0
  83. package/dist/skills/index.js.map +1 -0
  84. package/dist/skills/registry.d.ts +16 -0
  85. package/dist/skills/registry.js +128 -0
  86. package/dist/skills/registry.js.map +1 -0
  87. package/dist/skills/types.d.ts +48 -0
  88. package/dist/skills/types.js +3 -0
  89. package/dist/skills/types.js.map +1 -0
  90. package/dist/statusline.d.ts +21 -0
  91. package/dist/statusline.js +68 -0
  92. package/dist/statusline.js.map +1 -0
  93. package/dist/streaming.d.ts +25 -0
  94. package/dist/streaming.js +91 -0
  95. package/dist/streaming.js.map +1 -0
  96. package/dist/task.d.ts +9 -1
  97. package/dist/task.js +21 -0
  98. package/dist/task.js.map +1 -1
  99. package/dist/template-engine.d.ts +19 -0
  100. package/dist/template-engine.js +187 -0
  101. package/dist/template-engine.js.map +1 -0
  102. package/dist/template-registry.d.ts +36 -0
  103. package/dist/template-registry.js +294 -0
  104. package/dist/template-registry.js.map +1 -0
  105. package/dist/theme.d.ts +52 -0
  106. package/dist/theme.js +92 -0
  107. package/dist/theme.js.map +1 -0
  108. package/dist/tools/builtin.d.ts +11 -0
  109. package/dist/tools/builtin.js +491 -0
  110. package/dist/tools/builtin.js.map +1 -0
  111. package/dist/tools/index.d.ts +3 -0
  112. package/dist/tools/index.js +5 -0
  113. package/dist/tools/index.js.map +1 -0
  114. package/dist/tools/types.d.ts +186 -0
  115. package/dist/tools/types.js +29 -0
  116. package/dist/tools/types.js.map +1 -0
  117. package/dist/ui.js +34 -30
  118. package/dist/ui.js.map +1 -1
  119. package/dist/verbose.d.ts +20 -0
  120. package/dist/verbose.js +75 -0
  121. package/dist/verbose.js.map +1 -0
  122. package/package.json +12 -2
  123. package/templates/api-json/task.yaml +0 -2
  124. package/templates/coding/agent.md +39 -0
  125. package/templates/coding/agent.ts +83 -0
  126. package/templates/coding/task.yaml +36 -0
  127. package/templates/cron-digester/task.yaml +0 -2
  128. package/templates/harness/agent.md +43 -0
  129. package/templates/harness/harness.ts +145 -0
  130. package/templates/harness/task.yaml +4 -0
  131. package/templates/multi-agent/agent.ts +7 -8
  132. package/templates/multi-agent/task.yaml +1 -3
  133. package/templates/research/task.yaml +4 -0
  134. package/templates/support/task.yaml +0 -2
  135. package/templates/webhook-echo/task.yaml +0 -2
  136. package/templates/with-approval/task.yaml +0 -2
package/dist/index.js CHANGED
@@ -19,9 +19,15 @@ 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 { TEMPLATES, promptInit, promptConfirmUndeploy, promptGateApproval, promptGateQuestion, parseGateLine, } from "./prompts.js";
22
+ import { AutonError, exitCodeFor, formatError } from "./errors.js";
23
+ import { promptInit, promptConfirmUndeploy, promptGateApproval, promptGateQuestion, parseGateLine, listTemplatesForDisplay, } from "./prompts.js";
24
+ import { getTemplateRegistry } from "./template-registry.js";
25
+ import { renderTemplate } from "./template-engine.js";
23
26
  import { loadTaskManifest, MODES, SKILLS, EXIT, ExitError, } from "./task.js";
24
27
  import { runVerify } from "./verify.js";
28
+ import { createUiLogger, parseVerboseFlag } from "./verbose.js";
29
+ import { cmdDoctor } from "./doctor.js";
30
+ import { cmdCompletion } from "./completion.js";
25
31
  const SRC = dirname(fileURLToPath(import.meta.url));
26
32
  // runtime package real (monorepo). CLI linka em node_modules/@autonsh/runtime
27
33
  // do diretório do agente → handler importa "@autonsh/runtime" de qualquer lugar.
@@ -109,59 +115,113 @@ async function installRuntime(dir) {
109
115
  bar.stop();
110
116
  }
111
117
  }
112
- async function cmdInit(name, template, opts = {}) {
118
+ async function cmdInit(name, templateId, opts = {}) {
119
+ const registry = await getTemplateRegistry();
120
+ const template = await registry.get(templateId);
121
+ if (!template) {
122
+ throw new ExitError(EXIT.USAGE, `template não encontrado: ${templateId}. Rode 'auton template list' para ver disponíveis.`);
123
+ }
113
124
  const plain = name === "." ? basename(process.cwd()) : name;
114
125
  const dir = resolve(name === "." ? process.cwd() : join(process.cwd(), name));
115
126
  if (existsSync(dir) && readdirSync(dir).length > 0) {
116
127
  throw new ExitError(EXIT.USAGE, `diretório não vazio: ${dir}`);
117
128
  }
129
+ // Prepara contexto de renderização
130
+ const context = {
131
+ name: plain,
132
+ ...opts.variables,
133
+ };
134
+ if (opts.dryRun) {
135
+ console.log(info(`[dry-run] Scaffold seria criado em: ${dir}`));
136
+ console.log(info(`[dry-run] Template: ${template.name} (${template.id})`));
137
+ console.log(info(`[dry-run] Variáveis: ${JSON.stringify(context, null, 2)}`));
138
+ return;
139
+ }
118
140
  mkdirSync(dir, { recursive: true });
119
- cpSync(join(TEMPLATES_SRC, template), dir, { recursive: true });
120
- // seta o nome real no manifest (task.yaml desde 0.9.1)
141
+ // Renderiza template via engine (Handlebars)
142
+ const result = await renderTemplate(template, context, dir);
143
+ // Substitui name no task.yaml (backward compat: templates built-in têm name hardcoded)
121
144
  const yamlPath = join(dir, "task.yaml");
122
- const yaml = (await readFile(yamlPath, "utf8")).replace(/^name: .*$/m, `name: ${plain}`);
123
- await writeFile(yamlPath, yaml);
124
- // mode (pivô 0.11): permissões do worker; docs do modo viram agent.md do projeto.
145
+ if (existsSync(yamlPath)) {
146
+ let yaml = await readFile(yamlPath, "utf8");
147
+ yaml = yaml.replace(/^name: .*$/m, `name: ${plain}`);
148
+ await writeFile(yamlPath, yaml);
149
+ }
150
+ // Garante package.json (pode vir do template ou ser gerado)
151
+ const pkgPath = join(dir, "package.json");
152
+ if (!existsSync(pkgPath)) {
153
+ const pkgName = plain.toLowerCase().replace(/[^a-z0-9._-]/g, "-");
154
+ await writeFile(pkgPath, JSON.stringify({
155
+ name: pkgName || "agent",
156
+ version: "0.0.0",
157
+ private: true,
158
+ type: "module",
159
+ dependencies: { "@autonsh/runtime": "^0.11.0" },
160
+ }, null, 2) + "\n");
161
+ }
162
+ // Genesis custom (se fornecido via --genesis ou prompt)
163
+ if (opts.genesis) {
164
+ const yamlPath = join(dir, "task.yaml");
165
+ let yaml = await readFile(yamlPath, "utf8");
166
+ // Substitui ou adiciona bloco genesis
167
+ if (yaml.includes("genesis:")) {
168
+ yaml = yaml.replace(/^genesis:[\s\S]*?(?=\n\S|\n*$)/m, `genesis: |\n ${opts.genesis.replace(/\n/g, "\n ")}\n`);
169
+ }
170
+ else {
171
+ yaml += `\ngenesis: |\n ${opts.genesis.replace(/\n/g, "\n ")}\n`;
172
+ }
173
+ await writeFile(yamlPath, yaml);
174
+ }
175
+ // Mode + skills do template (podem ser sobrescritos por opts)
125
176
  const mode = opts.mode && MODES.includes(opts.mode)
126
177
  ? opts.mode
127
- : "build";
178
+ : template.defaultMode;
179
+ const skills = (opts.skills ?? template.skills).filter((s) => SKILLS.includes(s));
180
+ // Atualiza task.yaml com mode/skills apenas se override explícito
181
+ if (opts.mode || opts.skills) {
182
+ const yamlPath2 = join(dir, "task.yaml");
183
+ let yaml = await readFile(yamlPath2, "utf8");
184
+ yaml = yaml
185
+ .split("\n")
186
+ .filter((line) => !/^(mode|skills):/m.test(line) && !/^\s*-\s/.test(line))
187
+ .join("\n")
188
+ .trimEnd()
189
+ .concat("\n", `mode: ${mode}`, skills.length > 0
190
+ ? `\nskills:\n${skills.map((s) => ` - ${s}`).join("\n")}`
191
+ : "")
192
+ .concat("\n");
193
+ await writeFile(yamlPath2, yaml);
194
+ }
195
+ // Copia agent.md do modo se não existir
128
196
  const modeDoc = join(TEMPLATES_SRC, "modes", mode, "agent.md");
129
- if (existsSync(modeDoc)) {
197
+ if (existsSync(modeDoc) && !existsSync(join(dir, "agent.md"))) {
130
198
  cpSync(modeDoc, join(dir, "agent.md"));
131
199
  }
132
- const skills = (opts.skills ?? []).filter((s) => SKILLS.includes(s));
200
+ // Skills built-in
133
201
  for (const s of skills) {
134
- cpSync(join(TEMPLATES_SRC, "skills", s, "SKILL.md"), join(dir, "skills", s, "SKILL.md"), {
135
- recursive: true,
136
- });
202
+ try {
203
+ cpSync(join(TEMPLATES_SRC, "skills", s, "SKILL.md"), join(dir, "skills", s, "SKILL.md"), {
204
+ recursive: true,
205
+ });
206
+ }
207
+ catch {
208
+ // skill não existe — ignora
209
+ }
137
210
  }
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
211
  ensureRuntimeLink(dir);
158
212
  if (!HAS_LOCAL_RUNTIME) {
159
213
  await installRuntime(dir);
160
214
  }
161
215
  if (isTTY)
162
216
  console.log(logo());
163
- console.log(ok(`${plain} (template: ${template}) em ${dim(dir)}`));
217
+ console.log(ok(`${plain} (template: ${template.name}) em ${dim(dir)}`));
164
218
  console.log(info(`próximo: ${bold(`cd ${plain} && auton run "<objetivo>"`)}`));
219
+ // Deploy opcional
220
+ if (opts.deploy) {
221
+ console.log(info(`deployando ${bold(plain)}...`));
222
+ await cmdDeploy(dir);
223
+ console.log(ok(`${plain} deployado`));
224
+ }
165
225
  }
166
226
  const VERSION = JSON.parse(readFileSync(resolve(SRC, "../package.json"), "utf8")).version;
167
227
  const API = process.env.AUTON_API ?? "http://localhost:8080";
@@ -170,69 +230,27 @@ let cpStarted = false;
170
230
  async function ensureCPRunning() {
171
231
  if (cpStarted)
172
232
  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));
233
+ // Retry loop: 10x com 500ms = 5s total
234
+ for (let i = 0; i < 10; i++) {
220
235
  try {
221
236
  const res = await fetch(`${API}/v1/agents`, {
237
+ method: "GET",
222
238
  headers: authHeaders(),
223
239
  signal: AbortSignal.timeout(500),
224
240
  });
225
241
  if (res.ok) {
226
242
  cpStarted = true;
227
- console.log(ok("control-plane iniciado"));
228
243
  return;
229
244
  }
230
245
  }
231
246
  catch {
232
- // ainda subindo
247
+ // CP não responde ainda
233
248
  }
249
+ if (i < 9)
250
+ await new Promise((r) => setTimeout(r, 500));
234
251
  }
235
- console.log(dim("aviso: control-plane pode não ter subido a tempo"));
252
+ // Não subiu em 5s assume CP externo (já rodando em outra porta/host)
253
+ console.log(dim("aviso: control-plane não respondeu em 5s — assumindo externo"));
236
254
  }
237
255
  function authHeaders(extra) {
238
256
  const h = { ...extra };
@@ -261,29 +279,33 @@ Usage:
261
279
 
262
280
  Modelos:
263
281
  auton model Seletor interativo do modelo default
264
- (local ollama + providers configurados)
282
+ (local ollama + providers configurados)
265
283
  auton model ls [--json] Lista modelos locais + providers
266
284
  auton model set <spec> Define default (ex: ollama:qwen3)
267
285
  auton model test Testa latência dos providers
286
+ auton model search <query> [--json] Busca fuzzy no registry (id/name/aliases)
287
+ auton model info <spec> [--json] Detalhes do modelo (caps, context, cost, etc)
288
+ auton model pull <spec> [--json] Baixa ollama:* ou valida credencial remota
289
+ auton model rm <id> [--json] Remove provider do config pelo id
268
290
  auton login [provider] [--apikey X]
269
- Conecta provider (gemini/groq/ollama)
291
+ Conecta provider (gemini/groq/ollama)
270
292
  auton logout [id] Remove provider configurado
271
293
 
272
294
  Agentes:
273
295
  auton [nome] Sessão de trabalho (estilo opencode): dá
274
- tasks, acompanha o agente ao vivo, gates
275
- inline. Sem nome: cwd/picker.
296
+ tasks, acompanha o agente ao vivo, gates
297
+ inline. Sem nome: cwd/picker.
276
298
  auton chat [name] Alias da sessão de trabalho
277
299
  auton agent [dir] Deploy do agente no diretório
278
300
  auton ps Lista agentes + status
279
301
  auton logs [name] [--tail N] [--follow] [--since X] [--turn N]
280
- Stream de logs do agente (SSE)
302
+ Stream de logs do agente (SSE)
281
303
  auton status [name] Status do agente
282
304
  auton restart [name] Reinicia o agente
283
305
  auton invoke [name] [--stream] [-- prompt]
284
- Roda 1 turno (legado v0)
306
+ Roda 1 turno (legado v0)
285
307
  auton approve|reject [name] [-- razão]
286
- Decide o gate de aprovação
308
+ Decide o gate de aprovação
287
309
  auton answer [name] [-- texto] Responde pergunta pendente (ctx.ask)
288
310
  auton context [name] Work context: decisions/findings/artifacts
289
311
  auton undeploy [name] Remove o agente (--all remove tudo)
@@ -296,13 +318,22 @@ Tasks:
296
318
  auton verify [dir] [--json] Roda gates mecânicos do verify
297
319
  auton inspect [dir] [--json] Inspeciona task + evidência
298
320
  auton continue [name] [goal] Retoma a última task (sem redeploy)
299
- auton init [nome] [template] Scaffold de task (support|with-approval|...)
321
+ auton init [nome] [template] [--mode=X] [--skills=a,b] [--deploy] [--dry-run] [--genesis] [--var key=value]
322
+ Scaffold de task (templates built-in + custom)
323
+
324
+ Templates:
325
+ auton template list [--json] Lista templates (built-in + custom)
326
+ auton template create <id> Cria template custom (futuro)
300
327
 
301
328
  Infra:
302
329
  auton kv get|set|ls [name] [key] [value]
303
- Inspeciona o storage KV
330
+ Inspeciona o storage KV
304
331
  auton env set|get|ls [name] [key] [value]
305
- Env vars por agente
332
+ Env vars por agente
333
+
334
+ Sistema:
335
+ auton doctor [--json] Valida ambiente (config, creds, ollama, mcp, sandbox, disco, node, go)
336
+ auton completion <bash|zsh|fish> Gera script de completion para shell
306
337
 
307
338
  Options:
308
339
  --help, -h Mostra ajuda
@@ -323,7 +354,7 @@ function pickEnv(keys) {
323
354
  }
324
355
  return out;
325
356
  }
326
- async function cmdDeploy(dir, extraEnv) {
357
+ async function cmdDeploy(dir, extraEnv, models) {
327
358
  const manifest = await loadTaskManifest(dir);
328
359
  if (manifest.legacy) {
329
360
  console.log(dim(`aviso: ${bold("agent.yaml")} é legado v0 — renomeie para ${bold("task.yaml")}`));
@@ -338,7 +369,7 @@ async function cmdDeploy(dir, extraEnv) {
338
369
  entry: manifest.entry,
339
370
  dir,
340
371
  env: { ...pickEnv(manifest.env), ...extraEnv },
341
- models: manifest.models,
372
+ models: models ?? manifest.models,
342
373
  cron: manifest.cron,
343
374
  mode: manifest.mode,
344
375
  invoke_timeout_ms: manifest.invokeTimeoutMs,
@@ -545,10 +576,11 @@ async function cmdRun(dir, goalArg, skipVerify, model) {
545
576
  }
546
577
  // 0.17: modelo efetivo = --model > task.yaml > env > config default (auton model)
547
578
  const defaultModel = getDefaultModel();
548
- await precheckModel(model ?? manifest.models ?? process.env.AUTON_MODEL ?? defaultModel);
579
+ const resolvedModel = model ?? (manifest.models || undefined) ?? process.env.AUTON_MODEL ?? defaultModel;
580
+ await precheckModel(resolvedModel);
549
581
  // 0.15.1: credencial do `auton login` injetada no deploy (key/base);
550
582
  // --model (0.14.3) sobrescreve models: do task.yaml
551
- await cmdDeploy(dir, { ...credentialEnv(), ...(model ? { AUTON_MODEL: model } : {}) });
583
+ await cmdDeploy(dir, { ...credentialEnv(), AUTON_MODEL: resolvedModel }, resolvedModel);
552
584
  const lines = await runWithGates(manifest.name, goal);
553
585
  await printTaskDone(manifest.name, goal, lines);
554
586
  }
@@ -562,8 +594,9 @@ async function cmdRunAsync(dir, goalArg, skipVerify, model) {
562
594
  throw new Error(`task ${manifest.name} sem objetivo — passe "auton run \"<objetivo>\" --async" ou defina 'goal' no task.yaml`);
563
595
  }
564
596
  const defaultModel = getDefaultModel();
565
- await precheckModel(model ?? manifest.models ?? process.env.AUTON_MODEL ?? defaultModel);
566
- await cmdDeploy(dir, { ...credentialEnv(), ...(model ? { AUTON_MODEL: model } : {}) });
597
+ const resolvedModel = model ?? (manifest.models || undefined) ?? process.env.AUTON_MODEL ?? defaultModel;
598
+ await precheckModel(resolvedModel);
599
+ await cmdDeploy(dir, { ...credentialEnv(), AUTON_MODEL: resolvedModel }, resolvedModel);
567
600
  // Gera task-id único: agent-name + timestamp + random
568
601
  const taskId = `${manifest.name}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
569
602
  // Dispara invoke sem aguardar (fire-and-forget)
@@ -1057,7 +1090,10 @@ async function cmdInvoke(name, prompt, stream) {
1057
1090
  if (res.status === 408) {
1058
1091
  // 0.16.11: aviso cedo + poll de logs em vez de exit 5 seco
1059
1092
  console.log(info(`invoke estourou o timeout — turno segue em background, acompanhando...`));
1060
- return await pollBackground(agent);
1093
+ const bgLines = await pollBackground(agent);
1094
+ for (const line of bgLines)
1095
+ console.log(line);
1096
+ return bgLines;
1061
1097
  }
1062
1098
  throw new Error(`control plane ${res.status}: ${await res.text()}`);
1063
1099
  }
@@ -1303,13 +1339,80 @@ async function cmdLogin(realArgs) {
1303
1339
  async function cmdLogout(providerId) {
1304
1340
  await logoutCmd(providerId);
1305
1341
  }
1342
+ /** Project mode: `auton` bare — se não há agente, cria + deploya + entra no chat. */
1343
+ async function cmdProject() {
1344
+ // 1. Tenta achar agente no cwd (task.yaml)
1345
+ let agentName;
1346
+ try {
1347
+ const { loadTaskManifest } = await import("./task.js");
1348
+ const manifest = await loadTaskManifest(process.cwd());
1349
+ if (manifest?.name)
1350
+ agentName = manifest.name;
1351
+ }
1352
+ catch {
1353
+ // sem task.yaml
1354
+ }
1355
+ // 2. Se não há no cwd, tenta deployed agents
1356
+ if (!agentName) {
1357
+ const deployed = await listAgentNames();
1358
+ if (deployed.length === 1) {
1359
+ agentName = deployed[0];
1360
+ }
1361
+ else if (deployed.length > 1) {
1362
+ // Múltiplos deployados — usa picker (cmdChat já faz isso)
1363
+ await cmdChat(undefined);
1364
+ return;
1365
+ }
1366
+ }
1367
+ // 3. Tem agente (cwd ou único deployado) → entra no chat
1368
+ if (agentName) {
1369
+ console.log(info(`entrando no agente ${bold(agentName)}...`));
1370
+ await cmdChat(agentName);
1371
+ return;
1372
+ }
1373
+ // 4. Nenhum agente — oferece init interativo
1374
+ console.log(box("auton — nenhum agente encontrado", [
1375
+ "Este diretório não tem task.yaml e não há agentes deployados.",
1376
+ "Quer criar um novo agente aqui?",
1377
+ ]));
1378
+ const { confirm } = await import("@clack/prompts");
1379
+ const create = await confirm({
1380
+ message: "criar novo agente neste diretório?",
1381
+ active: "sim",
1382
+ inactive: "não",
1383
+ });
1384
+ if (!create) {
1385
+ console.log(dim("até logo."));
1386
+ return;
1387
+ }
1388
+ // Init interativo
1389
+ const { promptInit } = await import("./prompts.js");
1390
+ const p = await promptInit();
1391
+ // Deploy automático
1392
+ console.log(info(`criando e deployando ${bold(p.name)}...`));
1393
+ await cmdInit(p.name, p.templateId, {
1394
+ mode: p.mode,
1395
+ skills: p.skills,
1396
+ genesis: p.genesis,
1397
+ deploy: true,
1398
+ dryRun: false,
1399
+ variables: p.variables,
1400
+ });
1401
+ // Entra no chat
1402
+ console.log(info(`entrando no agente ${bold(p.name)}...`));
1403
+ await cmdChat(p.name);
1404
+ }
1306
1405
  async function main() {
1307
1406
  let realArgs = process.argv.slice(2);
1407
+ // Parse --verbose global flag
1408
+ const { verbose, remainingArgs } = parseVerboseFlag(realArgs);
1409
+ const logger = createUiLogger(verbose);
1410
+ realArgs = remainingArgs;
1308
1411
  // G3: auto-start CP para comandos que precisam dele (--no-auto-cp desliga)
1309
1412
  const noAutoCP = realArgs.includes("--no-auto-cp");
1310
- const noCP = new Set(["login", "logout", "model", "--help", "-h", "--version", "-v", "init"]);
1413
+ const noCP = new Set(["login", "logout", "model", "--help", "-h", "--version", "-v", "init", "doctor", "completion"]);
1311
1414
  const cmd = realArgs[0];
1312
- if (!noAutoCP && cmd && !noCP.has(cmd)) {
1415
+ if (!noAutoCP && (!cmd || !noCP.has(cmd))) {
1313
1416
  await ensureCPRunning();
1314
1417
  }
1315
1418
  // Remove --no-auto-cp dos realArgs antes do switch
@@ -1317,8 +1420,9 @@ async function main() {
1317
1420
  if (realArgs.length === 0) {
1318
1421
  // 0.17.0 — `auton` bare: abre sessão de trabalho (estilo opencode):
1319
1422
  // cwd é agente → sessão nele; senão picker. Pipe: mosta ajuda.
1423
+ // NOVO: project mode — se não há agente, oferece init + deploy + chat
1320
1424
  if (isTTY) {
1321
- await cmdChat(undefined);
1425
+ await cmdProject();
1322
1426
  return;
1323
1427
  }
1324
1428
  console.log(USAGE);
@@ -1345,6 +1449,7 @@ async function main() {
1345
1449
  "login", "logout", "model", "agent", "logs", "status", "restart", "run",
1346
1450
  "verify", "inspect", "continue", "invoke", "undeploy", "approve", "reject",
1347
1451
  "ps", "context", "env", "init", "kv", "chat", "answer", "wait", "result",
1452
+ "template", "doctor", "completion",
1348
1453
  ]);
1349
1454
  if (!KNOWN.has(realArgs[0]) && isTTY) {
1350
1455
  const deployed = await listAgentNames();
@@ -1594,27 +1699,88 @@ async function main() {
1594
1699
  break;
1595
1700
  }
1596
1701
  case "init": {
1597
- // deploy init [nome] [template] [--mode=X] [--skills=a,b] sem argumentos (TTY): pergunta interativo
1702
+ // auton init [nome] [template] [--mode=X] [--skills=a,b] [--deploy] [--dry-run] [--genesis] [--var key=value]
1598
1703
  const initFlags = realArgs.filter((a) => a.startsWith("--"));
1599
1704
  const initPos = realArgs.filter((a) => !a.startsWith("--"));
1600
- const initOpts = {
1601
- mode: initFlags.find((f) => f.startsWith("--mode="))?.slice(7),
1602
- skills: initFlags
1603
- .find((f) => f.startsWith("--skills="))
1604
- ?.slice(9)
1605
- .split(",")
1606
- .filter(Boolean),
1607
- };
1705
+ // Parse flags
1706
+ const deploy = initFlags.includes("--deploy");
1707
+ const dryRun = initFlags.includes("--dry-run");
1708
+ const mode = initFlags.find((f) => f.startsWith("--mode="))?.slice(7);
1709
+ const skills = initFlags
1710
+ .find((f) => f.startsWith("--skills="))
1711
+ ?.slice(9)
1712
+ .split(",")
1713
+ .filter(Boolean);
1714
+ const genesis = initFlags.find((f) => f.startsWith("--genesis="))?.slice(10);
1715
+ // Parse --var key=value
1716
+ const variables = {};
1717
+ for (const f of initFlags) {
1718
+ if (f.startsWith("--var=")) {
1719
+ const rest = f.slice(6); // remove "--var="
1720
+ const eqIdx = rest.indexOf("=");
1721
+ if (eqIdx > 0) {
1722
+ const key = rest.slice(0, eqIdx);
1723
+ const val = rest.slice(eqIdx + 1);
1724
+ variables[key] = val === "true" ? true : val === "false" ? false : val;
1725
+ }
1726
+ }
1727
+ }
1608
1728
  if (isTTY && !initPos[1] && !initPos[2]) {
1609
1729
  const p = await promptInit();
1610
- await cmdInit(p.name, p.template, initOpts);
1730
+ await cmdInit(p.name, p.templateId, {
1731
+ mode: p.mode ?? mode,
1732
+ skills: p.skills ?? skills,
1733
+ genesis: p.genesis ?? genesis,
1734
+ deploy,
1735
+ dryRun,
1736
+ variables,
1737
+ });
1611
1738
  }
1612
1739
  else {
1613
- const tpl = (initPos[2] ?? "support");
1614
- if (!TEMPLATES.includes(tpl)) {
1615
- throw new ExitError(EXIT.USAGE, `template desconhecido: ${tpl} (disponíveis: ${TEMPLATES.join(", ")})`);
1740
+ const name = initPos[1] ?? ".";
1741
+ const templateId = initPos[2];
1742
+ if (!templateId) {
1743
+ throw new ExitError(EXIT.USAGE, "uso: auton init <nome> <template-id> [--deploy] [--dry-run] ...");
1744
+ }
1745
+ // Valida template existe
1746
+ const registry = await getTemplateRegistry();
1747
+ const tpl = await registry.get(templateId);
1748
+ if (!tpl) {
1749
+ const list = await listTemplatesForDisplay();
1750
+ throw new ExitError(EXIT.USAGE, `template desconhecido: ${templateId}\nDisponíveis: ${list.map(t => `${t.id} (${t.category})`).join(", ")}`);
1751
+ }
1752
+ await cmdInit(name, templateId, {
1753
+ mode,
1754
+ skills,
1755
+ genesis,
1756
+ deploy,
1757
+ dryRun,
1758
+ variables,
1759
+ });
1760
+ }
1761
+ break;
1762
+ }
1763
+ case "template": {
1764
+ const sub = realArgs[1];
1765
+ if (sub === "list" || sub === "ls" || !sub) {
1766
+ const list = await listTemplatesForDisplay();
1767
+ if (realArgs.includes("--json")) {
1768
+ console.log(JSON.stringify(list, null, 2));
1769
+ }
1770
+ else {
1771
+ console.log(bold("Templates disponíveis:"));
1772
+ for (const t of list) {
1773
+ const srcTag = t.source === "custom" ? pc.cyan("(custom)") : pc.dim("(builtin)");
1774
+ console.log(` ${bold(t.id)} ${srcTag} — ${t.name} [${t.category}]`);
1775
+ console.log(` ${dim(t.description)}`);
1776
+ }
1616
1777
  }
1617
- await cmdInit(initPos[1] ?? ".", tpl, initOpts);
1778
+ }
1779
+ else if (sub === "create") {
1780
+ console.log(info("Use 'auton init' com template custom — criação de template virá em versão futura"));
1781
+ }
1782
+ else {
1783
+ console.log(USAGE);
1618
1784
  }
1619
1785
  break;
1620
1786
  }
@@ -1622,6 +1788,17 @@ async function main() {
1622
1788
  // deploy kv get|set|ls <nome> [chave] [valor]
1623
1789
  await cmdKv(realArgs[1], realArgs[2], realArgs[3], realArgs[4]);
1624
1790
  break;
1791
+ case "doctor":
1792
+ await cmdDoctor(realArgs.includes("--json"));
1793
+ break;
1794
+ case "completion": {
1795
+ const shell = realArgs[1];
1796
+ if (!shell || !["bash", "zsh", "fish"].includes(shell)) {
1797
+ throw new ExitError(EXIT.USAGE, "uso: auton completion <bash|zsh|fish>");
1798
+ }
1799
+ await cmdCompletion(shell);
1800
+ break;
1801
+ }
1625
1802
  default: {
1626
1803
  console.error(fail(`comando desconhecido: ${realArgs[0]}`));
1627
1804
  console.error(USAGE);
@@ -1630,7 +1807,15 @@ async function main() {
1630
1807
  }
1631
1808
  }
1632
1809
  main().catch((err) => {
1633
- console.error(fail(`erro: ${err.message}`));
1634
- process.exit(err.code ?? EXIT.ERR);
1810
+ console.error(fail(formatError(err)));
1811
+ let code = EXIT.ERR;
1812
+ if (err instanceof ExitError)
1813
+ code = err.code;
1814
+ else if (err instanceof AutonError)
1815
+ code = exitCodeFor(err.code);
1816
+ else if (err && typeof err === "object" && "code" in err && typeof err.code === "number") {
1817
+ code = err.code;
1818
+ }
1819
+ process.exit(code);
1635
1820
  });
1636
1821
  //# sourceMappingURL=index.js.map