@cortexkit/opencode-anthropic-auth 1.19.1 → 1.21.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.
- package/README.md +119 -2
- package/dist/cache-diagnostics.d.ts +79 -0
- package/dist/cli.js +2 -2
- package/dist/index-1db17bc2.js +2 -0
- package/dist/{index-dex8fs0m.js → index-4nz423bt.js} +1 -1
- package/dist/{index-dzs7w297.js → index-4x20896x.js} +1 -1
- package/dist/{index-2k47hc8b.js → index-w9d41yy9.js} +1 -1
- package/dist/index-wezdyxst.js +2 -0
- package/dist/{index-075t8qec.js → index-y0khnbt6.js} +1 -1
- package/dist/index-yskwj5e6.js +428 -0
- package/dist/index.d.ts +0 -37
- package/dist/index.js +23 -19
- package/dist/lane-start.d.ts +17 -0
- package/dist/{logger-n49md99d.js → logger-ftk4bg3p.js} +1 -1
- package/dist/prime-manager-registry.d.ts +7 -0
- package/dist/request-policy.d.ts +25 -0
- package/dist/rpc/port-file.js +1 -1
- package/dist/rpc/protocol.d.ts +2 -1
- package/dist/rpc/protocol.js +1 -0
- package/dist/rpc/rpc-client.js +1 -1
- package/dist/rpc/rpc-dir.js +1 -1
- package/dist/server-fallback.d.ts +2 -0
- package/dist/sidebar-state.d.ts +26 -1
- package/dist/sidebar-state.js +1 -1
- package/dist/transform.d.ts +13 -0
- package/dist/tui/command-dialogs.d.ts +16 -1
- package/dist/tui-preferences.js +1 -1
- package/package.json +4 -4
- package/src/rpc/protocol.ts +15 -10
- package/src/sidebar-state.ts +154 -17
- package/src/tui/command-dialogs.tsx +112 -0
- package/src/tui-compiled/rpc/protocol.ts +15 -10
- package/src/tui-compiled/sidebar-state.ts +154 -17
- package/src/tui-compiled/tui/command-dialogs.tsx +134 -18
- package/src/tui-compiled/tui.tsx +43 -1
- package/src/tui.tsx +28 -0
- package/dist/index-a13w4gm9.js +0 -2
- package/dist/index-vwgzgh5x.js +0 -422
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export declare const LANE_START_TEXT = "[lane start] \u2014 automated cache warm; no response needed.";
|
|
2
|
+
export declare const LANE_START_REQUEST_HEADER = "x-cortexkit-lane-start";
|
|
3
|
+
export declare function fireLaneStart(client: unknown, sessionId: string): Promise<void>;
|
|
4
|
+
export declare class LaneStartTracker {
|
|
5
|
+
#private;
|
|
6
|
+
observeSyntheticMessage(input: {
|
|
7
|
+
sessionId: string;
|
|
8
|
+
messageId: string;
|
|
9
|
+
parts: unknown[];
|
|
10
|
+
}): boolean;
|
|
11
|
+
markHeaders(input: {
|
|
12
|
+
sessionId: string;
|
|
13
|
+
messageId: string;
|
|
14
|
+
headers: Record<string, string>;
|
|
15
|
+
}): boolean;
|
|
16
|
+
clearSession(sessionId: string): void;
|
|
17
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{Fc as a,Gc as b,Hc as c,Ic as d,Jc as e,Kc as f,Lc as g,Mc as h,Nc as i,Oc as j,Pc as k,Qc as l,Rc as m}from"./index-4nz423bt.js";import"./index-4x20896x.js";export{d as shouldEmit,b as setLogLevel,m as relayLog,h as redactPayload,a as parseLogLevel,k as logger,l as log,g as isSecretKey,c as getLogLevel,e as getLogFilePath,i as formatLogLine,j as __setLogTestSink,f as SECRET_KEY_EXACT};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type PrimeManager } from '@cortexkit/anthropic-auth-core';
|
|
2
|
+
type PrimeManagerAdoption = {
|
|
3
|
+
slot: string;
|
|
4
|
+
rebind: (manager: PrimeManager) => void;
|
|
5
|
+
};
|
|
6
|
+
export declare function adoptPrimeManager(storagePath: string, create: () => PrimeManager, adoption: PrimeManagerAdoption): PrimeManager;
|
|
7
|
+
export {};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type AccountStorage, type OAuthQuotaSnapshot } from '@cortexkit/anthropic-auth-core';
|
|
2
|
+
/**
|
|
3
|
+
* Format the user-facing 429 message for a killswitch block. When the block
|
|
4
|
+
* is scoped-driven, name the model so the operator can distinguish a
|
|
5
|
+
* per-model weekly block from a whole-account kill.
|
|
6
|
+
*/
|
|
7
|
+
export declare function formatKillswitchBlockMessage(input: {
|
|
8
|
+
retryAfterSeconds: number;
|
|
9
|
+
modelName?: string;
|
|
10
|
+
}): string;
|
|
11
|
+
/**
|
|
12
|
+
* Decide whether a killswitch block is scoped-driven versus a whole-account
|
|
13
|
+
* 5h/7d block. Account-level limits take precedence over scoped limits.
|
|
14
|
+
*/
|
|
15
|
+
export declare function resolveScopedDrivenBlock(input: {
|
|
16
|
+
mainQuota: OAuthQuotaSnapshot | undefined;
|
|
17
|
+
requestModelId: string | undefined;
|
|
18
|
+
storage: AccountStorage | null;
|
|
19
|
+
}): {
|
|
20
|
+
isScopedDriven: true;
|
|
21
|
+
modelName: string;
|
|
22
|
+
modelId: string;
|
|
23
|
+
} | {
|
|
24
|
+
isScopedDriven: false;
|
|
25
|
+
};
|
package/dist/rpc/port-file.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{Sc as a,Tc as b}from"../index-w9d41yy9.js";import"../index-4x20896x.js";export{a as writePortFile,b as discoverPortFile};
|
package/dist/rpc/protocol.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
export
|
|
1
|
+
export declare const COMMAND_MODAL_NAMES: readonly ['claude-account', 'claude-cache', 'claude-cachekeep', 'claude-prime', 'claude-start', 'claude-quota', 'claude-dump', 'claude-fast', 'claude-routing', 'claude-killswitch', 'claude-logging'];
|
|
2
|
+
export type CommandModalName = (typeof COMMAND_MODAL_NAMES)[number];
|
|
2
3
|
export interface OpenDialogPayload {
|
|
3
4
|
command: CommandModalName;
|
|
4
5
|
text: string;
|
package/dist/rpc/protocol.js
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{Uc as a}from"../index-1db17bc2.js";import"../index-4x20896x.js";export{a as COMMAND_MODAL_NAMES};
|
package/dist/rpc/rpc-client.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{Tc as l}from"../index-w9d41yy9.js";import"../index-4x20896x.js";async function a(n,e,t,o){let r=await l(n,o);if(!r)return null;let i=new AbortController,p=setTimeout(()=>i.abort(),2000);try{let s=await fetch(`http://127.0.0.1:${r.port}/rpc/${e}`,{method:"POST",headers:{"content-type":"application/json",authorization:`Bearer ${r.token}`},body:JSON.stringify(t),signal:i.signal});if(!s.ok)return null;return await s.json()}catch{return null}finally{clearTimeout(p)}}function u(n,e){return{async pending(t,o){return(await a(n,"pending-notifications",{lastReceivedId:t,sessionId:o},e))?.messages??[]},async apply(t){return await a(n,"apply",{...t},e)??{text:"apply failed",knobs:{}}}}}export{u as createRpcClient};
|
package/dist/rpc/rpc-dir.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{Vc as a,Wc as b}from"../index-y0khnbt6.js";import"../index-4x20896x.js";export{a as tmpdir,b as getRpcDir};
|
|
@@ -18,9 +18,11 @@ export declare function applyServerSideFallbackToBody(body: Record<string, unkno
|
|
|
18
18
|
};
|
|
19
19
|
export declare function createServerSideFallbackStreamRewriter(options: {
|
|
20
20
|
requestedModel: string;
|
|
21
|
+
maxPendingBytes?: number;
|
|
21
22
|
onOutcome?: (outcome: ServerSideFallbackOutcome) => void;
|
|
22
23
|
onRefusalAfterToolUse?: () => boolean | undefined;
|
|
23
24
|
}): {
|
|
25
|
+
pendingLength(): number;
|
|
24
26
|
push(text: string): string;
|
|
25
27
|
flush(): string;
|
|
26
28
|
};
|
package/dist/sidebar-state.d.ts
CHANGED
|
@@ -53,6 +53,15 @@ export interface FableRecoverySidebarState {
|
|
|
53
53
|
/** Anthropic-selected target while server-side safety fallback is active. */
|
|
54
54
|
targetModelId?: string;
|
|
55
55
|
}
|
|
56
|
+
export interface PrimeSidebarAccountState {
|
|
57
|
+
id: string;
|
|
58
|
+
label: string;
|
|
59
|
+
nextDueAt?: number | null;
|
|
60
|
+
lastPrimedAt?: number | null;
|
|
61
|
+
lastResult?: 'ok' | 'error';
|
|
62
|
+
usage?: PrimeUsageCounters;
|
|
63
|
+
estimatedCostUsd?: number;
|
|
64
|
+
}
|
|
56
65
|
export interface SidebarState {
|
|
57
66
|
main: {
|
|
58
67
|
quota: AccountQuota | null;
|
|
@@ -75,9 +84,19 @@ export interface SidebarState {
|
|
|
75
84
|
window?: string;
|
|
76
85
|
trackedSessions?: number;
|
|
77
86
|
};
|
|
87
|
+
/**
|
|
88
|
+
* Prime opt-in flag plus per-account status. Absent on the wire when
|
|
89
|
+
* the feature is disabled — `normalizeSidebarState` validates every
|
|
90
|
+
* account independently and drops any entry it cannot prove.
|
|
91
|
+
*/
|
|
92
|
+
prime?: {
|
|
93
|
+
enabled: boolean;
|
|
94
|
+
accounts: PrimeSidebarAccountState[];
|
|
95
|
+
};
|
|
78
96
|
fableRecoveries?: FableRecoverySidebarState[];
|
|
79
97
|
lastUpdated: number;
|
|
80
98
|
}
|
|
99
|
+
import type { PrimeUsageCounters } from '@cortexkit/anthropic-auth-core';
|
|
81
100
|
export declare function getSidebarStateFile(): string;
|
|
82
101
|
export declare const DEFAULT_SIDEBAR_STATE: SidebarState;
|
|
83
102
|
export declare function normalizeSidebarState(raw: unknown): SidebarState;
|
|
@@ -93,7 +112,7 @@ interface SidebarStateWriteTestHooks {
|
|
|
93
112
|
lockRetryMinMs?: number;
|
|
94
113
|
lockRetryMaxMs?: number;
|
|
95
114
|
}
|
|
96
|
-
export declare function __setSidebarStateWriteTestHooks(hooks: SidebarStateWriteTestHooks | null): void;
|
|
115
|
+
export declare function __setSidebarStateWriteTestHooks(hooks: SidebarStateWriteTestHooks | null, stateFile?: string): void;
|
|
97
116
|
export interface InitialSidebarRoutingTestHooks {
|
|
98
117
|
beforeSidebarRead?: () => void | Promise<void>;
|
|
99
118
|
beforeStorageLoad?: () => void | Promise<void>;
|
|
@@ -126,6 +145,12 @@ export declare function formatScopedQuotaLabel(title: string): string;
|
|
|
126
145
|
* blank on a future model that has not yet been cataloged here.
|
|
127
146
|
*/
|
|
128
147
|
export declare function formatFallbackModelLabel(modelId: string | undefined): string;
|
|
148
|
+
export declare function formatPrimeTime(epochMs: number): string;
|
|
149
|
+
export declare function formatPrimeCost(value: number): string;
|
|
150
|
+
export declare function formatPrimeAccountValue(account: PrimeSidebarAccountState): {
|
|
151
|
+
text: string;
|
|
152
|
+
hasError: boolean;
|
|
153
|
+
};
|
|
129
154
|
export declare function getFableRecoverySummary(state: SidebarState, sessionId: string): string | undefined;
|
|
130
155
|
export declare function getCollapsedQuotaSummary(quota: AccountQuota | null): {
|
|
131
156
|
fiveHourUsedPercent: number | null;
|
package/dist/sidebar-state.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r}from"./index-
|
|
1
|
+
import{a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u}from"./index-wezdyxst.js";import"./index-yskwj5e6.js";import"./index-4nz423bt.js";import"./index-4x20896x.js";export{i as setSidebarState,k as resolveActiveAccount,c as normalizeSidebarState,a as getSidebarStateFile,h as getSidebarState,f as getInitialSidebarRoutingTestHooks,q as getFableRecoverySummary,r as getCollapsedQuotaSummary,l as formatScopedQuotaLabel,n as formatPrimeTime,o as formatPrimeCost,p as formatPrimeAccountValue,m as formatFallbackModelLabel,j as drainSidebarWrites,u as computeQuotaPacing,d as __setSidebarStateWriteTestHooks,e as __setInitialSidebarRoutingTestHooks,g as __acquireSidebarStateLockForTest,t as SEVEN_DAY_MS,s as FIVE_HOUR_MS,b as DEFAULT_SIDEBAR_STATE};
|
package/dist/transform.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type Cache1hMode, type ClaudeCodeIdentity } from '@cortexkit/anthropic-auth-core';
|
|
2
2
|
import { type ServerSideFallbackOutcome } from './server-fallback';
|
|
3
|
+
export declare const NON_STREAMING_DIAGNOSTICS_MAX_BYTES: number;
|
|
3
4
|
export type FetchInput = string | URL | Request;
|
|
4
5
|
/**
|
|
5
6
|
* Merge headers from a Request object and/or a RequestInit headers value
|
|
@@ -86,6 +87,8 @@ export declare function rewriteRequestBody(body: string, options?: {
|
|
|
86
87
|
perf?: RewritePerfCallback;
|
|
87
88
|
hybridStandbyAnchor?: HybridMessageCacheAnchor;
|
|
88
89
|
serverSideFallbackEnabled?: boolean;
|
|
90
|
+
laneStart?: boolean;
|
|
91
|
+
cacheDiagnosticsPreviousMessageId?: string | null;
|
|
89
92
|
}): Promise<string>;
|
|
90
93
|
/**
|
|
91
94
|
* Create a streaming response that strips the tool prefix from tool names.
|
|
@@ -99,5 +102,15 @@ export declare function createStrippedStream(response: Response, options?: {
|
|
|
99
102
|
contentFilterModel?: unknown;
|
|
100
103
|
serverSideFallbackModel?: string;
|
|
101
104
|
onServerSideFallbackOutcome?: (outcome: ServerSideFallbackOutcome) => void;
|
|
105
|
+
onMessageStart?: (message: Record<string, unknown>) => void;
|
|
106
|
+
onMessageDelta?: (delta: {
|
|
107
|
+
usage?: Record<string, unknown>;
|
|
108
|
+
stopReason?: string;
|
|
109
|
+
}) => void;
|
|
110
|
+
onMessageResponse?: (message: Record<string, unknown>) => void;
|
|
111
|
+
onStreamEnd?: () => void | Promise<void>;
|
|
112
|
+
responseMode?: 'json';
|
|
113
|
+
laneStart?: boolean;
|
|
114
|
+
laneStartOAuthServed?: boolean;
|
|
102
115
|
}): Response;
|
|
103
116
|
export {};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/** @jsxImportSource @opentui/solid */
|
|
2
|
+
import type { PrimeAccountStatus } from '@cortexkit/anthropic-auth-core';
|
|
2
3
|
import type { TuiPluginApi } from '@opencode-ai/plugin/tui';
|
|
3
4
|
import type { OpenDialogPayload } from '../rpc/protocol.js';
|
|
4
5
|
type ApplyFn = (command: OpenDialogPayload['command'], args: string) => Promise<{
|
|
@@ -10,6 +11,13 @@ type KillswitchDialogConfig = {
|
|
|
10
11
|
main?: Record<string, number>;
|
|
11
12
|
accounts?: Record<string, Record<string, number>>;
|
|
12
13
|
};
|
|
14
|
+
export declare const PRIME_DIALOG_OPTIONS: {
|
|
15
|
+
title: string;
|
|
16
|
+
value: string;
|
|
17
|
+
}[];
|
|
18
|
+
export declare function handlePrimeStatusOption(option: {
|
|
19
|
+
value: string;
|
|
20
|
+
}, renderMain: () => void): void;
|
|
13
21
|
export declare function buildKillswitchThresholdSeed(config: KillswitchDialogConfig, accountIds: string[]): string;
|
|
14
22
|
export declare function buildAccountDialogOption(account: {
|
|
15
23
|
id: string;
|
|
@@ -19,9 +27,16 @@ export declare function buildAccountDialogOption(account: {
|
|
|
19
27
|
quotaPercent: number | null;
|
|
20
28
|
tierLabel?: string;
|
|
21
29
|
}): {
|
|
22
|
-
description?: string | undefined;
|
|
23
30
|
title: string;
|
|
24
31
|
value: string;
|
|
32
|
+
description?: string | undefined;
|
|
25
33
|
};
|
|
34
|
+
/**
|
|
35
|
+
* Format the per-account status lines shown in the Claude prime Status
|
|
36
|
+
* view. Pure: consumed by the dialog's Status pane; the sidebar uses a
|
|
37
|
+
* different formatter (`formatPrimeSidebarValue`) for its one-line
|
|
38
|
+
* expanded row.
|
|
39
|
+
*/
|
|
40
|
+
export declare function buildPrimeStatusRows(accounts: PrimeAccountStatus[]): string[];
|
|
26
41
|
export declare function openCommandDialog(api: TuiPluginApi, payload: OpenDialogPayload, apply: ApplyFn): void;
|
|
27
42
|
export {};
|
package/dist/tui-preferences.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{Xc as c,Yc as C,Zc as v}from"./index-4x20896x.js";var m=C((h,k)=>{(function(Q){if(typeof k==="object"&&typeof k.exports==="object"){var J=Q(v,h);if(J!==void 0)k.exports=J}else if(typeof define==="function"&&define.amd)define(["require","exports","./impl/format","./impl/edit","./impl/scanner","./impl/parser"],Q)})(function(Q,J){Object.defineProperty(J,"__esModule",{value:!0}),J.applyEdits=J.modify=J.format=J.printParseErrorCode=J.ParseErrorCode=J.stripComments=J.visit=J.getNodeValue=J.getNodePath=J.findNodeAtOffset=J.findNodeAtLocation=J.parseTree=J.parse=J.getLocation=J.SyntaxKind=J.ScanError=J.createScanner=void 0;let X=Q("./impl/format"),G=Q("./impl/edit"),Z=Q("./impl/scanner"),$=Q("./impl/parser");J.createScanner=Z.createScanner;var V;(function(z){z[z.None=0]="None",z[z.UnexpectedEndOfComment=1]="UnexpectedEndOfComment",z[z.UnexpectedEndOfString=2]="UnexpectedEndOfString",z[z.UnexpectedEndOfNumber=3]="UnexpectedEndOfNumber",z[z.InvalidUnicode=4]="InvalidUnicode",z[z.InvalidEscapeCharacter=5]="InvalidEscapeCharacter",z[z.InvalidCharacter=6]="InvalidCharacter"})(V||(J.ScanError=V={}));var Y;(function(z){z[z.OpenBraceToken=1]="OpenBraceToken",z[z.CloseBraceToken=2]="CloseBraceToken",z[z.OpenBracketToken=3]="OpenBracketToken",z[z.CloseBracketToken=4]="CloseBracketToken",z[z.CommaToken=5]="CommaToken",z[z.ColonToken=6]="ColonToken",z[z.NullKeyword=7]="NullKeyword",z[z.TrueKeyword=8]="TrueKeyword",z[z.FalseKeyword=9]="FalseKeyword",z[z.StringLiteral=10]="StringLiteral",z[z.NumericLiteral=11]="NumericLiteral",z[z.LineCommentTrivia=12]="LineCommentTrivia",z[z.BlockCommentTrivia=13]="BlockCommentTrivia",z[z.LineBreakTrivia=14]="LineBreakTrivia",z[z.Trivia=15]="Trivia",z[z.Unknown=16]="Unknown",z[z.EOF=17]="EOF"})(Y||(J.SyntaxKind=Y={})),J.getLocation=$.getLocation,J.parse=$.parse,J.parseTree=$.parseTree,J.findNodeAtLocation=$.findNodeAtLocation,J.findNodeAtOffset=$.findNodeAtOffset,J.getNodePath=$.getNodePath,J.getNodeValue=$.getNodeValue,J.visit=$.visit,J.stripComments=$.stripComments;var A;(function(z){z[z.InvalidSymbol=1]="InvalidSymbol",z[z.InvalidNumberFormat=2]="InvalidNumberFormat",z[z.PropertyNameExpected=3]="PropertyNameExpected",z[z.ValueExpected=4]="ValueExpected",z[z.ColonExpected=5]="ColonExpected",z[z.CommaExpected=6]="CommaExpected",z[z.CloseBraceExpected=7]="CloseBraceExpected",z[z.CloseBracketExpected=8]="CloseBracketExpected",z[z.EndOfFileExpected=9]="EndOfFileExpected",z[z.InvalidCommentToken=10]="InvalidCommentToken",z[z.UnexpectedEndOfComment=11]="UnexpectedEndOfComment",z[z.UnexpectedEndOfString=12]="UnexpectedEndOfString",z[z.UnexpectedEndOfNumber=13]="UnexpectedEndOfNumber",z[z.InvalidUnicode=14]="InvalidUnicode",z[z.InvalidEscapeCharacter=15]="InvalidEscapeCharacter",z[z.InvalidCharacter=16]="InvalidCharacter"})(A||(J.ParseErrorCode=A={}));function L(z){switch(z){case 1:return"InvalidSymbol";case 2:return"InvalidNumberFormat";case 3:return"PropertyNameExpected";case 4:return"ValueExpected";case 5:return"ColonExpected";case 6:return"CommaExpected";case 7:return"CloseBraceExpected";case 8:return"CloseBracketExpected";case 9:return"EndOfFileExpected";case 10:return"InvalidCommentToken";case 11:return"UnexpectedEndOfComment";case 12:return"UnexpectedEndOfString";case 13:return"UnexpectedEndOfNumber";case 14:return"InvalidUnicode";case 15:return"InvalidEscapeCharacter";case 16:return"InvalidCharacter"}return"<unknown ParseErrorCode>"}J.printParseErrorCode=L;function W(z,B,j){return X.format(z,B,j)}J.format=W;function q(z,B,j,R){return G.setProperty(z,B,j,R)}J.modify=q;function O(z,B){let j=B.slice(0).sort((M,N)=>{let T=M.offset-N.offset;if(T===0)return M.length-N.length;return T}),R=z.length;for(let M=j.length-1;M>=0;M--){let N=j[M];if(N.offset+N.length<=R)z=G.applyEdit(z,N);else throw Error("Overlapping edit");R=N.offset}return z}J.applyEdits=O})});var I=c(m(),1);import{readFileSync as y,watch as S}from"node:fs";import{mkdir as E,readFile as g,rename as p,writeFile as l}from"node:fs/promises";import{homedir as x}from"node:os";import{basename as i,dirname as P,join as w}from"node:path";import{clearTimeout as _,setTimeout as f}from"node:timers";var s="OPENCODE_TUI_PREFERENCES_FILE",d="tui-preferences.jsonc";function b(){let Q=process.env[s];if(Q)return Q;let J=process.env.OPENCODE_CONFIG_DIR||w(process.env.XDG_CONFIG_HOME||w(x(),".config"),"opencode");return w(J,d)}function U(Q){return typeof Q==="object"&&Q!==null&&!Array.isArray(Q)}async function Yz(){try{let Q=await g(b(),"utf8"),J=[],X=I.parse(Q,J,{allowTrailingComma:!0});if(J.length>0)return{};return U(X)?X:{}}catch{return{}}}var n="anthropic-auth",t=160,u={forceToTop:!1,order:t,startCollapsed:!1,rememberCollapsed:!0,collapsed:null,pollMs:1500,refreshDebounceMs:200,header:{label:"CLAUDE",showVersion:!0},sections:{quota:!0,fallbackAccounts:!0,routing:!0,cache:!0,health:!0,pacing:!0},appearance:{barWidth:10,barFilledChar:"█",barEmptyChar:"░",warnThreshold:50,errorThreshold:80}};function H(Q,J){return typeof Q==="boolean"?Q:J}function D(Q,J,X,G){if(typeof Q!=="number"||!Number.isFinite(Q))return J;return Math.min(Math.max(Math.round(Q),X),G)}function a(Q,J,X){if(typeof Q!=="string"||Q.length===0)return J;return Q.slice(0,X)}function K(Q,J){if(typeof Q!=="string")return J;return[...Q][0]??J}function Bz(Q){let J=Q[n];if(!U(J))return structuredClone(u);let X=u,G=U(J.header)?J.header:{},Z=U(J.sections)?J.sections:{},$=U(J.appearance)?J.appearance:{},V=D($.warnThreshold,X.appearance.warnThreshold,0,99),Y=Math.max(D($.errorThreshold,X.appearance.errorThreshold,0,100),Math.min(V+1,100));return{forceToTop:H(J.forceToTop,X.forceToTop),order:D(J.order,X.order,-1e4,1e4),startCollapsed:H(J.startCollapsed,X.startCollapsed),rememberCollapsed:H(J.rememberCollapsed,X.rememberCollapsed),collapsed:typeof J.collapsed==="boolean"?J.collapsed:null,pollMs:D(J.pollMs,X.pollMs,500,30000),refreshDebounceMs:D(J.refreshDebounceMs,X.refreshDebounceMs,50,5000),header:{label:a(G.label,X.header.label,20),showVersion:H(G.showVersion,X.header.showVersion)},sections:{quota:H(Z.quota,X.sections.quota),fallbackAccounts:H(Z.fallbackAccounts,X.sections.fallbackAccounts),routing:H(Z.routing,X.sections.routing),cache:H(Z.cache,X.sections.cache),health:H(Z.health,X.sections.health),pacing:H(Z.pacing,X.sections.pacing)},appearance:{barWidth:D($.barWidth,X.appearance.barWidth,4,40),barFilledChar:K($.barFilledChar,X.appearance.barFilledChar),barEmptyChar:K($.barEmptyChar,X.appearance.barEmptyChar),warnThreshold:V,errorThreshold:Y}}}var o=-1e5;function Hz(Q,J,X){let G=Q[J];if(!U(G))return X;if(G.forceToTop===!0)return o+Object.keys(Q).indexOf(J);return D(G.order,X,-1e4,1e4)}var e=`// Shared preferences for opencode TUI plugins.
|
|
2
2
|
// One top-level key per plugin (short name). See each plugin's README for
|
|
3
3
|
// its supported settings. This file is safe to hand-edit; plugins update
|
|
4
4
|
// individual keys in place and preserve comments.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cortexkit/opencode-anthropic-auth",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.21.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -61,9 +61,9 @@
|
|
|
61
61
|
"@opencode-ai/plugin": "*"
|
|
62
62
|
},
|
|
63
63
|
"dependencies": {
|
|
64
|
-
"@cortexkit/anthropic-auth-core": "1.
|
|
65
|
-
"@opentui/core": "0.
|
|
66
|
-
"@opentui/solid": "0.
|
|
64
|
+
"@cortexkit/anthropic-auth-core": "1.21.0",
|
|
65
|
+
"@opentui/core": "0.5.7",
|
|
66
|
+
"@opentui/solid": "0.5.7",
|
|
67
67
|
"jsonc-parser": "^3.3.1",
|
|
68
68
|
"solid-js": "1.9.12"
|
|
69
69
|
}
|
package/src/rpc/protocol.ts
CHANGED
|
@@ -1,13 +1,18 @@
|
|
|
1
|
-
export
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
1
|
+
export const COMMAND_MODAL_NAMES = [
|
|
2
|
+
'claude-account',
|
|
3
|
+
'claude-cache',
|
|
4
|
+
'claude-cachekeep',
|
|
5
|
+
'claude-prime',
|
|
6
|
+
'claude-start',
|
|
7
|
+
'claude-quota',
|
|
8
|
+
'claude-dump',
|
|
9
|
+
'claude-fast',
|
|
10
|
+
'claude-routing',
|
|
11
|
+
'claude-killswitch',
|
|
12
|
+
'claude-logging',
|
|
13
|
+
] as const
|
|
14
|
+
|
|
15
|
+
export type CommandModalName = (typeof COMMAND_MODAL_NAMES)[number]
|
|
11
16
|
|
|
12
17
|
export interface OpenDialogPayload {
|
|
13
18
|
command: CommandModalName
|
package/src/sidebar-state.ts
CHANGED
|
@@ -52,6 +52,16 @@ export interface FableRecoverySidebarState {
|
|
|
52
52
|
targetModelId?: string
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
+
export interface PrimeSidebarAccountState {
|
|
56
|
+
id: string
|
|
57
|
+
label: string
|
|
58
|
+
nextDueAt?: number | null
|
|
59
|
+
lastPrimedAt?: number | null
|
|
60
|
+
lastResult?: 'ok' | 'error'
|
|
61
|
+
usage?: PrimeUsageCounters
|
|
62
|
+
estimatedCostUsd?: number
|
|
63
|
+
}
|
|
64
|
+
|
|
55
65
|
export interface SidebarState {
|
|
56
66
|
main: {
|
|
57
67
|
quota: AccountQuota | null
|
|
@@ -71,6 +81,15 @@ export interface SidebarState {
|
|
|
71
81
|
window?: string
|
|
72
82
|
trackedSessions?: number
|
|
73
83
|
}
|
|
84
|
+
/**
|
|
85
|
+
* Prime opt-in flag plus per-account status. Absent on the wire when
|
|
86
|
+
* the feature is disabled — `normalizeSidebarState` validates every
|
|
87
|
+
* account independently and drops any entry it cannot prove.
|
|
88
|
+
*/
|
|
89
|
+
prime?: {
|
|
90
|
+
enabled: boolean
|
|
91
|
+
accounts: PrimeSidebarAccountState[]
|
|
92
|
+
}
|
|
74
93
|
fableRecoveries?: FableRecoverySidebarState[]
|
|
75
94
|
lastUpdated: number
|
|
76
95
|
}
|
|
@@ -88,6 +107,7 @@ import {
|
|
|
88
107
|
} from 'node:fs/promises'
|
|
89
108
|
import { tmpdir } from 'node:os'
|
|
90
109
|
import { dirname, join } from 'node:path'
|
|
110
|
+
import type { PrimeUsageCounters } from '@cortexkit/anthropic-auth-core'
|
|
91
111
|
import { logger } from '@cortexkit/anthropic-auth-core'
|
|
92
112
|
|
|
93
113
|
const STATE_FILE_ENV = 'OPENCODE_ANTHROPIC_AUTH_SIDEBAR_STATE_FILE'
|
|
@@ -111,6 +131,77 @@ function isRecord(v: unknown): v is Record<string, unknown> {
|
|
|
111
131
|
return v !== null && typeof v === 'object' && !Array.isArray(v)
|
|
112
132
|
}
|
|
113
133
|
|
|
134
|
+
function isFiniteNumber(value: unknown): value is number {
|
|
135
|
+
return typeof value === 'number' && Number.isFinite(value)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function normalizePrimeUsage(value: unknown): PrimeUsageCounters | undefined {
|
|
139
|
+
if (!isRecord(value)) return undefined
|
|
140
|
+
const count = Number(value.count)
|
|
141
|
+
const inputTokens = Number(value.inputTokens)
|
|
142
|
+
const outputTokens = Number(value.outputTokens)
|
|
143
|
+
const since = Number(value.since)
|
|
144
|
+
if (
|
|
145
|
+
![count, inputTokens, outputTokens, since].every(Number.isFinite) ||
|
|
146
|
+
count < 0 ||
|
|
147
|
+
inputTokens < 0 ||
|
|
148
|
+
outputTokens < 0 ||
|
|
149
|
+
since < 0
|
|
150
|
+
) {
|
|
151
|
+
return undefined
|
|
152
|
+
}
|
|
153
|
+
return {
|
|
154
|
+
count: Math.floor(count),
|
|
155
|
+
inputTokens: Math.floor(inputTokens),
|
|
156
|
+
outputTokens: Math.floor(outputTokens),
|
|
157
|
+
since: Math.floor(since),
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function normalizePrimeAccount(
|
|
162
|
+
value: unknown,
|
|
163
|
+
): PrimeSidebarAccountState | undefined {
|
|
164
|
+
if (!isRecord(value)) return undefined
|
|
165
|
+
if (typeof value.id !== 'string' || !value.id.trim()) return undefined
|
|
166
|
+
if (typeof value.label !== 'string' || !value.label.trim()) return undefined
|
|
167
|
+
const account: PrimeSidebarAccountState = {
|
|
168
|
+
id: value.id.trim(),
|
|
169
|
+
label: value.label.trim(),
|
|
170
|
+
}
|
|
171
|
+
if (value.nextDueAt === null) {
|
|
172
|
+
account.nextDueAt = null
|
|
173
|
+
} else if (isFiniteNumber(value.nextDueAt)) {
|
|
174
|
+
account.nextDueAt = value.nextDueAt
|
|
175
|
+
}
|
|
176
|
+
if (value.lastPrimedAt === null) {
|
|
177
|
+
account.lastPrimedAt = null
|
|
178
|
+
} else if (isFiniteNumber(value.lastPrimedAt)) {
|
|
179
|
+
account.lastPrimedAt = value.lastPrimedAt
|
|
180
|
+
}
|
|
181
|
+
if (value.lastResult === 'ok' || value.lastResult === 'error') {
|
|
182
|
+
account.lastResult = value.lastResult
|
|
183
|
+
}
|
|
184
|
+
const usage = normalizePrimeUsage(value.usage)
|
|
185
|
+
if (usage) account.usage = usage
|
|
186
|
+
if (isFiniteNumber(value.estimatedCostUsd)) {
|
|
187
|
+
account.estimatedCostUsd = value.estimatedCostUsd
|
|
188
|
+
}
|
|
189
|
+
return account
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function normalizePrimeSection(
|
|
193
|
+
value: unknown,
|
|
194
|
+
): SidebarState['prime'] | undefined {
|
|
195
|
+
if (!isRecord(value)) return undefined
|
|
196
|
+
if (typeof value.enabled !== 'boolean') return undefined
|
|
197
|
+
const accounts = Array.isArray(value.accounts)
|
|
198
|
+
? value.accounts
|
|
199
|
+
.map(normalizePrimeAccount)
|
|
200
|
+
.filter((a): a is PrimeSidebarAccountState => a != null)
|
|
201
|
+
: []
|
|
202
|
+
return { enabled: value.enabled, accounts }
|
|
203
|
+
}
|
|
204
|
+
|
|
114
205
|
function normalizeQuotaWindow(value: unknown): QuotaWindow | undefined {
|
|
115
206
|
if (!isRecord(value)) return undefined
|
|
116
207
|
const usedPercent = Number(value.usedPercent)
|
|
@@ -322,6 +413,7 @@ export function normalizeSidebarState(raw: unknown): SidebarState {
|
|
|
322
413
|
? raw.fastMode
|
|
323
414
|
: DEFAULT_SIDEBAR_STATE.fastMode,
|
|
324
415
|
cacheKeep,
|
|
416
|
+
prime: normalizePrimeSection(raw.prime),
|
|
325
417
|
fableRecoveries: fableRecoveries.length > 0 ? fableRecoveries : undefined,
|
|
326
418
|
lastUpdated: typeof raw.lastUpdated === 'number' ? raw.lastUpdated : 0,
|
|
327
419
|
}
|
|
@@ -348,12 +440,20 @@ interface SidebarStateWriteTestHooks {
|
|
|
348
440
|
lockRetryMaxMs?: number
|
|
349
441
|
}
|
|
350
442
|
|
|
351
|
-
|
|
443
|
+
const sidebarStateWriteTestHooks = new Map<string, SidebarStateWriteTestHooks>()
|
|
352
444
|
|
|
353
445
|
export function __setSidebarStateWriteTestHooks(
|
|
354
446
|
hooks: SidebarStateWriteTestHooks | null,
|
|
447
|
+
stateFile = getSidebarStateFile(),
|
|
355
448
|
): void {
|
|
356
|
-
sidebarStateWriteTestHooks
|
|
449
|
+
if (hooks) sidebarStateWriteTestHooks.set(stateFile, hooks)
|
|
450
|
+
else sidebarStateWriteTestHooks.delete(stateFile)
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
function sidebarStateWriteHooksFor(
|
|
454
|
+
stateFile: string,
|
|
455
|
+
): SidebarStateWriteTestHooks | undefined {
|
|
456
|
+
return sidebarStateWriteTestHooks.get(stateFile)
|
|
357
457
|
}
|
|
358
458
|
|
|
359
459
|
// Boot-routing test hooks live here rather than in index.ts: the plugin entry
|
|
@@ -388,12 +488,10 @@ async function acquireSidebarStateLock(stateFile: string): Promise<{
|
|
|
388
488
|
ownsLock: () => Promise<boolean>
|
|
389
489
|
} | null> {
|
|
390
490
|
const lockDir = `${stateFile}.lock`
|
|
391
|
-
const
|
|
392
|
-
|
|
393
|
-
const retryMinMs =
|
|
394
|
-
|
|
395
|
-
const retryMaxMs =
|
|
396
|
-
sidebarStateWriteTestHooks?.lockRetryMaxMs ?? SIDEBAR_LOCK_RETRY_MAX_MS
|
|
491
|
+
const testHooks = sidebarStateWriteHooksFor(stateFile)
|
|
492
|
+
const budgetMs = testHooks?.lockBudgetMs ?? SIDEBAR_LOCK_BUDGET_MS
|
|
493
|
+
const retryMinMs = testHooks?.lockRetryMinMs ?? SIDEBAR_LOCK_RETRY_MIN_MS
|
|
494
|
+
const retryMaxMs = testHooks?.lockRetryMaxMs ?? SIDEBAR_LOCK_RETRY_MAX_MS
|
|
397
495
|
const deadline = Date.now() + budgetMs
|
|
398
496
|
|
|
399
497
|
while (true) {
|
|
@@ -406,7 +504,7 @@ async function acquireSidebarStateLock(stateFile: string): Promise<{
|
|
|
406
504
|
mode: 0o600,
|
|
407
505
|
flag: 'wx',
|
|
408
506
|
})
|
|
409
|
-
await
|
|
507
|
+
await testHooks?.onLockAcquired?.(lockDir)
|
|
410
508
|
return {
|
|
411
509
|
ownsLock: async () => {
|
|
412
510
|
try {
|
|
@@ -424,9 +522,7 @@ async function acquireSidebarStateLock(stateFile: string): Promise<{
|
|
|
424
522
|
} catch {
|
|
425
523
|
return
|
|
426
524
|
}
|
|
427
|
-
await
|
|
428
|
-
lockDir,
|
|
429
|
-
)
|
|
525
|
+
await testHooks?.beforeReleaseDirectoryRemoval?.(lockDir)
|
|
430
526
|
await rmdir(lockDir).catch(() => {})
|
|
431
527
|
},
|
|
432
528
|
}
|
|
@@ -443,7 +539,7 @@ async function acquireSidebarStateLock(stateFile: string): Promise<{
|
|
|
443
539
|
try {
|
|
444
540
|
const lockStat = await stat(lockDir)
|
|
445
541
|
if (Date.now() - lockStat.mtimeMs > SIDEBAR_LOCK_STALE_MS) {
|
|
446
|
-
await
|
|
542
|
+
await testHooks?.afterStaleLockStat?.(lockDir)
|
|
447
543
|
const evictedLockDir = `${lockDir}.evict-${process.pid}-${randomUUID()}`
|
|
448
544
|
try {
|
|
449
545
|
await rename(lockDir, evictedLockDir)
|
|
@@ -451,7 +547,7 @@ async function acquireSidebarStateLock(stateFile: string): Promise<{
|
|
|
451
547
|
if ((error as NodeJS.ErrnoException).code === 'ENOENT') continue
|
|
452
548
|
throw error
|
|
453
549
|
}
|
|
454
|
-
await
|
|
550
|
+
await testHooks?.onStaleLockClaimed?.(lockDir)
|
|
455
551
|
await rm(evictedLockDir, { recursive: true, force: true }).catch(
|
|
456
552
|
() => {},
|
|
457
553
|
)
|
|
@@ -491,6 +587,7 @@ async function writeSidebarStateAtomic(
|
|
|
491
587
|
state: SidebarState,
|
|
492
588
|
ownsLock: () => Promise<boolean>,
|
|
493
589
|
): Promise<'written' | 'lock-lost-before-rename' | 'lock-lost-after-rename'> {
|
|
590
|
+
const testHooks = sidebarStateWriteHooksFor(stateFile)
|
|
494
591
|
const tempFile = `${stateFile}.${process.pid}.${randomUUID()}.tmp`
|
|
495
592
|
await writeFile(tempFile, JSON.stringify(state), {
|
|
496
593
|
encoding: 'utf8',
|
|
@@ -504,7 +601,7 @@ async function writeSidebarStateAtomic(
|
|
|
504
601
|
await rm(tempFile, { force: true }).catch(() => {})
|
|
505
602
|
return 'lock-lost-before-rename'
|
|
506
603
|
}
|
|
507
|
-
await
|
|
604
|
+
await testHooks?.beforeRename?.(stateFile, tempFile)
|
|
508
605
|
// No production await separates this ownership fence from rename. A process
|
|
509
606
|
// freeze between the adjacent syscalls remains possible, so rename is also
|
|
510
607
|
// fenced from the other side below.
|
|
@@ -516,7 +613,7 @@ async function writeSidebarStateAtomic(
|
|
|
516
613
|
return 'lock-lost-before-rename'
|
|
517
614
|
}
|
|
518
615
|
await rename(tempFile, stateFile)
|
|
519
|
-
await
|
|
616
|
+
await testHooks?.afterRename?.(stateFile)
|
|
520
617
|
if (!(await ownsLock())) return 'lock-lost-after-rename'
|
|
521
618
|
return 'written'
|
|
522
619
|
} catch (error) {
|
|
@@ -601,7 +698,9 @@ export async function setSidebarState(
|
|
|
601
698
|
),
|
|
602
699
|
}
|
|
603
700
|
}
|
|
604
|
-
await
|
|
701
|
+
await sidebarStateWriteHooksFor(stateFile)?.afterMergeRead?.(
|
|
702
|
+
stateFile,
|
|
703
|
+
)
|
|
605
704
|
} else if (repairingPostRenameLoss) {
|
|
606
705
|
const current = await getSidebarState(stateFile)
|
|
607
706
|
// A successor owns its fresh account/quota and recovery snapshots;
|
|
@@ -710,6 +809,44 @@ export function formatFallbackModelLabel(modelId: string | undefined): string {
|
|
|
710
809
|
return modelId ?? 'Fable 5'
|
|
711
810
|
}
|
|
712
811
|
|
|
812
|
+
export function formatPrimeTime(epochMs: number): string {
|
|
813
|
+
return new Date(epochMs).toLocaleTimeString([], {
|
|
814
|
+
hour: '2-digit',
|
|
815
|
+
minute: '2-digit',
|
|
816
|
+
})
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
export function formatPrimeCost(value: number): string {
|
|
820
|
+
if (value === 0) return '0'
|
|
821
|
+
if (value < 0.0001) return value.toExponential(2)
|
|
822
|
+
return value.toFixed(Math.min(6, Math.max(0, 4)))
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
export function formatPrimeAccountValue(account: PrimeSidebarAccountState): {
|
|
826
|
+
text: string
|
|
827
|
+
hasError: boolean
|
|
828
|
+
} {
|
|
829
|
+
if (account.lastResult === 'error') {
|
|
830
|
+
return { text: 'err', hasError: true }
|
|
831
|
+
}
|
|
832
|
+
if (account.nextDueAt && account.nextDueAt > Date.now()) {
|
|
833
|
+
return { text: formatPrimeTime(account.nextDueAt), hasError: false }
|
|
834
|
+
}
|
|
835
|
+
if (account.lastPrimedAt) {
|
|
836
|
+
return {
|
|
837
|
+
text: `primed ${formatPrimeTime(account.lastPrimedAt)} \u2713`,
|
|
838
|
+
hasError: false,
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
if (account.usage?.count) {
|
|
842
|
+
return {
|
|
843
|
+
text: `\u2713 ${account.usage.count} \u2248 $${formatPrimeCost(account.estimatedCostUsd ?? 0)}`,
|
|
844
|
+
hasError: false,
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
return { text: '\u2014', hasError: false }
|
|
848
|
+
}
|
|
849
|
+
|
|
713
850
|
export function getFableRecoverySummary(
|
|
714
851
|
state: SidebarState,
|
|
715
852
|
sessionId: string,
|