@link-assistant/hive-mind 2.12.4 → 2.13.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.
@@ -2,6 +2,7 @@
2
2
 
3
3
  import { retryLimits } from './config.lib.mjs';
4
4
  import { resolveDefaultFallbackModel, resolveModelId } from './models/index.mjs';
5
+ import { detectSubscriptionError, isTransientAuthError } from './subscription-error.lib.mjs';
5
6
 
6
7
  const normalizeMessage = value => {
7
8
  if (value === null || value === undefined) return '';
@@ -27,6 +28,34 @@ export const classifyRetryableError = value => {
27
28
  const message = normalizeMessage(value);
28
29
  const lower = message.toLowerCase();
29
30
 
31
+ // Issue #2161: account/subscription-level blocks ("Your organization has
32
+ // disabled Claude subscription access for Claude Code", "You do not have
33
+ // access to Codex", revoked OAuth tokens, expired subscriptions, …). These are
34
+ // terminal by nature: the credentials themselves are no longer accepted, so
35
+ // neither a backoff nor a different model can recover — the run must stop and
36
+ // the operator must restore access. isCapacity stays false so
37
+ // maybeSwitchToFallbackModel() never burns a fallback hop on them.
38
+ //
39
+ // Checked first, because several of these messages contain words ("timed
40
+ // out", "rate", "503") that later transient branches would otherwise claim.
41
+ // detectSubscriptionError() itself excludes provider errors that are
42
+ // explicitly described as temporary — see isTransientAuthError below.
43
+ const subscriptionError = detectSubscriptionError(message);
44
+ if (subscriptionError) {
45
+ return { message, isRetryable: false, isCapacity: false, isSubscriptionError: true, subscriptionError, label: 'subscription access blocked' };
46
+ }
47
+
48
+ // Issue #2161: the counterpart — Claude Code's own wording marks this
49
+ // authentication failure as temporary ("This may be a temporary network
50
+ // issue, please try again"). Without an explicit branch it would fall through
51
+ // to the non-retryable default and abort a run that a retry would have saved.
52
+ // The `auth` guard keeps purely network-level members of that list (e.g.
53
+ // "Temporary failure in name resolution") on their own, more specific branches
54
+ // below — this branch only claims the *authentication* wordings.
55
+ if (isTransientAuthError(lower) && lower.includes('auth')) {
56
+ return { message, isRetryable: true, isCapacity: false, label: 'Transient authentication/network error' };
57
+ }
58
+
30
59
  // Genuine model-specific capacity: the API explicitly tells us this *particular*
31
60
  // model is full and recommends trying a *different* model (e.g. Codex's
32
61
  // "Selected model is at capacity. Please try a different model."). Here a model