hobots 1.7.0 → 1.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -33,11 +33,11 @@ function validateBaseUrl(raw, prefix) {
33
33
  function resolveConfig(options, prefix = "[hobots]") {
34
34
  const key = options.clientSecret?.trim();
35
35
  if (!key) {
36
- throw new Error(`${prefix} clientSecret ausente \u2014 copie o Client Secret do projeto em Configura\xE7\xF5es \u2192 Projetos`);
36
+ throw new Error(`${prefix} clientSecret ausente \u2014 copie o Client Secret do agente em Configura\xE7\xF5es \u2192 Agentes`);
37
37
  }
38
38
  if (!SECRET_PATTERN.test(key)) {
39
39
  throw new Error(
40
- `${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`
40
+ `${prefix} clientSecret com formato inv\xE1lido (${key.length} caracteres) \u2014 esperado "hb_" + 64 hex; copie o Client Secret do agente em Configura\xE7\xF5es \u2192 Agentes`
41
41
  );
42
42
  }
43
43
  const baseUrl = validateBaseUrl(envBaseUrl() ?? DEFAULT_BASE_URL, prefix);
@@ -103,7 +103,7 @@ function scrubSecrets(text) {
103
103
 
104
104
  // src/utils.ts
105
105
  var SDK_NAME = "hobots";
106
- var SDK_VERSION = true ? "2.0.0" : "0.0.0-dev";
106
+ var SDK_VERSION = true ? "1.7.1" : "0.0.0-dev";
107
107
  function isNode() {
108
108
  return typeof process !== "undefined" && typeof process.versions?.node === "string";
109
109
  }
@@ -1008,6 +1008,15 @@ var RunReporter = class {
1008
1008
  this.clearFlushTimer();
1009
1009
  this.buffer = [];
1010
1010
  }
1011
+ /**
1012
+ * Drena o buffer pendente para o PATCH único do exit path (chame ANTES de kill,
1013
+ * que descarta o buffer). Capado em um chunk — o exit path não tem retry nem fila,
1014
+ * então preserva os logs mais recentes, os mais valiosos na morte do processo.
1015
+ */
1016
+ drainLogs() {
1017
+ this.clearFlushTimer();
1018
+ return this.takeLogs().slice(-MAX_LOGS_PER_PATCH);
1019
+ }
1011
1020
  log(level, message) {
1012
1021
  if (this.dead) return;
1013
1022
  const scrubbed = scrubSecrets(message);
@@ -1100,10 +1109,16 @@ var RunReporter = class {
1100
1109
  return this.chain;
1101
1110
  }
1102
1111
  enqueue(update) {
1103
- if (this.dead) return;
1112
+ if (this.dead) {
1113
+ this.salvageLogs(update.logs);
1114
+ return;
1115
+ }
1104
1116
  this.pendingUpdates++;
1105
1117
  this.chain = this.chain.then(async () => {
1106
- if (this.dead) return;
1118
+ if (this.dead) {
1119
+ this.salvageLogs(update.logs);
1120
+ return;
1121
+ }
1107
1122
  const payload = update.logs && update.logs.length === 0 ? { ...update, logs: void 0 } : update;
1108
1123
  try {
1109
1124
  await this.api.updateRun(this.runId, payload);
@@ -1112,16 +1127,35 @@ var RunReporter = class {
1112
1127
  this.dead = true;
1113
1128
  this.stopCancelWatch();
1114
1129
  this.abort();
1115
- this.buffer = [];
1116
- this.logger.warn(`run ${this.runId} cancelada/removida no servidor \u2014 reporte suprimido`);
1130
+ const pending = this.buffer.splice(0, this.buffer.length);
1131
+ this.salvageLogs(pending);
1132
+ this.logger.warn(
1133
+ `run ${this.runId} cancelada/finalizada no servidor \u2014 status suprimido` + (pending.length > 0 ? `, ${pending.length} log(s) enviados como log tardio` : "")
1134
+ );
1117
1135
  return;
1118
1136
  }
1137
+ if (update.logs && update.logs.length > 0) {
1138
+ this.buffer.unshift(...update.logs);
1139
+ this.scheduleFlush();
1140
+ }
1119
1141
  this.logger.error(`update da run ${this.runId} perdido:`, error);
1120
1142
  }
1121
1143
  }).finally(() => {
1122
1144
  this.pendingUpdates--;
1123
1145
  });
1124
1146
  }
1147
+ /**
1148
+ * Best-effort de log tardio: envia logs para uma run já terminal, fora da fila.
1149
+ * O servidor anexa os logs mesmo respondendo 409; erros são engolidos — este é
1150
+ * o último recurso, não um canal confiável.
1151
+ */
1152
+ salvageLogs(logs) {
1153
+ if (!logs || logs.length === 0) return;
1154
+ for (let i = 0; i < logs.length; i += MAX_LOGS_PER_PATCH) {
1155
+ void this.api.updateRunOnce(this.runId, { status: "running", logs: logs.slice(i, i + MAX_LOGS_PER_PATCH) }).catch(() => {
1156
+ });
1157
+ }
1158
+ }
1125
1159
  };
1126
1160
 
1127
1161
  // src/tasks/run-context-store.ts
@@ -1277,9 +1311,14 @@ var TaskAgent = class {
1277
1311
  const pending = [];
1278
1312
  for (const reporter of this.reporters) {
1279
1313
  if (reporter.isDead) continue;
1314
+ const logs = reporter.drainLogs();
1280
1315
  reporter.kill();
1281
1316
  pending.push(
1282
- this.api.updateRunOnce(reporter.context.runId, { status: "failed", error: { type: "AgentTerminated", message } }, timeoutMs).catch(() => {
1317
+ this.api.updateRunOnce(
1318
+ reporter.context.runId,
1319
+ { status: "failed", error: { type: "AgentTerminated", message }, logs: logs.length > 0 ? logs : void 0 },
1320
+ timeoutMs
1321
+ ).catch(() => {
1283
1322
  })
1284
1323
  );
1285
1324
  }
@@ -1335,7 +1374,7 @@ var TaskAgent = class {
1335
1374
  if (error instanceof TasksApiError && error.status === 401) {
1336
1375
  this.consecutiveAuthFailures++;
1337
1376
  if (this.consecutiveAuthFailures === 1 || this.consecutiveAuthFailures % 10 === 0) {
1338
- this.logger.error("chave rejeitada (401) \u2014 verifique o Client Secret do projeto em Configura\xE7\xF5es \u2192 Projetos");
1377
+ this.logger.error("chave rejeitada (401) \u2014 verifique o Client Secret do agente em Configura\xE7\xF5es \u2192 Agentes");
1339
1378
  }
1340
1379
  return Math.max(this.pollIntervalMs, AUTH_FAILURE_INTERVAL_MS);
1341
1380
  }