@cortexkit/pi-anthropic-auth 2.4.2 → 2.4.4

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/native.d.ts CHANGED
@@ -67,7 +67,7 @@ export declare class PiNativeRuntime {
67
67
  view(signal?: AbortSignal): Promise<NativeAccountSnapshot>;
68
68
  /** Admit a model request without rediscovering a healthy roster. */
69
69
  requestView(signal?: AbortSignal): Promise<NativeAccountSnapshot>;
70
- authorize(routeId: string, signal?: AbortSignal, modelId?: string): Promise<PiNativeAttempt>;
70
+ authorize(routeId: string, signal?: AbortSignal, modelId?: string, intent?: 'serve' | 'cachekeep'): Promise<PiNativeAttempt>;
71
71
  retry(routeId: string, served: PiNativeAttempt, signal?: AbortSignal, modelId?: string): Promise<PiNativeAttempt | undefined>;
72
72
  report(served: PiNativeAttempt, status: number, source: NativeCustodyReporterSource): Promise<void>;
73
73
  markUsed(served: PiNativeAttempt, servingRuntime?: NativeAccountRuntime): Promise<void>;
package/dist/native.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { resolve } from 'node:path';
2
- import { acquireNativeAccountRuntime, createNativeUsagePublisher, decidePiStateLayout, getAccountStatePath, getHostClaustrumEnrollmentPaths, isKillswitchEnabled, killswitchPassesPolicy, LEGACY_STATE_LAYOUT, logger, nativeAccountCanServe, nativeMigrationAuthorityPhase, nativeRuntimeOptionIdentity, quotaSnapshotHasStandardWindows, quotaSnapshotPassesModelScope, quotaSnapshotPassesPolicy, readNativeAccountsForRequest, readNativeMigrationJournal, resolveClaustrumConnectionPath, resolveLocalRoutingDestination, resolveNativePoolPaths, } from '@cortexkit/anthropic-auth-core';
2
+ import { acquireNativeAccountRuntime, createNativeUsagePublisher, decidePiStateLayout, getAccountStatePath, getHostClaustrumEnrollmentPaths, getPersistedLogLevel, isKillswitchEnabled, killswitchPassesPolicy, LEGACY_STATE_LAYOUT, logger, NativeAccountRefusal, nativeAccountCanServe, nativeAccountRefusal, nativeLocalAccountRefusal, nativeMigrationAuthorityPhase, nativeRuntimeOptionIdentity, quotaSnapshotHasStandardWindows, quotaSnapshotPassesModelScope, quotaSnapshotPassesPolicy, readNativeAccountsForRequest, readNativeMigrationJournal, resolveClaustrumConnectionPath, resolveLocalRoutingDestination, resolveNativePoolPaths, setLogLevel, } from '@cortexkit/anthropic-auth-core';
3
3
  import { getPiAccountStoragePath, getPiClaustrumConnectionOptions, getPiConfigDir, requirePiNativeHostAuth, } from './paths.js';
4
4
  export function piAttemptAccessToken(attempt) {
5
5
  return attempt.source === 'vault'
@@ -125,6 +125,14 @@ export class PiNativeRuntime {
125
125
  identity,
126
126
  },
127
127
  });
128
+ // Apply local or vault preferences before the watcher can log. Match
129
+ // OpenCode's startup precedence without blocking migration refusals.
130
+ try {
131
+ const initial = await runtime.read();
132
+ if (!env.OPENCODE_ANTHROPIC_AUTH_LOG_LEVEL)
133
+ setLogLevel(getPersistedLogLevel(initial.policyStorage) ?? 'info');
134
+ }
135
+ catch { }
128
136
  if (this.closed)
129
137
  runtime.close();
130
138
  // Refresh returns at once while this host uses local accounts, so the
@@ -206,19 +214,31 @@ export class PiNativeRuntime {
206
214
  const runtime = await this.service();
207
215
  return readNativeAccountsForRequest(runtime, signal);
208
216
  }
209
- async authorize(routeId, signal, modelId) {
217
+ async authorize(routeId, signal, modelId, intent = 'serve') {
218
+ const background = intent === 'cachekeep';
210
219
  const runtime = await this.service();
211
220
  const snapshot = await runtime.read();
212
221
  const account = snapshot.accounts.find((candidate) => candidate.id === routeId);
213
222
  if (!nativeAccountCanServe(account) || account?.type !== 'oauth')
214
- throw new Error('Pi native OAuth route is unavailable');
223
+ throw background
224
+ ? new NativeAccountRefusal('account-unavailable')
225
+ : new Error('Pi native OAuth route is unavailable');
215
226
  const policy = requestPolicy(routeId, modelId);
216
227
  if (policy(account, snapshot).status === 'blocked')
217
- throw new Error('Pi native quota policy refused the OAuth route');
228
+ throw background
229
+ ? new NativeAccountRefusal('account-policy')
230
+ : new Error('Pi native quota policy refused the OAuth route');
218
231
  if (snapshot.mode === 'claustrum') {
219
- const receipt = await runtime.authorizeVault(routeId, signal);
232
+ const receipt = await runtime
233
+ .authorizeVault(routeId, signal)
234
+ .catch((error) => {
235
+ const refusal = background && nativeAccountRefusal(error);
236
+ throw refusal || error;
237
+ });
220
238
  if (!receipt.assertedAccountIdentity)
221
- throw new Error('Pi native OAuth identity is unasserted');
239
+ throw background
240
+ ? new NativeAccountRefusal('account-unavailable')
241
+ : new Error('Pi native OAuth identity is unasserted');
222
242
  const current = await runtime.read();
223
243
  const admitted = current.accounts.find((candidate) => candidate.id === routeId);
224
244
  // After the vault lookup, recheck quota limits for this request’s model.
@@ -227,7 +247,13 @@ export class PiNativeRuntime {
227
247
  current.mode !== 'claustrum' ||
228
248
  admitted.accountIdentity !== receipt.assertedAccountIdentity ||
229
249
  requestPolicy(routeId, modelId)(admitted, current).status === 'blocked')
230
- throw new Error('Pi native quota policy refused the OAuth route');
250
+ throw background
251
+ ? new NativeAccountRefusal(!admitted || current.mode !== 'claustrum'
252
+ ? 'account-unavailable'
253
+ : admitted.accountIdentity !== receipt.assertedAccountIdentity
254
+ ? 'credential-changed'
255
+ : 'account-policy')
256
+ : new Error('Pi native quota policy refused the OAuth route');
231
257
  return {
232
258
  source: 'vault',
233
259
  accountIdentity: receipt.assertedAccountIdentity,
@@ -235,8 +261,16 @@ export class PiNativeRuntime {
235
261
  };
236
262
  }
237
263
  const admission = await runtime.authorizeLocal(routeId, { signal, policy });
238
- if (admission.status !== 'usable' || !admission.binding.identity)
264
+ if (admission.status !== 'usable') {
265
+ const refusal = background && nativeLocalAccountRefusal(admission);
266
+ if (refusal)
267
+ throw refusal;
239
268
  throw new Error('Pi native OAuth admission refused');
269
+ }
270
+ if (!admission.binding.identity)
271
+ throw background
272
+ ? new NativeAccountRefusal('account-unavailable')
273
+ : new Error('Pi native OAuth admission refused');
240
274
  return {
241
275
  source: 'local',
242
276
  accountIdentity: admission.binding.identity,
package/dist/stream.js CHANGED
@@ -1,4 +1,4 @@
1
- import { applyClaudeCodeHeaders, applyCustomHeaders, CACHE_KEEP_EXTENDED_TTL_BETA, CacheKeepManager, CacheKeepSessionRegistry, createProviderErrorResponseScope, createSseFramer, createStickyNoRouteResponse, decideStickyQuotaFailure, decodeSseFrame, dumpDirectRequest, FAST_MODE_BETA, getCache1hPersistentMode, getClaudeCodeIdentityForVerifiedAccount, getDefaultCacheKeepRegistryDirectory, getFallbackReauthLabels, getQuotaCheckIntervalMs, getRequestGzipLatch, getRequestGzipLatchPath, getRoutingMode, getScopedQuotaWindowForModel, getThinkingPrefixMismatchBehavior, isCache1hPersistentlyEnabled, isCacheKeepHybridActive, isDumpPersistentlyEnabled, isFastModePersistentlyEnabled, isKillswitchEnabled, isNativeTransientAccountError, isOAuthAccount, isPermanentRefreshError, isValidApiBaseURL, killswitchPassesPolicy, logger, mergeAnthropicBetas, NativeVaultNoAccountError, nativeAccountCanServe, parseSseFrame, QuotaManager, quotaBackoffActive, quotaSnapshotHasStandardWindows, quotaSnapshotModelScopeIsExhausted, quotaSnapshotPassesModelScope, quotaSnapshotPassesPolicy, STICKY_ROUTING_MAIN_ACCOUNT_ID, StickySessionRouter, sendViaRelay, sendWithRequestGzip, setDumpEnabled, shouldFallbackStatus, stickyQuotaSnapshotIsFresh, stickyRetryAfterWithJitter, stickyRouteFamilyForModel, } from '@cortexkit/anthropic-auth-core';
1
+ import { applyClaudeCodeHeaders, applyCustomHeaders, CACHE_KEEP_EXTENDED_TTL_BETA, CacheKeepManager, CacheKeepSessionRegistry, createProviderErrorResponseScope, createSseFramer, createStickyNoRouteResponse, decideStickyQuotaFailure, decodeSseFrame, dumpDirectRequest, FAST_MODE_BETA, getCache1hPersistentMode, getClaudeCodeIdentityForVerifiedAccount, getDefaultCacheKeepRegistryDirectory, getFallbackReauthLabels, getQuotaCheckIntervalMs, getRequestGzipLatch, getRequestGzipLatchPath, getRoutingMode, getScopedQuotaWindowForModel, getThinkingPrefixMismatchBehavior, isCache1hPersistentlyEnabled, isCacheKeepHybridActive, isDumpPersistentlyEnabled, isFastModePersistentlyEnabled, isKillswitchEnabled, isNativeTransientAccountError, isOAuthAccount, isPermanentRefreshError, isValidApiBaseURL, killswitchPassesPolicy, logger, mergeAnthropicBetas, NativeAccountRefusal, NativeVaultNoAccountError, nativeAccountCanServe, parseSseFrame, QuotaManager, quotaBackoffActive, quotaSnapshotHasStandardWindows, quotaSnapshotModelScopeIsExhausted, quotaSnapshotPassesModelScope, quotaSnapshotPassesPolicy, STICKY_ROUTING_MAIN_ACCOUNT_ID, StickySessionRouter, sendViaRelay, sendWithRequestGzip, setDumpEnabled, shouldFallbackStatus, stickyQuotaSnapshotIsFresh, stickyRetryAfterWithJitter, stickyRouteFamilyForModel, } from '@cortexkit/anthropic-auth-core';
2
2
  import { calculateCost, createAssistantMessageEventStream, } from '@earendil-works/pi-ai';
3
3
  import { buildAnthropicRequest, fromClaudeCodeToolName } from './convert.js';
4
4
  import { getPiNativeRuntime, piAttemptAccessToken, } from './native.js';
@@ -164,10 +164,10 @@ const cacheKeepManager = new CacheKeepManager({
164
164
  const id = target.oauthAccountId ?? STICKY_ROUTING_MAIN_ACCOUNT_ID;
165
165
  const current = await runtime.view();
166
166
  const body = JSON.parse(target.bodyText);
167
- const served = await runtime.authorize(id, attempt.signal, typeof body.model === 'string' ? body.model : undefined);
167
+ const served = await runtime.authorize(id, attempt.signal, typeof body.model === 'string' ? body.model : undefined, 'cachekeep');
168
168
  if (!target.oauthAccountIdentity ||
169
169
  served.accountIdentity !== target.oauthAccountIdentity)
170
- throw new Error('CacheKeep account identity changed');
170
+ throw new NativeAccountRefusal('credential-changed');
171
171
  const identity = getClaudeCodeIdentityForVerifiedAccount(id === STICKY_ROUTING_MAIN_ACCOUNT_ID
172
172
  ? (current.policyStorage.mainAccountId ?? id)
173
173
  : id, served.accountIdentity);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cortexkit/pi-anthropic-auth",
3
- "version": "2.4.2",
3
+ "version": "2.4.4",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
@@ -36,7 +36,7 @@
36
36
  "prepublishOnly": "bun run build"
37
37
  },
38
38
  "dependencies": {
39
- "@cortexkit/anthropic-auth-core": "2.4.2"
39
+ "@cortexkit/anthropic-auth-core": "2.4.4"
40
40
  },
41
41
  "peerDependencies": {
42
42
  "@earendil-works/pi-ai": ">=0.86.1 <2",