@cortexkit/opencode-anthropic-auth 1.14.0 → 1.15.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/README.md +1 -0
- package/dist/cli.js +1 -1
- package/dist/fable-fallback.d.ts +34 -0
- package/dist/{index-se4sd5kz.js → index-6gdd6e4s.js} +1 -1
- package/dist/index-bxs26mw4.js +2 -0
- package/dist/{index-ha0gz07d.js → index-jkbar3k3.js} +1 -1
- package/dist/{index-97vmbv5w.js → index-qejbx8c9.js} +1 -1
- package/dist/{index-1gc9eney.js → index-qsaph2g4.js} +1 -1
- package/dist/index-z03wayzs.js +417 -0
- package/dist/index.js +12 -12
- package/dist/{logger-sg9wxpvj.js → logger-vxnb5hjr.js} +1 -1
- package/dist/prompt-context.d.ts +5 -2
- package/dist/rpc/port-file.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 +8 -0
- package/dist/sidebar-state.js +1 -1
- package/dist/transform.d.ts +16 -0
- package/dist/tui-preferences.js +1 -1
- package/package.json +13 -10
- package/src/sidebar-state.ts +47 -0
- package/src/tui/entry.mjs +37 -0
- package/src/tui-compiled/rpc/port-file.ts +70 -0
- package/src/tui-compiled/rpc/protocol.ts +34 -0
- package/src/tui-compiled/rpc/rpc-client.ts +62 -0
- package/src/tui-compiled/rpc/rpc-dir.ts +19 -0
- package/src/tui-compiled/sidebar-state.ts +410 -0
- package/src/tui-compiled/tui/command-dialogs.tsx +615 -0
- package/src/tui-compiled/tui-preferences.ts +370 -0
- package/src/tui-compiled/tui.tsx +1102 -0
- package/src/tui.tsx +54 -15
- package/dist/index-8meqn6xw.js +0 -2
- package/dist/index-fwjqfkj2.js +0 -417
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cortexkit/opencode-anthropic-auth",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.15.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
},
|
|
17
17
|
"./tui": {
|
|
18
18
|
"types": "./dist/tui.d.ts",
|
|
19
|
-
"import": "./src/tui.
|
|
19
|
+
"import": "./src/tui/entry.mjs"
|
|
20
20
|
},
|
|
21
21
|
"./tui-prefs": {
|
|
22
22
|
"types": "./dist/tui-preferences.d.ts",
|
|
@@ -36,7 +36,8 @@
|
|
|
36
36
|
"files": [
|
|
37
37
|
"dist",
|
|
38
38
|
"src/tui.tsx",
|
|
39
|
-
"src/tui
|
|
39
|
+
"src/tui",
|
|
40
|
+
"src/tui-compiled",
|
|
40
41
|
"src/sidebar-state.ts",
|
|
41
42
|
"src/tui-preferences.ts",
|
|
42
43
|
"src/rpc",
|
|
@@ -44,24 +45,26 @@
|
|
|
44
45
|
"LICENSE"
|
|
45
46
|
],
|
|
46
47
|
"scripts": {
|
|
47
|
-
"build": "rm -rf dist && bun build src/index.ts src/cli.ts src/sidebar-state.ts src/tui-preferences.ts src/rpc/rpc-client.ts src/rpc/port-file.ts src/rpc/protocol.ts src/rpc/rpc-dir.ts --outdir dist --target node --format esm --splitting --external @opencode-ai/plugin --minify && tsc -p tsconfig.build.json --emitDeclarationOnly",
|
|
48
|
+
"build": "rm -rf dist && bun build src/index.ts src/cli.ts src/sidebar-state.ts src/tui-preferences.ts src/rpc/rpc-client.ts src/rpc/port-file.ts src/rpc/protocol.ts src/rpc/rpc-dir.ts --outdir dist --target node --format esm --splitting --external @opencode-ai/plugin --minify && tsc -p tsconfig.build.json --emitDeclarationOnly && bun run build:tui",
|
|
49
|
+
"build:tui": "bun scripts/build-tui.ts",
|
|
50
|
+
"smoke:tui": "bun scripts/smoke-tui-pack-install.ts",
|
|
48
51
|
"build:dev": "rm -rf dist && tsc -p tsconfig.build.json",
|
|
49
52
|
"dev": "bun ../../scripts/dev.ts",
|
|
50
53
|
"dev:clean": "bun ../../scripts/dev-clean.ts",
|
|
51
54
|
"extract": "bun ../../scripts/extract-system-prompt.ts",
|
|
52
55
|
"test": "bun test src/tests",
|
|
53
|
-
"typecheck": "tsc",
|
|
54
|
-
"types": "tsc",
|
|
56
|
+
"typecheck": "tsc && tsc -p tsconfig.scripts.json",
|
|
57
|
+
"types": "tsc && tsc -p tsconfig.scripts.json",
|
|
55
58
|
"prepublishOnly": "bun run build"
|
|
56
59
|
},
|
|
57
60
|
"peerDependencies": {
|
|
58
61
|
"@opencode-ai/plugin": "*"
|
|
59
62
|
},
|
|
60
63
|
"dependencies": {
|
|
61
|
-
"@cortexkit/anthropic-auth-core": "1.
|
|
62
|
-
"@opentui/core": "
|
|
63
|
-
"@opentui/solid": "
|
|
64
|
+
"@cortexkit/anthropic-auth-core": "1.15.1",
|
|
65
|
+
"@opentui/core": "0.4.3",
|
|
66
|
+
"@opentui/solid": "0.4.3",
|
|
64
67
|
"jsonc-parser": "^3.3.1",
|
|
65
|
-
"solid-js": "
|
|
68
|
+
"solid-js": "1.9.12"
|
|
66
69
|
}
|
|
67
70
|
}
|
package/src/sidebar-state.ts
CHANGED
|
@@ -27,6 +27,13 @@ export interface SidebarAccountState {
|
|
|
27
27
|
needsReauth: boolean
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
export interface FableRecoverySidebarState {
|
|
31
|
+
sessionId: string
|
|
32
|
+
mode: 'opus' | 'fable'
|
|
33
|
+
remaining: number
|
|
34
|
+
changedAt: number
|
|
35
|
+
}
|
|
36
|
+
|
|
30
37
|
export interface SidebarState {
|
|
31
38
|
main: {
|
|
32
39
|
quota: AccountQuota | null
|
|
@@ -45,6 +52,7 @@ export interface SidebarState {
|
|
|
45
52
|
window?: string
|
|
46
53
|
trackedSessions?: number
|
|
47
54
|
}
|
|
55
|
+
fableRecoveries?: FableRecoverySidebarState[]
|
|
48
56
|
lastUpdated: number
|
|
49
57
|
}
|
|
50
58
|
|
|
@@ -185,6 +193,32 @@ export function normalizeSidebarState(raw: unknown): SidebarState {
|
|
|
185
193
|
}
|
|
186
194
|
}
|
|
187
195
|
|
|
196
|
+
const fableRecoveries: FableRecoverySidebarState[] = Array.isArray(
|
|
197
|
+
raw.fableRecoveries,
|
|
198
|
+
)
|
|
199
|
+
? raw.fableRecoveries
|
|
200
|
+
.filter(isRecord)
|
|
201
|
+
.flatMap((recovery): FableRecoverySidebarState[] => {
|
|
202
|
+
if (
|
|
203
|
+
typeof recovery.sessionId !== 'string' ||
|
|
204
|
+
(recovery.mode !== 'opus' && recovery.mode !== 'fable') ||
|
|
205
|
+
typeof recovery.remaining !== 'number' ||
|
|
206
|
+
!Number.isFinite(recovery.remaining) ||
|
|
207
|
+
typeof recovery.changedAt !== 'number' ||
|
|
208
|
+
!Number.isFinite(recovery.changedAt)
|
|
209
|
+
)
|
|
210
|
+
return []
|
|
211
|
+
return [
|
|
212
|
+
{
|
|
213
|
+
sessionId: recovery.sessionId,
|
|
214
|
+
mode: recovery.mode,
|
|
215
|
+
remaining: Math.max(0, Math.floor(recovery.remaining)),
|
|
216
|
+
changedAt: recovery.changedAt,
|
|
217
|
+
},
|
|
218
|
+
]
|
|
219
|
+
})
|
|
220
|
+
: []
|
|
221
|
+
|
|
188
222
|
return {
|
|
189
223
|
main,
|
|
190
224
|
fallbacks,
|
|
@@ -197,6 +231,7 @@ export function normalizeSidebarState(raw: unknown): SidebarState {
|
|
|
197
231
|
? raw.fastMode
|
|
198
232
|
: DEFAULT_SIDEBAR_STATE.fastMode,
|
|
199
233
|
cacheKeep,
|
|
234
|
+
fableRecoveries: fableRecoveries.length > 0 ? fableRecoveries : undefined,
|
|
200
235
|
lastUpdated: typeof raw.lastUpdated === 'number' ? raw.lastUpdated : 0,
|
|
201
236
|
}
|
|
202
237
|
}
|
|
@@ -265,6 +300,18 @@ export function formatScopedQuotaLabel(title: string) {
|
|
|
265
300
|
return /^fable$/i.test(label) ? 'Fa' : label
|
|
266
301
|
}
|
|
267
302
|
|
|
303
|
+
export function getFableRecoverySummary(
|
|
304
|
+
state: SidebarState,
|
|
305
|
+
sessionId: string,
|
|
306
|
+
): string | undefined {
|
|
307
|
+
const recovery = state.fableRecoveries?.find(
|
|
308
|
+
(candidate) => candidate.sessionId === sessionId,
|
|
309
|
+
)
|
|
310
|
+
if (!recovery) return undefined
|
|
311
|
+
if (recovery.mode === 'fable') return 'Fable 5 · restored'
|
|
312
|
+
return `Opus 4.8 · ${recovery.remaining} left`
|
|
313
|
+
}
|
|
314
|
+
|
|
268
315
|
export function getCollapsedQuotaSummary(quota: AccountQuota | null): {
|
|
269
316
|
fiveHourUsedPercent: number | null
|
|
270
317
|
sevenDayUsedPercent: number | null
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// Prefer the host OpenTUI runtime registry when it exists. OpenTUI 0.4.x
|
|
2
|
+
// registers these virtual modules process-wide, allowing the precompiled TUI to
|
|
3
|
+
// share the host's single Solid/OpenTUI runtime when loaded from node_modules.
|
|
4
|
+
const runtimeProbe = `opentui:runtime-module:${encodeURIComponent('@opentui/solid')}`
|
|
5
|
+
|
|
6
|
+
function isMissingRuntimeRegistry(error) {
|
|
7
|
+
const message = error instanceof Error ? error.message : String(error)
|
|
8
|
+
return (
|
|
9
|
+
/Cannot find|Could not resolve|Module not found|Unable to resolve/.test(
|
|
10
|
+
message,
|
|
11
|
+
) && message.includes('opentui:runtime-module:')
|
|
12
|
+
)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
let mod
|
|
16
|
+
try {
|
|
17
|
+
await import(runtimeProbe)
|
|
18
|
+
} catch (error) {
|
|
19
|
+
if (!isMissingRuntimeRegistry(error)) {
|
|
20
|
+
console.error('Anthropic Auth TUI runtime registry probe failed', error)
|
|
21
|
+
throw error
|
|
22
|
+
}
|
|
23
|
+
// Older hosts and bare Bun do not provide the virtual registry. Their source
|
|
24
|
+
// loader still applies the Solid transform, so retain the raw TSX fallback.
|
|
25
|
+
mod = await import('../tui.tsx')
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (!mod) {
|
|
29
|
+
try {
|
|
30
|
+
mod = await import('../tui-compiled/tui.tsx')
|
|
31
|
+
} catch (error) {
|
|
32
|
+
console.error('Anthropic Auth compiled TUI failed to load', error)
|
|
33
|
+
throw error
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export default mod.default
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import {
|
|
2
|
+
mkdir,
|
|
3
|
+
readdir,
|
|
4
|
+
readFile,
|
|
5
|
+
rename,
|
|
6
|
+
unlink,
|
|
7
|
+
writeFile,
|
|
8
|
+
} from 'node:fs/promises'
|
|
9
|
+
import { join } from 'node:path'
|
|
10
|
+
|
|
11
|
+
export interface PortFileEntry {
|
|
12
|
+
port: number
|
|
13
|
+
token: string
|
|
14
|
+
pid: number
|
|
15
|
+
startedAt: number
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function pidAlive(pid: number): boolean {
|
|
19
|
+
try {
|
|
20
|
+
process.kill(pid, 0)
|
|
21
|
+
return true
|
|
22
|
+
} catch (error) {
|
|
23
|
+
return (error as NodeJS.ErrnoException).code === 'EPERM'
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export async function writePortFile(
|
|
28
|
+
dir: string,
|
|
29
|
+
entry: { port: number; token: string; pid: number },
|
|
30
|
+
): Promise<string> {
|
|
31
|
+
await mkdir(dir, { recursive: true })
|
|
32
|
+
const full: PortFileEntry = { ...entry, startedAt: Date.now() }
|
|
33
|
+
const target = join(dir, `port-${entry.pid}.json`)
|
|
34
|
+
const tmp = `${target}.${process.pid}.tmp`
|
|
35
|
+
await writeFile(tmp, JSON.stringify(full), { encoding: 'utf8', mode: 0o600 })
|
|
36
|
+
await rename(tmp, target)
|
|
37
|
+
return target
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export async function discoverPortFile(
|
|
41
|
+
dir: string,
|
|
42
|
+
expectedPid?: number,
|
|
43
|
+
): Promise<PortFileEntry | null> {
|
|
44
|
+
let names: string[]
|
|
45
|
+
try {
|
|
46
|
+
names = await readdir(dir)
|
|
47
|
+
} catch {
|
|
48
|
+
return null
|
|
49
|
+
}
|
|
50
|
+
const live: PortFileEntry[] = []
|
|
51
|
+
for (const name of names) {
|
|
52
|
+
if (!name.startsWith('port-') || !name.endsWith('.json')) continue
|
|
53
|
+
try {
|
|
54
|
+
const parsed = JSON.parse(
|
|
55
|
+
await readFile(join(dir, name), 'utf8'),
|
|
56
|
+
) as PortFileEntry
|
|
57
|
+
if (Number.isFinite(parsed.port)) {
|
|
58
|
+
if (pidAlive(parsed.pid)) live.push(parsed)
|
|
59
|
+
else unlink(join(dir, name)).catch(() => {})
|
|
60
|
+
}
|
|
61
|
+
} catch {}
|
|
62
|
+
}
|
|
63
|
+
if (live.length === 0) return null
|
|
64
|
+
const candidates =
|
|
65
|
+
expectedPid && expectedPid >= 1
|
|
66
|
+
? live.filter((entry) => entry.pid === expectedPid)
|
|
67
|
+
: []
|
|
68
|
+
const entries = candidates.length > 0 ? candidates : live
|
|
69
|
+
return entries.sort((a, b) => b.startedAt - a.startedAt)[0] ?? null
|
|
70
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export type CommandModalName =
|
|
2
|
+
| 'claude-account'
|
|
3
|
+
| 'claude-cache'
|
|
4
|
+
| 'claude-cachekeep'
|
|
5
|
+
| 'claude-quota'
|
|
6
|
+
| 'claude-dump'
|
|
7
|
+
| 'claude-fast'
|
|
8
|
+
| 'claude-routing'
|
|
9
|
+
| 'claude-killswitch'
|
|
10
|
+
| 'claude-logging'
|
|
11
|
+
|
|
12
|
+
export interface OpenDialogPayload {
|
|
13
|
+
command: CommandModalName
|
|
14
|
+
text: string
|
|
15
|
+
knobs: Record<string, unknown>
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface RpcNotification {
|
|
19
|
+
id: number
|
|
20
|
+
type: 'open-dialog'
|
|
21
|
+
payload: OpenDialogPayload
|
|
22
|
+
sessionId?: string
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface ApplyRequest {
|
|
26
|
+
command: CommandModalName
|
|
27
|
+
arguments: string
|
|
28
|
+
sessionId?: string
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface ApplyResult {
|
|
32
|
+
text: string
|
|
33
|
+
knobs: Record<string, unknown>
|
|
34
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { discoverPortFile } from './port-file'
|
|
2
|
+
import type { ApplyRequest, ApplyResult, RpcNotification } from './protocol'
|
|
3
|
+
|
|
4
|
+
export interface RpcClient {
|
|
5
|
+
pending: (
|
|
6
|
+
lastReceivedId: number,
|
|
7
|
+
sessionId?: string,
|
|
8
|
+
) => Promise<RpcNotification[]>
|
|
9
|
+
apply: (request: ApplyRequest) => Promise<ApplyResult>
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
async function call<T>(
|
|
13
|
+
dir: string,
|
|
14
|
+
method: string,
|
|
15
|
+
params: Record<string, unknown>,
|
|
16
|
+
expectedPid?: number,
|
|
17
|
+
): Promise<T | null> {
|
|
18
|
+
const entry = await discoverPortFile(dir, expectedPid)
|
|
19
|
+
if (!entry) return null
|
|
20
|
+
const controller = new AbortController()
|
|
21
|
+
const timer = setTimeout(() => controller.abort(), 2_000)
|
|
22
|
+
try {
|
|
23
|
+
const res = await fetch(`http://127.0.0.1:${entry.port}/rpc/${method}`, {
|
|
24
|
+
method: 'POST',
|
|
25
|
+
headers: {
|
|
26
|
+
'content-type': 'application/json',
|
|
27
|
+
authorization: `Bearer ${entry.token}`,
|
|
28
|
+
},
|
|
29
|
+
body: JSON.stringify(params),
|
|
30
|
+
signal: controller.signal,
|
|
31
|
+
})
|
|
32
|
+
if (!res.ok) return null
|
|
33
|
+
return (await res.json()) as T
|
|
34
|
+
} catch {
|
|
35
|
+
return null
|
|
36
|
+
} finally {
|
|
37
|
+
clearTimeout(timer)
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function createRpcClient(dir: string, expectedPid?: number): RpcClient {
|
|
42
|
+
return {
|
|
43
|
+
async pending(lastReceivedId, sessionId) {
|
|
44
|
+
const out = await call<{ messages: RpcNotification[] }>(
|
|
45
|
+
dir,
|
|
46
|
+
'pending-notifications',
|
|
47
|
+
{ lastReceivedId, sessionId },
|
|
48
|
+
expectedPid,
|
|
49
|
+
)
|
|
50
|
+
return out?.messages ?? []
|
|
51
|
+
},
|
|
52
|
+
async apply(request) {
|
|
53
|
+
const out = await call<ApplyResult>(
|
|
54
|
+
dir,
|
|
55
|
+
'apply',
|
|
56
|
+
{ ...request },
|
|
57
|
+
expectedPid,
|
|
58
|
+
)
|
|
59
|
+
return out ?? { text: 'apply failed', knobs: {} }
|
|
60
|
+
},
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto'
|
|
2
|
+
import { homedir, tmpdir } from 'node:os'
|
|
3
|
+
import { join, resolve } from 'node:path'
|
|
4
|
+
|
|
5
|
+
const RPC_DIR_ENV = 'OPENCODE_ANTHROPIC_AUTH_RPC_DIR'
|
|
6
|
+
|
|
7
|
+
// Both processes must resolve the SAME dir from the SAME project directory.
|
|
8
|
+
export function getRpcDir(projectDirectory: string): string {
|
|
9
|
+
const override = process.env[RPC_DIR_ENV]?.trim()
|
|
10
|
+
if (override) return resolve(projectDirectory, override)
|
|
11
|
+
const hash = createHash('sha256')
|
|
12
|
+
.update(projectDirectory)
|
|
13
|
+
.digest('hex')
|
|
14
|
+
.slice(0, 16)
|
|
15
|
+
const base = process.env.XDG_STATE_HOME || join(homedir(), '.local', 'state')
|
|
16
|
+
return join(base, 'cortexkit', 'anthropic-auth', 'rpc', hash)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export { tmpdir }
|