@cortexkit/opencode-anthropic-auth 2.3.0 → 2.4.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.
@@ -1053,20 +1053,36 @@ export function fitQuotaRow(input: {
1053
1053
  /**
1054
1054
  * The pacing subline for a window that is off pace: `deficit 12% · out in
1055
1055
  * 1d23h` for a deficit that runs out before the reset, otherwise the delta
1056
- * and `lasts to reset` (`reserve 4% · lasts to reset`). When it is wider than
1057
- * `width` cells it is cut to fit and ends in `…` rather than wrapping. Null
1058
- * when there is no pacing or the window is on pace.
1056
+ * and `lasts to reset` (`reserve 4% · lasts to reset`). A window already at
1057
+ * 0% left is used up until its reset (`used up · resets in 2h10m`, with no
1058
+ * deficit percentage and no `out in` clause). A runout under a minute away
1059
+ * reads `out in <1m`, never `out in now`. When the line is wider than `width`
1060
+ * cells it is cut to fit and ends in `…` rather than wrapping. Null when
1061
+ * there is no pacing or the window is on pace.
1059
1062
  */
1060
1063
  export function fitPaceLine(
1061
1064
  pacing: QuotaPacing | null,
1062
1065
  width: number | undefined,
1063
1066
  runsOutIn: string | undefined,
1067
+ resetIn?: string | undefined,
1068
+ remainingPercent?: number | undefined,
1064
1069
  ): string | null {
1065
1070
  if (!pacing || pacing.state === 'on-pace') return null
1071
+ // An exhausted window reports its deficit as a large percentage with a
1072
+ // runout of `now`, which reads as broken wording. The percentage no longer
1073
+ // means anything once nothing is left, so the line names the state instead.
1074
+ const exhausted = remainingPercent !== undefined && remainingPercent <= 0
1075
+ // A projected runout under a minute away is not `now` while quota remains.
1076
+ const normalizedRunsOutIn =
1077
+ runsOutIn === 'now' || runsOutIn === '0m' ? '<1m' : runsOutIn
1066
1078
  const head = `${pacing.state} ${Math.round(Math.abs(pacing.deltaPercent))}%`
1067
- const line = runsOutIn
1068
- ? `${head} \u00b7 out in ${runsOutIn}`
1069
- : `${head} \u00b7 lasts to reset`
1079
+ const line = exhausted
1080
+ ? resetIn
1081
+ ? `used up \u00b7 resets in ${resetIn}`
1082
+ : 'used up'
1083
+ : normalizedRunsOutIn
1084
+ ? `${head} \u00b7 out in ${normalizedRunsOutIn}`
1085
+ : `${head} \u00b7 lasts to reset`
1070
1086
  if (width === undefined || Bun.stringWidth(line) <= width) return line
1071
1087
  if (width <= 0) return ''
1072
1088
  let cut = ''
@@ -172,7 +172,9 @@ function quotaBarSegments(
172
172
  function formatResetIn(resetsAt: string | undefined, now: number): string {
173
173
  if (!resetsAt) return ''
174
174
  const ms = new Date(resetsAt).getTime() - now
175
- if (ms <= 0) return 'now'
175
+ // A pacing runout under a minute away is not `now` while quota remains;
176
+ // the exhausted window never reaches this formatter with an `out in` line.
177
+ if (ms < 60_000) return '<1m'
176
178
  const mins = Math.floor(ms / 60_000)
177
179
  if (mins < 60) return `${mins}m`
178
180
  const hrs = Math.floor(mins / 60)
@@ -318,7 +320,8 @@ function Cell(props: { fg: SidebarColor; text: string }) {
318
320
  // instead of letting it wrap. When pacing data is present, the bar gains a
319
321
  // pace segment and an off-pace window adds a one-line subline under the bar
320
322
  // with the reserve/deficit delta and either the projected runout or
321
- // `lasts to reset`.
323
+ // `lasts to reset`; a window already at 0% left names itself used up until
324
+ // its reset instead.
322
325
  function QuotaRow(props: {
323
326
  theme: SidebarTheme
324
327
  appearance: AppearancePrefs
@@ -354,6 +357,8 @@ function QuotaRow(props: {
354
357
  props.pacing?.runsOutAt
355
358
  ? formatResetIn(props.pacing.runsOutAt, props.now)
356
359
  : undefined,
360
+ props.part?.resetIn,
361
+ props.part?.remainingPercent,
357
362
  )
358
363
  return (
359
364
  <Show
@@ -7,12 +7,18 @@ import {
7
7
  writeFile,
8
8
  } from 'node:fs/promises'
9
9
  import { join } from 'node:path'
10
+ import { type WriterStamp, writerStamp } from '@cortexkit/anthropic-auth-core'
10
11
 
11
12
  export interface PortFileEntry {
12
13
  port: number
13
14
  token: string
14
15
  pid: number
15
16
  startedAt: number
17
+ /**
18
+ * Present in files written by 2.3.0 and later, so a later version can tell
19
+ * them from files of older versions. Older readers ignore it.
20
+ */
21
+ writer?: WriterStamp
16
22
  }
17
23
 
18
24
  function pidAlive(pid: number): boolean {
@@ -29,7 +35,11 @@ export async function writePortFile(
29
35
  entry: { port: number; token: string; pid: number },
30
36
  ): Promise<string> {
31
37
  await mkdir(dir, { recursive: true })
32
- const full: PortFileEntry = { ...entry, startedAt: Date.now() }
38
+ const full: PortFileEntry = {
39
+ ...entry,
40
+ startedAt: Date.now(),
41
+ writer: writerStamp(),
42
+ }
33
43
  const target = join(dir, `port-${entry.pid}.json`)
34
44
  const tmp = `${target}.${process.pid}.tmp`
35
45
  await writeFile(tmp, JSON.stringify(full), { encoding: 'utf8', mode: 0o600 })
@@ -1,6 +1,7 @@
1
1
  import { createHash } from 'node:crypto'
2
2
  import { homedir, tmpdir } from 'node:os'
3
3
  import { join, resolve } from 'node:path'
4
+ import { anthropicAuthStateRoot } from '@cortexkit/anthropic-auth-core'
4
5
 
5
6
  const RPC_DIR_ENV = 'OPENCODE_ANTHROPIC_AUTH_RPC_DIR'
6
7
 
@@ -12,8 +13,12 @@ export function getRpcDir(projectDirectory: string): string {
12
13
  .update(projectDirectory)
13
14
  .digest('hex')
14
15
  .slice(0, 16)
15
- const base = process.env.XDG_STATE_HOME || join(homedir(), '.local', 'state')
16
- return join(base, 'cortexkit', 'anthropic-auth', 'rpc', hash)
16
+ const root = anthropicAuthStateRoot({
17
+ xdgStateHome: process.env.XDG_STATE_HOME,
18
+ home: homedir(),
19
+ acceptRelative: true,
20
+ })
21
+ return join(root, 'rpc', hash)
17
22
  }
18
23
 
19
24
  export { tmpdir }
@@ -1053,20 +1053,36 @@ export function fitQuotaRow(input: {
1053
1053
  /**
1054
1054
  * The pacing subline for a window that is off pace: `deficit 12% · out in
1055
1055
  * 1d23h` for a deficit that runs out before the reset, otherwise the delta
1056
- * and `lasts to reset` (`reserve 4% · lasts to reset`). When it is wider than
1057
- * `width` cells it is cut to fit and ends in `…` rather than wrapping. Null
1058
- * when there is no pacing or the window is on pace.
1056
+ * and `lasts to reset` (`reserve 4% · lasts to reset`). A window already at
1057
+ * 0% left is used up until its reset (`used up · resets in 2h10m`, with no
1058
+ * deficit percentage and no `out in` clause). A runout under a minute away
1059
+ * reads `out in <1m`, never `out in now`. When the line is wider than `width`
1060
+ * cells it is cut to fit and ends in `…` rather than wrapping. Null when
1061
+ * there is no pacing or the window is on pace.
1059
1062
  */
1060
1063
  export function fitPaceLine(
1061
1064
  pacing: QuotaPacing | null,
1062
1065
  width: number | undefined,
1063
1066
  runsOutIn: string | undefined,
1067
+ resetIn?: string | undefined,
1068
+ remainingPercent?: number | undefined,
1064
1069
  ): string | null {
1065
1070
  if (!pacing || pacing.state === 'on-pace') return null
1071
+ // An exhausted window reports its deficit as a large percentage with a
1072
+ // runout of `now`, which reads as broken wording. The percentage no longer
1073
+ // means anything once nothing is left, so the line names the state instead.
1074
+ const exhausted = remainingPercent !== undefined && remainingPercent <= 0
1075
+ // A projected runout under a minute away is not `now` while quota remains.
1076
+ const normalizedRunsOutIn =
1077
+ runsOutIn === 'now' || runsOutIn === '0m' ? '<1m' : runsOutIn
1066
1078
  const head = `${pacing.state} ${Math.round(Math.abs(pacing.deltaPercent))}%`
1067
- const line = runsOutIn
1068
- ? `${head} \u00b7 out in ${runsOutIn}`
1069
- : `${head} \u00b7 lasts to reset`
1079
+ const line = exhausted
1080
+ ? resetIn
1081
+ ? `used up \u00b7 resets in ${resetIn}`
1082
+ : 'used up'
1083
+ : normalizedRunsOutIn
1084
+ ? `${head} \u00b7 out in ${normalizedRunsOutIn}`
1085
+ : `${head} \u00b7 lasts to reset`
1070
1086
  if (width === undefined || Bun.stringWidth(line) <= width) return line
1071
1087
  if (width <= 0) return ''
1072
1088
  let cut = ''
@@ -110,7 +110,9 @@ function quotaBarSegments(usedPct, appearance, pacing, width) {
110
110
  function formatResetIn(resetsAt, now) {
111
111
  if (!resetsAt) return '';
112
112
  const ms = new Date(resetsAt).getTime() - now;
113
- if (ms <= 0) return 'now';
113
+ // A pacing runout under a minute away is not `now` while quota remains;
114
+ // the exhausted window never reaches this formatter with an `out in` line.
115
+ if (ms < 60_000) return '<1m';
114
116
  const mins = Math.floor(ms / 60_000);
115
117
  if (mins < 60) return `${mins}m`;
116
118
  const hrs = Math.floor(mins / 60);
@@ -303,7 +305,8 @@ function Cell(props) {
303
305
  // instead of letting it wrap. When pacing data is present, the bar gains a
304
306
  // pace segment and an off-pace window adds a one-line subline under the bar
305
307
  // with the reserve/deficit delta and either the projected runout or
306
- // `lasts to reset`.
308
+ // `lasts to reset`; a window already at 0% left names itself used up until
309
+ // its reset instead.
307
310
  function QuotaRow(props) {
308
311
  const used = () => props.usedPercent ?? 0;
309
312
  const labelCell = () => `${props.label}${' '.repeat(Math.max(0, props.labelWidth - Bun.stringWidth(props.label)))} `;
@@ -315,7 +318,7 @@ function QuotaRow(props) {
315
318
  figure: figure(),
316
319
  reset: props.part?.resetIn
317
320
  });
318
- const paceLine = () => fitPaceLine(props.pacing, props.width === undefined ? undefined : props.width - props.labelWidth - 1, props.pacing?.runsOutAt ? formatResetIn(props.pacing.runsOutAt, props.now) : undefined);
321
+ const paceLine = () => fitPaceLine(props.pacing, props.width === undefined ? undefined : props.width - props.labelWidth - 1, props.pacing?.runsOutAt ? formatResetIn(props.pacing.runsOutAt, props.now) : undefined, props.part?.resetIn, props.part?.remainingPercent);
319
322
  return _$createComponent(Show, {
320
323
  get when() {
321
324
  return props.part;