@cortexkit/opencode-anthropic-auth 2.1.2 → 2.2.1
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/cli.js +36 -36
- package/dist/{index-f2ne65w4.js → index-62x1p34p.js} +1 -1
- package/dist/index-88zg9ztr.js +2 -0
- package/dist/{index-x325vp4e.js → index-8ysjtqek.js} +13 -13
- package/dist/{index-ah5s0bew.js → index-ppdrzs41.js} +1 -1
- package/dist/index-xbwa4x53.js +2 -0
- package/dist/index.js +1 -1
- package/dist/rpc/port-file.js +1 -1
- package/dist/rpc/protocol.js +1 -1
- package/dist/rpc/rpc-client.js +1 -1
- package/dist/rpc/rpc-dir.js +1 -1
- package/dist/sidebar-state.d.ts +54 -1
- package/dist/sidebar-state.js +1 -1
- package/dist/transform.d.ts +4 -0
- package/dist/tui/claude-sidebar.d.ts +99 -0
- package/dist/tui-preferences.js +1 -1
- package/dist/v2/menu-contract.d.ts +3 -0
- package/dist/v2/rpc.d.ts +9 -0
- package/dist/v2/server.js +4 -4
- package/dist/v2/sidebar.d.ts +13 -0
- package/dist/v2/source.d.ts +2 -0
- package/dist/v2/tui.d.ts +9 -1
- package/dist/v2/tui.js +2 -2
- package/dist/v2/wire.d.ts +4 -0
- package/package.json +5 -5
- package/src/sidebar-state.ts +133 -3
- package/src/tui/claude-sidebar.tsx +1146 -0
- package/src/tui/entry.mjs +15 -1
- package/src/tui-compiled/sidebar-state.ts +133 -3
- package/src/tui-compiled/tui/claude-sidebar.tsx +1310 -0
- package/src/tui-compiled/tui.tsx +46 -1137
- package/src/tui.tsx +15 -886
- package/dist/index-53nnxq39.js +0 -2
- package/dist/index-jexctf5w.js +0 -2
package/src/tui/entry.mjs
CHANGED
|
@@ -37,6 +37,17 @@ async function loadLegacyTui() {
|
|
|
37
37
|
return mod.default
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
// The quota sidebar renderer shared with OpenCode 1, loaded the same way.
|
|
41
|
+
async function loadSidebar() {
|
|
42
|
+
try {
|
|
43
|
+
await import(runtimeProbe)
|
|
44
|
+
} catch (error) {
|
|
45
|
+
if (!isMissingRuntimeRegistry(error)) throw error
|
|
46
|
+
return import('./claude-sidebar.tsx')
|
|
47
|
+
}
|
|
48
|
+
return import('../tui-compiled/tui/claude-sidebar.tsx')
|
|
49
|
+
}
|
|
50
|
+
|
|
40
51
|
let legacyModule
|
|
41
52
|
|
|
42
53
|
// OpenCode 1 reads id and tui from the default definition; OpenCode 2 reads
|
|
@@ -57,7 +68,10 @@ export const setup = async (context) => {
|
|
|
57
68
|
// TUI must not load the OpenCode 1 renderer or start that renderer's separate
|
|
58
69
|
// loopback notification poller.
|
|
59
70
|
const { setupAnthropicTui } = await import('../../dist/v2/tui.js')
|
|
60
|
-
return setupAnthropicTui(context
|
|
71
|
+
return setupAnthropicTui(context, {
|
|
72
|
+
mountSidebar: async (ctx, read) =>
|
|
73
|
+
(await loadSidebar()).mountClaudeSidebar(ctx, read),
|
|
74
|
+
})
|
|
61
75
|
}
|
|
62
76
|
|
|
63
77
|
export default { id, tui, setup }
|
|
@@ -132,6 +132,7 @@ import {
|
|
|
132
132
|
isQuotaStale,
|
|
133
133
|
logger,
|
|
134
134
|
quotaDisplayProjection,
|
|
135
|
+
quotaTextParts,
|
|
135
136
|
} from '@cortexkit/anthropic-auth-core'
|
|
136
137
|
|
|
137
138
|
const STATE_FILE_ENV = 'OPENCODE_ANTHROPIC_AUTH_SIDEBAR_STATE_FILE'
|
|
@@ -888,7 +889,10 @@ export function formatPrimeCost(value: number): string {
|
|
|
888
889
|
return value.toFixed(Math.min(6, Math.max(0, 4)))
|
|
889
890
|
}
|
|
890
891
|
|
|
891
|
-
export function formatPrimeAccountValue(
|
|
892
|
+
export function formatPrimeAccountValue(
|
|
893
|
+
account: PrimeSidebarAccountState,
|
|
894
|
+
now = Date.now(),
|
|
895
|
+
): {
|
|
892
896
|
text: string
|
|
893
897
|
hasError: boolean
|
|
894
898
|
} {
|
|
@@ -898,7 +902,7 @@ export function formatPrimeAccountValue(account: PrimeSidebarAccountState): {
|
|
|
898
902
|
if (account.lastResult === 'skipped') {
|
|
899
903
|
return { text: 'skip', hasError: false }
|
|
900
904
|
}
|
|
901
|
-
if (account.nextDueAt && account.nextDueAt >
|
|
905
|
+
if (account.nextDueAt && account.nextDueAt > now) {
|
|
902
906
|
return { text: formatPrimeTime(account.nextDueAt), hasError: false }
|
|
903
907
|
}
|
|
904
908
|
if (account.lastPrimedAt) {
|
|
@@ -948,6 +952,130 @@ export function formatQuotaRowLabel(name: string, width = 10): string {
|
|
|
948
952
|
return label + ' '.repeat(Math.max(0, width - Bun.stringWidth(label)))
|
|
949
953
|
}
|
|
950
954
|
|
|
955
|
+
/**
|
|
956
|
+
* The short names model-scoped rows read under, in the order of `quota.scoped`:
|
|
957
|
+
* the names common-auth's narrow one-line form gives them (`Fa` for Fable;
|
|
958
|
+
* models whose short names would collide are extended until they differ, as
|
|
959
|
+
* `Fabl` and `Fabr`), so the expanded rows and the collapsed line agree.
|
|
960
|
+
*
|
|
961
|
+
* common-auth exposes that short name only inside the narrow text, and the
|
|
962
|
+
* narrow line shows just one model window (the tightest). So each window's
|
|
963
|
+
* name is read from a narrow line of a copy of the reading in which that
|
|
964
|
+
* window alone is spent: every model window stays in, so collisions resolve
|
|
965
|
+
* exactly as they do in the real line, and the one piece the line shows is
|
|
966
|
+
* `<short name> 0% left`. The figures in the copy are never displayed.
|
|
967
|
+
*/
|
|
968
|
+
export function scopedQuotaShortNames(
|
|
969
|
+
quota: Pick<AccountQuota, 'scoped'> | null | undefined,
|
|
970
|
+
now = Date.now(),
|
|
971
|
+
): string[] {
|
|
972
|
+
const scoped = quota?.scoped ?? []
|
|
973
|
+
return scoped.map((window, index) => {
|
|
974
|
+
const probe = quotaDisplayProjection(
|
|
975
|
+
{
|
|
976
|
+
scoped: scoped.map((other, at) => ({
|
|
977
|
+
...other,
|
|
978
|
+
usedPercent: at === index ? 100 : 0,
|
|
979
|
+
remainingPercent: at === index ? 0 : 100,
|
|
980
|
+
checkedAt: now,
|
|
981
|
+
})),
|
|
982
|
+
},
|
|
983
|
+
now,
|
|
984
|
+
)
|
|
985
|
+
const piece = quotaTextParts(probe, { now, form: 'narrow' })[0]
|
|
986
|
+
const name = piece?.replace(/ 0% left$/, '')
|
|
987
|
+
return name && name !== piece ? name : window.title
|
|
988
|
+
})
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
/**
|
|
992
|
+
* The width of the quota rows' label column: the longest label any of these
|
|
993
|
+
* accounts shows. `5h` and `7d` always show, so it is at least 2.
|
|
994
|
+
*/
|
|
995
|
+
export function quotaLabelColumnWidth(
|
|
996
|
+
quotas: readonly (AccountQuota | null | undefined)[],
|
|
997
|
+
now = Date.now(),
|
|
998
|
+
): number {
|
|
999
|
+
return Math.max(
|
|
1000
|
+
2,
|
|
1001
|
+
...quotas.flatMap((quota) =>
|
|
1002
|
+
scopedQuotaShortNames(quota, now).map((name) => Bun.stringWidth(name)),
|
|
1003
|
+
),
|
|
1004
|
+
)
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
/** The narrowest a quota row's bar shrinks to. */
|
|
1008
|
+
export const QUOTA_BAR_MIN_CELLS = 3
|
|
1009
|
+
|
|
1010
|
+
export interface QuotaRowFit {
|
|
1011
|
+
/** Bar cells to draw. */
|
|
1012
|
+
barCells: number
|
|
1013
|
+
/** The reset text to draw at the right edge, or undefined for none. */
|
|
1014
|
+
reset?: string
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
/**
|
|
1018
|
+
* Fits one quota row into `width` cells. The row reads `label bar figure` on
|
|
1019
|
+
* the left and the reset at the right edge, with a one-cell gap before the
|
|
1020
|
+
* reset that the caller always draws. When the full row is too wide, the
|
|
1021
|
+
* reset is dropped first, so the figure (the percent left) is never cut to
|
|
1022
|
+
* keep it; then the bar shrinks, down to `QUOTA_BAR_MIN_CELLS`. A row still
|
|
1023
|
+
* too wide at that point keeps the minimum bar and is cut at the right edge
|
|
1024
|
+
* by the caller's no-wrap text, which cuts the figure's end. Without a
|
|
1025
|
+
* measured width the full row is used.
|
|
1026
|
+
*/
|
|
1027
|
+
export function fitQuotaRow(input: {
|
|
1028
|
+
width: number | undefined
|
|
1029
|
+
labelWidth: number
|
|
1030
|
+
barWidth: number
|
|
1031
|
+
/** The figure with any binding marker, such as `97% left •`. */
|
|
1032
|
+
figure: string
|
|
1033
|
+
reset?: string
|
|
1034
|
+
}): QuotaRowFit {
|
|
1035
|
+
const { width, labelWidth, barWidth, figure, reset } = input
|
|
1036
|
+
const full: QuotaRowFit = { barCells: barWidth, reset: reset || undefined }
|
|
1037
|
+
if (width === undefined) return full
|
|
1038
|
+
const cells = (fit: QuotaRowFit) =>
|
|
1039
|
+
labelWidth +
|
|
1040
|
+
1 +
|
|
1041
|
+
(fit.barCells > 0 ? fit.barCells + 1 : 0) +
|
|
1042
|
+
Bun.stringWidth(figure) +
|
|
1043
|
+
(fit.reset ? 1 + Bun.stringWidth(fit.reset) : 0)
|
|
1044
|
+
const minimum = Math.min(QUOTA_BAR_MIN_CELLS, barWidth)
|
|
1045
|
+
const candidates: QuotaRowFit[] = [full]
|
|
1046
|
+
for (let barCells = barWidth; barCells >= minimum; barCells--) {
|
|
1047
|
+
candidates.push({ barCells })
|
|
1048
|
+
}
|
|
1049
|
+
return candidates.find((fit) => cells(fit) <= width) ?? { barCells: minimum }
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
/**
|
|
1053
|
+
* The pacing subline for a window that is off pace: `deficit 12% · out in
|
|
1054
|
+
* 1d23h` for a deficit that runs out before the reset, otherwise the delta
|
|
1055
|
+
* and `lasts to reset` (`reserve 4% · lasts to reset`). When it is wider than
|
|
1056
|
+
* `width` cells it is cut to fit and ends in `…` rather than wrapping. Null
|
|
1057
|
+
* when there is no pacing or the window is on pace.
|
|
1058
|
+
*/
|
|
1059
|
+
export function fitPaceLine(
|
|
1060
|
+
pacing: QuotaPacing | null,
|
|
1061
|
+
width: number | undefined,
|
|
1062
|
+
runsOutIn: string | undefined,
|
|
1063
|
+
): string | null {
|
|
1064
|
+
if (!pacing || pacing.state === 'on-pace') return null
|
|
1065
|
+
const head = `${pacing.state} ${Math.round(Math.abs(pacing.deltaPercent))}%`
|
|
1066
|
+
const line = runsOutIn
|
|
1067
|
+
? `${head} \u00b7 out in ${runsOutIn}`
|
|
1068
|
+
: `${head} \u00b7 lasts to reset`
|
|
1069
|
+
if (width === undefined || Bun.stringWidth(line) <= width) return line
|
|
1070
|
+
if (width <= 0) return ''
|
|
1071
|
+
let cut = ''
|
|
1072
|
+
for (const character of line) {
|
|
1073
|
+
if (Bun.stringWidth(cut + character) > width - 1) break
|
|
1074
|
+
cut += character
|
|
1075
|
+
}
|
|
1076
|
+
return `${cut.trimEnd()}\u2026`
|
|
1077
|
+
}
|
|
1078
|
+
|
|
951
1079
|
export function getCollapsedQuotaSummary(
|
|
952
1080
|
quota: AccountQuota | null,
|
|
953
1081
|
now = Date.now(),
|
|
@@ -994,7 +1122,9 @@ export function getCollapsedAccounts(
|
|
|
994
1122
|
state: SidebarState,
|
|
995
1123
|
showFallbacks = true,
|
|
996
1124
|
) {
|
|
997
|
-
|
|
1125
|
+
// Before any request no account is active; do not mark main as serving.
|
|
1126
|
+
const activeId =
|
|
1127
|
+
state.activeId === undefined ? undefined : resolveActiveAccount(state).id
|
|
998
1128
|
return [
|
|
999
1129
|
{
|
|
1000
1130
|
id: 'main',
|