@hienlh/ppm 0.7.16 → 0.7.17

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.
Files changed (39) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/bunfig.toml +2 -0
  3. package/dist/web/assets/chat-tab-C0AcTU9S.js +7 -0
  4. package/dist/web/assets/{code-editor-DXqocnye.js → code-editor-CYt4hqge.js} +1 -1
  5. package/dist/web/assets/{database-viewer-ChX5vA56.js → database-viewer-CDto4TrW.js} +1 -1
  6. package/dist/web/assets/{diff-viewer-8RNfSVOl.js → diff-viewer-2zSPeCzX.js} +1 -1
  7. package/dist/web/assets/git-graph-HfH98qwn.js +1 -0
  8. package/dist/web/assets/index-CTOMzCnZ.js +28 -0
  9. package/dist/web/assets/index-D6GLlwUx.css +2 -0
  10. package/dist/web/assets/keybindings-store-DrjDQzVs.js +1 -0
  11. package/dist/web/assets/{markdown-renderer-BOHSi1fK.js → markdown-renderer-dqkYhU3y.js} +1 -1
  12. package/dist/web/assets/{postgres-viewer-DRo3924t.js → postgres-viewer-kqZBNVYW.js} +1 -1
  13. package/dist/web/assets/settings-tab-jhRBFgf_.js +1 -0
  14. package/dist/web/assets/{sqlite-viewer-0iVQjCmF.js → sqlite-viewer-C2744fw1.js} +1 -1
  15. package/dist/web/assets/switch-PAf5UhcN.js +1 -0
  16. package/dist/web/assets/{terminal-tab-Cuznr8Lg.js → terminal-tab-BDqc6Dl5.js} +1 -1
  17. package/dist/web/index.html +3 -3
  18. package/dist/web/sw.js +1 -1
  19. package/package.json +1 -1
  20. package/src/server/routes/accounts.ts +60 -6
  21. package/src/services/account.service.ts +180 -17
  22. package/src/services/claude-usage.service.ts +9 -2
  23. package/src/services/db.service.ts +25 -3
  24. package/src/web/components/chat/chat-history-bar.tsx +2 -1
  25. package/src/web/components/chat/message-list.tsx +4 -2
  26. package/src/web/components/chat/usage-badge.tsx +118 -22
  27. package/src/web/components/settings/accounts-settings-section.tsx +268 -33
  28. package/src/web/lib/api-settings.ts +49 -0
  29. package/src/web/styles/globals.css +7 -0
  30. package/test-claude-oauth-v2.mjs +165 -0
  31. package/test-claude-oauth.mjs +175 -0
  32. package/test-verify-oat.mjs +106 -0
  33. package/dist/web/assets/ai-settings-section-BxCMGg-I.js +0 -1
  34. package/dist/web/assets/chat-tab-DtIaMWNT.js +0 -7
  35. package/dist/web/assets/git-graph-DYbWcg6M.js +0 -1
  36. package/dist/web/assets/index-BzhcIgja.js +0 -28
  37. package/dist/web/assets/index-sMxUHxFZ.css +0 -2
  38. package/dist/web/assets/keybindings-store-DBQQ_pTh.js +0 -1
  39. package/dist/web/assets/settings-tab-6ytjTMb9.js +0 -1
@@ -0,0 +1,165 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * Claude OAuth PKCE test — fixed version
4
+ *
5
+ * Fixes vs v1:
6
+ * 1. Token endpoint: console.anthropic.com (not api.anthropic.com)
7
+ * 2. Content-Type: application/x-www-form-urlencoded (not JSON)
8
+ * 3. Removed `state` from token exchange body (client-side CSRF only)
9
+ * 4. Only platform.claude.com redirect (confirmed to work with this client_id)
10
+ *
11
+ * Usage: bun test-claude-oauth-v2.mjs
12
+ */
13
+
14
+ import crypto from 'crypto'
15
+ import readline from 'readline'
16
+ import { execSync } from 'child_process'
17
+
18
+ const CLIENT_ID = '9d1c250a-e61b-44d9-88ed-5944d1962f5e'
19
+ const REDIRECT = 'https://platform.claude.com/oauth/code/callback'
20
+ const SCOPE = 'org:create_api_key user:profile user:inference user:sessions:claude_code user:mcp_servers user:file_upload'
21
+ const TOKEN_URL = 'https://console.anthropic.com/v1/oauth/token'
22
+
23
+ // ── PKCE ────────────────────────────────────────────────────────────────────
24
+
25
+ function generatePKCE() {
26
+ // 32 random bytes → 43 base64url chars (RFC 7636 minimum entropy)
27
+ const verifier = crypto.randomBytes(32).toString('base64url')
28
+ const challenge = crypto.createHash('sha256').update(verifier).digest('base64url')
29
+ const state = crypto.randomBytes(16).toString('base64url')
30
+ return { verifier, challenge, state }
31
+ }
32
+
33
+ // ── Helpers ──────────────────────────────────────────────────────────────────
34
+
35
+ function copyToClipboard(text) {
36
+ try { execSync(`echo ${JSON.stringify(text)} | pbcopy`); return true }
37
+ catch { return false }
38
+ }
39
+
40
+ function ask(rl, question) {
41
+ return new Promise(resolve => rl.question(question, resolve))
42
+ }
43
+
44
+ function parseCode(input) {
45
+ input = input.trim()
46
+ // Full URL
47
+ try {
48
+ const url = new URL(input)
49
+ const code = url.searchParams.get('code')
50
+ if (code) return code.split('#')[0]
51
+ } catch {}
52
+ // platform.claude.com format: CODE#STATE
53
+ if (input.includes('#')) return input.split('#')[0]
54
+ // raw code
55
+ return input.split('?')[0].split('&')[0]
56
+ }
57
+
58
+ // ── Token exchange ───────────────────────────────────────────────────────────
59
+
60
+ async function exchangeCode({ code, verifier }) {
61
+ console.log(`\nPOST ${TOKEN_URL}`)
62
+
63
+ const body = new URLSearchParams({
64
+ grant_type: 'authorization_code',
65
+ client_id: CLIENT_ID,
66
+ code,
67
+ redirect_uri: REDIRECT,
68
+ code_verifier: verifier,
69
+ })
70
+
71
+ const res = await fetch(TOKEN_URL, {
72
+ method: 'POST',
73
+ headers: {
74
+ 'Content-Type': 'application/x-www-form-urlencoded',
75
+ 'Accept': 'application/json',
76
+ },
77
+ body,
78
+ })
79
+
80
+ const data = await res.json()
81
+ return { ok: res.ok, status: res.status, data }
82
+ }
83
+
84
+ // ── Main ─────────────────────────────────────────────────────────────────────
85
+
86
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout })
87
+
88
+ console.log('\n╔══════════════════════════════════════════╗')
89
+ console.log('║ Claude OAuth PKCE Test — v2 (fixed) ║')
90
+ console.log('╚══════════════════════════════════════════╝\n')
91
+
92
+ const { verifier, challenge, state } = generatePKCE()
93
+
94
+ console.log(`verifier (${verifier.length} chars): ${verifier.slice(0, 20)}...`)
95
+ console.log(`challenge (${challenge.length} chars): ${challenge}`)
96
+ console.log(`state (${state.length} chars): ${state}\n`)
97
+
98
+ // Build auth URL — code=true tells claude.ai to show a code page instead of redirecting
99
+ const params = new URLSearchParams({
100
+ code: 'true',
101
+ client_id: CLIENT_ID,
102
+ response_type: 'code',
103
+ redirect_uri: REDIRECT,
104
+ scope: SCOPE,
105
+ code_challenge: challenge,
106
+ code_challenge_method: 'S256',
107
+ state,
108
+ })
109
+ const authUrl = `https://claude.ai/oauth/authorize?${params}`
110
+
111
+ console.log('┌─ Authorization URL ──────────────────────────────────────────────')
112
+ console.log(`│ ${authUrl}`)
113
+ console.log('└─────────────────────────────────────────────────────────────────\n')
114
+
115
+ const copied = copyToClipboard(authUrl)
116
+ if (copied) console.log('✓ Copied to clipboard\n')
117
+
118
+ console.log('1. Mở URL trong browser')
119
+ console.log('2. Login / approve')
120
+ console.log('3. platform.claude.com sẽ hiển thị code dạng: XXXX#STATE\n')
121
+
122
+ const input = await ask(rl, 'Paste code/URL: ')
123
+ const code = parseCode(input)
124
+
125
+ if (!code) {
126
+ console.error('❌ Không parse được code')
127
+ rl.close()
128
+ process.exit(1)
129
+ }
130
+
131
+ console.log(`\n✓ code = ${code.slice(0, 30)}...`)
132
+
133
+ // Validate state (CSRF check — client-side only, not sent to server)
134
+ const returnedState = input.includes('#') ? input.split('#')[1]?.split('&')[0] : null
135
+ if (returnedState && returnedState !== state) {
136
+ console.warn(`⚠️ State mismatch! Expected: ${state}, Got: ${returnedState}`)
137
+ } else if (returnedState) {
138
+ console.log(`✓ state OK`)
139
+ }
140
+
141
+ console.log('\nExchanging code for token...')
142
+ const { ok, status, data } = await exchangeCode({ code, verifier })
143
+
144
+ console.log(`\nHTTP ${status}`)
145
+
146
+ if (ok) {
147
+ console.log('\n✅ SUCCESS!')
148
+ console.log('─'.repeat(50))
149
+ console.log(`access_token: ${(data.access_token ?? data.accessToken)?.slice(0, 35)}...`)
150
+ console.log(`refresh_token: ${(data.refresh_token ?? data.refreshToken)?.slice(0, 35)}...`)
151
+ console.log(`token_type: ${data.token_type}`)
152
+ console.log(`expires_in: ${data.expires_in}s`)
153
+ if (data.account) {
154
+ console.log(`email: ${data.account.email_address}`)
155
+ console.log(`account_uuid: ${data.account.uuid}`)
156
+ }
157
+ console.log('─'.repeat(50))
158
+ console.log('\nFull response:')
159
+ console.log(JSON.stringify(data, null, 2))
160
+ } else {
161
+ console.log('\n❌ FAILED')
162
+ console.log(JSON.stringify(data, null, 2))
163
+ }
164
+
165
+ rl.close()
@@ -0,0 +1,175 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * Test Claude OAuth flow — manual copy/paste approach
4
+ * Usage: bun test-claude-oauth.mjs
5
+ */
6
+
7
+ import crypto from 'crypto'
8
+ import readline from 'readline'
9
+ import { execSync } from 'child_process'
10
+
11
+ const CLIENT_ID = '9d1c250a-e61b-44d9-88ed-5944d1962f5e'
12
+ const SCOPE = 'org:create_api_key user:profile user:inference user:sessions:claude_code user:mcp_servers user:file_upload'
13
+
14
+ // Redirect URIs to test (in order)
15
+ const REDIRECT_URI_OPTIONS = [
16
+ { label: 'platform.claude.com (manual code page)', uri: 'https://platform.claude.com/oauth/code/callback' },
17
+ { label: 'localhost:54545 (CLIProxyAPI style)', uri: 'http://localhost:54545/callback' },
18
+ { label: 'localhost (no port)', uri: 'http://localhost/callback' },
19
+ ]
20
+
21
+ // Token endpoints to try
22
+ const TOKEN_ENDPOINTS = [
23
+ 'https://api.anthropic.com/v1/oauth/token',
24
+ 'https://claude.ai/api/oauth/token',
25
+ ]
26
+
27
+ // ── PKCE ────────────────────────────────────────────────────────────────────
28
+
29
+ function generatePKCE() {
30
+ // 96 bytes → 128 base64url chars (matches CLIProxyAPI exactly)
31
+ const verifierBytes = crypto.randomBytes(96)
32
+ const verifier = verifierBytes.toString('base64url')
33
+ const challenge = crypto.createHash('sha256').update(verifier).digest('base64url')
34
+ const state = crypto.randomBytes(16).toString('base64url')
35
+ return { verifier, challenge, state }
36
+ }
37
+
38
+ // ── CLI helpers ──────────────────────────────────────────────────────────────
39
+
40
+ function copyToClipboard(text) {
41
+ try {
42
+ execSync(`echo ${JSON.stringify(text)} | pbcopy`)
43
+ return true
44
+ } catch { return false }
45
+ }
46
+
47
+ function ask(rl, question) {
48
+ return new Promise(resolve => rl.question(question, resolve))
49
+ }
50
+
51
+ function parseCode(input) {
52
+ input = input.trim()
53
+ // Full URL: http://localhost/callback?code=XXX&state=YYY
54
+ try {
55
+ const url = new URL(input)
56
+ const code = url.searchParams.get('code')
57
+ if (code) return code.split('#')[0]
58
+ } catch {}
59
+ // code#state format (platform.claude.com)
60
+ if (input.includes('#')) return input.split('#')[0]
61
+ // Raw code
62
+ return input.split('?')[0].split('&')[0]
63
+ }
64
+
65
+ // ── Token exchange ───────────────────────────────────────────────────────────
66
+
67
+ async function exchangeCode({ code, verifier, state, redirectUri }) {
68
+ const body = {
69
+ grant_type: 'authorization_code',
70
+ client_id: CLIENT_ID,
71
+ code,
72
+ redirect_uri: redirectUri,
73
+ code_verifier: verifier,
74
+ state,
75
+ }
76
+
77
+ for (const endpoint of TOKEN_ENDPOINTS) {
78
+ process.stdout.write(` → POST ${endpoint} ... `)
79
+ const res = await fetch(endpoint, {
80
+ method: 'POST',
81
+ headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' },
82
+ body: JSON.stringify(body),
83
+ })
84
+ const data = await res.json()
85
+ console.log(`HTTP ${res.status}`)
86
+
87
+ if (res.ok) return { endpoint, data }
88
+ console.log(` error: ${JSON.stringify(data?.error || data)}`)
89
+ }
90
+ return null
91
+ }
92
+
93
+ // ── Main ─────────────────────────────────────────────────────────────────────
94
+
95
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout })
96
+
97
+ console.log('\n╔══════════════════════════════════════════╗')
98
+ console.log('║ Claude OAuth Test — PPM ║')
99
+ console.log('╚══════════════════════════════════════════╝\n')
100
+
101
+ // Pick redirect URI
102
+ console.log('Redirect URI options:')
103
+ REDIRECT_URI_OPTIONS.forEach((o, i) => console.log(` ${i + 1}. ${o.label}`))
104
+ const choice = parseInt(await ask(rl, '\nChọn (1-3) [default: 1]: ') || '1') - 1
105
+ const { uri: redirectUri, label } = REDIRECT_URI_OPTIONS[choice] || REDIRECT_URI_OPTIONS[0]
106
+ console.log(`✓ Using: ${redirectUri}\n`)
107
+
108
+ // Generate PKCE + URL
109
+ const { verifier, challenge, state } = generatePKCE()
110
+ console.log(`code_verifier length: ${verifier.length} chars`)
111
+
112
+ const params = new URLSearchParams({
113
+ client_id: CLIENT_ID,
114
+ response_type: 'code',
115
+ redirect_uri: redirectUri,
116
+ scope: SCOPE,
117
+ code_challenge: challenge,
118
+ code_challenge_method: 'S256',
119
+ state,
120
+ prompt: 'login',
121
+ })
122
+ // platform.claude.com redirect uses special `code=true` trigger
123
+ if (redirectUri.includes('platform.claude.com')) {
124
+ params.set('code', 'true')
125
+ }
126
+ const authUrl = `https://claude.ai/oauth/authorize?${params}`
127
+
128
+ console.log('\n┌─ Authorization URL ──────────────────────────────────────────────')
129
+ console.log(`│ ${authUrl}`)
130
+ console.log('└─────────────────────────────────────────────────────────────────\n')
131
+
132
+ const copied = copyToClipboard(authUrl)
133
+ if (copied) console.log('✓ Copied to clipboard (pbcopy)\n')
134
+
135
+ console.log('Mở URL trong browser → authorize → copy code/URL trả về\n')
136
+ if (label.includes('platform')) {
137
+ console.log(' platform.claude.com sẽ hiện code dạng: XXXX#STATE')
138
+ } else {
139
+ console.log(' Browser sẽ redirect về localhost (lỗi kết nối là bình thường)')
140
+ console.log(' Copy toàn bộ URL từ address bar: http://localhost.../callback?code=XXX')
141
+ }
142
+
143
+ const input = await ask(rl, '\nPaste code/URL: ')
144
+ const code = parseCode(input)
145
+ if (!code) { console.error('❌ Không parse được code'); process.exit(1) }
146
+ console.log(`✓ code = ${code.slice(0, 20)}...\n`)
147
+
148
+ // Exchange
149
+ console.log('Thử exchange token:')
150
+ const result = await exchangeCode({ code, verifier, state, redirectUri })
151
+
152
+ if (result) {
153
+ const { endpoint, data } = result
154
+ console.log(`\n✅ Success! Endpoint: ${endpoint}`)
155
+ console.log('\n── Token info ──────────────────────────────────────')
156
+ console.log(` access_token: ${data.access_token?.slice(0, 30)}...`)
157
+ console.log(` refresh_token: ${data.refresh_token?.slice(0, 30)}...`)
158
+ console.log(` token_type: ${data.token_type}`)
159
+ console.log(` expires_in: ${data.expires_in}s`)
160
+ if (data.account) {
161
+ console.log(` email: ${data.account.email_address}`)
162
+ console.log(` account_uuid: ${data.account.uuid}`)
163
+ }
164
+ if (data.organization) {
165
+ console.log(` org_name: ${data.organization.name}`)
166
+ console.log(` org_uuid: ${data.organization.uuid}`)
167
+ }
168
+ console.log('────────────────────────────────────────────────────')
169
+ console.log('\nFull response:')
170
+ console.log(JSON.stringify(data, null, 2))
171
+ } else {
172
+ console.log('\n❌ Tất cả endpoints đều fail')
173
+ }
174
+
175
+ rl.close()
@@ -0,0 +1,106 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * Test verify sk-ant-oat token — see what APIs return
4
+ * Usage: bun test-verify-oat.mjs [TOKEN]
5
+ * If no TOKEN arg, reads TEST_OAUTH_TOKEN_1 from .env.test
6
+ */
7
+
8
+ import { readFileSync } from "node:fs";
9
+ import { resolve, dirname } from "node:path";
10
+ import { fileURLToPath } from "node:url";
11
+
12
+ const __dir = dirname(fileURLToPath(import.meta.url));
13
+
14
+ // Token from CLI arg or .env.test
15
+ let token = process.argv[2];
16
+ if (!token) {
17
+ const envPath = resolve(__dir, ".env.test");
18
+ const env = Object.fromEntries(
19
+ readFileSync(envPath, "utf-8")
20
+ .split("\n")
21
+ .filter((l) => l && !l.startsWith("#"))
22
+ .map((l) => l.split("=").map((s) => s.trim()))
23
+ .filter(([k, v]) => k && v),
24
+ );
25
+ token = env.TEST_OAUTH_TOKEN_1;
26
+ }
27
+
28
+ if (!token || token.startsWith("REPLACE")) {
29
+ console.error("Usage: bun test-verify-oat.mjs [TOKEN]");
30
+ process.exit(1);
31
+ }
32
+
33
+ console.log(`Token: ${token.slice(0, 30)}...`);
34
+
35
+ // ── Helper ──────────────────────────────────────────────
36
+ async function tryEndpoint({ label, url, method = "GET", headers = {}, body }) {
37
+ console.log(`\n── ${label} ──`);
38
+ try {
39
+ const opts = {
40
+ method,
41
+ headers: {
42
+ Accept: "application/json",
43
+ Authorization: `Bearer ${token}`,
44
+ ...headers,
45
+ },
46
+ signal: AbortSignal.timeout(10_000),
47
+ };
48
+ if (body) opts.body = typeof body === "string" ? body : JSON.stringify(body);
49
+ const res = await fetch(url, opts);
50
+ const text = await res.text();
51
+ console.log(`HTTP ${res.status}`);
52
+ try {
53
+ console.log(JSON.stringify(JSON.parse(text), null, 2));
54
+ } catch {
55
+ console.log(text.slice(0, 500));
56
+ }
57
+ } catch (e) {
58
+ console.log(`ERROR: ${e.message}`);
59
+ }
60
+ }
61
+
62
+ // ── 1. claude auth status (CLI) ─────────────────────────
63
+ console.log("\n── claude auth status (CLI) ──");
64
+ try {
65
+ const proc = Bun.spawn(["claude", "auth", "status"], {
66
+ env: { ...process.env, CLAUDE_CODE_OAUTH_TOKEN: token, ANTHROPIC_API_KEY: "" },
67
+ stdout: "pipe",
68
+ stderr: "pipe",
69
+ });
70
+ const stdout = await new Response(proc.stdout).text();
71
+ const stderr = await new Response(proc.stderr).text();
72
+ await proc.exited;
73
+ console.log("stdout:", stdout);
74
+ if (stderr) console.log("stderr:", stderr);
75
+ } catch (e) {
76
+ console.log(`ERROR: ${e.message}`);
77
+ }
78
+
79
+ // ── 2. /api/oauth/usage ─────────────────────────────────
80
+ await tryEndpoint({
81
+ label: "GET /api/oauth/usage",
82
+ url: "https://api.anthropic.com/api/oauth/usage",
83
+ headers: { "anthropic-beta": "oauth-2025-04-20", "User-Agent": "ppm/1.0" },
84
+ });
85
+
86
+ // ── 3. /v1/organizations (org info) ─────────────────────
87
+ await tryEndpoint({
88
+ label: "GET /v1/organizations",
89
+ url: "https://api.anthropic.com/v1/organizations",
90
+ headers: { "anthropic-version": "2023-06-01" },
91
+ });
92
+
93
+ // ── 4. /api/auth/session (claude.ai session) ────────────
94
+ await tryEndpoint({
95
+ label: "GET /api/auth/session (claude.ai)",
96
+ url: "https://claude.ai/api/auth/session",
97
+ });
98
+
99
+ // ── 5. /v1/messages (minimal — test if token works) ─────
100
+ await tryEndpoint({
101
+ label: "POST /v1/messages (1 token test)",
102
+ url: "https://api.anthropic.com/v1/messages",
103
+ method: "POST",
104
+ headers: { "Content-Type": "application/json", "anthropic-version": "2023-06-01" },
105
+ body: { model: "claude-sonnet-4-20250514", max_tokens: 1, messages: [{ role: "user", content: "hi" }] },
106
+ });
@@ -1 +0,0 @@
1
- import{i as e,t}from"./react-CYzKIDNi.js";import{A as n,C as r,D as i,N as a,_ as o,a as s,b as c,d as l,f as u,g as d,h as f,i as p,l as m,m as h,n as g,o as _,p as v,r as y,s as b,t as x,u as S,v as C,w,x as T,y as E}from"./input-CVIzrYsH.js";import{n as D,t as O}from"./jsx-runtime-wQxeESYQ.js";import{n as k}from"./utils-DC-bdPS3.js";import{t as A}from"./api-client-TUmacMRS.js";var j=D(`bell-off`,[[`path`,{d:`M10.268 21a2 2 0 0 0 3.464 0`,key:`vwvbt9`}],[`path`,{d:`M17 17H4a1 1 0 0 1-.74-1.673C4.59 13.956 6 12.499 6 8a6 6 0 0 1 .258-1.742`,key:`178tsu`}],[`path`,{d:`m2 2 20 20`,key:`1ooewy`}],[`path`,{d:`M8.668 3.01A6 6 0 0 1 18 8c0 2.687.77 4.653 1.707 6.05`,key:`1hqiys`}]]),M=D(`check`,[[`path`,{d:`M20 6 9 17l-5-5`,key:`1gmf2c`}]]),N=D(`chevron-down`,[[`path`,{d:`m6 9 6 6 6-6`,key:`qrunsl`}]]),P=D(`chevron-up`,[[`path`,{d:`m18 15-6-6-6 6`,key:`153udz`}]]),F=e(t(),1),I=O(),L=Object.freeze({position:`absolute`,border:0,width:1,height:1,padding:0,margin:-1,overflow:`hidden`,clip:`rect(0, 0, 0, 0)`,whiteSpace:`nowrap`,wordWrap:`normal`}),R=`VisuallyHidden`,ee=F.forwardRef((e,t)=>(0,I.jsx)(w.span,{...e,ref:t,style:{...L,...e.style}}));ee.displayName=R;var z=ee;function B(e){let t=F.useRef({value:e,previous:e});return F.useMemo(()=>(t.current.value!==e&&(t.current.previous=t.current.value,t.current.value=e),t.current.previous),[e])}var te=`Label`,V=F.forwardRef((e,t)=>(0,I.jsx)(w.label,{...e,ref:t,onMouseDown:t=>{t.target.closest(`button, input, select, textarea`)||(e.onMouseDown?.(t),!t.defaultPrevented&&t.detail>1&&t.preventDefault())}}));V.displayName=te;var H=V,ne=e(a(),1),re=[` `,`Enter`,`ArrowUp`,`ArrowDown`],ie=[` `,`Enter`],U=`Select`,[W,ae,oe]=T(U),[G,se]=r(U,[oe,b]),K=b(),[ce,q]=G(U),[le,ue]=G(U),de=e=>{let{__scopeSelect:t,children:n,open:r,defaultOpen:i,onOpenChange:a,value:s,defaultValue:c,onValueChange:l,dir:u,name:f,autoComplete:p,disabled:m,required:h,form:g}=e,v=K(t),[y,b]=F.useState(null),[x,S]=F.useState(null),[w,T]=F.useState(!1),E=d(u),[D,O]=C({prop:r,defaultProp:i??!1,onChange:a,caller:U}),[k,A]=C({prop:s,defaultProp:c,onChange:l,caller:U}),j=F.useRef(null),M=y?g||!!y.closest(`form`):!0,[N,P]=F.useState(new Set),L=Array.from(N).map(e=>e.props.value).join(`;`);return(0,I.jsx)(_,{...v,children:(0,I.jsxs)(ce,{required:h,scope:t,trigger:y,onTriggerChange:b,valueNode:x,onValueNodeChange:S,valueNodeHasChildren:w,onValueNodeHasChildrenChange:T,contentId:o(),value:k,onValueChange:A,open:D,onOpenChange:O,dir:E,triggerPointerDownPosRef:j,disabled:m,children:[(0,I.jsx)(W.Provider,{scope:t,children:(0,I.jsx)(le,{scope:e.__scopeSelect,onNativeOptionAdd:F.useCallback(e=>{P(t=>new Set(t).add(e))},[]),onNativeOptionRemove:F.useCallback(e=>{P(t=>{let n=new Set(t);return n.delete(e),n})},[]),children:n})}),M?(0,I.jsxs)(tt,{"aria-hidden":!0,required:h,tabIndex:-1,name:f,autoComplete:p,value:k,onChange:e=>A(e.target.value),disabled:m,form:g,children:[k===void 0?(0,I.jsx)(`option`,{value:``}):null,Array.from(N)]},L):null]})})};de.displayName=U;var fe=`SelectTrigger`,pe=F.forwardRef((e,t)=>{let{__scopeSelect:r,disabled:i=!1,...a}=e,o=K(r),s=q(fe,r),l=s.disabled||i,u=n(t,s.onTriggerChange),d=ae(r),f=F.useRef(`touch`),[p,m,h]=rt(e=>{let t=d().filter(e=>!e.disabled),n=it(t,e,t.find(e=>e.value===s.value));n!==void 0&&s.onValueChange(n.value)}),g=e=>{l||(s.onOpenChange(!0),h()),e&&(s.triggerPointerDownPosRef.current={x:Math.round(e.pageX),y:Math.round(e.pageY)})};return(0,I.jsx)(y,{asChild:!0,...o,children:(0,I.jsx)(w.button,{type:`button`,role:`combobox`,"aria-controls":s.contentId,"aria-expanded":s.open,"aria-required":s.required,"aria-autocomplete":`none`,dir:s.dir,"data-state":s.open?`open`:`closed`,disabled:l,"data-disabled":l?``:void 0,"data-placeholder":nt(s.value)?``:void 0,...a,ref:u,onClick:c(a.onClick,e=>{e.currentTarget.focus(),f.current!==`mouse`&&g(e)}),onPointerDown:c(a.onPointerDown,e=>{f.current=e.pointerType;let t=e.target;t.hasPointerCapture(e.pointerId)&&t.releasePointerCapture(e.pointerId),e.button===0&&e.ctrlKey===!1&&e.pointerType===`mouse`&&(g(e),e.preventDefault())}),onKeyDown:c(a.onKeyDown,e=>{let t=p.current!==``;!(e.ctrlKey||e.altKey||e.metaKey)&&e.key.length===1&&m(e.key),!(t&&e.key===` `)&&re.includes(e.key)&&(g(),e.preventDefault())})})})});pe.displayName=fe;var me=`SelectValue`,he=F.forwardRef((e,t)=>{let{__scopeSelect:r,className:i,style:a,children:o,placeholder:s=``,...c}=e,l=q(me,r),{onValueNodeHasChildrenChange:u}=l,d=o!==void 0,f=n(t,l.onValueNodeChange);return E(()=>{u(d)},[u,d]),(0,I.jsx)(w.span,{...c,ref:f,style:{pointerEvents:`none`},children:nt(l.value)?(0,I.jsx)(I.Fragment,{children:s}):o})});he.displayName=me;var ge=`SelectIcon`,_e=F.forwardRef((e,t)=>{let{__scopeSelect:n,children:r,...i}=e;return(0,I.jsx)(w.span,{"aria-hidden":!0,...i,ref:t,children:r||`▼`})});_e.displayName=ge;var ve=`SelectPortal`,ye=e=>(0,I.jsx)(u,{asChild:!0,...e});ye.displayName=ve;var J=`SelectContent`,be=F.forwardRef((e,t)=>{let n=q(J,e.__scopeSelect),[r,i]=F.useState();if(E(()=>{i(new DocumentFragment)},[]),!n.open){let t=r;return t?ne.createPortal((0,I.jsx)(xe,{scope:e.__scopeSelect,children:(0,I.jsx)(W.Slot,{scope:e.__scopeSelect,children:(0,I.jsx)(`div`,{children:e.children})})}),t):null}return(0,I.jsx)(we,{...e,ref:t})});be.displayName=J;var Y=10,[xe,X]=G(J),Se=`SelectContentImpl`,Ce=i(`SelectContent.RemoveScroll`),we=F.forwardRef((e,t)=>{let{__scopeSelect:r,position:i=`item-aligned`,onCloseAutoFocus:a,onEscapeKeyDown:o,onPointerDownOutside:s,side:u,sideOffset:d,align:f,alignOffset:p,arrowPadding:g,collisionBoundary:_,collisionPadding:y,sticky:b,hideWhenDetached:x,avoidCollisions:C,...w}=e,T=q(J,r),[E,D]=F.useState(null),[O,k]=F.useState(null),A=n(t,e=>D(e)),[j,M]=F.useState(null),[N,P]=F.useState(null),L=ae(r),[R,ee]=F.useState(!1),z=F.useRef(!1);F.useEffect(()=>{if(E)return m(E)},[E]),l();let B=F.useCallback(e=>{let[t,...n]=L().map(e=>e.ref.current),[r]=n.slice(-1),i=document.activeElement;for(let n of e)if(n===i||(n?.scrollIntoView({block:`nearest`}),n===t&&O&&(O.scrollTop=0),n===r&&O&&(O.scrollTop=O.scrollHeight),n?.focus(),document.activeElement!==i))return},[L,O]),te=F.useCallback(()=>B([j,E]),[B,j,E]);F.useEffect(()=>{R&&te()},[R,te]);let{onOpenChange:V,triggerPointerDownPosRef:H}=T;F.useEffect(()=>{if(E){let e={x:0,y:0},t=t=>{e={x:Math.abs(Math.round(t.pageX)-(H.current?.x??0)),y:Math.abs(Math.round(t.pageY)-(H.current?.y??0))}},n=n=>{e.x<=10&&e.y<=10?n.preventDefault():E.contains(n.target)||V(!1),document.removeEventListener(`pointermove`,t),H.current=null};return H.current!==null&&(document.addEventListener(`pointermove`,t),document.addEventListener(`pointerup`,n,{capture:!0,once:!0})),()=>{document.removeEventListener(`pointermove`,t),document.removeEventListener(`pointerup`,n,{capture:!0})}}},[E,V,H]),F.useEffect(()=>{let e=()=>V(!1);return window.addEventListener(`blur`,e),window.addEventListener(`resize`,e),()=>{window.removeEventListener(`blur`,e),window.removeEventListener(`resize`,e)}},[V]);let[ne,re]=rt(e=>{let t=L().filter(e=>!e.disabled),n=it(t,e,t.find(e=>e.ref.current===document.activeElement));n&&setTimeout(()=>n.ref.current.focus())}),ie=F.useCallback((e,t,n)=>{let r=!z.current&&!n;(T.value!==void 0&&T.value===t||r)&&(M(e),r&&(z.current=!0))},[T.value]),U=F.useCallback(()=>E?.focus(),[E]),W=F.useCallback((e,t,n)=>{let r=!z.current&&!n;(T.value!==void 0&&T.value===t||r)&&P(e)},[T.value]),oe=i===`popper`?Oe:Ee,G=oe===Oe?{side:u,sideOffset:d,align:f,alignOffset:p,arrowPadding:g,collisionBoundary:_,collisionPadding:y,sticky:b,hideWhenDetached:x,avoidCollisions:C}:{};return(0,I.jsx)(xe,{scope:r,content:E,viewport:O,onViewportChange:k,itemRefCallback:ie,selectedItem:j,onItemLeave:U,itemTextRefCallback:W,focusSelectedItem:te,selectedItemText:N,position:i,isPositioned:R,searchRef:ne,children:(0,I.jsx)(S,{as:Ce,allowPinchZoom:!0,children:(0,I.jsx)(v,{asChild:!0,trapped:T.open,onMountAutoFocus:e=>{e.preventDefault()},onUnmountAutoFocus:c(a,e=>{T.trigger?.focus({preventScroll:!0}),e.preventDefault()}),children:(0,I.jsx)(h,{asChild:!0,disableOutsidePointerEvents:!0,onEscapeKeyDown:o,onPointerDownOutside:s,onFocusOutside:e=>e.preventDefault(),onDismiss:()=>T.onOpenChange(!1),children:(0,I.jsx)(oe,{role:`listbox`,id:T.contentId,"data-state":T.open?`open`:`closed`,dir:T.dir,onContextMenu:e=>e.preventDefault(),...w,...G,onPlaced:()=>ee(!0),ref:A,style:{display:`flex`,flexDirection:`column`,outline:`none`,...w.style},onKeyDown:c(w.onKeyDown,e=>{let t=e.ctrlKey||e.altKey||e.metaKey;if(e.key===`Tab`&&e.preventDefault(),!t&&e.key.length===1&&re(e.key),[`ArrowUp`,`ArrowDown`,`Home`,`End`].includes(e.key)){let t=L().filter(e=>!e.disabled).map(e=>e.ref.current);if([`ArrowUp`,`End`].includes(e.key)&&(t=t.slice().reverse()),[`ArrowUp`,`ArrowDown`].includes(e.key)){let n=e.target,r=t.indexOf(n);t=t.slice(r+1)}setTimeout(()=>B(t)),e.preventDefault()}})})})})})})});we.displayName=Se;var Te=`SelectItemAlignedPosition`,Ee=F.forwardRef((e,t)=>{let{__scopeSelect:r,onPlaced:i,...a}=e,o=q(J,r),s=X(J,r),[c,l]=F.useState(null),[u,d]=F.useState(null),f=n(t,e=>d(e)),p=ae(r),m=F.useRef(!1),h=F.useRef(!0),{viewport:_,selectedItem:v,selectedItemText:y,focusSelectedItem:b}=s,x=F.useCallback(()=>{if(o.trigger&&o.valueNode&&c&&u&&_&&v&&y){let e=o.trigger.getBoundingClientRect(),t=u.getBoundingClientRect(),n=o.valueNode.getBoundingClientRect(),r=y.getBoundingClientRect();if(o.dir!==`rtl`){let i=r.left-t.left,a=n.left-i,o=e.left-a,s=e.width+o,l=Math.max(s,t.width),u=window.innerWidth-Y,d=g(a,[Y,Math.max(Y,u-l)]);c.style.minWidth=s+`px`,c.style.left=d+`px`}else{let i=t.right-r.right,a=window.innerWidth-n.right-i,o=window.innerWidth-e.right-a,s=e.width+o,l=Math.max(s,t.width),u=window.innerWidth-Y,d=g(a,[Y,Math.max(Y,u-l)]);c.style.minWidth=s+`px`,c.style.right=d+`px`}let a=p(),s=window.innerHeight-Y*2,l=_.scrollHeight,d=window.getComputedStyle(u),f=parseInt(d.borderTopWidth,10),h=parseInt(d.paddingTop,10),b=parseInt(d.borderBottomWidth,10),x=parseInt(d.paddingBottom,10),S=f+h+l+x+b,C=Math.min(v.offsetHeight*5,S),w=window.getComputedStyle(_),T=parseInt(w.paddingTop,10),E=parseInt(w.paddingBottom,10),D=e.top+e.height/2-Y,O=s-D,k=v.offsetHeight/2,A=v.offsetTop+k,j=f+h+A,M=S-j;if(j<=D){let e=a.length>0&&v===a[a.length-1].ref.current;c.style.bottom=`0px`;let t=u.clientHeight-_.offsetTop-_.offsetHeight,n=j+Math.max(O,k+(e?E:0)+t+b);c.style.height=n+`px`}else{let e=a.length>0&&v===a[0].ref.current;c.style.top=`0px`;let t=Math.max(D,f+_.offsetTop+(e?T:0)+k)+M;c.style.height=t+`px`,_.scrollTop=j-D+_.offsetTop}c.style.margin=`${Y}px 0`,c.style.minHeight=C+`px`,c.style.maxHeight=s+`px`,i?.(),requestAnimationFrame(()=>m.current=!0)}},[p,o.trigger,o.valueNode,c,u,_,v,y,o.dir,i]);E(()=>x(),[x]);let[S,C]=F.useState();return E(()=>{u&&C(window.getComputedStyle(u).zIndex)},[u]),(0,I.jsx)(ke,{scope:r,contentWrapper:c,shouldExpandOnScrollRef:m,onScrollButtonChange:F.useCallback(e=>{e&&h.current===!0&&(x(),b?.(),h.current=!1)},[x,b]),children:(0,I.jsx)(`div`,{ref:l,style:{display:`flex`,flexDirection:`column`,position:`fixed`,zIndex:S},children:(0,I.jsx)(w.div,{...a,ref:f,style:{boxSizing:`border-box`,maxHeight:`100%`,...a.style}})})})});Ee.displayName=Te;var De=`SelectPopperPosition`,Oe=F.forwardRef((e,t)=>{let{__scopeSelect:n,align:r=`start`,collisionPadding:i=Y,...a}=e,o=K(n);return(0,I.jsx)(s,{...o,...a,ref:t,align:r,collisionPadding:i,style:{boxSizing:`border-box`,...a.style,"--radix-select-content-transform-origin":`var(--radix-popper-transform-origin)`,"--radix-select-content-available-width":`var(--radix-popper-available-width)`,"--radix-select-content-available-height":`var(--radix-popper-available-height)`,"--radix-select-trigger-width":`var(--radix-popper-anchor-width)`,"--radix-select-trigger-height":`var(--radix-popper-anchor-height)`}})});Oe.displayName=De;var[ke,Ae]=G(J,{}),je=`SelectViewport`,Me=F.forwardRef((e,t)=>{let{__scopeSelect:r,nonce:i,...a}=e,o=X(je,r),s=Ae(je,r),l=n(t,o.onViewportChange),u=F.useRef(0);return(0,I.jsxs)(I.Fragment,{children:[(0,I.jsx)(`style`,{dangerouslySetInnerHTML:{__html:`[data-radix-select-viewport]{scrollbar-width:none;-ms-overflow-style:none;-webkit-overflow-scrolling:touch;}[data-radix-select-viewport]::-webkit-scrollbar{display:none}`},nonce:i}),(0,I.jsx)(W.Slot,{scope:r,children:(0,I.jsx)(w.div,{"data-radix-select-viewport":``,role:`presentation`,...a,ref:l,style:{position:`relative`,flex:1,overflow:`hidden auto`,...a.style},onScroll:c(a.onScroll,e=>{let t=e.currentTarget,{contentWrapper:n,shouldExpandOnScrollRef:r}=s;if(r?.current&&n){let e=Math.abs(u.current-t.scrollTop);if(e>0){let r=window.innerHeight-Y*2,i=parseFloat(n.style.minHeight),a=parseFloat(n.style.height),o=Math.max(i,a);if(o<r){let i=o+e,a=Math.min(r,i),s=i-a;n.style.height=a+`px`,n.style.bottom===`0px`&&(t.scrollTop=s>0?s:0,n.style.justifyContent=`flex-end`)}}}u.current=t.scrollTop})})})]})});Me.displayName=je;var Ne=`SelectGroup`,[Pe,Fe]=G(Ne),Ie=F.forwardRef((e,t)=>{let{__scopeSelect:n,...r}=e,i=o();return(0,I.jsx)(Pe,{scope:n,id:i,children:(0,I.jsx)(w.div,{role:`group`,"aria-labelledby":i,...r,ref:t})})});Ie.displayName=Ne;var Le=`SelectLabel`,Re=F.forwardRef((e,t)=>{let{__scopeSelect:n,...r}=e,i=Fe(Le,n);return(0,I.jsx)(w.div,{id:i.id,...r,ref:t})});Re.displayName=Le;var Z=`SelectItem`,[ze,Be]=G(Z),Ve=F.forwardRef((e,t)=>{let{__scopeSelect:r,value:i,disabled:a=!1,textValue:s,...l}=e,u=q(Z,r),d=X(Z,r),f=u.value===i,[p,m]=F.useState(s??``),[h,g]=F.useState(!1),_=n(t,e=>d.itemRefCallback?.(e,i,a)),v=o(),y=F.useRef(`touch`),b=()=>{a||(u.onValueChange(i),u.onOpenChange(!1))};if(i===``)throw Error(`A <Select.Item /> must have a value prop that is not an empty string. This is because the Select value can be set to an empty string to clear the selection and show the placeholder.`);return(0,I.jsx)(ze,{scope:r,value:i,disabled:a,textId:v,isSelected:f,onItemTextChange:F.useCallback(e=>{m(t=>t||(e?.textContent??``).trim())},[]),children:(0,I.jsx)(W.ItemSlot,{scope:r,value:i,disabled:a,textValue:p,children:(0,I.jsx)(w.div,{role:`option`,"aria-labelledby":v,"data-highlighted":h?``:void 0,"aria-selected":f&&h,"data-state":f?`checked`:`unchecked`,"aria-disabled":a||void 0,"data-disabled":a?``:void 0,tabIndex:a?void 0:-1,...l,ref:_,onFocus:c(l.onFocus,()=>g(!0)),onBlur:c(l.onBlur,()=>g(!1)),onClick:c(l.onClick,()=>{y.current!==`mouse`&&b()}),onPointerUp:c(l.onPointerUp,()=>{y.current===`mouse`&&b()}),onPointerDown:c(l.onPointerDown,e=>{y.current=e.pointerType}),onPointerMove:c(l.onPointerMove,e=>{y.current=e.pointerType,a?d.onItemLeave?.():y.current===`mouse`&&e.currentTarget.focus({preventScroll:!0})}),onPointerLeave:c(l.onPointerLeave,e=>{e.currentTarget===document.activeElement&&d.onItemLeave?.()}),onKeyDown:c(l.onKeyDown,e=>{d.searchRef?.current!==``&&e.key===` `||(ie.includes(e.key)&&b(),e.key===` `&&e.preventDefault())})})})})});Ve.displayName=Z;var Q=`SelectItemText`,He=F.forwardRef((e,t)=>{let{__scopeSelect:r,className:i,style:a,...o}=e,s=q(Q,r),c=X(Q,r),l=Be(Q,r),u=ue(Q,r),[d,f]=F.useState(null),p=n(t,e=>f(e),l.onItemTextChange,e=>c.itemTextRefCallback?.(e,l.value,l.disabled)),m=d?.textContent,h=F.useMemo(()=>(0,I.jsx)(`option`,{value:l.value,disabled:l.disabled,children:m},l.value),[l.disabled,l.value,m]),{onNativeOptionAdd:g,onNativeOptionRemove:_}=u;return E(()=>(g(h),()=>_(h)),[g,_,h]),(0,I.jsxs)(I.Fragment,{children:[(0,I.jsx)(w.span,{id:l.textId,...o,ref:p}),l.isSelected&&s.valueNode&&!s.valueNodeHasChildren?ne.createPortal(o.children,s.valueNode):null]})});He.displayName=Q;var Ue=`SelectItemIndicator`,We=F.forwardRef((e,t)=>{let{__scopeSelect:n,...r}=e;return Be(Ue,n).isSelected?(0,I.jsx)(w.span,{"aria-hidden":!0,...r,ref:t}):null});We.displayName=Ue;var Ge=`SelectScrollUpButton`,Ke=F.forwardRef((e,t)=>{let r=X(Ge,e.__scopeSelect),i=Ae(Ge,e.__scopeSelect),[a,o]=F.useState(!1),s=n(t,i.onScrollButtonChange);return E(()=>{if(r.viewport&&r.isPositioned){let e=function(){o(t.scrollTop>0)},t=r.viewport;return e(),t.addEventListener(`scroll`,e),()=>t.removeEventListener(`scroll`,e)}},[r.viewport,r.isPositioned]),a?(0,I.jsx)(Ye,{...e,ref:s,onAutoScroll:()=>{let{viewport:e,selectedItem:t}=r;e&&t&&(e.scrollTop-=t.offsetHeight)}}):null});Ke.displayName=Ge;var qe=`SelectScrollDownButton`,Je=F.forwardRef((e,t)=>{let r=X(qe,e.__scopeSelect),i=Ae(qe,e.__scopeSelect),[a,o]=F.useState(!1),s=n(t,i.onScrollButtonChange);return E(()=>{if(r.viewport&&r.isPositioned){let e=function(){let e=t.scrollHeight-t.clientHeight;o(Math.ceil(t.scrollTop)<e)},t=r.viewport;return e(),t.addEventListener(`scroll`,e),()=>t.removeEventListener(`scroll`,e)}},[r.viewport,r.isPositioned]),a?(0,I.jsx)(Ye,{...e,ref:s,onAutoScroll:()=>{let{viewport:e,selectedItem:t}=r;e&&t&&(e.scrollTop+=t.offsetHeight)}}):null});Je.displayName=qe;var Ye=F.forwardRef((e,t)=>{let{__scopeSelect:n,onAutoScroll:r,...i}=e,a=X(`SelectScrollButton`,n),o=F.useRef(null),s=ae(n),l=F.useCallback(()=>{o.current!==null&&(window.clearInterval(o.current),o.current=null)},[]);return F.useEffect(()=>()=>l(),[l]),E(()=>{s().find(e=>e.ref.current===document.activeElement)?.ref.current?.scrollIntoView({block:`nearest`})},[s]),(0,I.jsx)(w.div,{"aria-hidden":!0,...i,ref:t,style:{flexShrink:0,...i.style},onPointerDown:c(i.onPointerDown,()=>{o.current===null&&(o.current=window.setInterval(r,50))}),onPointerMove:c(i.onPointerMove,()=>{a.onItemLeave?.(),o.current===null&&(o.current=window.setInterval(r,50))}),onPointerLeave:c(i.onPointerLeave,()=>{l()})})}),Xe=`SelectSeparator`,Ze=F.forwardRef((e,t)=>{let{__scopeSelect:n,...r}=e;return(0,I.jsx)(w.div,{"aria-hidden":!0,...r,ref:t})});Ze.displayName=Xe;var Qe=`SelectArrow`,$e=F.forwardRef((e,t)=>{let{__scopeSelect:n,...r}=e,i=K(n),a=q(Qe,n),o=X(Qe,n);return a.open&&o.position===`popper`?(0,I.jsx)(p,{...i,...r,ref:t}):null});$e.displayName=Qe;var et=`SelectBubbleInput`,tt=F.forwardRef(({__scopeSelect:e,value:t,...r},i)=>{let a=F.useRef(null),o=n(i,a),s=B(t);return F.useEffect(()=>{let e=a.current;if(!e)return;let n=window.HTMLSelectElement.prototype,r=Object.getOwnPropertyDescriptor(n,`value`).set;if(s!==t&&r){let n=new Event(`change`,{bubbles:!0});r.call(e,t),e.dispatchEvent(n)}},[s,t]),(0,I.jsx)(w.select,{...r,style:{...L,...r.style},ref:o,defaultValue:t})});tt.displayName=et;function nt(e){return e===``||e===void 0}function rt(e){let t=f(e),n=F.useRef(``),r=F.useRef(0),i=F.useCallback(e=>{let i=n.current+e;t(i),(function e(t){n.current=t,window.clearTimeout(r.current),t!==``&&(r.current=window.setTimeout(()=>e(``),1e3))})(i)},[t]),a=F.useCallback(()=>{n.current=``,window.clearTimeout(r.current)},[]);return F.useEffect(()=>()=>window.clearTimeout(r.current),[]),[n,i,a]}function it(e,t,n){let r=t.length>1&&Array.from(t).every(e=>e===t[0])?t[0]:t,i=n?e.indexOf(n):-1,a=at(e,Math.max(i,0));r.length===1&&(a=a.filter(e=>e!==n));let o=a.find(e=>e.textValue.toLowerCase().startsWith(r.toLowerCase()));return o===n?void 0:o}function at(e,t){return e.map((n,r)=>e[(t+r)%e.length])}var ot=de,st=pe,ct=he,lt=_e,ut=ye,dt=be,ft=Me,pt=Ve,mt=He,ht=We,gt=Ke,_t=Je;function $({className:e,...t}){return(0,I.jsx)(H,{"data-slot":`label`,className:k(`flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50`,e),...t})}function vt({...e}){return(0,I.jsx)(ot,{"data-slot":`select`,...e})}function yt({...e}){return(0,I.jsx)(ct,{"data-slot":`select-value`,...e})}function bt({className:e,size:t=`default`,children:n,...r}){return(0,I.jsxs)(st,{"data-slot":`select-trigger`,"data-size":t,className:k(`flex w-fit items-center justify-between gap-2 rounded-md border border-input bg-transparent px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 data-[placeholder]:text-muted-foreground data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 dark:bg-input/30 dark:hover:bg-input/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground`,e),...r,children:[n,(0,I.jsx)(lt,{asChild:!0,children:(0,I.jsx)(N,{className:`size-4 opacity-50`})})]})}function xt({className:e,children:t,position:n=`item-aligned`,align:r=`center`,...i}){return(0,I.jsx)(ut,{children:(0,I.jsxs)(dt,{"data-slot":`select-content`,className:k(`relative z-50 max-h-(--radix-select-content-available-height) min-w-[8rem] origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border bg-popover text-popover-foreground shadow-md data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95`,n===`popper`&&`data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1`,e),position:n,align:r,...i,children:[(0,I.jsx)(Ct,{}),(0,I.jsx)(ft,{className:k(`p-1`,n===`popper`&&`h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1`),children:t}),(0,I.jsx)(wt,{})]})})}function St({className:e,children:t,...n}){return(0,I.jsxs)(pt,{"data-slot":`select-item`,className:k(`relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2`,e),...n,children:[(0,I.jsx)(`span`,{"data-slot":`select-item-indicator`,className:`absolute right-2 flex size-3.5 items-center justify-center`,children:(0,I.jsx)(ht,{children:(0,I.jsx)(M,{className:`size-4`})})}),(0,I.jsx)(mt,{children:t})]})}function Ct({className:e,...t}){return(0,I.jsx)(gt,{"data-slot":`select-scroll-up-button`,className:k(`flex cursor-default items-center justify-center py-1`,e),...t,children:(0,I.jsx)(P,{className:`size-4`})})}function wt({className:e,...t}){return(0,I.jsx)(_t,{"data-slot":`select-scroll-down-button`,className:k(`flex cursor-default items-center justify-center py-1`,e),...t,children:(0,I.jsx)(N,{className:`size-4`})})}function Tt(){return A.get(`/api/accounts`)}function Et(){return A.get(`/api/accounts/active`)}function Dt(e){return A.post(`/api/accounts`,e)}function Ot(e){return A.del(`/api/accounts/${e}`)}function kt(e,t){return A.patch(`/api/accounts/${e}`,t)}function At(){return A.get(`/api/accounts/settings`)}function jt(e){return A.put(`/api/accounts/settings`,e)}function Mt(){return A.get(`/api/accounts/usage`)}function Nt(){return A.get(`/api/settings/ai`)}function Pt(e){return A.put(`/api/settings/ai`,e)}var Ft=[{value:`claude-sonnet-4-6`,label:`Claude Sonnet 4.6`},{value:`claude-opus-4-6`,label:`Claude Opus 4.6`},{value:`claude-haiku-4-5`,label:`Claude Haiku 4.5`}],It=[{value:`low`,label:`Low`},{value:`medium`,label:`Medium`},{value:`high`,label:`High`}];function Lt({compact:e}={}){let[t,n]=(0,F.useState)(null),[r,i]=(0,F.useState)(!1),[a,o]=(0,F.useState)(null),[s,c]=(0,F.useState)(0);(0,F.useEffect)(()=>{Nt().then(n).catch(e=>o(e.message))},[]);let l=t?.default_provider??`claude`,u=t?.providers[l],d=async(e,r)=>{if(t){i(!0),o(null);try{n(await Pt({providers:{[l]:{[e]:r}}})),c(e=>e+1)}catch(e){o(e.message)}finally{i(!1)}}},f=e?`text-[11px]`:`text-sm`,p=e?`text-xs`:`text-sm`,m=e?`space-y-2`:`space-y-4`,h=e?`space-y-1.5`:`space-y-3`,g=e?`space-y-1`:`space-y-1.5`;return t?(0,I.jsxs)(`div`,{className:m,children:[(0,I.jsx)(`h3`,{className:`${p} font-medium text-text-secondary`,children:`AI Provider`}),(0,I.jsxs)(`div`,{className:h,children:[(0,I.jsxs)(`div`,{className:g,children:[(0,I.jsx)($,{htmlFor:`ai-model`,className:e?f:void 0,children:`Model`}),(0,I.jsxs)(vt,{value:u?.model??`claude-sonnet-4-6`,onValueChange:e=>d(`model`,e),children:[(0,I.jsx)(bt,{id:`ai-model`,className:`w-full ${e?`h-7 text-[11px]`:``}`,children:(0,I.jsx)(yt,{})}),(0,I.jsx)(xt,{children:Ft.map(e=>(0,I.jsx)(St,{value:e.value,children:e.label},e.value))})]})]}),(0,I.jsxs)(`div`,{className:g,children:[(0,I.jsx)($,{htmlFor:`ai-effort`,className:e?f:void 0,children:`Effort`}),(0,I.jsxs)(vt,{value:u?.effort??`high`,onValueChange:e=>d(`effort`,e),children:[(0,I.jsx)(bt,{id:`ai-effort`,className:`w-full ${e?`h-7 text-[11px]`:``}`,children:(0,I.jsx)(yt,{})}),(0,I.jsx)(xt,{children:It.map(e=>(0,I.jsx)(St,{value:e.value,children:e.label},e.value))})]})]}),(0,I.jsxs)(`div`,{className:g,children:[(0,I.jsx)($,{htmlFor:`ai-max-turns`,className:e?f:void 0,children:`Max Turns (1-500)`}),(0,I.jsx)(x,{id:`ai-max-turns`,type:`number`,min:1,max:500,defaultValue:u?.max_turns??100,className:e?`h-7 text-[11px]`:void 0,onBlur:e=>{let t=parseInt(e.target.value);isNaN(t)||d(`max_turns`,t)}},`turns-${s}`)]}),(0,I.jsxs)(`div`,{className:g,children:[(0,I.jsx)($,{htmlFor:`ai-budget`,className:e?f:void 0,children:`Max Budget (USD)`}),(0,I.jsx)(x,{id:`ai-budget`,type:`number`,step:.1,min:.01,max:50,defaultValue:u?.max_budget_usd??``,placeholder:`No limit`,className:e?`h-7 text-[11px]`:void 0,onBlur:e=>{let t=parseFloat(e.target.value);d(`max_budget_usd`,isNaN(t)?void 0:t)}},`budget-${s}`)]}),(0,I.jsxs)(`div`,{className:g,children:[(0,I.jsx)($,{htmlFor:`ai-thinking`,className:e?f:void 0,children:`Thinking Budget (tokens)`}),(0,I.jsx)(x,{id:`ai-thinking`,type:`number`,min:0,defaultValue:u?.thinking_budget_tokens??``,placeholder:`Disabled`,className:e?`h-7 text-[11px]`:void 0,onBlur:e=>{let t=parseInt(e.target.value);d(`thinking_budget_tokens`,isNaN(t)?void 0:t)}},`thinking-${s}`)]})]}),r&&(0,I.jsx)(`p`,{className:`text-xs text-text-subtle`,children:`Saving...`}),a&&(0,I.jsx)(`p`,{className:`text-xs text-red-500`,children:a})]}):(0,I.jsxs)(`div`,{className:h,children:[(0,I.jsx)(`h3`,{className:`${p} font-medium text-text-secondary`,children:`AI Provider`}),(0,I.jsx)(`p`,{className:`${f} text-text-subtle`,children:a?`Error: ${a}`:`Loading...`})]})}export{z as _,Tt as a,M as b,kt as c,xt as d,St as f,B as g,$ as h,At as i,jt as l,yt as m,Dt as n,Et as o,bt as p,Ot as r,Mt as s,Lt as t,vt as u,P as v,j as x,N as y};