@cortexkit/opencode-openai-auth 0.7.2 → 0.9.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 +9 -5
- package/dist/index-301y4qa1.js +2 -0
- package/dist/index-338z7171.js +211 -0
- package/dist/index-5y4vzdf8.js +2 -0
- package/dist/{index-zxqb5ydj.js → index-9ehhb051.js} +1 -1
- package/dist/{index-zg1x8sty.js → index-jwn4r3sw.js} +1 -1
- package/dist/{index-9jpc8yct.js → index-sdt2d2ra.js} +1 -1
- package/dist/index-w42s0g6m.js +2 -0
- package/dist/index.d.ts +213 -36
- package/dist/index.js +59 -154
- package/dist/internal-Y7QNVDJT.d.ts +908 -0
- package/dist/quota-normalize-3qffywcm.js +1 -0
- package/dist/rpc/port-file.d.ts +11 -9
- package/dist/rpc/port-file.js +1 -1
- package/dist/rpc/protocol.d.ts +2 -21
- package/dist/rpc/rpc-client.d.ts +7 -4
- package/dist/rpc/rpc-client.js +1 -1
- package/dist/rpc/rpc-dir.d.ts +7 -5
- package/dist/rpc/rpc-dir.js +1 -1
- package/dist/sidebar-state-B98sERYt.d.ts +219 -0
- package/dist/sidebar-state.d.ts +2 -171
- package/dist/sidebar-state.js +1 -1
- package/dist/{token-bvp0y166.js → token-9823y0pc.js} +1 -1
- package/dist/token-util-ypgz7rge.js +1 -0
- package/dist/tui-preferences.d.ts +27 -26
- package/dist/tui-preferences.js +1 -1
- package/dist/tui.d.ts +42 -19
- package/package.json +8 -14
- package/src/tui/entry.mjs +2 -2
- package/src/tui-compiled/{core/account-paths.ts → raw/core-account-paths.ts} +29 -18
- package/src/tui-compiled/raw/core-custody-state.ts +243 -0
- package/src/tui-compiled/raw/logger.ts +53 -0
- package/src/tui-compiled/{rpc/port-file.ts → raw/rpc-port-file.ts} +1 -1
- package/src/tui-compiled/raw/rpc-protocol.ts +12 -0
- package/src/{rpc/rpc-client.ts → tui-compiled/raw/rpc-rpc-client.ts} +2 -2
- package/src/{sidebar-state.ts → tui-compiled/raw/sidebar-state.ts} +142 -13
- package/src/{tui/command-dialogs.tsx → tui-compiled/raw/tui-command-dialogs.tsx} +94 -44
- package/src/{tui.tsx → tui-compiled/raw/tui.tsx} +149 -28
- package/src/{core/account-paths.ts → tui-compiled/runtime/core-account-paths.ts} +29 -18
- package/src/tui-compiled/runtime/core-custody-state.ts +243 -0
- package/src/tui-compiled/runtime/logger.ts +53 -0
- package/src/{rpc/port-file.ts → tui-compiled/runtime/rpc-port-file.ts} +1 -1
- package/src/tui-compiled/runtime/rpc-protocol.ts +12 -0
- package/src/tui-compiled/{rpc/rpc-client.ts → runtime/rpc-rpc-client.ts} +2 -2
- package/src/tui-compiled/{sidebar-state.ts → runtime/sidebar-state.ts} +142 -13
- package/src/tui-compiled/{tui/command-dialogs.tsx → runtime/tui-command-dialogs.tsx} +73 -37
- package/src/tui-compiled/{tui.tsx → runtime/tui.tsx} +251 -153
- package/src/tui-compiled/shared/internal.ts +6 -0
- package/src/{logger.ts → tui-compiled/shared/logger.ts} +91 -23
- package/src/tui-compiled/shared/paths.ts +33 -0
- package/src/{core → tui-compiled/shared}/refresh-file-lock.ts +7 -4
- package/dist/cli.d.ts +0 -2
- package/dist/cli.js +0 -15
- package/dist/codex-http.d.ts +0 -3
- package/dist/commands.d.ts +0 -88
- package/dist/config.d.ts +0 -47
- package/dist/core/account-paths.d.ts +0 -25
- package/dist/core/accounts.d.ts +0 -330
- package/dist/core/atomic-write.d.ts +0 -1
- package/dist/core/background-quota-refresh.d.ts +0 -46
- package/dist/core/backoff.d.ts +0 -53
- package/dist/core/cachekeep.d.ts +0 -118
- package/dist/core/oauth.d.ts +0 -138
- package/dist/core/provider.d.ts +0 -70
- package/dist/core/quota-manager.d.ts +0 -192
- package/dist/core/refresh-all-quota.d.ts +0 -86
- package/dist/core/refresh-file-lock.d.ts +0 -12
- package/dist/core/reset-credits.d.ts +0 -116
- package/dist/core/sticky-routing.d.ts +0 -43
- package/dist/dump.d.ts +0 -20
- package/dist/hosted-web-search.d.ts +0 -5
- package/dist/index-87145jkw.js +0 -2
- package/dist/index-8f1200qx.js +0 -6
- package/dist/index-cfjed1st.js +0 -89
- package/dist/index-nrvjr97q.js +0 -3
- package/dist/index-qaggaze1.js +0 -2
- package/dist/index-sdcpzbnk.js +0 -2
- package/dist/logger.d.ts +0 -22
- package/dist/model-costs.d.ts +0 -29
- package/dist/prompt-context.d.ts +0 -19
- package/dist/quota-normalize-dvwtmy7f.js +0 -1
- package/dist/quota-normalize.d.ts +0 -43
- package/dist/raw-ws-bun.d.ts +0 -40
- package/dist/raw-ws-node.d.ts +0 -37
- package/dist/raw-ws-upgrade.d.ts +0 -2
- package/dist/raw-ws.d.ts +0 -3
- package/dist/response-stream-error.d.ts +0 -12
- package/dist/rpc/notifications.d.ts +0 -5
- package/dist/rpc/rpc-server.d.ts +0 -17
- package/dist/token-util-jcj7k7pa.js +0 -1
- package/dist/tui/command-dialogs.d.ts +0 -21
- package/dist/util/error.d.ts +0 -1
- package/dist/util/open-url.d.ts +0 -6
- package/dist/util/proxy-env.d.ts +0 -4
- package/dist/util/record.d.ts +0 -1
- package/dist/util/stable-json.d.ts +0 -1
- package/dist/util/uuid-v7.d.ts +0 -1
- package/dist/version.d.ts +0 -1
- package/dist/ws-pool.d.ts +0 -57
- package/dist/ws.d.ts +0 -71
- package/src/rpc/notifications.ts +0 -54
- package/src/rpc/protocol.ts +0 -33
- package/src/rpc/rpc-server.ts +0 -172
- package/src/tui-compiled/core/refresh-file-lock.ts +0 -381
- package/src/tui-compiled/logger.ts +0 -196
- package/src/tui-compiled/rpc/protocol.ts +0 -33
- package/src/util/error.ts +0 -9
- package/src/util/open-url.ts +0 -30
- package/src/util/proxy-env.ts +0 -42
- package/src/util/record.ts +0 -3
- package/src/util/stable-json.ts +0 -15
- package/src/util/uuid-v7.ts +0 -18
- /package/src/{rpc/rpc-dir.ts → tui-compiled/raw/rpc-rpc-dir.ts} +0 -0
- /package/src/tui-compiled/{tui-preferences.ts → raw/tui-preferences.ts} +0 -0
- /package/src/tui-compiled/{rpc/rpc-dir.ts → runtime/rpc-rpc-dir.ts} +0 -0
- /package/src/{tui-preferences.ts → tui-compiled/runtime/tui-preferences.ts} +0 -0
- /package/src/tui-compiled/{util → shared/util}/error.ts +0 -0
- /package/src/tui-compiled/{util → shared/util}/open-url.ts +0 -0
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenCode's log destination.
|
|
3
|
+
*
|
|
4
|
+
* The logger itself lives in the shared core so both hosts get the same
|
|
5
|
+
* redaction rules. What stays here is the part that is specific to this host:
|
|
6
|
+
* which file the lines go to, which level floor applies, and when the buffer is
|
|
7
|
+
* drained at process exit. Those are the only three things that read this
|
|
8
|
+
* host's environment variables, and the core reads none.
|
|
9
|
+
*
|
|
10
|
+
* The init runs at module load rather than from one call site because every
|
|
11
|
+
* entry point in this package — the plugin loader, the RPC server, the separate
|
|
12
|
+
* TUI process — reaches the logger through this module, and a core logger no
|
|
13
|
+
* host has initialised silently drops every line. Both values are passed as
|
|
14
|
+
* functions so the destination and level keep resolving on each write, which is
|
|
15
|
+
* what they do today.
|
|
16
|
+
*/
|
|
17
|
+
import { tmpdir } from 'node:os'
|
|
18
|
+
import { join } from 'node:path'
|
|
19
|
+
import {
|
|
20
|
+
flushLogs,
|
|
21
|
+
initLogger,
|
|
22
|
+
type Level,
|
|
23
|
+
} from '../shared/internal.ts'
|
|
24
|
+
|
|
25
|
+
export {
|
|
26
|
+
createLogger,
|
|
27
|
+
flushForTest,
|
|
28
|
+
flushLogs,
|
|
29
|
+
type Level,
|
|
30
|
+
redact,
|
|
31
|
+
redactStrings,
|
|
32
|
+
setLogLevel,
|
|
33
|
+
} from '../shared/internal.ts'
|
|
34
|
+
|
|
35
|
+
const LEVELS: readonly Level[] = ['error', 'warn', 'info', 'debug', 'trace']
|
|
36
|
+
|
|
37
|
+
export function getLogFile(): string {
|
|
38
|
+
return (
|
|
39
|
+
process.env.OPENCODE_OPENAI_AUTH_LOG_FILE ??
|
|
40
|
+
join(tmpdir(), 'opencode-openai-auth.log')
|
|
41
|
+
)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function getEnvLogLevel(): Level | undefined {
|
|
45
|
+
const env = process.env.OPENCODE_OPENAI_AUTH_LOG_LEVEL as Level | undefined
|
|
46
|
+
return env && LEVELS.includes(env) ? env : undefined
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
initLogger({ file: getLogFile, level: getEnvLogLevel })
|
|
50
|
+
|
|
51
|
+
// Under `bun test` the buffer is drained explicitly by the tests that assert on
|
|
52
|
+
// it, and registering a process-wide exit handler per test file is noise.
|
|
53
|
+
if (process.env.NODE_ENV !== 'test') process.on('exit', flushLogs)
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The RPC payload types now live in the shared core, because both hosts build
|
|
3
|
+
* the same payloads. This file stays on disk as a re-export so the existing
|
|
4
|
+
* build entry and every importer that names `rpc/protocol` keep working.
|
|
5
|
+
*/
|
|
6
|
+
export type {
|
|
7
|
+
ApplyRequest,
|
|
8
|
+
ApplyResult,
|
|
9
|
+
CommandModalName,
|
|
10
|
+
OpenDialogPayload,
|
|
11
|
+
RpcNotification,
|
|
12
|
+
} from '../shared/internal.ts'
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { discoverPortFile, type PortFileEntry } from './port-file'
|
|
2
|
-
import type { ApplyRequest, ApplyResult, RpcNotification } from './protocol'
|
|
1
|
+
import { discoverPortFile, type PortFileEntry } from './rpc-port-file.ts'
|
|
2
|
+
import type { ApplyRequest, ApplyResult, RpcNotification } from './rpc-protocol.ts'
|
|
3
3
|
|
|
4
4
|
export interface RpcClient {
|
|
5
5
|
pending: (
|
|
@@ -6,10 +6,23 @@ export interface QuotaWindow {
|
|
|
6
6
|
windowMinutes?: number
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
+
export interface SpendControlReading {
|
|
10
|
+
limit: number
|
|
11
|
+
used: number
|
|
12
|
+
remaining: number
|
|
13
|
+
usedPercent: number
|
|
14
|
+
remainingPercent: number
|
|
15
|
+
resetsAt?: string
|
|
16
|
+
unit?: string
|
|
17
|
+
source?: string
|
|
18
|
+
reached: boolean
|
|
19
|
+
}
|
|
20
|
+
|
|
9
21
|
export interface AccountQuota {
|
|
10
22
|
checkedAt?: number
|
|
11
23
|
primary?: QuotaWindow
|
|
12
24
|
secondary?: QuotaWindow
|
|
25
|
+
spendControl?: SpendControlReading
|
|
13
26
|
resetCreditsAvailable?: number
|
|
14
27
|
}
|
|
15
28
|
|
|
@@ -88,6 +101,17 @@ export interface SidebarAccountState {
|
|
|
88
101
|
killed: boolean
|
|
89
102
|
enabled: boolean
|
|
90
103
|
resetCredits?: number
|
|
104
|
+
custody?: SidebarAccountCustody
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export type SidebarCustodyState = 'vault' | 'needsLogin' | 'local' | 'inert'
|
|
108
|
+
|
|
109
|
+
export type SidebarCustodyReason = CustodyInertReason | 'corrupt'
|
|
110
|
+
|
|
111
|
+
export interface SidebarAccountCustody {
|
|
112
|
+
state: SidebarCustodyState
|
|
113
|
+
reason?: SidebarCustodyReason
|
|
114
|
+
recordVersion?: number
|
|
91
115
|
}
|
|
92
116
|
|
|
93
117
|
export interface ActiveRoutingEntry {
|
|
@@ -132,6 +156,7 @@ export interface SidebarState {
|
|
|
132
156
|
quota: AccountQuota | null
|
|
133
157
|
/** ChatGPT identity of the main account this quota belongs to. */
|
|
134
158
|
mainAccountId?: string
|
|
159
|
+
custody?: SidebarAccountCustody
|
|
135
160
|
killed: boolean
|
|
136
161
|
quotaBackedOff?: boolean
|
|
137
162
|
quotaBackoffUntil?: number
|
|
@@ -155,8 +180,13 @@ import { createHash, randomUUID } from 'node:crypto'
|
|
|
155
180
|
import { chmod, mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises'
|
|
156
181
|
import { tmpdir } from 'node:os'
|
|
157
182
|
import { dirname, join } from 'node:path'
|
|
158
|
-
import { acquireRefreshFileLock } from '
|
|
159
|
-
import {
|
|
183
|
+
import { acquireRefreshFileLock } from '../shared/internal.ts'
|
|
184
|
+
import {
|
|
185
|
+
CUSTODY_INERT_REASONS,
|
|
186
|
+
type CustodyInertReason,
|
|
187
|
+
type CustodyVerdict,
|
|
188
|
+
} from './core-custody-state.ts'
|
|
189
|
+
import { createLogger } from './logger.ts'
|
|
160
190
|
|
|
161
191
|
const logSb = createLogger('sidebar')
|
|
162
192
|
|
|
@@ -183,6 +213,49 @@ function resetCreditsField(value: unknown): { resetCredits?: number } {
|
|
|
183
213
|
return credits !== undefined ? { resetCredits: credits } : {}
|
|
184
214
|
}
|
|
185
215
|
|
|
216
|
+
const CUSTODY_STATES = new Set<SidebarCustodyState>([
|
|
217
|
+
'vault',
|
|
218
|
+
'needsLogin',
|
|
219
|
+
'local',
|
|
220
|
+
'inert',
|
|
221
|
+
])
|
|
222
|
+
|
|
223
|
+
const CUSTODY_REASONS = new Set<SidebarCustodyReason>([
|
|
224
|
+
...CUSTODY_INERT_REASONS,
|
|
225
|
+
'corrupt',
|
|
226
|
+
])
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Tolerant reader for the per-fallback `custody` projection. Unknown state
|
|
230
|
+
* or reason values are dropped (NOT replaced with a default — a stale state
|
|
231
|
+
* file with an experimental `vaultHealing` value must not silently render
|
|
232
|
+
* as `local`, it must render as no-projection-at-all). Valid values round-
|
|
233
|
+
* trip byte-identical. The output contains only `state` and `reason`.
|
|
234
|
+
*/
|
|
235
|
+
function normalizeSidebarCustody(
|
|
236
|
+
value: unknown,
|
|
237
|
+
): SidebarAccountCustody | undefined {
|
|
238
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value)) {
|
|
239
|
+
return undefined
|
|
240
|
+
}
|
|
241
|
+
const c = value as Record<string, unknown>
|
|
242
|
+
if (
|
|
243
|
+
typeof c.state !== 'string' ||
|
|
244
|
+
!CUSTODY_STATES.has(c.state as SidebarCustodyState)
|
|
245
|
+
) {
|
|
246
|
+
return undefined
|
|
247
|
+
}
|
|
248
|
+
const state = c.state as SidebarCustodyState
|
|
249
|
+
const out: SidebarAccountCustody = { state }
|
|
250
|
+
if (
|
|
251
|
+
typeof c.reason === 'string' &&
|
|
252
|
+
CUSTODY_REASONS.has(c.reason as SidebarCustodyReason)
|
|
253
|
+
) {
|
|
254
|
+
out.reason = c.reason as SidebarCustodyReason
|
|
255
|
+
}
|
|
256
|
+
return out
|
|
257
|
+
}
|
|
258
|
+
|
|
186
259
|
function normalizeActiveRouting(value: unknown): ActiveRoutingMap | undefined {
|
|
187
260
|
if (value === null || typeof value !== 'object' || Array.isArray(value)) {
|
|
188
261
|
return undefined
|
|
@@ -276,6 +349,23 @@ export function getSidebarStateFile(): string {
|
|
|
276
349
|
return process.env[STATE_FILE_ENV] || DEFAULT_STATE_FILE
|
|
277
350
|
}
|
|
278
351
|
|
|
352
|
+
export function projectCustodyForSidebar(
|
|
353
|
+
verdict: CustodyVerdict,
|
|
354
|
+
): SidebarAccountCustody {
|
|
355
|
+
switch (verdict.kind) {
|
|
356
|
+
case 'LOCAL':
|
|
357
|
+
return { state: 'local' }
|
|
358
|
+
case 'VAULT':
|
|
359
|
+
return { state: 'vault' }
|
|
360
|
+
case 'INERT':
|
|
361
|
+
return { state: 'inert', reason: verdict.reason }
|
|
362
|
+
case 'NEEDS_LOGIN':
|
|
363
|
+
return verdict.reason === 'corrupt'
|
|
364
|
+
? { state: 'needsLogin', reason: 'corrupt' }
|
|
365
|
+
: { state: 'needsLogin' }
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
279
369
|
export const DEFAULT_SIDEBAR_STATE: SidebarState = {
|
|
280
370
|
main: { quota: null, killed: false },
|
|
281
371
|
fallbacks: [],
|
|
@@ -315,6 +405,10 @@ export function normalizeSidebarState(raw: unknown): SidebarState {
|
|
|
315
405
|
...(typeof m.mainAccountId === 'string'
|
|
316
406
|
? { mainAccountId: m.mainAccountId }
|
|
317
407
|
: {}),
|
|
408
|
+
...(() => {
|
|
409
|
+
const custody = normalizeSidebarCustody(m.custody)
|
|
410
|
+
return custody ? { custody } : {}
|
|
411
|
+
})(),
|
|
318
412
|
// Preserve optional backoff fields if present
|
|
319
413
|
...(typeof m.quotaBackedOff === 'boolean'
|
|
320
414
|
? { quotaBackedOff: m.quotaBackedOff }
|
|
@@ -347,17 +441,21 @@ export function normalizeSidebarState(raw: unknown): SidebarState {
|
|
|
347
441
|
!Array.isArray(entry) &&
|
|
348
442
|
typeof (entry as Record<string, unknown>).id === 'string',
|
|
349
443
|
)
|
|
350
|
-
.map((e) =>
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
444
|
+
.map((e) => {
|
|
445
|
+
const custody = normalizeSidebarCustody(e.custody)
|
|
446
|
+
return {
|
|
447
|
+
id: e.id as string,
|
|
448
|
+
label: typeof e.label === 'string' ? e.label : undefined,
|
|
449
|
+
...(typeof e.accountId === 'string'
|
|
450
|
+
? { accountId: e.accountId }
|
|
451
|
+
: {}),
|
|
452
|
+
quota: ('quota' in e ? e.quota : null) as AccountQuota | null,
|
|
453
|
+
killed: typeof e.killed === 'boolean' ? e.killed : false,
|
|
454
|
+
enabled: typeof e.enabled === 'boolean' ? e.enabled : true,
|
|
455
|
+
...resetCreditsField(e.resetCredits),
|
|
456
|
+
...(custody ? { custody } : {}),
|
|
457
|
+
}
|
|
458
|
+
})
|
|
361
459
|
: []
|
|
362
460
|
|
|
363
461
|
// activeId — string or undefined
|
|
@@ -428,6 +526,27 @@ export function isUsableRoutingEntry(
|
|
|
428
526
|
)
|
|
429
527
|
}
|
|
430
528
|
|
|
529
|
+
// The credit budget's own exhaustion signal, shared by admission and sticky
|
|
530
|
+
// migration so both agree on what "spent" means. `reached` is the provider's
|
|
531
|
+
// authoritative boolean — the percentage is only a display approximation — and
|
|
532
|
+
// the check fails open on a missing or lapsed reset exactly like a rate-limit
|
|
533
|
+
// window, so a stale or corrupt reading never blocks.
|
|
534
|
+
export function spendControlExhaustedResetAt(
|
|
535
|
+
quota: AccountQuota | null | undefined,
|
|
536
|
+
now = Date.now(),
|
|
537
|
+
): { resetsAt: string; resetAtMs: number } | undefined {
|
|
538
|
+
const spendControl = quota?.spendControl
|
|
539
|
+
if (
|
|
540
|
+
spendControl?.reached !== true ||
|
|
541
|
+
typeof spendControl.resetsAt !== 'string'
|
|
542
|
+
) {
|
|
543
|
+
return undefined
|
|
544
|
+
}
|
|
545
|
+
const resetAtMs = Date.parse(spendControl.resetsAt)
|
|
546
|
+
if (!Number.isFinite(resetAtMs) || resetAtMs <= now) return undefined
|
|
547
|
+
return { resetsAt: spendControl.resetsAt, resetAtMs }
|
|
548
|
+
}
|
|
549
|
+
|
|
431
550
|
// Earliest future reset among the quota's exhausted windows, or undefined when
|
|
432
551
|
// no present window is exhausted. Every present window is evaluated — matching
|
|
433
552
|
// the admission policy, which rejects an account when ANY live window is below
|
|
@@ -454,6 +573,12 @@ export function exhaustedQuotaResetAt(
|
|
|
454
573
|
earliest = { resetsAt: window.resetsAt, resetAtMs }
|
|
455
574
|
}
|
|
456
575
|
}
|
|
576
|
+
// The credit budget is a third axis on its own reset clock (a month, not
|
|
577
|
+
// 5h/7d), judged by the same shared signal sticky migration uses.
|
|
578
|
+
const spendReset = spendControlExhaustedResetAt(quota, now)
|
|
579
|
+
if (spendReset && (!earliest || spendReset.resetAtMs < earliest.resetAtMs)) {
|
|
580
|
+
earliest = spendReset
|
|
581
|
+
}
|
|
457
582
|
return earliest
|
|
458
583
|
}
|
|
459
584
|
|
|
@@ -1004,6 +1129,9 @@ function mergeQuotaByWindow(
|
|
|
1004
1129
|
incoming.checkedAt,
|
|
1005
1130
|
existing.checkedAt,
|
|
1006
1131
|
)
|
|
1132
|
+
const spendControl = existingSnapshotIsFresher
|
|
1133
|
+
? (existing.spendControl ?? incoming.spendControl)
|
|
1134
|
+
: (incoming.spendControl ?? existing.spendControl)
|
|
1007
1135
|
let checkedAt: number | undefined
|
|
1008
1136
|
for (const stamp of [
|
|
1009
1137
|
finiteWindowCheckedAt(primary),
|
|
@@ -1017,6 +1145,7 @@ function mergeQuotaByWindow(
|
|
|
1017
1145
|
...incoming,
|
|
1018
1146
|
primary,
|
|
1019
1147
|
secondary,
|
|
1148
|
+
...(spendControl !== undefined ? { spendControl } : {}),
|
|
1020
1149
|
checkedAt: checkedAt ?? incoming.checkedAt,
|
|
1021
1150
|
}
|
|
1022
1151
|
}
|
|
@@ -7,10 +7,9 @@ import { createElement as _$createElement } from "opentui:runtime-module:%40open
|
|
|
7
7
|
import { createComponent as _$createComponent } from "opentui:runtime-module:%40opentui%2Fsolid";
|
|
8
8
|
/** @jsxImportSource @opentui/solid */
|
|
9
9
|
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import { openUrl } from "../util/open-url";
|
|
10
|
+
import { errorMessage, openUrl } from "../shared/internal.ts";
|
|
11
|
+
import { createLogger } from "./logger.ts";
|
|
12
|
+
import { getCollapsedQuotaSummary, getSidebarState, resolveSessionSidebarRouting } from "./sidebar-state.ts";
|
|
14
13
|
const log = createLogger('rpc-tui');
|
|
15
14
|
export function buildCachekeepDialogOptions(payload) {
|
|
16
15
|
const enabled = payload.knobs.enabled === true;
|
|
@@ -467,7 +466,7 @@ export function openCommandDialog(api, payload, apply, sessionId) {
|
|
|
467
466
|
return;
|
|
468
467
|
}
|
|
469
468
|
if (payload.command === 'openai-account') {
|
|
470
|
-
openAccountDialog(api, apply, sessionId);
|
|
469
|
+
openAccountDialog(api, apply, sessionId, payload);
|
|
471
470
|
return;
|
|
472
471
|
}
|
|
473
472
|
|
|
@@ -508,8 +507,49 @@ export function buildAccountDialogRows(state, sessionId) {
|
|
|
508
507
|
description: formatQuotaWindows(fb.quota)
|
|
509
508
|
}))];
|
|
510
509
|
}
|
|
511
|
-
function
|
|
510
|
+
export function accountDialogModeOption(mode) {
|
|
511
|
+
const claustrum = mode === 'claustrum';
|
|
512
|
+
return {
|
|
513
|
+
title: claustrum ? 'Leave Claustrum' : 'Enter Claustrum',
|
|
514
|
+
value: claustrum ? '__local__' : '__claustrum__',
|
|
515
|
+
description: claustrum ? 'Require fresh local logins before local refresh resumes' : 'Verify every enabled account before custody takes over'
|
|
516
|
+
};
|
|
517
|
+
}
|
|
518
|
+
export function buildFallbackAccountOptions(input) {
|
|
519
|
+
const name = input.label ?? input.id;
|
|
520
|
+
const options = [{
|
|
521
|
+
title: input.enabled ? 'Disable' : 'Enable',
|
|
522
|
+
value: input.enabled ? 'disable' : 'enable',
|
|
523
|
+
description: `${input.enabled ? 'Disable' : 'Enable'} ${name}`
|
|
524
|
+
}, {
|
|
525
|
+
title: 'Remove',
|
|
526
|
+
value: 'remove',
|
|
527
|
+
description: `Remove ${name}`
|
|
528
|
+
}];
|
|
529
|
+
if (input.index > 0) {
|
|
530
|
+
options.push({
|
|
531
|
+
title: 'Move up',
|
|
532
|
+
value: 'move_up',
|
|
533
|
+
description: 'Swap with the preceding fallback'
|
|
534
|
+
});
|
|
535
|
+
}
|
|
536
|
+
if (input.index < input.count - 1) {
|
|
537
|
+
options.push({
|
|
538
|
+
title: 'Move down',
|
|
539
|
+
value: 'move_down',
|
|
540
|
+
description: 'Swap with the following fallback'
|
|
541
|
+
});
|
|
542
|
+
}
|
|
543
|
+
options.push({
|
|
544
|
+
title: 'Back',
|
|
545
|
+
value: 'back',
|
|
546
|
+
description: 'Return to account list'
|
|
547
|
+
});
|
|
548
|
+
return options;
|
|
549
|
+
}
|
|
550
|
+
function openAccountDialog(api, apply, sessionId, payload) {
|
|
512
551
|
const DialogConfirm = api.ui.DialogConfirm;
|
|
552
|
+
let claustrumMode = payload?.knobs.claustrumMode;
|
|
513
553
|
function showL1() {
|
|
514
554
|
void getSidebarState().then(state => {
|
|
515
555
|
const DialogSelectInner = api.ui.DialogSelect;
|
|
@@ -517,13 +557,24 @@ function openAccountDialog(api, apply, sessionId) {
|
|
|
517
557
|
api.ui.dialog.replace(() => _$createComponent(DialogSelectInner, {
|
|
518
558
|
title: "OpenAI Accounts",
|
|
519
559
|
get options() {
|
|
520
|
-
return [...buildAccountDialogRows(state, sessionId), {
|
|
560
|
+
return [accountDialogModeOption(claustrumMode), ...buildAccountDialogRows(state, sessionId), {
|
|
521
561
|
title: 'Add account\u2026',
|
|
522
562
|
value: '__add__',
|
|
523
563
|
description: 'Sign in to a new OpenAI account'
|
|
524
564
|
}];
|
|
525
565
|
},
|
|
526
566
|
onSelect: option => {
|
|
567
|
+
if (option.value === '__claustrum__' || option.value === '__local__') {
|
|
568
|
+
const args = option.value === '__claustrum__' ? 'claustrum' : 'local';
|
|
569
|
+
void apply('openai-account', args).then(r => {
|
|
570
|
+
api.ui.toast({
|
|
571
|
+
message: r.text
|
|
572
|
+
});
|
|
573
|
+
claustrumMode = r.knobs.claustrumMode;
|
|
574
|
+
showL1();
|
|
575
|
+
});
|
|
576
|
+
return;
|
|
577
|
+
}
|
|
527
578
|
if (option.value === '__add__') {
|
|
528
579
|
showAddFlow();
|
|
529
580
|
return;
|
|
@@ -545,36 +596,12 @@ function openAccountDialog(api, apply, sessionId) {
|
|
|
545
596
|
showL1();
|
|
546
597
|
return;
|
|
547
598
|
}
|
|
548
|
-
const options =
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
if (fbIndex > 0) {
|
|
555
|
-
const neighbor = state.fallbacks[fbIndex - 1];
|
|
556
|
-
if (neighbor) {
|
|
557
|
-
options.push({
|
|
558
|
-
title: 'Move up',
|
|
559
|
-
value: 'move_up',
|
|
560
|
-
description: `Swap with ${neighbor.label ?? neighbor.id}`
|
|
561
|
-
});
|
|
562
|
-
}
|
|
563
|
-
}
|
|
564
|
-
if (fbIndex < state.fallbacks.length - 1) {
|
|
565
|
-
const neighbor = state.fallbacks[fbIndex + 1];
|
|
566
|
-
if (neighbor) {
|
|
567
|
-
options.push({
|
|
568
|
-
title: 'Move down',
|
|
569
|
-
value: 'move_down',
|
|
570
|
-
description: `Swap with ${neighbor.label ?? neighbor.id}`
|
|
571
|
-
});
|
|
572
|
-
}
|
|
573
|
-
}
|
|
574
|
-
options.push({
|
|
575
|
-
title: 'Back',
|
|
576
|
-
value: 'back',
|
|
577
|
-
description: 'Return to account list'
|
|
599
|
+
const options = buildFallbackAccountOptions({
|
|
600
|
+
id: fb.id,
|
|
601
|
+
label: fb.label,
|
|
602
|
+
enabled: fb.enabled,
|
|
603
|
+
index: fbIndex,
|
|
604
|
+
count: state.fallbacks.length
|
|
578
605
|
});
|
|
579
606
|
api.ui.dialog.setSize('xlarge');
|
|
580
607
|
api.ui.dialog.replace(() => _$createComponent(DialogSelectInner, {
|
|
@@ -602,6 +629,15 @@ function openAccountDialog(api, apply, sessionId) {
|
|
|
602
629
|
}));
|
|
603
630
|
return;
|
|
604
631
|
}
|
|
632
|
+
if (option.value === 'enable' || option.value === 'disable') {
|
|
633
|
+
void apply('openai-account', `${option.value} ${id}`).then(r => {
|
|
634
|
+
api.ui.toast({
|
|
635
|
+
message: r.text
|
|
636
|
+
});
|
|
637
|
+
showL1();
|
|
638
|
+
});
|
|
639
|
+
return;
|
|
640
|
+
}
|
|
605
641
|
if (option.value === 'move_up') {
|
|
606
642
|
const neighbor = state.fallbacks[fbIndex - 1];
|
|
607
643
|
if (neighbor) {
|