hobots 1.5.1 → 1.6.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
@@ -65,7 +65,7 @@ Cada projeto tem **um único Client Secret** — a mesma credencial autentica o
65
65
  hb_<64 hex>
66
66
  ```
67
67
 
68
- (Chaves antigas, 64 hex puros, continuam válidas no servidor.) A credencial é **secreta** e viaja sempre no header `Authorization: Bearer` — nunca na URL. Copie o Client Secret no app, em **Configurações → Projetos** — os snippets de integração já vêm prontos. O SDK fala com a API oficial `https://api2.hobots.app` automaticamente; em desenvolvimento, aponte para outro host com a env `HOBOTS_API_URL` (ex.: `HOBOTS_API_URL=http://localhost:3001`).
68
+ A credencial é **secreta** e viaja sempre no header `Authorization: Bearer` — nunca na URL. Copie o Client Secret no app, em **Configurações → Projetos** — os snippets de integração já vêm prontos. O SDK fala com a API oficial `https://api2.hobots.app` automaticamente; em desenvolvimento, aponte para outro host com a env `HOBOTS_API_URL` (ex.: `HOBOTS_API_URL=http://localhost:3001`).
69
69
 
70
70
  ---
71
71
 
@@ -354,37 +354,7 @@ Para parar de aceitar execuções **sem** derrubar a telemetria, use `stop(timeo
354
354
  | `hobots` | Tudo: `init`, Monitor (captura, transactions, crons, heartbeat), Manager (`register`/`start`/`stop`), `close`, classes e tipos. |
355
355
  | `hobots/protocol` | Tipos do wire format (Monitor e Manager). |
356
356
 
357
- Empacotado em **ESM e CommonJS** com **definições de tipos** (`.d.ts`) para todas as entradas. (`hobots/manager/protocol` segue existindo como alias transitório de tipos.)
358
-
359
- ---
360
-
361
- ## Migração da API antiga (`hobots/manager`)
362
-
363
- O Manager foi unificado no import raiz — `hobots/manager` **foi removido**:
364
-
365
- ```diff
366
- -import * as Monitor from 'hobots';
367
- -import * as Manager from 'hobots/manager';
368
- +import * as Hobots from 'hobots';
369
-
370
- -Monitor.init({ dsn, serverName: 'vm-01', heartbeat: true });
371
- -Manager.init({ dsn, agentName: 'vm-01' });
372
- +Hobots.init({ clientSecret, instanceId: 'vm-01', heartbeat: true, manager: true });
373
-
374
- -Manager.register('minha-task', handler);
375
- -Manager.start();
376
- +Hobots.register('minha-task', handler);
377
- +Hobots.start();
378
-
379
- -await Manager.stop(15_000);
380
- -await Monitor.close(3_000);
381
- +await Hobots.close(15_000);
382
- ```
383
-
384
- - A `dsn` (mecanismo antigo, `https://<secretKey>@host/<slug>`) não existe mais — passe `clientSecret` (em desenvolvimento, aponte para outro host com a env `HOBOTS_API_URL`). Copie o Client Secret em **Configurações → Projetos**.
385
- - `agentName` e `serverName` não existem mais — a identidade do agente é o `instanceId` (obrigatório, sem fallback).
386
- - As opções do Manager (`pollIntervalMs`, `concurrency`, `taskTimeoutMs`, `logFlushIntervalMs`, `cancelCheckIntervalMs`, `installExitHandlers`) vão no campo `manager` do `init()`; `clientSecret` e `debug` não se repetem.
387
- - Tipos (`ManagerTaskHandler`, `RunContext`, `ManagerOptions`) e classes (`ManagerAgent`, `ManagerApi`) agora vêm de `hobots`; o wire format vem de `hobots/protocol`.
357
+ Empacotado em **ESM e CommonJS** com **definições de tipos** (`.d.ts`) para todas as entradas.
388
358
 
389
359
  ---
390
360
 
package/dist/index.cjs CHANGED
@@ -48,6 +48,7 @@ __export(src_exports, {
48
48
  init: () => init,
49
49
  register: () => register,
50
50
  resolveConfig: () => resolveConfig,
51
+ scrubSecrets: () => scrubSecrets,
51
52
  setContext: () => setContext,
52
53
  setExtra: () => setExtra,
53
54
  setTag: () => setTag,
@@ -63,21 +64,47 @@ module.exports = __toCommonJS(src_exports);
63
64
 
64
65
  // src/config.ts
65
66
  var DEFAULT_BASE_URL = "https://api2.hobots.app";
67
+ var SECRET_PATTERN = /^(hb_)?[a-f0-9]{64}$/i;
66
68
  function envBaseUrl() {
67
69
  if (typeof process === "undefined" || !process.env) return void 0;
68
70
  return process.env.HOBOTS_API_URL?.trim() || void 0;
69
71
  }
72
+ function isLoopbackHost(hostname2) {
73
+ return hostname2 === "localhost" || hostname2.endsWith(".localhost") || hostname2.startsWith("127.") || hostname2 === "[::1]" || hostname2 === "::1" || hostname2 === "0.0.0.0";
74
+ }
75
+ var warnedInsecureBaseUrl = false;
76
+ function validateBaseUrl(raw, prefix) {
77
+ let url;
78
+ try {
79
+ url = new URL(raw);
80
+ } catch {
81
+ throw new Error(`${prefix} HOBOTS_API_URL inv\xE1lida \u2014 esperado URL http(s), ex.: http://localhost:3001`);
82
+ }
83
+ if (url.protocol !== "http:" && url.protocol !== "https:") {
84
+ throw new Error(`${prefix} HOBOTS_API_URL com esquema "${url.protocol}" n\xE3o suportado \u2014 use http(s)`);
85
+ }
86
+ if (url.username || url.password) {
87
+ throw new Error(`${prefix} HOBOTS_API_URL n\xE3o pode conter credenciais na URL \u2014 a autentica\xE7\xE3o \xE9 s\xF3 pelo Client Secret`);
88
+ }
89
+ if (url.protocol === "http:" && !isLoopbackHost(url.hostname) && !warnedInsecureBaseUrl) {
90
+ warnedInsecureBaseUrl = true;
91
+ console.warn(
92
+ `${prefix} HOBOTS_API_URL usa http para o host remoto "${url.hostname}" \u2014 o Client Secret trafega sem TLS`
93
+ );
94
+ }
95
+ return raw.replace(/\/+$/, "");
96
+ }
70
97
  function resolveConfig(options, prefix = "[hobots]") {
71
98
  const key = options.clientSecret?.trim();
72
99
  if (!key) {
73
100
  throw new Error(`${prefix} clientSecret ausente \u2014 copie o Client Secret do projeto em Configura\xE7\xF5es \u2192 Projetos`);
74
101
  }
75
- const baseUrl = (envBaseUrl() ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
76
- try {
77
- new URL(baseUrl);
78
- } catch {
79
- throw new Error(`${prefix} HOBOTS_API_URL inv\xE1lida: "${baseUrl}" \u2014 esperado ex.: http://localhost:3001`);
102
+ if (!SECRET_PATTERN.test(key)) {
103
+ throw new Error(
104
+ `${prefix} clientSecret com formato inv\xE1lido (${key.length} caracteres) \u2014 esperado "hb_" + 64 hex; copie o Client Secret do projeto em Configura\xE7\xF5es \u2192 Projetos`
105
+ );
80
106
  }
107
+ const baseUrl = validateBaseUrl(envBaseUrl() ?? DEFAULT_BASE_URL, prefix);
81
108
  return {
82
109
  key,
83
110
  baseUrl,
@@ -119,9 +146,28 @@ function parseStacktrace(stack) {
119
146
  return frames;
120
147
  }
121
148
 
149
+ // src/scrub.ts
150
+ var SECRET_PATTERNS = [
151
+ // client secret da Hobots
152
+ [/hb_[a-f0-9]{16,}/gi, "[REDACTED]"],
153
+ // tokens bearer em headers/mensagens
154
+ [/\b(authorization:?\s*)?bearer\s+[a-z0-9._~+/=-]{8,}/gi, "Bearer [REDACTED]"],
155
+ // chaves no formato sk-… (OpenAI e afins)
156
+ [/\bsk-[a-z0-9_-]{16,}\b/gi, "[REDACTED]"],
157
+ // credenciais embutidas em URL (https://user:pass@host)
158
+ [/\/\/[^/\s:@]+:[^/\s@]+@/g, "//[REDACTED]@"]
159
+ ];
160
+ function scrubSecrets(text) {
161
+ let out = text;
162
+ for (const [pattern, replacement] of SECRET_PATTERNS) {
163
+ out = out.replace(pattern, replacement);
164
+ }
165
+ return out;
166
+ }
167
+
122
168
  // src/utils.ts
123
169
  var SDK_NAME = "hobots";
124
- var SDK_VERSION = true ? "1.5.0" : "0.0.0-dev";
170
+ var SDK_VERSION = true ? "1.6.0" : "0.0.0-dev";
125
171
  function isNode() {
126
172
  return typeof process !== "undefined" && typeof process.versions?.node === "string";
127
173
  }
@@ -130,6 +176,12 @@ function uuid4() {
130
176
  if (cryptoRef && typeof cryptoRef.randomUUID === "function") {
131
177
  return cryptoRef.randomUUID().replace(/-/g, "");
132
178
  }
179
+ if (cryptoRef && typeof cryptoRef.getRandomValues === "function") {
180
+ const bytes = cryptoRef.getRandomValues(new Uint8Array(16));
181
+ bytes[6] = bytes[6] & 15 | 64;
182
+ bytes[8] = bytes[8] & 63 | 128;
183
+ return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
184
+ }
133
185
  let out = "";
134
186
  for (let i = 0; i < 32; i++) {
135
187
  out += Math.floor(Math.random() * 16).toString(16);
@@ -148,7 +200,42 @@ function sleep(ms) {
148
200
  unrefTimer(timer);
149
201
  });
150
202
  }
151
- var PREFIX = "[hobots-monitor]";
203
+ function jitter(baseMs) {
204
+ return Math.floor(baseMs / 2 + Math.random() * (baseMs / 2));
205
+ }
206
+ var MAX_RETRY_AFTER_MS = 6e4;
207
+ function retryAfterMs(response) {
208
+ const header = response.headers.get("retry-after");
209
+ if (!header) return void 0;
210
+ const seconds = Number(header);
211
+ if (Number.isFinite(seconds)) {
212
+ return Math.min(MAX_RETRY_AFTER_MS, Math.max(0, seconds * 1e3));
213
+ }
214
+ const date = Date.parse(header);
215
+ if (Number.isNaN(date)) return void 0;
216
+ return Math.min(MAX_RETRY_AFTER_MS, Math.max(0, date - Date.now()));
217
+ }
218
+ function withTimeoutSignal(timeoutMs, external) {
219
+ const controller = new AbortController();
220
+ const onAbort = () => controller.abort(external?.reason);
221
+ if (external?.aborted) {
222
+ onAbort();
223
+ } else {
224
+ external?.addEventListener("abort", onAbort, { once: true });
225
+ }
226
+ const timer = setTimeout(() => {
227
+ controller.abort(Object.assign(new Error(`timeout ap\xF3s ${timeoutMs}ms`), { name: "TimeoutError" }));
228
+ }, timeoutMs);
229
+ unrefTimer(timer);
230
+ return {
231
+ signal: controller.signal,
232
+ cleanup: () => {
233
+ clearTimeout(timer);
234
+ external?.removeEventListener("abort", onAbort);
235
+ }
236
+ };
237
+ }
238
+ var PREFIX = "[hobots]";
152
239
  function makeLogger(enabled, prefix = PREFIX) {
153
240
  return {
154
241
  debug: (...args) => enabled && console.debug(colorize(prefix, "gray"), ...args),
@@ -189,11 +276,11 @@ function eventFromException(error, level = "error") {
189
276
  let frames = [];
190
277
  if (error instanceof Error) {
191
278
  type = error.name || "Error";
192
- value = error.message;
279
+ value = scrubSecrets(error.message);
193
280
  frames = parseStacktrace(error.stack);
194
281
  } else {
195
282
  type = "NonError";
196
- value = safeString(error);
283
+ value = scrubSecrets(safeString(error));
197
284
  }
198
285
  return {
199
286
  event_id: uuid4(),
@@ -211,12 +298,13 @@ function eventFromMessage(message, level = "info") {
211
298
  event_id: uuid4(),
212
299
  timestamp: nowISO(),
213
300
  level,
214
- message
301
+ message: scrubSecrets(message)
215
302
  };
216
303
  }
217
304
 
218
305
  // src/transport.ts
219
306
  var RETRY_DELAYS_MS = [1e3, 4e3, 16e3];
307
+ var REQUEST_TIMEOUT_MS = 1e4;
220
308
  var DEFAULT_FLUSH_INTERVAL_MS = 2e3;
221
309
  var DEFAULT_MAX_BATCH_SIZE = 10;
222
310
  var DEFAULT_MAX_QUEUE_SIZE = 200;
@@ -283,11 +371,13 @@ var Transport = class {
283
371
  }
284
372
  async sendWithRetry(envelope) {
285
373
  for (let attempt = 0; ; attempt++) {
374
+ let serverDelay;
286
375
  try {
287
376
  const response = await fetch(this.endpoint, {
288
377
  method: "POST",
289
378
  headers: { "content-type": "application/json", authorization: `Bearer ${this.key}` },
290
- body: JSON.stringify(envelope)
379
+ body: JSON.stringify(envelope),
380
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
291
381
  });
292
382
  if (response.ok) {
293
383
  this.logger.debug(`envelope enviado (${envelope.items.length} itens)`);
@@ -297,13 +387,15 @@ var Transport = class {
297
387
  this.logger.error(`envelope rejeitado (HTTP ${response.status}), descartado`);
298
388
  return;
299
389
  }
390
+ if (response.status === 429) serverDelay = retryAfterMs(response);
300
391
  throw new Error(`HTTP ${response.status}`);
301
392
  } catch (error) {
302
- const delay = RETRY_DELAYS_MS[attempt];
303
- if (delay === void 0) {
393
+ const base = RETRY_DELAYS_MS[attempt];
394
+ if (base === void 0) {
304
395
  this.logger.error("envelope descartado ap\xF3s retries:", error);
305
396
  return;
306
397
  }
398
+ const delay = serverDelay ?? jitter(base);
307
399
  this.logger.warn(`falha no envio (${String(error)}), retry em ${delay}ms`);
308
400
  await sleep(delay);
309
401
  }
@@ -333,22 +425,38 @@ function runtimeContexts() {
333
425
  return { runtime: { name: "browser" } };
334
426
  }
335
427
  var Client = class {
336
- options;
337
- config;
338
428
  logger;
429
+ // campos privados + getters de protótipo: o clientSecret não aparece em
430
+ // JSON.stringify/serialização enumerável do Client (ex.: um objeto capturado
431
+ // que referencie o client), mas client.options/config seguem funcionando
432
+ #options;
433
+ #config;
339
434
  transport;
340
435
  constructor(options) {
341
- this.options = options;
436
+ this.#options = options;
342
437
  this.logger = makeLogger(!!options.debug);
343
- this.config = resolveConfig(options);
438
+ this.#config = resolveConfig(options);
344
439
  this.transport = new Transport({
345
- endpoint: this.config.ingestEndpoint,
346
- key: this.config.key,
440
+ endpoint: this.#config.ingestEndpoint,
441
+ key: this.#config.key,
347
442
  logger: this.logger,
348
443
  flushIntervalMs: options.flushIntervalMs,
349
444
  maxBatchSize: options.maxBatchSize
350
445
  });
351
446
  }
447
+ get options() {
448
+ return this.#options;
449
+ }
450
+ get config() {
451
+ return this.#config;
452
+ }
453
+ /** Serialização explícita nunca inclui o secret. */
454
+ toJSON() {
455
+ return { sdk: SDK_NAME, version: SDK_VERSION, baseUrl: this.#config.baseUrl };
456
+ }
457
+ [/* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom")]() {
458
+ return `Client { baseUrl: '${this.#config.baseUrl}' }`;
459
+ }
352
460
  captureException(error, hint, scope2) {
353
461
  return this.captureEvent(eventFromException(error, hint?.level ?? "error"), hint, scope2);
354
462
  }
@@ -767,6 +875,8 @@ async function withMonitorImpl(client2, captureError, monitorSlug, fn, options)
767
875
 
768
876
  // src/manager/api.ts
769
877
  var RETRY_DELAYS_MS2 = [1e3, 4e3, 16e3];
878
+ var POLL_TIMEOUT_MS = 3e4;
879
+ var UPDATE_TIMEOUT_MS = 1e4;
770
880
  var ManagerApiError = class extends Error {
771
881
  constructor(message, status) {
772
882
  super(message);
@@ -791,16 +901,39 @@ var ManagerApi = class {
791
901
  }
792
902
  /** Um request só — o loop de polling é quem decide o backoff entre tentativas. */
793
903
  async poll(request, signal) {
794
- const response = await fetch(`${this.baseUrl}/poll`, {
795
- method: "POST",
796
- headers: this.headers(),
797
- body: JSON.stringify(request),
798
- signal
799
- });
904
+ const { signal: timeoutSignal, cleanup } = withTimeoutSignal(POLL_TIMEOUT_MS, signal);
905
+ let response;
906
+ try {
907
+ response = await fetch(`${this.baseUrl}/poll`, {
908
+ method: "POST",
909
+ headers: this.headers(),
910
+ body: JSON.stringify(request),
911
+ signal: timeoutSignal
912
+ });
913
+ } finally {
914
+ cleanup();
915
+ }
800
916
  if (!response.ok) {
801
917
  throw new ManagerApiError(`poll falhou (HTTP ${response.status})`, response.status);
802
918
  }
803
- return await response.json();
919
+ return this.parsePollResponse(await response.json(), request.max ?? 1);
920
+ }
921
+ /** Nunca confia no shape da resposta: runs malformadas são descartadas e o `max` é respeitado. */
922
+ parsePollResponse(body, max) {
923
+ const runs = body?.runs;
924
+ if (!Array.isArray(runs)) {
925
+ throw new ManagerApiError("resposta inv\xE1lida do poll (campo runs ausente)", 0);
926
+ }
927
+ const valid = [];
928
+ for (const run of runs.slice(0, Math.max(0, max))) {
929
+ if (typeof run?.id !== "string" || typeof run.task !== "string") continue;
930
+ const params = run.params && typeof run.params === "object" && !Array.isArray(run.params) ? run.params : {};
931
+ valid.push({ ...run, id: run.id, task: run.task, params });
932
+ }
933
+ if (valid.length < runs.length) {
934
+ this.logger.warn(`poll retornou ${runs.length - valid.length} run(s) inv\xE1lida(s)/excedente(s) \u2014 descartadas`);
935
+ }
936
+ return { runs: valid };
804
937
  }
805
938
  /**
806
939
  * PATCH de status/logs com retry em falha de rede/5xx/429.
@@ -809,25 +942,29 @@ var ManagerApi = class {
809
942
  async updateRun(runId, update) {
810
943
  for (let attempt = 0; ; attempt++) {
811
944
  let retriable;
945
+ let serverDelay;
812
946
  try {
813
947
  const response = await fetch(`${this.baseUrl}/runs/${encodeURIComponent(runId)}`, {
814
948
  method: "PATCH",
815
949
  headers: this.headers(),
816
- body: JSON.stringify(update)
950
+ body: JSON.stringify(update),
951
+ signal: AbortSignal.timeout(UPDATE_TIMEOUT_MS)
817
952
  });
818
953
  if (response.ok) return;
819
954
  if (response.status >= 400 && response.status < 500 && response.status !== 429) {
820
955
  throw new ManagerApiError(`update rejeitado (HTTP ${response.status})`, response.status);
821
956
  }
957
+ if (response.status === 429) serverDelay = retryAfterMs(response);
822
958
  retriable = new Error(`HTTP ${response.status}`);
823
959
  } catch (error) {
824
960
  if (error instanceof ManagerApiError) throw error;
825
961
  retriable = error;
826
962
  }
827
- const delay = RETRY_DELAYS_MS2[attempt];
828
- if (delay === void 0) {
963
+ const base = RETRY_DELAYS_MS2[attempt];
964
+ if (base === void 0) {
829
965
  throw new Error(`update da run ${runId} descartado ap\xF3s retries: ${String(retriable)}`);
830
966
  }
967
+ const delay = serverDelay ?? jitter(base);
831
968
  this.logger.warn(`falha no update da run ${runId} (${String(retriable)}), retry em ${delay}ms`);
832
969
  await sleep(delay);
833
970
  }
@@ -951,13 +1088,14 @@ var RunReporter = class {
951
1088
  }
952
1089
  log(level, message) {
953
1090
  if (this.dead) return;
954
- printRunLog(this.context.task, level, message);
1091
+ const scrubbed = scrubSecrets(message);
1092
+ printRunLog(this.context.task, level, scrubbed);
955
1093
  if (this.loggedCount >= MAX_LOGS_PER_RUN) {
956
1094
  this.droppedCount++;
957
1095
  return;
958
1096
  }
959
1097
  this.loggedCount++;
960
- const truncated = message.length > MAX_LOG_MESSAGE_CHARS ? `${message.slice(0, MAX_LOG_MESSAGE_CHARS)}\u2026 [truncado]` : message;
1098
+ const truncated = scrubbed.length > MAX_LOG_MESSAGE_CHARS ? `${scrubbed.slice(0, MAX_LOG_MESSAGE_CHARS)}\u2026 [truncado]` : scrubbed;
961
1099
  this.buffer.push({ ts: nowISO(), level, message: truncated });
962
1100
  if (this.buffer.length >= FLUSH_AT_BUFFERED) {
963
1101
  this.flushLogs();
@@ -1141,8 +1279,8 @@ var ManagerAgent = class {
1141
1279
  constructor(options, registry2) {
1142
1280
  this.options = options;
1143
1281
  this.registry = registry2;
1144
- this.logger = makeLogger(options.debug ?? false, "[hobots-manager]");
1145
- const config = resolveConfig(options, "[hobots-manager]");
1282
+ this.logger = makeLogger(options.debug ?? false, "[hobots]");
1283
+ const config = resolveConfig(options, "[hobots]");
1146
1284
  this.api = new ManagerApi({ baseUrl: config.managerBaseUrl, key: config.key, logger: this.logger });
1147
1285
  this.client = options.client;
1148
1286
  this.pollIntervalMs = Math.max(MIN_POLL_INTERVAL_MS, options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS);
@@ -1176,10 +1314,10 @@ var ManagerAgent = class {
1176
1314
  start() {
1177
1315
  if (this.state === "started") return;
1178
1316
  if (this.state === "stopping") {
1179
- throw new Error("[hobots-manager] start() chamado durante stop() \u2014 aguarde o stop terminar");
1317
+ throw new Error("[hobots] start() chamado durante stop() \u2014 aguarde o stop terminar");
1180
1318
  }
1181
1319
  if (this.registry.size === 0) {
1182
- throw new Error("[hobots-manager] nenhuma task registrada \u2014 chame register() antes de start()");
1320
+ throw new Error("[hobots] nenhuma task registrada \u2014 chame register() antes de start()");
1183
1321
  }
1184
1322
  this.state = "started";
1185
1323
  if (this.options.installExitHandlers !== false && !this.uninstallShutdown) {
@@ -1261,6 +1399,7 @@ var ManagerAgent = class {
1261
1399
  this.consecutiveFailures = 0;
1262
1400
  this.consecutiveAuthFailures = 0;
1263
1401
  for (const run of response.runs) {
1402
+ if (this.activeRuns.size >= this.concurrency) break;
1264
1403
  this.dispatch(run);
1265
1404
  }
1266
1405
  this.schedule(response.runs.length > 0 ? 0 : this.pollIntervalMs);
@@ -1281,7 +1420,7 @@ var ManagerAgent = class {
1281
1420
  }
1282
1421
  this.consecutiveFailures++;
1283
1422
  const ladder = POLL_RETRY_DELAYS_MS[Math.min(this.consecutiveFailures - 1, POLL_RETRY_DELAYS_MS.length - 1)];
1284
- const delay = Math.min(Math.max(ladder, 0), Math.max(this.pollIntervalMs, 16e3));
1423
+ const delay = Math.min(Math.max(jitter(ladder), 0), Math.max(this.pollIntervalMs, 16e3));
1285
1424
  this.logger.warn(`poll falhou (${String(error)}), pr\xF3xima tentativa em ${delay}ms`);
1286
1425
  return delay;
1287
1426
  }
@@ -1293,7 +1432,7 @@ var ManagerAgent = class {
1293
1432
  this.activeRuns.add(promise);
1294
1433
  }
1295
1434
  async executeRun(run) {
1296
- const tx = new Transaction(this.client, `run:${run.task}`, "manager.run", true, run.id);
1435
+ const tx = new Transaction(this.client, `run:${run.task}`, "hobots.task", true, run.id);
1297
1436
  const reporter = new RunReporter(this.api, run.id, run.task, this.logger, tx, this.logFlushIntervalMs, this.cancelCheckIntervalMs);
1298
1437
  this.reporters.add(reporter);
1299
1438
  try {
@@ -1359,11 +1498,11 @@ function toRunError(error) {
1359
1498
  if (error instanceof Error) {
1360
1499
  return {
1361
1500
  type: error.name,
1362
- message: truncate(error.message, MAX_ERROR_MESSAGE_CHARS),
1363
- stack: error.stack ? truncate(error.stack, MAX_ERROR_STACK_CHARS) : void 0
1501
+ message: scrubSecrets(truncate(error.message, MAX_ERROR_MESSAGE_CHARS)),
1502
+ stack: error.stack ? scrubSecrets(truncate(error.stack, MAX_ERROR_STACK_CHARS)) : void 0
1364
1503
  };
1365
1504
  }
1366
- return { message: truncate(String(error), MAX_ERROR_MESSAGE_CHARS) };
1505
+ return { message: scrubSecrets(truncate(String(error), MAX_ERROR_MESSAGE_CHARS)) };
1367
1506
  }
1368
1507
 
1369
1508
  // src/core.ts