@stigmer/cli 3.32.0 → 3.34.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.
@@ -21,12 +21,19 @@ export interface TarballBinarySource {
21
21
  label: string;
22
22
  /** Override the fetch implementation (tests). */
23
23
  fetchImpl?: typeof fetch;
24
+ /** Override the wait between download attempts (tests). */
25
+ sleep?: (ms: number) => Promise<void>;
24
26
  }
27
+ /** Attempts per download before a transient failure is reported. */
28
+ export declare const DOWNLOAD_ATTEMPTS = 4;
29
+ /** The wait before the second attempt; it doubles before each later one (1 s, 2 s, 4 s). */
30
+ export declare const DOWNLOAD_RETRY_BASE_DELAY_MS = 1000;
25
31
  /**
26
32
  * Download a `.tar.gz`, optionally verify its sha256, extract the named entry,
27
- * and write it to `binPath` with executable permissions. Throws a
28
- * {@link CliExitError} with the URL on any network, checksum, or extraction
29
- * failure.
33
+ * and write it to `binPath` with executable permissions. Transient network
34
+ * failures are retried (see the module header). Throws a {@link CliExitError}
35
+ * with the URL on a persistent network failure, a non-transient HTTP status, a
36
+ * checksum mismatch, or an extraction failure.
30
37
  */
31
38
  export declare function fetchTarballBinary(src: TarballBinarySource): Promise<void>;
32
39
  /** Lowercase hex sha256 of `bytes`. */
@@ -1 +1 @@
1
- {"version":3,"file":"artifact.d.ts","sourceRoot":"","sources":["../../src/local/artifact.ts"],"names":[],"mappings":"AAkBA,gFAAgF;AAChF,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,QAAQ,GAAG,MAAM,CAS9D;AAED,oFAAoF;AACpF,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CASnD;AAED,MAAM,WAAW,mBAAmB;IAClC,oCAAoC;IACpC,GAAG,EAAE,MAAM,CAAC;IACZ;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,yDAAyD;IACzD,SAAS,EAAE,MAAM,CAAC;IAClB,kEAAkE;IAClE,OAAO,EAAE,MAAM,CAAC;IAChB,kFAAkF;IAClF,KAAK,EAAE,MAAM,CAAC;IACd,iDAAiD;IACjD,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CAC1B;AAED;;;;;GAKG;AACH,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CA4BhF;AAED,uCAAuC;AACvC,wBAAgB,SAAS,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAEnD;AAyBD;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAOrE;AASD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAoBhF"}
1
+ {"version":3,"file":"artifact.d.ts","sourceRoot":"","sources":["../../src/local/artifact.ts"],"names":[],"mappings":"AAyBA,gFAAgF;AAChF,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,QAAQ,GAAG,MAAM,CAS9D;AAED,oFAAoF;AACpF,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CASnD;AAED,MAAM,WAAW,mBAAmB;IAClC,oCAAoC;IACpC,GAAG,EAAE,MAAM,CAAC;IACZ;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,yDAAyD;IACzD,SAAS,EAAE,MAAM,CAAC;IAClB,kEAAkE;IAClE,OAAO,EAAE,MAAM,CAAC;IAChB,kFAAkF;IAClF,KAAK,EAAE,MAAM,CAAC;IACd,iDAAiD;IACjD,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,2DAA2D;IAC3D,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC;AAED,oEAAoE;AACpE,eAAO,MAAM,iBAAiB,IAAI,CAAC;AAEnC,4FAA4F;AAC5F,eAAO,MAAM,4BAA4B,OAAQ,CAAC;AAElD;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CA4BhF;AAED,uCAAuC;AACvC,wBAAgB,SAAS,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAEnD;AAmED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAOrE;AASD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAoBhF"}
package/local/artifact.js CHANGED
@@ -8,9 +8,16 @@
8
8
  // second consumer until the server became an npm artifact.) The tar reader is a
9
9
  // tiny POSIX/ustar implementation: no native `tar` dependency, which keeps the
10
10
  // base install lean (DD-002).
11
+ //
12
+ // Retrying a transient failure is part of the contract. A connection that resets
13
+ // before or during the body, a 5xx or a 429 is tried again with a doubling wait,
14
+ // so a network blip does not fail a first `stigmer up`, a CI lane or an image
15
+ // build. Any other HTTP status and a checksum mismatch are answers: they fail at
16
+ // once.
11
17
  import { createHash } from "node:crypto";
12
18
  import { chmodSync, mkdirSync, writeFileSync } from "node:fs";
13
19
  import { dirname } from "node:path";
20
+ import { setTimeout as delay } from "node:timers/promises";
14
21
  import { gunzipSync } from "fflate";
15
22
  import { CliExitError } from "../errors/cli-exit-error.js";
16
23
  import { ExitCode } from "../errors/exit-codes.js";
@@ -36,18 +43,23 @@ export function mapReleaseArch(arch) {
36
43
  return arch;
37
44
  }
38
45
  }
46
+ /** Attempts per download before a transient failure is reported. */
47
+ export const DOWNLOAD_ATTEMPTS = 4;
48
+ /** The wait before the second attempt; it doubles before each later one (1 s, 2 s, 4 s). */
49
+ export const DOWNLOAD_RETRY_BASE_DELAY_MS = 1_000;
39
50
  /**
40
51
  * Download a `.tar.gz`, optionally verify its sha256, extract the named entry,
41
- * and write it to `binPath` with executable permissions. Throws a
42
- * {@link CliExitError} with the URL on any network, checksum, or extraction
43
- * failure.
52
+ * and write it to `binPath` with executable permissions. Transient network
53
+ * failures are retried (see the module header). Throws a {@link CliExitError}
54
+ * with the URL on a persistent network failure, a non-transient HTTP status, a
55
+ * checksum mismatch, or an extraction failure.
44
56
  */
45
57
  export async function fetchTarballBinary(src) {
46
- const doFetch = src.fetchImpl ?? fetch;
47
- const archive = await fetchBytes(doFetch, src.url, src.label);
58
+ const net = { doFetch: src.fetchImpl ?? fetch, sleep: src.sleep ?? delay };
59
+ const archive = await fetchBytes(net, src.url, src.label);
48
60
  if (src.checksumUrl !== undefined) {
49
61
  const archiveName = archiveBasename(src.url);
50
- const expected = parseShasum(await fetchText(doFetch, src.checksumUrl, `${src.label} checksum`), archiveName);
62
+ const expected = parseShasum(await fetchText(net, src.checksumUrl, `${src.label} checksum`), archiveName);
51
63
  const actual = sha256Hex(archive);
52
64
  if (expected === "" || expected !== actual) {
53
65
  throw new CliExitError(`${src.label} checksum mismatch — refusing to use the download`, ExitCode.General, [
@@ -72,26 +84,53 @@ export async function fetchTarballBinary(src) {
72
84
  export function sha256Hex(bytes) {
73
85
  return createHash("sha256").update(bytes).digest("hex");
74
86
  }
75
- async function fetchBytes(doFetch, url, label) {
76
- const res = await doFetchOrThrow(doFetch, url, label);
77
- return new Uint8Array(await res.arrayBuffer());
87
+ async function fetchBytes(net, url, label) {
88
+ return fetchWithRetry(net, url, label, async (res) => new Uint8Array(await res.arrayBuffer()));
78
89
  }
79
- async function fetchText(doFetch, url, label) {
80
- const res = await doFetchOrThrow(doFetch, url, label);
81
- return res.text();
90
+ async function fetchText(net, url, label) {
91
+ return fetchWithRetry(net, url, label, (res) => res.text());
82
92
  }
83
- async function doFetchOrThrow(doFetch, url, label) {
84
- let res;
85
- try {
86
- res = await doFetch(url);
87
- }
88
- catch (err) {
89
- throw new CliExitError(`failed to download ${label} from ${url}`, ExitCode.General, [String(err)]);
90
- }
91
- if (!res.ok) {
92
- throw new CliExitError(`failed to download ${label}: HTTP ${res.status} from ${url}`, ExitCode.General);
93
+ // One download, with its body read inside the attempt: a connection that drops
94
+ // after the headers is as transient as one that never connects, and is retried
95
+ // the same way. The error after the last attempt carries the last failure's
96
+ // cause, which for Node's fetch is the socket error behind "fetch failed".
97
+ async function fetchWithRetry(net, url, label, read) {
98
+ let lastFailure = "";
99
+ for (let attempt = 1; attempt <= DOWNLOAD_ATTEMPTS; attempt++) {
100
+ if (attempt > 1)
101
+ await net.sleep(DOWNLOAD_RETRY_BASE_DELAY_MS * 2 ** (attempt - 2));
102
+ let res;
103
+ try {
104
+ res = await net.doFetch(url);
105
+ }
106
+ catch (err) {
107
+ lastFailure = describeFailure(err);
108
+ continue;
109
+ }
110
+ if (!res.ok) {
111
+ if (!isTransientStatus(res.status)) {
112
+ throw new CliExitError(`failed to download ${label}: HTTP ${res.status} from ${url}`, ExitCode.General);
113
+ }
114
+ lastFailure = `HTTP ${res.status}`;
115
+ continue;
116
+ }
117
+ try {
118
+ return await read(res);
119
+ }
120
+ catch (err) {
121
+ lastFailure = describeFailure(err);
122
+ }
93
123
  }
94
- return res;
124
+ throw new CliExitError(`failed to download ${label} from ${url} after ${DOWNLOAD_ATTEMPTS} attempts: ${lastFailure}`, ExitCode.General, ["check the network connection, then run the command again"]);
125
+ }
126
+ // A server error or a rate limit may clear on its own; any other status will not.
127
+ function isTransientStatus(status) {
128
+ return status >= 500 || status === 429;
129
+ }
130
+ function describeFailure(err) {
131
+ if (!(err instanceof Error))
132
+ return String(err);
133
+ return err.cause instanceof Error ? `${err.message}: ${err.cause.message}` : err.message;
95
134
  }
96
135
  /**
97
136
  * The sha256 a `shasum`/`sha256sum`-format file records for `filename`, lowercase
@@ -1 +1 @@
1
- {"version":3,"file":"artifact.js","sourceRoot":"","sources":["../../src/local/artifact.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"artifact.js","sourceRoot":"","sources":["../../src/local/artifact.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,9 @@
1
1
  export { extractTarEntry } from "../artifact.js";
2
- /** Default Temporal CLI version (matches the Go CLI's `DefaultTemporalVersion`). */
2
+ /**
3
+ * The Temporal CLI version every channel runs: `stigmer up`, the all-in-one
4
+ * image, and the CI lanes and developer machines that install it with
5
+ * `make install-temporal-cli`. Bump it deliberately; it moves all of them.
6
+ */
3
7
  export declare const DEFAULT_TEMPORAL_VERSION = "1.5.1";
4
8
  /** The release's `sha256sum`-format digest file, one line per published asset. */
5
9
  export declare const TEMPORAL_CHECKSUMS_FILE = "checksums.txt";
@@ -14,6 +18,8 @@ export interface TemporalDownloadTarget {
14
18
  arch?: string;
15
19
  /** Override the fetch implementation (tests). */
16
20
  fetchImpl?: typeof fetch;
21
+ /** Override the wait between download attempts (tests). */
22
+ sleep?: (ms: number) => Promise<void>;
17
23
  }
18
24
  /** The release asset name for a version on a platform, as Temporal publishes it. */
19
25
  export declare function temporalArchiveName(version: string, platform: NodeJS.Platform, arch: string): string;
@@ -1 +1 @@
1
- {"version":3,"file":"download.d.ts","sourceRoot":"","sources":["../../../src/local/temporal/download.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEjD,oFAAoF;AACpF,eAAO,MAAM,wBAAwB,UAAU,CAAC;AAEhD,kFAAkF;AAClF,eAAO,MAAM,uBAAuB,kBAAkB,CAAC;AAEvD,MAAM,WAAW,sBAAsB;IACrC,0CAA0C;IAC1C,OAAO,EAAE,MAAM,CAAC;IAChB,iEAAiE;IACjE,OAAO,EAAE,MAAM,CAAC;IAChB,oDAAoD;IACpD,QAAQ,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC;IAC3B,4CAA4C;IAC5C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,iDAAiD;IACjD,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CAC1B;AAED,oFAAoF;AACpF,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAEpG;AAED,kEAAkE;AAClE,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAE9E;AAED,yEAAyE;AACzE,wBAAsB,mBAAmB,CAAC,MAAM,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAWvF;AAED,iEAAiE;AACjE,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAE5D"}
1
+ {"version":3,"file":"download.d.ts","sourceRoot":"","sources":["../../../src/local/temporal/download.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEjD;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,UAAU,CAAC;AAEhD,kFAAkF;AAClF,eAAO,MAAM,uBAAuB,kBAAkB,CAAC;AAEvD,MAAM,WAAW,sBAAsB;IACrC,0CAA0C;IAC1C,OAAO,EAAE,MAAM,CAAC;IAChB,iEAAiE;IACjE,OAAO,EAAE,MAAM,CAAC;IAChB,oDAAoD;IACpD,QAAQ,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC;IAC3B,4CAA4C;IAC5C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,iDAAiD;IACjD,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,2DAA2D;IAC3D,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC;AAED,oFAAoF;AACpF,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAEpG;AAED,kEAAkE;AAClE,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAE9E;AAED,yEAAyE;AACzE,wBAAsB,mBAAmB,CAAC,MAAM,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAYvF;AAED,iEAAiE;AACjE,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAE5D"}
@@ -15,7 +15,11 @@ import { fetchTarballBinary, mapReleaseArch, mapReleaseOs } from "../artifact.js
15
15
  // Re-exported so existing consumers (temporal/index.ts, download.test.ts) keep
16
16
  // importing the tar reader from here.
17
17
  export { extractTarEntry } from "../artifact.js";
18
- /** Default Temporal CLI version (matches the Go CLI's `DefaultTemporalVersion`). */
18
+ /**
19
+ * The Temporal CLI version every channel runs: `stigmer up`, the all-in-one
20
+ * image, and the CI lanes and developer machines that install it with
21
+ * `make install-temporal-cli`. Bump it deliberately; it moves all of them.
22
+ */
19
23
  export const DEFAULT_TEMPORAL_VERSION = "1.5.1";
20
24
  /** The release's `sha256sum`-format digest file, one line per published asset. */
21
25
  export const TEMPORAL_CHECKSUMS_FILE = "checksums.txt";
@@ -37,6 +41,7 @@ export async function downloadTemporalCli(target) {
37
41
  binPath: target.binPath,
38
42
  label: "Temporal CLI",
39
43
  fetchImpl: target.fetchImpl,
44
+ sleep: target.sleep,
40
45
  });
41
46
  }
42
47
  /** True if a Temporal binary is already present at `binPath`. */
@@ -1 +1 @@
1
- {"version":3,"file":"download.js","sourceRoot":"","sources":["../../../src/local/temporal/download.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,EAAE;AACF,8EAA8E;AAC9E,8EAA8E;AAC9E,uEAAuE;AACvE,mDAAmD;AACnD,EAAE;AACF,wEAAwE;AACxE,gFAAgF;AAChF,6EAA6E;AAC7E,+EAA+E;AAC/E,+EAA+E;AAE/E,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAElF,+EAA+E;AAC/E,sCAAsC;AACtC,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEjD,oFAAoF;AACpF,MAAM,CAAC,MAAM,wBAAwB,GAAG,OAAO,CAAC;AAEhD,kFAAkF;AAClF,MAAM,CAAC,MAAM,uBAAuB,GAAG,eAAe,CAAC;AAevD,oFAAoF;AACpF,MAAM,UAAU,mBAAmB,CAAC,OAAe,EAAE,QAAyB,EAAE,IAAY;IAC1F,OAAO,gBAAgB,OAAO,IAAI,YAAY,CAAC,QAAQ,CAAC,IAAI,cAAc,CAAC,IAAI,CAAC,SAAS,CAAC;AAC5F,CAAC;AAED,kEAAkE;AAClE,MAAM,UAAU,uBAAuB,CAAC,OAAe,EAAE,KAAa;IACpE,OAAO,wDAAwD,OAAO,IAAI,KAAK,EAAE,CAAC;AACpF,CAAC;AAED,yEAAyE;AACzE,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,MAA8B;IACtE,MAAM,OAAO,GAAG,mBAAmB,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,QAAQ,IAAI,OAAO,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEtH,MAAM,kBAAkB,CAAC;QACvB,GAAG,EAAE,uBAAuB,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC;QACrD,WAAW,EAAE,uBAAuB,CAAC,MAAM,CAAC,OAAO,EAAE,uBAAuB,CAAC;QAC7E,SAAS,EAAE,UAAU;QACrB,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,KAAK,EAAE,cAAc;QACrB,SAAS,EAAE,MAAM,CAAC,SAAS;KAC5B,CAAC,CAAC;AACL,CAAC;AAED,iEAAiE;AACjE,MAAM,UAAU,mBAAmB,CAAC,OAAe;IACjD,OAAO,UAAU,CAAC,OAAO,CAAC,CAAC;AAC7B,CAAC"}
1
+ {"version":3,"file":"download.js","sourceRoot":"","sources":["../../../src/local/temporal/download.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,EAAE;AACF,8EAA8E;AAC9E,8EAA8E;AAC9E,uEAAuE;AACvE,mDAAmD;AACnD,EAAE;AACF,wEAAwE;AACxE,gFAAgF;AAChF,6EAA6E;AAC7E,+EAA+E;AAC/E,+EAA+E;AAE/E,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAElF,+EAA+E;AAC/E,sCAAsC;AACtC,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEjD;;;;GAIG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,OAAO,CAAC;AAEhD,kFAAkF;AAClF,MAAM,CAAC,MAAM,uBAAuB,GAAG,eAAe,CAAC;AAiBvD,oFAAoF;AACpF,MAAM,UAAU,mBAAmB,CAAC,OAAe,EAAE,QAAyB,EAAE,IAAY;IAC1F,OAAO,gBAAgB,OAAO,IAAI,YAAY,CAAC,QAAQ,CAAC,IAAI,cAAc,CAAC,IAAI,CAAC,SAAS,CAAC;AAC5F,CAAC;AAED,kEAAkE;AAClE,MAAM,UAAU,uBAAuB,CAAC,OAAe,EAAE,KAAa;IACpE,OAAO,wDAAwD,OAAO,IAAI,KAAK,EAAE,CAAC;AACpF,CAAC;AAED,yEAAyE;AACzE,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,MAA8B;IACtE,MAAM,OAAO,GAAG,mBAAmB,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,QAAQ,IAAI,OAAO,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEtH,MAAM,kBAAkB,CAAC;QACvB,GAAG,EAAE,uBAAuB,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC;QACrD,WAAW,EAAE,uBAAuB,CAAC,MAAM,CAAC,OAAO,EAAE,uBAAuB,CAAC;QAC7E,SAAS,EAAE,UAAU;QACrB,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,KAAK,EAAE,cAAc;QACrB,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,KAAK,EAAE,MAAM,CAAC,KAAK;KACpB,CAAC,CAAC;AACL,CAAC;AAED,iEAAiE;AACjE,MAAM,UAAU,mBAAmB,CAAC,OAAe;IACjD,OAAO,UAAU,CAAC,OAAO,CAAC,CAAC;AAC7B,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stigmer/cli",
3
- "version": "3.32.0",
3
+ "version": "3.34.0",
4
4
  "description": "Stigmer command-line interface — manage agents, workflows, MCP servers, skills, and executions from the terminal",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -35,12 +35,12 @@
35
35
  "@connectrpc/connect": "^2.0.0",
36
36
  "@connectrpc/connect-node": "^2.1.1",
37
37
  "@modelcontextprotocol/sdk": "^1.26.0",
38
- "@stigmer/ink": "3.32.0",
39
- "@stigmer/mcp-server": "3.32.0",
40
- "@stigmer/plugin-package": "3.32.0",
41
- "@stigmer/protos": "3.32.0",
42
- "@stigmer/sdk": "3.32.0",
43
- "@stigmer/zip-structure": "3.32.0",
38
+ "@stigmer/ink": "3.34.0",
39
+ "@stigmer/mcp-server": "3.34.0",
40
+ "@stigmer/plugin-package": "3.34.0",
41
+ "@stigmer/protos": "3.34.0",
42
+ "@stigmer/sdk": "3.34.0",
43
+ "@stigmer/zip-structure": "3.34.0",
44
44
  "commander": "^12.1.0",
45
45
  "fflate": "^0.8.3",
46
46
  "ink": "^7.0.0",
@@ -8,10 +8,17 @@
8
8
  // second consumer until the server became an npm artifact.) The tar reader is a
9
9
  // tiny POSIX/ustar implementation: no native `tar` dependency, which keeps the
10
10
  // base install lean (DD-002).
11
+ //
12
+ // Retrying a transient failure is part of the contract. A connection that resets
13
+ // before or during the body, a 5xx or a 429 is tried again with a doubling wait,
14
+ // so a network blip does not fail a first `stigmer up`, a CI lane or an image
15
+ // build. Any other HTTP status and a checksum mismatch are answers: they fail at
16
+ // once.
11
17
 
12
18
  import { createHash } from "node:crypto";
13
19
  import { chmodSync, mkdirSync, writeFileSync } from "node:fs";
14
20
  import { dirname } from "node:path";
21
+ import { setTimeout as delay } from "node:timers/promises";
15
22
  import { gunzipSync } from "fflate";
16
23
  import { CliExitError } from "../errors/cli-exit-error.js";
17
24
  import { ExitCode } from "../errors/exit-codes.js";
@@ -59,21 +66,30 @@ export interface TarballBinarySource {
59
66
  label: string;
60
67
  /** Override the fetch implementation (tests). */
61
68
  fetchImpl?: typeof fetch;
69
+ /** Override the wait between download attempts (tests). */
70
+ sleep?: (ms: number) => Promise<void>;
62
71
  }
63
72
 
73
+ /** Attempts per download before a transient failure is reported. */
74
+ export const DOWNLOAD_ATTEMPTS = 4;
75
+
76
+ /** The wait before the second attempt; it doubles before each later one (1 s, 2 s, 4 s). */
77
+ export const DOWNLOAD_RETRY_BASE_DELAY_MS = 1_000;
78
+
64
79
  /**
65
80
  * Download a `.tar.gz`, optionally verify its sha256, extract the named entry,
66
- * and write it to `binPath` with executable permissions. Throws a
67
- * {@link CliExitError} with the URL on any network, checksum, or extraction
68
- * failure.
81
+ * and write it to `binPath` with executable permissions. Transient network
82
+ * failures are retried (see the module header). Throws a {@link CliExitError}
83
+ * with the URL on a persistent network failure, a non-transient HTTP status, a
84
+ * checksum mismatch, or an extraction failure.
69
85
  */
70
86
  export async function fetchTarballBinary(src: TarballBinarySource): Promise<void> {
71
- const doFetch = src.fetchImpl ?? fetch;
72
- const archive = await fetchBytes(doFetch, src.url, src.label);
87
+ const net: Download = { doFetch: src.fetchImpl ?? fetch, sleep: src.sleep ?? delay };
88
+ const archive = await fetchBytes(net, src.url, src.label);
73
89
 
74
90
  if (src.checksumUrl !== undefined) {
75
91
  const archiveName = archiveBasename(src.url);
76
- const expected = parseShasum(await fetchText(doFetch, src.checksumUrl, `${src.label} checksum`), archiveName);
92
+ const expected = parseShasum(await fetchText(net, src.checksumUrl, `${src.label} checksum`), archiveName);
77
93
  const actual = sha256Hex(archive);
78
94
  if (expected === "" || expected !== actual) {
79
95
  throw new CliExitError(`${src.label} checksum mismatch — refusing to use the download`, ExitCode.General, [
@@ -102,27 +118,69 @@ export function sha256Hex(bytes: Uint8Array): string {
102
118
  return createHash("sha256").update(bytes).digest("hex");
103
119
  }
104
120
 
105
- async function fetchBytes(doFetch: typeof fetch, url: string, label: string): Promise<Uint8Array> {
106
- const res = await doFetchOrThrow(doFetch, url, label);
107
- return new Uint8Array(await res.arrayBuffer());
121
+ // The network a download runs over: the fetch it calls and the wait between attempts.
122
+ interface Download {
123
+ doFetch: typeof fetch;
124
+ sleep: (ms: number) => Promise<void>;
108
125
  }
109
126
 
110
- async function fetchText(doFetch: typeof fetch, url: string, label: string): Promise<string> {
111
- const res = await doFetchOrThrow(doFetch, url, label);
112
- return res.text();
127
+ async function fetchBytes(net: Download, url: string, label: string): Promise<Uint8Array> {
128
+ return fetchWithRetry(net, url, label, async (res) => new Uint8Array(await res.arrayBuffer()));
113
129
  }
114
130
 
115
- async function doFetchOrThrow(doFetch: typeof fetch, url: string, label: string): Promise<Response> {
116
- let res: Response;
117
- try {
118
- res = await doFetch(url);
119
- } catch (err) {
120
- throw new CliExitError(`failed to download ${label} from ${url}`, ExitCode.General, [String(err)]);
121
- }
122
- if (!res.ok) {
123
- throw new CliExitError(`failed to download ${label}: HTTP ${res.status} from ${url}`, ExitCode.General);
131
+ async function fetchText(net: Download, url: string, label: string): Promise<string> {
132
+ return fetchWithRetry(net, url, label, (res) => res.text());
133
+ }
134
+
135
+ // One download, with its body read inside the attempt: a connection that drops
136
+ // after the headers is as transient as one that never connects, and is retried
137
+ // the same way. The error after the last attempt carries the last failure's
138
+ // cause, which for Node's fetch is the socket error behind "fetch failed".
139
+ async function fetchWithRetry<T>(
140
+ net: Download,
141
+ url: string,
142
+ label: string,
143
+ read: (res: Response) => Promise<T>,
144
+ ): Promise<T> {
145
+ let lastFailure = "";
146
+ for (let attempt = 1; attempt <= DOWNLOAD_ATTEMPTS; attempt++) {
147
+ if (attempt > 1) await net.sleep(DOWNLOAD_RETRY_BASE_DELAY_MS * 2 ** (attempt - 2));
148
+
149
+ let res: Response;
150
+ try {
151
+ res = await net.doFetch(url);
152
+ } catch (err) {
153
+ lastFailure = describeFailure(err);
154
+ continue;
155
+ }
156
+ if (!res.ok) {
157
+ if (!isTransientStatus(res.status)) {
158
+ throw new CliExitError(`failed to download ${label}: HTTP ${res.status} from ${url}`, ExitCode.General);
159
+ }
160
+ lastFailure = `HTTP ${res.status}`;
161
+ continue;
162
+ }
163
+ try {
164
+ return await read(res);
165
+ } catch (err) {
166
+ lastFailure = describeFailure(err);
167
+ }
124
168
  }
125
- return res;
169
+ throw new CliExitError(
170
+ `failed to download ${label} from ${url} after ${DOWNLOAD_ATTEMPTS} attempts: ${lastFailure}`,
171
+ ExitCode.General,
172
+ ["check the network connection, then run the command again"],
173
+ );
174
+ }
175
+
176
+ // A server error or a rate limit may clear on its own; any other status will not.
177
+ function isTransientStatus(status: number): boolean {
178
+ return status >= 500 || status === 429;
179
+ }
180
+
181
+ function describeFailure(err: unknown): string {
182
+ if (!(err instanceof Error)) return String(err);
183
+ return err.cause instanceof Error ? `${err.message}: ${err.cause.message}` : err.message;
126
184
  }
127
185
 
128
186
  /**
@@ -1,9 +1,17 @@
1
+ // The Temporal CLI download end to end over a scripted `fetch`: asset naming,
2
+ // verification against the release's checksums.txt, extraction, and the retry
3
+ // contract `../artifact.ts` gives every release download. The retry cases pin
4
+ // which failures are transient (a dropped connection before or during the body,
5
+ // a 5xx, a 429) and which are answers (a 404, a bad digest), the backoff, and
6
+ // the error a persistent failure ends in. A recording `sleep` keeps them instant.
7
+
1
8
  import { createHash } from "node:crypto";
2
9
  import { existsSync, mkdtempSync, readFileSync } from "node:fs";
3
10
  import { tmpdir } from "node:os";
4
11
  import { join } from "node:path";
5
12
  import { gzipSync } from "fflate";
6
13
  import { describe, expect, it } from "vitest";
14
+ import { CliExitError } from "../../errors/cli-exit-error.js";
7
15
  import {
8
16
  TEMPORAL_CHECKSUMS_FILE,
9
17
  downloadTemporalCli,
@@ -130,3 +138,111 @@ describe("downloadTemporalCli", () => {
130
138
  await expect(downloadTemporalCli({ version: "9.9.9", binPath, fetchImpl })).rejects.toThrow(/HTTP 404/);
131
139
  });
132
140
  });
141
+
142
+ type Failure = "reject" | "body" | number;
143
+
144
+ // Wraps a release so requests for one asset fail as scripted before the real
145
+ // release answers: each entry of `failures` is consumed by one request for
146
+ // `asset`. "reject" is a connection that never answers (Node's fetch rejects
147
+ // with the socket error as `cause`), "body" one that drops after the headers,
148
+ // a number an HTTP status. `calls` counts the requests for `asset`.
149
+ function flaky(inner: typeof fetch, asset: string, failures: Failure[]): { fetchImpl: typeof fetch; calls: () => number } {
150
+ let calls = 0;
151
+ const fetchImpl = (async (input: string | URL | Request) => {
152
+ const url = String(input);
153
+ if (!url.endsWith(`/${asset}`)) return inner(input);
154
+ calls += 1;
155
+ const failure = failures[calls - 1];
156
+ if (failure === "reject") throw new TypeError("fetch failed", { cause: new Error("read ECONNRESET") });
157
+ if (failure === "body") {
158
+ return {
159
+ ok: true,
160
+ status: 200,
161
+ arrayBuffer: async () => {
162
+ throw new TypeError("terminated", { cause: new Error("other side closed") });
163
+ },
164
+ } as unknown as Response;
165
+ }
166
+ if (typeof failure === "number") {
167
+ return { ok: false, status: failure, arrayBuffer: async () => new ArrayBuffer(0) } as unknown as Response;
168
+ }
169
+ return inner(input);
170
+ }) as unknown as typeof fetch;
171
+ return { fetchImpl, calls: () => calls };
172
+ }
173
+
174
+ describe("downloadTemporalCli over an unreliable network", () => {
175
+ const linuxArm = temporalArchiveName("1.5.1", "linux", "arm64");
176
+ const arm = archiveFor(Buffer.from("the-arm64-binary"));
177
+ const good = release("1.5.1", { [linuxArm]: arm }, `${sha256(arm)} ${linuxArm}\n`);
178
+
179
+ function install(fetchImpl: typeof fetch): { binPath: string; delays: number[]; run: Promise<void> } {
180
+ const binPath = join(mkdtempSync(join(tmpdir(), "stigmer-temporal-")), "temporal");
181
+ const delays: number[] = [];
182
+ const sleep = async (ms: number): Promise<void> => {
183
+ delays.push(ms);
184
+ };
185
+ const run = downloadTemporalCli({ version: "1.5.1", binPath, platform: "linux", arch: "arm64", fetchImpl, sleep });
186
+ return { binPath, delays, run };
187
+ }
188
+
189
+ it("retries a connection that never answers, then installs the verified binary", async () => {
190
+ const net = flaky(good, linuxArm, ["reject"]);
191
+ const { binPath, delays, run } = install(net.fetchImpl);
192
+ await run;
193
+ expect(readFileSync(binPath, "utf8")).toBe("the-arm64-binary");
194
+ expect(net.calls()).toBe(2);
195
+ expect(delays).toEqual([1000]);
196
+ });
197
+
198
+ it("retries a connection that drops after the headers", async () => {
199
+ const net = flaky(good, linuxArm, ["body"]);
200
+ const { binPath, run } = install(net.fetchImpl);
201
+ await run;
202
+ expect(readFileSync(binPath, "utf8")).toBe("the-arm64-binary");
203
+ expect(net.calls()).toBe(2);
204
+ });
205
+
206
+ it("retries a 5xx and a 429, doubling the wait", async () => {
207
+ const net = flaky(good, linuxArm, [503, 429]);
208
+ const { binPath, delays, run } = install(net.fetchImpl);
209
+ await run;
210
+ expect(readFileSync(binPath, "utf8")).toBe("the-arm64-binary");
211
+ expect(net.calls()).toBe(3);
212
+ expect(delays).toEqual([1000, 2000]);
213
+ });
214
+
215
+ it("retries the checksums.txt fetch the same way", async () => {
216
+ const net = flaky(good, TEMPORAL_CHECKSUMS_FILE, ["reject"]);
217
+ const { binPath, run } = install(net.fetchImpl);
218
+ await run;
219
+ expect(readFileSync(binPath, "utf8")).toBe("the-arm64-binary");
220
+ expect(net.calls()).toBe(2);
221
+ });
222
+
223
+ it("takes a 404 as the answer and does not retry it", async () => {
224
+ const net = flaky(good, linuxArm, [404]);
225
+ const { delays, run } = install(net.fetchImpl);
226
+ await expect(run).rejects.toThrow(/HTTP 404/);
227
+ expect(net.calls()).toBe(1);
228
+ expect(delays).toEqual([]);
229
+ });
230
+
231
+ it("gives up after four attempts, saying what failed and what to do", async () => {
232
+ const net = flaky(good, linuxArm, ["reject", "reject", "reject", "reject"]);
233
+ const { binPath, delays, run } = install(net.fetchImpl);
234
+ const err: unknown = await run.then(
235
+ () => undefined,
236
+ (e: unknown) => e,
237
+ );
238
+ expect(err).toBeInstanceOf(CliExitError);
239
+ const exit = err as CliExitError;
240
+ expect(exit.message).toBe(
241
+ `failed to download Temporal CLI from ${temporalReleaseAssetUrl("1.5.1", linuxArm)} after 4 attempts: fetch failed: read ECONNRESET`,
242
+ );
243
+ expect(exit.hints).toEqual(["check the network connection, then run the command again"]);
244
+ expect(net.calls()).toBe(4);
245
+ expect(delays).toEqual([1000, 2000, 4000]);
246
+ expect(existsSync(binPath)).toBe(false);
247
+ });
248
+ });
@@ -18,7 +18,11 @@ import { fetchTarballBinary, mapReleaseArch, mapReleaseOs } from "../artifact.js
18
18
  // importing the tar reader from here.
19
19
  export { extractTarEntry } from "../artifact.js";
20
20
 
21
- /** Default Temporal CLI version (matches the Go CLI's `DefaultTemporalVersion`). */
21
+ /**
22
+ * The Temporal CLI version every channel runs: `stigmer up`, the all-in-one
23
+ * image, and the CI lanes and developer machines that install it with
24
+ * `make install-temporal-cli`. Bump it deliberately; it moves all of them.
25
+ */
22
26
  export const DEFAULT_TEMPORAL_VERSION = "1.5.1";
23
27
 
24
28
  /** The release's `sha256sum`-format digest file, one line per published asset. */
@@ -35,6 +39,8 @@ export interface TemporalDownloadTarget {
35
39
  arch?: string;
36
40
  /** Override the fetch implementation (tests). */
37
41
  fetchImpl?: typeof fetch;
42
+ /** Override the wait between download attempts (tests). */
43
+ sleep?: (ms: number) => Promise<void>;
38
44
  }
39
45
 
40
46
  /** The release asset name for a version on a platform, as Temporal publishes it. */
@@ -58,6 +64,7 @@ export async function downloadTemporalCli(target: TemporalDownloadTarget): Promi
58
64
  binPath: target.binPath,
59
65
  label: "Temporal CLI",
60
66
  fetchImpl: target.fetchImpl,
67
+ sleep: target.sleep,
61
68
  });
62
69
  }
63
70