@bli-cockpit/cli 0.2.108 → 0.2.109

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.
@@ -15,7 +15,7 @@ export async function runCockpitCli(argv, io) {
15
15
  }
16
16
 
17
17
  if (command === "--version" || command === "-V" || command === "version") {
18
- writeLine(io?.stdout ?? process.stdout, "0.2.108");
18
+ writeLine(io?.stdout ?? process.stdout, "0.2.109");
19
19
  return 0;
20
20
  }
21
21
 
@@ -1,3 +1,4 @@
1
+ import { gzipSync } from "node:zlib";
1
2
  import { COMMIT_CRASHED_PLATFORM, RawEvidenceUploadCommitResponseSchema, isPermanentUploadFailure, } from "@bli-cockpit/telemetry-core";
2
3
  import { beginOneObject } from "./evidence-upload-terminal.js";
3
4
  import { isNonJsonResponseBody, requestJson, safeFailureDetail, sha256, } from "./evidence-upload-transport.js";
@@ -46,8 +47,14 @@ async function uploadObjectChunks(options, entry, disposition, chunkSizeBytes, o
46
47
  if (received.has(index))
47
48
  continue;
48
49
  const chunk = entry.bytes.subarray(index * chunkSizeBytes, Math.min((index + 1) * chunkSizeBytes, entry.bytes.byteLength));
50
+ const encodedChunk = gzipSync(chunk);
51
+ console.error("[evidence-upload] chunk encoded", JSON.stringify({
52
+ upload_id: disposition.upload_id, chunk_index: index, chunk_encoding: "gzip",
53
+ bytes_before: chunk.length, bytes_after: encodedChunk.length,
54
+ }));
49
55
  const chunkResponse = await requestJson(options, "/api/ambient/evidence/upload/chunk", {
50
- schema_version: "ambient-raw-evidence-upload-chunk.v1",
56
+ schema_version: "ambient-raw-evidence-upload-chunk.v2",
57
+ encoding: "gzip",
51
58
  generated_at: options.generatedAt,
52
59
  provenance: options.provenance,
53
60
  upload_id: disposition.upload_id,
@@ -55,7 +62,7 @@ async function uploadObjectChunks(options, entry, disposition, chunkSizeBytes, o
55
62
  chunk_index: index,
56
63
  chunk_count: entry.chunkCount,
57
64
  chunk_hash_sha256: sha256(chunk),
58
- content_base64: chunk.toString("base64"),
65
+ content_base64: encodedChunk.toString("base64"),
59
66
  });
60
67
  if (!chunkResponse.ok) {
61
68
  // Same treatment the commit path has had since BLI-2528: the server's
@@ -70,7 +70,9 @@ export function rawEvidenceStagingStatePath(stateDir) {
70
70
  export async function readRawEvidenceStagingState(stateDir) {
71
71
  try {
72
72
  const raw = JSON.parse(await fs.readFile(rawEvidenceStagingStatePath(stateDir), "utf8"));
73
- return parseStagingState(raw);
73
+ const state = parseStagingState(raw);
74
+ resetStorage403ForEncoding(state);
75
+ return state;
74
76
  }
75
77
  catch (error) {
76
78
  // Empty is right before the first staged pack. Unreadable is not: this
@@ -160,6 +162,7 @@ export function recordDeliveryFailure(state, contentHash, options) {
160
162
  const attemptedAtIso = options.attemptedAt.toISOString();
161
163
  const entry = {
162
164
  attempts,
165
+ ...(previous?.encoding_retry_version ? { encoding_retry_version: previous.encoding_retry_version } : {}),
163
166
  ...(terminalDeliveryReason(options.reason) ? { terminal_reason: options.reason } : {}),
164
167
  first_failed_at: previous?.first_failed_at ?? attemptedAtIso,
165
168
  last_attempt_at: attemptedAtIso,
@@ -295,6 +298,7 @@ function parseAttemptEntry(value) {
295
298
  const attempts = optionalNumber(record["attempts"]);
296
299
  return {
297
300
  ...(terminalDeliveryReason(optionalString(record["last_reason"])) ? { terminal_reason: String(record["last_reason"]) } : {}),
301
+ ...(record["encoding_retry_version"] === 1 ? { encoding_retry_version: 1 } : {}),
298
302
  attempts: attempts > 0 ? attempts : 1,
299
303
  first_failed_at: optionalString(record["first_failed_at"]) ?? lastAttemptAt,
300
304
  last_attempt_at: lastAttemptAt,
@@ -320,4 +324,21 @@ function shortHash(value) {
320
324
  /** A persisted clock cannot extend a retry beyond the last attempt's ceiling. */
321
325
  export function deliveryRetryAtMs(entry) {
322
326
  return Math.min(Date.parse(entry.next_attempt_at), Date.parse(entry.last_attempt_at) + EVIDENCE_DELIVERY_BACKOFF_MAX_MS);
327
+ }
328
+ /** One retry per object for the encoding repair, without erasing other refusals. */
329
+ export function resetStorage403ForEncoding(state) {
330
+ let count = 0;
331
+ for (const entry of Object.values(state.delivery_attempts)) {
332
+ if (entry.encoding_retry_version === 1 || !/^chunk_\d+_failed_http_503_chunk_staging_upload_refused_storage_403$/u.test(entry.last_reason))
333
+ continue;
334
+ entry.encoding_retry_version = 1;
335
+ entry.next_attempt_at = new Date(0).toISOString();
336
+ delete entry.terminal_reason;
337
+ count += 1;
338
+ }
339
+ if (count > 0)
340
+ console.error("[raw-evidence-staging] storage refusals offered with encoding", JSON.stringify({
341
+ reason: "storage_403_encoding_retry", chunk_encoding: "gzip", objects_reset: count,
342
+ }));
343
+ return count;
323
344
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bli-cockpit/cli",
3
- "version": "0.2.108",
3
+ "version": "0.2.109",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "bin": {
@@ -27,8 +27,8 @@
27
27
  "test": "node dist/cli.js --help && node ../../scripts/assert-public-cli-routing.mjs && node ../../scripts/assert-public-cli-verb-help.mjs && node ../../scripts/assert-public-cli-runtime-files.mjs && node ../../scripts/assert-public-cli-exit-contract.mjs && node ../../scripts/assert-public-cli-no-fleet-posts.mjs && node ../../scripts/assert-public-package-pack.mjs --workspace=@bli-cockpit/cli"
28
28
  },
29
29
  "dependencies": {
30
- "@bli-cockpit/memory-mcp": "0.1.27",
31
- "@bli-cockpit/mcp": "0.1.36",
32
- "@bli-cockpit/telemetry-core": "0.1.43"
30
+ "@bli-cockpit/memory-mcp": "0.1.28",
31
+ "@bli-cockpit/mcp": "0.1.37",
32
+ "@bli-cockpit/telemetry-core": "0.1.44"
33
33
  }
34
34
  }