hobots 4.2.0 → 4.5.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/README.md CHANGED
@@ -27,11 +27,13 @@ CommonJS: `const { hobots } = require('hobots')`.
27
27
  ## Em 30 segundos
28
28
 
29
29
  ```bash
30
- export HOBOTS_CLIENT_SECRET=hb_<64 hex> # Configurações → Agentes
30
+ export HOBOTS_CLIENT_SECRET=hb_<64 hex> # Central: agente → Configurações → agente → aba credenciais
31
31
  export HOBOTS_INSTANCE_ID=vm-cliente-01 # opcional — default: hostname da máquina
32
32
  export HOBOTS_ENVIRONMENT=staging # opcional — default: production
33
33
  ```
34
34
 
35
+ Ou num arquivo `.env` na pasta de onde o bot é executado — o SDK o carrega sozinho (sem `dotenv`), veja [Credenciais e identidade](#credenciais-e-identidade).
36
+
35
37
  ```js
36
38
  import hobots from 'hobots';
37
39
 
@@ -55,8 +57,14 @@ Um robô que vive rodando usa `start` no lugar de `register` — o handler é o
55
57
  hobots.start(async () => {
56
58
  while (true) {
57
59
  await hobots.sleep(60_000); // cancelável
58
- for (const arquivo of await novosArquivos()) hobots.items.succeeded({ arquivo });
60
+ for (const arquivo of await novosArquivos()) {
61
+ const step = hobots.transaction.start('arquivo', arquivo);
62
+ await processar(arquivo);
63
+ step.succeeded();
64
+ hobots.items.succeeded({ arquivo });
65
+ }
59
66
  hobots.log.info('ciclo ok');
67
+ await hobots.flush(); // envia as etapas, itens e logs deste ciclo agora
60
68
  }
61
69
  });
62
70
  ```
@@ -69,13 +77,16 @@ O objeto **`hobots`** é global: `hobots.log`, `hobots.items`, `hobots.progress`
69
77
 
70
78
  | Env | Opção | O que é |
71
79
  | --- | --- | --- |
72
- | `HOBOTS_CLIENT_SECRET` | `clientSecret` | O **Client Secret do agente** (`hb_<64 hex>`), copiado em **Configurações → Agentes**. Viaja só no header `Authorization: Bearer`, nunca na URL. Ausente ou inválido → `register()`/`start()` lança na hora, citando a env (sem ecoar o valor). |
80
+ | `HOBOTS_CLIENT_SECRET` | `clientSecret` | O **Client Secret do agente** (`hb_<64 hex>`), copiado na Central em **agente → Configurações → agente → aba credenciais**. Viaja só no header `Authorization: Bearer`, nunca na URL. Ausente ou inválido → `register()`/`start()` lança na hora, citando a env (sem ecoar o valor). |
73
81
  | `HOBOTS_INSTANCE_ID` | `instanceId` | Identidade **estável** desta instância do robô (`vm-cliente-01`). Sem ela, o hostname. Heartbeat e execuções convergem nela: **um agente só** no painel. |
82
+ | `HOBOTS_RUN_ID` | `runId` | Definida por quem lança o processo (o Studio): o `register()` não faz poll — inicia essa run, executa o handler uma vez e sai. O código do bot não muda. |
74
83
  | `HOBOTS_ENVIRONMENT` | `environment` | Ambiente lógico do robô (`development` \| `testing` \| `staging` \| `production`). Sem ela, `production`. |
75
84
  | `HOBOTS_API_URL` | — | Só em desenvolvimento: aponta o SDK para outro host (`http://localhost:3001`). Em produção é sempre `https://api2.hobots.app`. |
76
85
 
77
86
  A opção passada em `register()`/`start()` tem precedência sobre a env — útil para copiar e colar o snippet do app.
78
87
 
88
+ **`.env` automático.** Ao ser importado, o SDK carrega o arquivo `.env` da pasta de trabalho (`process.cwd()`) em `process.env` — o bot não precisa de `dotenv` nem de `--env-file`, e o próprio código do bot também enxerga as variáveis (`process.env.SENHA_PORTAL`), inclusive no topo do módulo. A env já definida no ambiente **vence** o arquivo. Sem `.env`, nada muda. Usa o parser nativo do Node (`process.loadEnvFile`, Node ≥ 20.12); em Node mais antigo o arquivo é ignorado.
89
+
79
90
  ---
80
91
 
81
92
  ## Os dois modos
@@ -104,7 +115,7 @@ A opção passada em `register()`/`start()` tem precedência sobre a env — út
104
115
  | `hobots.items.each(lista, async (el, item) => …, { id, payload }?)` | **Loop com o contrato garantido**: cada elemento vira step + item; exceção no handler = item `failed` com a mensagem e o loop **segue** até o fim; progresso automático. Só cancelamento/timeout interrompem. |
105
116
  | `hobots.progress.total(n)` · `.advance(k = 1)` · `.set(atual, total?)` · `.current` · `.snapshot` | Barra, percentual e tempo restante na execução. Sem `total()` nada é enviado. |
106
117
  | `hobots.flush(timeoutMs?)` | **Entrega já** o que a execução fez: as steps raiz finalizadas viram transactions parciais (waterfall na Central sem esperar a run terminar) e itens, logs e progresso pendentes saem sem esperar o throttle. O bot decide quando — num agente `start()`, ao fim de cada rodada que processou itens. Aguarda com teto (15 s) e nunca lança. |
107
- | `hobots.transaction.startChild(op, descrição)` | Uma **step** no waterfall de performance da execução. A transaction da execução (`run`) já existe e é finalizada pelo SDK. `step.setStatus(status, msg?, { image })` / `setError(err, msg?, { image })` penduram um print na step. |
118
+ | `hobots.transaction.start(op, descrição)` | Uma **step** no waterfall de performance da execução. A transaction da execução (`run`) já existe e é finalizada pelo SDK. `step.setStatus(status, msg?, { image })` / `failed(err, msg?, { image })` penduram um print na step. |
108
119
  | `hobots.image(bytes \| caminho, { caption?, contentType? })` | Embrulha um **print** (PNG/JPEG/WEBP, até 5 MB, 20 por execução) para ir junto de um log, item ou step. Puro: o upload roda em segundo plano quando o evento é registrado; nunca lança nem bloqueia. |
109
120
  | `hobots.captureException(erro, hint?)` | Abre uma **issue** (módulo Issues). `hint.attachment` anexa um print à linha de log correspondente. |
110
121
  | `hobots.retry(fn, { retries = 3, delayMs = 1_000, shouldRetry? })` | async-retry ciente do cancelamento da execução. `delayMs` aceita função `(tentativa) => ms`. |
@@ -151,7 +162,7 @@ hobots.register(async () => {
151
162
 
152
163
  Uma execução cancelada no app **não mata** o handler — o SDK dispara `hobots.signal` e o próximo ponto de parada lança **`RunCanceled`**:
153
164
 
154
- - `hobots.items.*`, `hobots.progress.total/advance/set`, `hobots.transaction.startChild()`, `hobots.sleep()` e cada tentativa de `hobots.retry()`.
165
+ - `hobots.items.*`, `hobots.progress.total/advance/set`, `hobots.transaction.start()`, `hobots.sleep()` e cada tentativa de `hobots.retry()`.
155
166
  - **Nunca `hobots.log.*`** — um log dentro de um `finally` de limpeza não pode explodir.
156
167
 
157
168
  Num loop de itens, isso costuma bastar: registrar o item processado já é o ponto de parada. Para controle fino, `hobots.throwIfCanceled()` e `hobots.signal` continuam disponíveis. Quando o cancelamento veio do app, o `RunCanceled` é **suprimido** — a execução já está `cancelada` no servidor e nada é reportado por cima. Limpeza (fechar navegador, desfazer estado) vai em `try/finally`.
@@ -195,6 +206,7 @@ hobots.start(handler, options?: StartOptions);
195
206
  | `timeoutMs` | — (infinito) | Timeout por tentativa; terminal (`TaskTimeout`). O handler não é morto: o signal dispara e o slot é liberado |
196
207
  | `concurrency` (register) | `1` | Execuções simultâneas do agente (1..5) |
197
208
  | `pollIntervalMs` (register) | `2_000` | Intervalo entre polls sem trabalho (mín. 1_000) |
209
+ | `runId` (register) | env `HOBOTS_RUN_ID` | Avançado: executa só esta run (já reivindicada, ex.: pelo Studio) sem poll e encerra o SDK |
198
210
  | avançadas: `installExitHandlers`, `logFlushIntervalMs`, `cancelCheckIntervalMs`, `cancelGraceMs` | `true`, `2_000`, `5_000`, `10_000` | Ver [Referência de API](./docs/api-reference.md) |
199
211
 
200
212
  Como só há uma chamada por processo, todas as opções são as **do agente** — não existe "opção de processo" separada da "opção da task".
@@ -219,6 +231,7 @@ Sem handler próprio de sinal, um `SIGINT`/`SIGTERM` (ou erro fatal) com execuç
219
231
 
220
232
  ## Changelog resumido
221
233
 
234
+ - **4.3.0** — `register()` com env `HOBOTS_RUN_ID` (ou opção `runId`) executa só essa run: `POST /v1/runs/{id}/start` no lugar do poll, handler uma vez e `close()`; tipos `RunStartRequest`/`RunStartResponse` em `hobots/protocol`; itens recusados por armazenamento cheio (`402 storage_limit`) viram um aviso só por episódio, sem parar os envios.
222
235
  - **4.2.0** — **arquivos do formulário**: `hobots.files` (`list`, `get`, `download`, `downloadAll`, `read`) e `isFileRef`; tipos `FileRef`, `FileStorage`, `FileDownloadResponse` em `hobots/protocol`.
223
236
  - **4.0.0** — **o agente é a própria tarefa** (breaking): `register(handler, options?)`/`start(handler, options?)` **sem slug**; **uma chamada por processo** (a segunda lança); `hobots.task`/`ctx.task` removidos; tipos `TaskHandler`→`RunHandler`, `TaskOptions`→`RunOptions`, `TaskItemsOptions`→`ItemsOptions`; wire: `InstanceInfo.mode` (`on_demand` \| `always_on`) e `InstanceInfo.items` no lugar de `tasks`/`task_items`, endpoints em `/v1/runs/*`; eco no terminal `[hobots] INFO …`. Guia de migração no [CHANGELOG](./CHANGELOG.md).
224
237
  - **3.4.0** — `hobots.attach()` removido; o print vai junto do evento: `hobots.image(...)` no último argumento de `log.*`, `{ image }` em itens e steps.