@link-assistant/hive-mind 2.15.1 → 2.16.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.
@@ -75,11 +75,25 @@ export const GITHUB_SERVER_TRANSIENT_PATTERNS = Object.freeze([
75
75
  */
76
76
  export const GIT_TRANSIENT_PATTERNS = Object.freeze(['unexpected disconnect', 'sideband', 'early eof', 'the remote end hung up', 'remote end hung up unexpectedly', 'rpc failed', 'fetch-pack', 'index-pack failed', 'transfer closed', 'unable to access', 'could not read from remote repository', 'failed to connect to github.com', 'operation timed out after', 'gnutls_handshake() failed', 'the requested url returned error: 5']);
77
77
 
78
+ /**
79
+ * GitHub throttling *anonymous* git downloads (issue #2192):
80
+ *
81
+ * fatal: remote error: GitHub is temporarily limiting some unauthenticated
82
+ * downloads to protect the stability of the platform. Please retry later or
83
+ * authenticate.
84
+ *
85
+ * Retryable — GitHub itself says "retry later" — but the *real* fix is to
86
+ * authenticate, which `src/git-auth-transport.lib.mjs` does before retrying.
87
+ * Kept as its own category so a run that hits this is never diagnosed as a
88
+ * generic network fault (the failing run reported "Unknown error" three times).
89
+ */
90
+ export const ANONYMOUS_DOWNLOAD_LIMIT_PATTERNS = Object.freeze(['temporarily limiting some unauthenticated downloads', 'limiting some unauthenticated downloads', 'please retry later or authenticate', 'retry later or authenticate']);
91
+
78
92
  /**
79
93
  * Union used by the general-purpose `isTransientNetworkError` helpers. Kept as
80
94
  * a single flat list so a caller cannot accidentally miss a category.
81
95
  */
82
- export const ALL_TRANSIENT_PATTERNS = Object.freeze([...NETWORK_TRANSIENT_PATTERNS, ...GITHUB_SERVER_TRANSIENT_PATTERNS, ...GIT_TRANSIENT_PATTERNS]);
96
+ export const ALL_TRANSIENT_PATTERNS = Object.freeze([...NETWORK_TRANSIENT_PATTERNS, ...GITHUB_SERVER_TRANSIENT_PATTERNS, ...GIT_TRANSIENT_PATTERNS, ...ANONYMOUS_DOWNLOAD_LIMIT_PATTERNS]);
83
97
 
84
98
  /**
85
99
  * Pull every plausible string out of an error-ish value so pattern matches
@@ -126,6 +140,15 @@ const matchPattern = (error, patterns) => {
126
140
  */
127
141
  export const isTransientNetworkError = error => matchPattern(error, ALL_TRANSIENT_PATTERNS) !== null;
128
142
 
143
+ /**
144
+ * True when `error` is GitHub refusing an *unauthenticated* git download.
145
+ * The remedy is to authenticate the transport, not merely to wait.
146
+ *
147
+ * @param {unknown} error
148
+ * @returns {boolean}
149
+ */
150
+ export const isAnonymousDownloadLimit = error => matchPattern(error, ANONYMOUS_DOWNLOAD_LIMIT_PATTERNS) !== null;
151
+
129
152
  /**
130
153
  * True when `error` is a GitHub server-side fault (5xx or GraphQL internal).
131
154
  * Narrower than `isTransientNetworkError` — used for logging/classification.
@@ -174,7 +197,7 @@ export const parseGitHubRequestId = error => {
174
197
  * Full classification of a failure, for retry decisions *and* for diagnostics.
175
198
  *
176
199
  * @param {unknown} error
177
- * @returns {{transient: boolean, category: 'network'|'github-server'|'git-transport'|null, matchedPattern: string|null, requestId: string|null, text: string}}
200
+ * @returns {{transient: boolean, category: 'network'|'github-server'|'git-transport'|'github-anonymous-rate-limit'|null, matchedPattern: string|null, requestId: string|null, text: string}}
178
201
  */
179
202
  export const describeTransientError = error => {
180
203
  const text = collectErrorText(error);
@@ -184,10 +207,16 @@ export const describeTransientError = error => {
184
207
  const networkPattern = find(NETWORK_TRANSIENT_PATTERNS);
185
208
  const serverPattern = find(GITHUB_SERVER_TRANSIENT_PATTERNS);
186
209
  const gitPattern = find(GIT_TRANSIENT_PATTERNS);
210
+ const anonymousPattern = find(ANONYMOUS_DOWNLOAD_LIMIT_PATTERNS);
187
211
 
188
212
  let category = null;
189
213
  let matchedPattern = null;
190
- if (networkPattern) {
214
+ if (anonymousPattern) {
215
+ // Checked first: this failure has a specific remedy (authenticate) and its
216
+ // text also mentions timeouts/retries that the other lists could match.
217
+ category = 'github-anonymous-rate-limit';
218
+ matchedPattern = anonymousPattern;
219
+ } else if (networkPattern) {
191
220
  category = 'network';
192
221
  matchedPattern = networkPattern;
193
222
  } else if (serverPattern) {
@@ -224,11 +253,13 @@ export const formatTransientDiagnostics = description => {
224
253
  };
225
254
 
226
255
  export default {
256
+ ANONYMOUS_DOWNLOAD_LIMIT_PATTERNS,
227
257
  NETWORK_TRANSIENT_PATTERNS,
228
258
  GITHUB_SERVER_TRANSIENT_PATTERNS,
229
259
  GIT_TRANSIENT_PATTERNS,
230
260
  ALL_TRANSIENT_PATTERNS,
231
261
  collectErrorText,
262
+ isAnonymousDownloadLimit,
232
263
  isTransientNetworkError,
233
264
  isGitHubServerError,
234
265
  matchTransientPattern,