Stijnus commited on
Commit
27eab59
·
1 Parent(s): 4e6f18e
app/components/settings/connections/ConnectionsTab.tsx CHANGED
@@ -35,6 +35,7 @@ interface GitHubStats {
35
  interface GitHubConnection {
36
  user: GitHubUserResponse | null;
37
  token: string;
 
38
  stats?: GitHubStats;
39
  }
40
 
@@ -42,6 +43,7 @@ export default function ConnectionsTab() {
42
  const [connection, setConnection] = useState<GitHubConnection>({
43
  user: null,
44
  token: '',
 
45
  });
46
  const [isLoading, setIsLoading] = useState(true);
47
  const [isConnecting, setIsConnecting] = useState(false);
@@ -53,7 +55,14 @@ export default function ConnectionsTab() {
53
 
54
  if (savedConnection) {
55
  const parsed = JSON.parse(savedConnection);
 
 
 
 
 
 
56
  setConnection(parsed);
 
57
  if (parsed.user && parsed.token) {
58
  fetchGitHubStats(parsed.token);
59
  }
@@ -73,7 +82,9 @@ export default function ConnectionsTab() {
73
  },
74
  });
75
 
76
- if (!reposResponse.ok) throw new Error('Failed to fetch repositories');
 
 
77
 
78
  const repos = (await reposResponse.json()) as GitHubRepoInfo[];
79
 
@@ -107,10 +118,16 @@ export default function ConnectionsTab() {
107
  },
108
  });
109
 
110
- if (!response.ok) throw new Error('Invalid token or unauthorized');
 
 
111
 
112
  const data = (await response.json()) as GitHubUserResponse;
113
- const newConnection = { user: data, token };
 
 
 
 
114
 
115
  // Save connection
116
  localStorage.setItem('github_connection', JSON.stringify(newConnection));
@@ -123,7 +140,7 @@ export default function ConnectionsTab() {
123
  } catch (error) {
124
  logStore.logError('Failed to authenticate with GitHub', { error });
125
  toast.error('Failed to connect to GitHub');
126
- setConnection({ user: null, token: '' });
127
  } finally {
128
  setIsConnecting(false);
129
  }
@@ -136,11 +153,13 @@ export default function ConnectionsTab() {
136
 
137
  const handleDisconnect = () => {
138
  localStorage.removeItem('github_connection');
139
- setConnection({ user: null, token: '' });
140
  toast.success('Disconnected from GitHub');
141
  };
142
 
143
- if (isLoading) return <LoadingSpinner />;
 
 
144
 
145
  return (
146
  <div className="space-y-4">
@@ -174,31 +193,37 @@ export default function ConnectionsTab() {
174
 
175
  <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
176
  <div>
177
- <label className="block text-sm text-bolt-elements-textSecondary mb-2">GitHub Username</label>
178
- <input
179
- type="text"
180
- value={connection.user?.login || ''}
181
- disabled={true}
182
- placeholder="Not connected"
 
183
  className={classNames(
184
  'w-full px-3 py-2 rounded-lg text-sm',
185
  'bg-[#F8F8F8] dark:bg-[#1A1A1A]',
186
  'border border-[#E5E5E5] dark:border-[#333333]',
187
- 'text-bolt-elements-textPrimary placeholder-bolt-elements-textTertiary',
188
  'focus:outline-none focus:ring-1 focus:ring-purple-500',
189
  'disabled:opacity-50',
190
  )}
191
- />
 
 
 
192
  </div>
193
 
194
  <div>
195
- <label className="block text-sm text-bolt-elements-textSecondary mb-2">Personal Access Token</label>
 
 
196
  <input
197
  type="password"
198
  value={connection.token}
199
  onChange={(e) => setConnection((prev) => ({ ...prev, token: e.target.value }))}
200
  disabled={isConnecting || !!connection.user}
201
- placeholder="Enter your GitHub token"
202
  className={classNames(
203
  'w-full px-3 py-2 rounded-lg text-sm',
204
  'bg-[#F8F8F8] dark:bg-[#1A1A1A]',
@@ -257,69 +282,49 @@ export default function ConnectionsTab() {
257
  )}
258
  </div>
259
 
260
- {connection.user && connection.stats && (
261
- <div className="mt-6 border-t border-[#E5E5E5] dark:border-[#1A1A1A] pt-6">
262
- <div className="flex items-center gap-4 mb-6">
263
  <img
264
  src={connection.user.avatar_url}
265
  alt={connection.user.login}
266
- className="w-16 h-16 rounded-full"
267
  />
268
  <div>
269
- <h3 className="text-lg font-medium text-bolt-elements-textPrimary">
270
- {connection.user.name || connection.user.login}
271
- </h3>
272
- {connection.user.bio && (
273
- <p className="text-sm text-bolt-elements-textSecondary">{connection.user.bio}</p>
274
- )}
275
- <div className="flex gap-4 mt-2 text-sm text-bolt-elements-textSecondary">
276
- <span className="flex items-center gap-1">
277
- <div className="i-ph:users w-4 h-4" />
278
- {connection.user.followers} followers
279
- </span>
280
- <span className="flex items-center gap-1">
281
- <div className="i-ph:star w-4 h-4" />
282
- {connection.stats.totalStars} stars
283
- </span>
284
- <span className="flex items-center gap-1">
285
- <div className="i-ph:git-fork w-4 h-4" />
286
- {connection.stats.totalForks} forks
287
- </span>
288
- </div>
289
  </div>
290
  </div>
291
 
292
- <h4 className="text-sm font-medium text-bolt-elements-textPrimary mb-3">Recent Repositories</h4>
293
- <div className="space-y-3">
294
- {connection.stats.repos.map((repo) => (
295
- <a
296
- key={repo.full_name}
297
- href={repo.html_url}
298
- target="_blank"
299
- rel="noopener noreferrer"
300
- className="block p-3 rounded-lg bg-[#F8F8F8] dark:bg-[#1A1A1A] hover:bg-[#F0F0F0] dark:hover:bg-[#252525] transition-colors"
301
- >
302
- <div className="flex items-center justify-between">
303
- <div>
304
- <h5 className="text-sm font-medium text-bolt-elements-textPrimary">{repo.name}</h5>
305
- {repo.description && (
306
- <p className="text-xs text-bolt-elements-textSecondary mt-1">{repo.description}</p>
307
- )}
308
- </div>
309
- <div className="flex items-center gap-3 text-xs text-bolt-elements-textSecondary">
310
- <span className="flex items-center gap-1">
311
- <div className="i-ph:star w-3 h-3" />
312
- {repo.stargazers_count}
313
- </span>
314
- <span className="flex items-center gap-1">
315
- <div className="i-ph:git-fork w-3 h-3" />
316
- {repo.forks_count}
317
- </span>
318
- </div>
319
  </div>
320
- </a>
321
- ))}
322
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
323
  </div>
324
  )}
325
  </div>
 
35
  interface GitHubConnection {
36
  user: GitHubUserResponse | null;
37
  token: string;
38
+ tokenType: 'classic' | 'fine-grained';
39
  stats?: GitHubStats;
40
  }
41
 
 
43
  const [connection, setConnection] = useState<GitHubConnection>({
44
  user: null,
45
  token: '',
46
+ tokenType: 'classic',
47
  });
48
  const [isLoading, setIsLoading] = useState(true);
49
  const [isConnecting, setIsConnecting] = useState(false);
 
55
 
56
  if (savedConnection) {
57
  const parsed = JSON.parse(savedConnection);
58
+
59
+ // Ensure backward compatibility with existing connections
60
+ if (!parsed.tokenType) {
61
+ parsed.tokenType = 'classic';
62
+ }
63
+
64
  setConnection(parsed);
65
+
66
  if (parsed.user && parsed.token) {
67
  fetchGitHubStats(parsed.token);
68
  }
 
82
  },
83
  });
84
 
85
+ if (!reposResponse.ok) {
86
+ throw new Error('Failed to fetch repositories');
87
+ }
88
 
89
  const repos = (await reposResponse.json()) as GitHubRepoInfo[];
90
 
 
118
  },
119
  });
120
 
121
+ if (!response.ok) {
122
+ throw new Error('Invalid token or unauthorized');
123
+ }
124
 
125
  const data = (await response.json()) as GitHubUserResponse;
126
+ const newConnection: GitHubConnection = {
127
+ user: data,
128
+ token,
129
+ tokenType: connection.tokenType,
130
+ };
131
 
132
  // Save connection
133
  localStorage.setItem('github_connection', JSON.stringify(newConnection));
 
140
  } catch (error) {
141
  logStore.logError('Failed to authenticate with GitHub', { error });
142
  toast.error('Failed to connect to GitHub');
143
+ setConnection({ user: null, token: '', tokenType: 'classic' });
144
  } finally {
145
  setIsConnecting(false);
146
  }
 
153
 
154
  const handleDisconnect = () => {
155
  localStorage.removeItem('github_connection');
156
+ setConnection({ user: null, token: '', tokenType: 'classic' });
157
  toast.success('Disconnected from GitHub');
158
  };
159
 
160
+ if (isLoading) {
161
+ return <LoadingSpinner />;
162
+ }
163
 
164
  return (
165
  <div className="space-y-4">
 
193
 
194
  <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
195
  <div>
196
+ <label className="block text-sm text-bolt-elements-textSecondary mb-2">Token Type</label>
197
+ <select
198
+ value={connection.tokenType}
199
+ onChange={(e) =>
200
+ setConnection((prev) => ({ ...prev, tokenType: e.target.value as 'classic' | 'fine-grained' }))
201
+ }
202
+ disabled={isConnecting || !!connection.user}
203
  className={classNames(
204
  'w-full px-3 py-2 rounded-lg text-sm',
205
  'bg-[#F8F8F8] dark:bg-[#1A1A1A]',
206
  'border border-[#E5E5E5] dark:border-[#333333]',
207
+ 'text-bolt-elements-textPrimary',
208
  'focus:outline-none focus:ring-1 focus:ring-purple-500',
209
  'disabled:opacity-50',
210
  )}
211
+ >
212
+ <option value="classic">Personal Access Token (Classic)</option>
213
+ <option value="fine-grained">Fine-grained Token</option>
214
+ </select>
215
  </div>
216
 
217
  <div>
218
+ <label className="block text-sm text-bolt-elements-textSecondary mb-2">
219
+ {connection.tokenType === 'classic' ? 'Personal Access Token' : 'Fine-grained Token'}
220
+ </label>
221
  <input
222
  type="password"
223
  value={connection.token}
224
  onChange={(e) => setConnection((prev) => ({ ...prev, token: e.target.value }))}
225
  disabled={isConnecting || !!connection.user}
226
+ placeholder={`Enter your GitHub ${connection.tokenType === 'classic' ? 'personal access token' : 'fine-grained token'}`}
227
  className={classNames(
228
  'w-full px-3 py-2 rounded-lg text-sm',
229
  'bg-[#F8F8F8] dark:bg-[#1A1A1A]',
 
282
  )}
283
  </div>
284
 
285
+ {connection.user && (
286
+ <div className="p-4 bg-[#F8F8F8] dark:bg-[#1A1A1A] rounded-lg">
287
+ <div className="flex items-center gap-4">
288
  <img
289
  src={connection.user.avatar_url}
290
  alt={connection.user.login}
291
+ className="w-12 h-12 rounded-full"
292
  />
293
  <div>
294
+ <h4 className="text-sm font-medium text-bolt-elements-textPrimary">{connection.user.name}</h4>
295
+ <p className="text-sm text-bolt-elements-textSecondary">@{connection.user.login}</p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
296
  </div>
297
  </div>
298
 
299
+ {isFetchingStats ? (
300
+ <div className="mt-4 flex items-center gap-2 text-sm text-bolt-elements-textSecondary">
301
+ <div className="i-ph:spinner-gap w-4 h-4 animate-spin" />
302
+ Fetching GitHub stats...
303
+ </div>
304
+ ) : (
305
+ connection.stats && (
306
+ <div className="mt-4 grid grid-cols-3 gap-4">
307
+ <div>
308
+ <p className="text-sm text-bolt-elements-textSecondary">Public Repos</p>
309
+ <p className="text-lg font-medium text-bolt-elements-textPrimary">
310
+ {connection.user.public_repos}
311
+ </p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
312
  </div>
313
+ <div>
314
+ <p className="text-sm text-bolt-elements-textSecondary">Total Stars</p>
315
+ <p className="text-lg font-medium text-bolt-elements-textPrimary">
316
+ {connection.stats.totalStars}
317
+ </p>
318
+ </div>
319
+ <div>
320
+ <p className="text-sm text-bolt-elements-textSecondary">Total Forks</p>
321
+ <p className="text-lg font-medium text-bolt-elements-textPrimary">
322
+ {connection.stats.totalForks}
323
+ </p>
324
+ </div>
325
+ </div>
326
+ )
327
+ )}
328
  </div>
329
  )}
330
  </div>
app/components/settings/connections/components/ConnectionForm.tsx ADDED
@@ -0,0 +1,180 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React, { useEffect } from 'react';
2
+ import { classNames } from '~/utils/classNames';
3
+ import type { GitHubAuthState } from '~/components/settings/connections/types/GitHub';
4
+ import Cookies from 'js-cookie';
5
+ import { getLocalStorage } from '~/utils/localStorage';
6
+
7
+ const GITHUB_TOKEN_KEY = 'github_token';
8
+
9
+ interface ConnectionFormProps {
10
+ authState: GitHubAuthState;
11
+ setAuthState: React.Dispatch<React.SetStateAction<GitHubAuthState>>;
12
+ onSave: (e: React.FormEvent) => void;
13
+ onDisconnect: () => void;
14
+ }
15
+
16
+ export function ConnectionForm({ authState, setAuthState, onSave, onDisconnect }: ConnectionFormProps) {
17
+ // Check for saved token on mount
18
+ useEffect(() => {
19
+ const savedToken = Cookies.get(GITHUB_TOKEN_KEY) || getLocalStorage(GITHUB_TOKEN_KEY);
20
+
21
+ if (savedToken && !authState.tokenInfo?.token) {
22
+ setAuthState((prev: GitHubAuthState) => ({
23
+ ...prev,
24
+ tokenInfo: {
25
+ token: savedToken,
26
+ scope: [],
27
+ avatar_url: '',
28
+ name: null,
29
+ created_at: new Date().toISOString(),
30
+ followers: 0,
31
+ },
32
+ }));
33
+ }
34
+ }, []);
35
+
36
+ return (
37
+ <div className="rounded-xl bg-white dark:bg-[#0A0A0A] border border-[#E5E5E5] dark:border-[#1A1A1A] overflow-hidden">
38
+ <div className="p-6">
39
+ <div className="flex items-center justify-between mb-6">
40
+ <div className="flex items-center gap-3">
41
+ <div className="p-2 rounded-lg bg-[#F5F5F5] dark:bg-[#1A1A1A] border border-[#E5E5E5] dark:border-[#1A1A1A]">
42
+ <div className="i-ph:plug-fill text-bolt-elements-textTertiary" />
43
+ </div>
44
+ <div>
45
+ <h3 className="text-lg font-medium text-bolt-elements-textPrimary">Connection Settings</h3>
46
+ <p className="text-sm text-bolt-elements-textSecondary">Configure your GitHub connection</p>
47
+ </div>
48
+ </div>
49
+ </div>
50
+
51
+ <form onSubmit={onSave} className="space-y-4">
52
+ <div>
53
+ <label htmlFor="username" className="block text-sm font-medium text-bolt-elements-textSecondary mb-2">
54
+ GitHub Username
55
+ </label>
56
+ <input
57
+ id="username"
58
+ type="text"
59
+ value={authState.username}
60
+ onChange={(e) => setAuthState((prev: GitHubAuthState) => ({ ...prev, username: e.target.value }))}
61
+ className={classNames(
62
+ 'w-full px-4 py-2.5 bg-[#F5F5F5] dark:bg-[#1A1A1A] border rounded-lg',
63
+ 'text-bolt-elements-textPrimary placeholder-bolt-elements-textTertiary text-base',
64
+ 'border-[#E5E5E5] dark:border-[#1A1A1A]',
65
+ 'focus:ring-2 focus:ring-purple-500/50 focus:border-purple-500',
66
+ 'transition-all duration-200',
67
+ )}
68
+ placeholder="e.g., octocat"
69
+ />
70
+ </div>
71
+
72
+ <div>
73
+ <div className="flex items-center justify-between mb-2">
74
+ <label htmlFor="token" className="block text-sm font-medium text-bolt-elements-textSecondary">
75
+ Personal Access Token
76
+ </label>
77
+ <a
78
+ href="https://github.com/settings/tokens/new?scopes=repo,user,read:org,workflow,delete_repo,write:packages,read:packages"
79
+ target="_blank"
80
+ rel="noopener noreferrer"
81
+ className={classNames(
82
+ 'inline-flex items-center gap-1.5 text-xs',
83
+ 'text-purple-500 hover:text-purple-600 dark:text-purple-400 dark:hover:text-purple-300',
84
+ 'transition-colors duration-200',
85
+ )}
86
+ >
87
+ <span>Generate new token</span>
88
+ <div className="i-ph:plus-circle" />
89
+ </a>
90
+ </div>
91
+ <input
92
+ id="token"
93
+ type="password"
94
+ value={authState.tokenInfo?.token || ''}
95
+ onChange={(e) =>
96
+ setAuthState((prev: GitHubAuthState) => ({
97
+ ...prev,
98
+ tokenInfo: {
99
+ token: e.target.value,
100
+ scope: [],
101
+ avatar_url: '',
102
+ name: null,
103
+ created_at: new Date().toISOString(),
104
+ followers: 0,
105
+ },
106
+ username: '',
107
+ isConnected: false,
108
+ isVerifying: false,
109
+ isLoadingRepos: false,
110
+ }))
111
+ }
112
+ className={classNames(
113
+ 'w-full px-4 py-2.5 bg-[#F5F5F5] dark:bg-[#1A1A1A] border rounded-lg',
114
+ 'text-bolt-elements-textPrimary placeholder-bolt-elements-textTertiary text-base',
115
+ 'border-[#E5E5E5] dark:border-[#1A1A1A]',
116
+ 'focus:ring-2 focus:ring-purple-500/50 focus:border-purple-500',
117
+ 'transition-all duration-200',
118
+ )}
119
+ placeholder="ghp_xxxxxxxxxxxx"
120
+ />
121
+ </div>
122
+
123
+ <div className="flex items-center justify-between pt-4 border-t border-[#E5E5E5] dark:border-[#1A1A1A]">
124
+ <div className="flex items-center gap-4">
125
+ {!authState.isConnected ? (
126
+ <button
127
+ type="submit"
128
+ disabled={authState.isVerifying || !authState.username || !authState.tokenInfo?.token}
129
+ className={classNames(
130
+ 'inline-flex items-center gap-2 px-4 py-2 text-sm font-medium rounded-lg transition-colors',
131
+ 'bg-purple-500 hover:bg-purple-600',
132
+ 'text-white',
133
+ 'disabled:opacity-50 disabled:cursor-not-allowed',
134
+ )}
135
+ >
136
+ {authState.isVerifying ? (
137
+ <>
138
+ <div className="i-ph:spinner animate-spin" />
139
+ <span>Verifying...</span>
140
+ </>
141
+ ) : (
142
+ <>
143
+ <div className="i-ph:plug-fill" />
144
+ <span>Connect</span>
145
+ </>
146
+ )}
147
+ </button>
148
+ ) : (
149
+ <>
150
+ <button
151
+ onClick={onDisconnect}
152
+ className={classNames(
153
+ 'inline-flex items-center gap-2 px-4 py-2 text-sm font-medium rounded-lg transition-colors',
154
+ 'bg-[#F5F5F5] hover:bg-red-500/10 hover:text-red-500',
155
+ 'dark:bg-[#1A1A1A] dark:hover:bg-red-500/20 dark:hover:text-red-500',
156
+ 'text-bolt-elements-textPrimary',
157
+ )}
158
+ >
159
+ <div className="i-ph:plug-fill" />
160
+ <span>Disconnect</span>
161
+ </button>
162
+ <span className="inline-flex items-center gap-2 px-3 py-1.5 text-sm text-green-600 dark:text-green-400 bg-green-500/5 rounded-lg border border-green-500/20">
163
+ <div className="i-ph:check-circle-fill" />
164
+ <span>Connected</span>
165
+ </span>
166
+ </>
167
+ )}
168
+ </div>
169
+ {authState.rateLimits && (
170
+ <div className="flex items-center gap-2 text-sm text-bolt-elements-textTertiary">
171
+ <div className="i-ph:clock-countdown opacity-60" />
172
+ <span>Rate limit resets at {authState.rateLimits.reset.toLocaleTimeString()}</span>
173
+ </div>
174
+ )}
175
+ </div>
176
+ </form>
177
+ </div>
178
+ </div>
179
+ );
180
+ }
app/components/settings/connections/components/CreateBranchDialog.tsx ADDED
@@ -0,0 +1,150 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { useState } from 'react';
2
+ import * as Dialog from '@radix-ui/react-dialog';
3
+ import { classNames } from '~/utils/classNames';
4
+ import type { GitHubRepoInfo } from '~/components/settings/connections/types/GitHub';
5
+ import { GitBranch } from '@phosphor-icons/react';
6
+
7
+ interface GitHubBranch {
8
+ name: string;
9
+ default?: boolean;
10
+ }
11
+
12
+ interface CreateBranchDialogProps {
13
+ isOpen: boolean;
14
+ onClose: () => void;
15
+ onConfirm: (branchName: string, sourceBranch: string) => void;
16
+ repository: GitHubRepoInfo;
17
+ branches?: GitHubBranch[];
18
+ }
19
+
20
+ export function CreateBranchDialog({ isOpen, onClose, onConfirm, repository, branches }: CreateBranchDialogProps) {
21
+ const [branchName, setBranchName] = useState('');
22
+ const [sourceBranch, setSourceBranch] = useState(branches?.find((b) => b.default)?.name || 'main');
23
+
24
+ const handleSubmit = (e: React.FormEvent) => {
25
+ e.preventDefault();
26
+ onConfirm(branchName, sourceBranch);
27
+ setBranchName('');
28
+ onClose();
29
+ };
30
+
31
+ return (
32
+ <Dialog.Root open={isOpen} onOpenChange={onClose}>
33
+ <Dialog.Portal>
34
+ <Dialog.Overlay className="fixed inset-0 bg-black/50 dark:bg-black/80" />
35
+ <Dialog.Content
36
+ className={classNames(
37
+ 'fixed top-[50%] left-[50%] translate-x-[-50%] translate-y-[-50%]',
38
+ 'w-full max-w-md p-6 rounded-xl shadow-lg',
39
+ 'bg-white dark:bg-[#0A0A0A]',
40
+ 'border border-[#E5E5E5] dark:border-[#1A1A1A]',
41
+ )}
42
+ >
43
+ <Dialog.Title className="text-lg font-medium text-bolt-elements-textPrimary mb-4">
44
+ Create New Branch
45
+ </Dialog.Title>
46
+
47
+ <form onSubmit={handleSubmit}>
48
+ <div className="space-y-4">
49
+ <div>
50
+ <label htmlFor="branchName" className="block text-sm font-medium text-bolt-elements-textSecondary mb-2">
51
+ Branch Name
52
+ </label>
53
+ <input
54
+ id="branchName"
55
+ type="text"
56
+ value={branchName}
57
+ onChange={(e) => setBranchName(e.target.value)}
58
+ placeholder="feature/my-new-branch"
59
+ className={classNames(
60
+ 'w-full px-3 py-2 rounded-lg',
61
+ 'bg-[#F5F5F5] dark:bg-[#1A1A1A]',
62
+ 'border border-[#E5E5E5] dark:border-[#1A1A1A]',
63
+ 'text-bolt-elements-textPrimary placeholder:text-bolt-elements-textTertiary',
64
+ 'focus:outline-none focus:ring-2 focus:ring-purple-500/50',
65
+ )}
66
+ required
67
+ />
68
+ </div>
69
+
70
+ <div>
71
+ <label
72
+ htmlFor="sourceBranch"
73
+ className="block text-sm font-medium text-bolt-elements-textSecondary mb-2"
74
+ >
75
+ Source Branch
76
+ </label>
77
+ <select
78
+ id="sourceBranch"
79
+ value={sourceBranch}
80
+ onChange={(e) => setSourceBranch(e.target.value)}
81
+ className={classNames(
82
+ 'w-full px-3 py-2 rounded-lg',
83
+ 'bg-[#F5F5F5] dark:bg-[#1A1A1A]',
84
+ 'border border-[#E5E5E5] dark:border-[#1A1A1A]',
85
+ 'text-bolt-elements-textPrimary',
86
+ 'focus:outline-none focus:ring-2 focus:ring-purple-500/50',
87
+ )}
88
+ >
89
+ {branches?.map((branch) => (
90
+ <option key={branch.name} value={branch.name}>
91
+ {branch.name} {branch.default ? '(default)' : ''}
92
+ </option>
93
+ ))}
94
+ </select>
95
+ </div>
96
+
97
+ <div className="mt-4 p-3 bg-[#F5F5F5] dark:bg-[#1A1A1A] rounded-lg">
98
+ <h4 className="text-sm font-medium text-bolt-elements-textSecondary mb-2">Branch Overview</h4>
99
+ <ul className="space-y-2 text-sm text-bolt-elements-textSecondary">
100
+ <li className="flex items-center gap-2">
101
+ <GitBranch className="text-lg" />
102
+ Repository: {repository.name}
103
+ </li>
104
+ {branchName && (
105
+ <li className="flex items-center gap-2">
106
+ <div className="i-ph:check-circle text-green-500" />
107
+ New branch will be created as: {branchName}
108
+ </li>
109
+ )}
110
+ <li className="flex items-center gap-2">
111
+ <div className="i-ph:check-circle text-green-500" />
112
+ Based on: {sourceBranch}
113
+ </li>
114
+ </ul>
115
+ </div>
116
+ </div>
117
+
118
+ <div className="mt-6 flex justify-end gap-3">
119
+ <button
120
+ type="button"
121
+ onClick={onClose}
122
+ className={classNames(
123
+ 'px-4 py-2 rounded-lg text-sm font-medium',
124
+ 'text-bolt-elements-textPrimary',
125
+ 'bg-[#F5F5F5] dark:bg-[#1A1A1A]',
126
+ 'hover:bg-purple-500/10 hover:text-purple-500',
127
+ 'dark:hover:bg-purple-500/20 dark:hover:text-purple-500',
128
+ 'transition-colors',
129
+ )}
130
+ >
131
+ Cancel
132
+ </button>
133
+ <button
134
+ type="submit"
135
+ className={classNames(
136
+ 'px-4 py-2 rounded-lg text-sm font-medium',
137
+ 'text-white bg-purple-500',
138
+ 'hover:bg-purple-600',
139
+ 'transition-colors',
140
+ )}
141
+ >
142
+ Create Branch
143
+ </button>
144
+ </div>
145
+ </form>
146
+ </Dialog.Content>
147
+ </Dialog.Portal>
148
+ </Dialog.Root>
149
+ );
150
+ }
app/components/settings/connections/types/GitHub.ts ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ export interface GitHubUserResponse {
2
+ login: string;
3
+ avatar_url: string;
4
+ html_url: string;
5
+ name: string;
6
+ bio: string;
7
+ public_repos: number;
8
+ followers: number;
9
+ following: number;
10
+ }
11
+
12
+ export interface GitHubRepoInfo {
13
+ name: string;
14
+ full_name: string;
15
+ html_url: string;
16
+ description: string;
17
+ stargazers_count: number;
18
+ forks_count: number;
19
+ default_branch: string;
20
+ updated_at: string;
21
+ }
22
+
23
+ export interface GitHubStats {
24
+ repos: GitHubRepoInfo[];
25
+ totalStars: number;
26
+ totalForks: number;
27
+ }
28
+
29
+ export interface GitHubConnection {
30
+ user: GitHubUserResponse | null;
31
+ token: string;
32
+ tokenType: 'classic' | 'fine-grained';
33
+ stats?: GitHubStats;
34
+ }
35
+
36
+ export interface GitHubTokenInfo {
37
+ token: string;
38
+ scope: string[];
39
+ avatar_url: string;
40
+ name: string | null;
41
+ created_at: string;
42
+ followers: number;
43
+ }
44
+
45
+ export interface GitHubRateLimits {
46
+ limit: number;
47
+ remaining: number;
48
+ reset: Date;
49
+ used: number;
50
+ }
51
+
52
+ export interface GitHubAuthState {
53
+ username: string;
54
+ tokenInfo: GitHubTokenInfo | null;
55
+ isConnected: boolean;
56
+ isVerifying: boolean;
57
+ isLoadingRepos: boolean;
58
+ rateLimits?: GitHubRateLimits;
59
+ }
app/components/settings/data/DataTab.tsx CHANGED
@@ -305,9 +305,9 @@ export default function DataTab() {
305
  >
306
  <div className="flex items-center gap-2 mb-2">
307
  <div className="i-ph:chat-circle-duotone w-5 h-5 text-purple-500" />
308
- <h3 className="text-lg font-medium">Chat History</h3>
309
  </div>
310
- <p className="text-sm text-bolt-elements-textSecondary mb-4">Export or delete all your chat history.</p>
311
  <div className="flex gap-4">
312
  <motion.button
313
  className="inline-flex items-center gap-2 px-4 py-2 rounded-lg bg-purple-500 text-white text-sm hover:bg-purple-600"
@@ -339,9 +339,9 @@ export default function DataTab() {
339
  >
340
  <div className="flex items-center gap-2 mb-2">
341
  <div className="i-ph:gear-duotone w-5 h-5 text-purple-500" />
342
- <h3 className="text-lg font-medium">Settings Backup</h3>
343
  </div>
344
- <p className="text-sm text-bolt-elements-textSecondary mb-4">
345
  Export your settings to a JSON file or import settings from a previously exported file.
346
  </p>
347
  <div className="flex gap-4">
@@ -364,7 +364,7 @@ export default function DataTab() {
364
  Import Settings
365
  </motion.button>
366
  <motion.button
367
- className="inline-flex items-center gap-2 px-4 py-2 rounded-lg bg-yellow-50 text-yellow-600 text-sm hover:bg-yellow-100 dark:bg-yellow-500/10 dark:hover:bg-yellow-500/20"
368
  whileHover={{ scale: 1.02 }}
369
  whileTap={{ scale: 0.98 }}
370
  onClick={() => setShowResetInlineConfirm(true)}
@@ -384,9 +384,9 @@ export default function DataTab() {
384
  >
385
  <div className="flex items-center gap-2 mb-2">
386
  <div className="i-ph:key-duotone w-5 h-5 text-purple-500" />
387
- <h3 className="text-lg font-medium">API Keys Management</h3>
388
  </div>
389
- <p className="text-sm text-bolt-elements-textSecondary mb-4">
390
  Import API keys from a JSON file or download a template to fill in your keys.
391
  </p>
392
  <div className="flex gap-4">
@@ -405,7 +405,7 @@ export default function DataTab() {
405
  disabled={isDownloadingTemplate}
406
  >
407
  {isDownloadingTemplate ? (
408
- <div className="i-ph:spinner-gap-bold animate-spin" />
409
  ) : (
410
  <div className="i-ph:download-simple w-4 h-4" />
411
  )}
 
305
  >
306
  <div className="flex items-center gap-2 mb-2">
307
  <div className="i-ph:chat-circle-duotone w-5 h-5 text-purple-500" />
308
+ <h3 className="text-lg font-medium text-gray-900 dark:text-white">Chat History</h3>
309
  </div>
310
+ <p className="text-sm text-gray-600 dark:text-gray-400 mb-4">Export or delete all your chat history.</p>
311
  <div className="flex gap-4">
312
  <motion.button
313
  className="inline-flex items-center gap-2 px-4 py-2 rounded-lg bg-purple-500 text-white text-sm hover:bg-purple-600"
 
339
  >
340
  <div className="flex items-center gap-2 mb-2">
341
  <div className="i-ph:gear-duotone w-5 h-5 text-purple-500" />
342
+ <h3 className="text-lg font-medium text-gray-900 dark:text-white">Settings Backup</h3>
343
  </div>
344
+ <p className="text-sm text-gray-600 dark:text-gray-400 mb-4">
345
  Export your settings to a JSON file or import settings from a previously exported file.
346
  </p>
347
  <div className="flex gap-4">
 
364
  Import Settings
365
  </motion.button>
366
  <motion.button
367
+ className="inline-flex items-center gap-2 px-4 py-2 rounded-lg bg-yellow-50 text-yellow-600 text-sm hover:bg-yellow-100 dark:bg-yellow-500/10 dark:hover:bg-yellow-500/20 dark:text-yellow-500"
368
  whileHover={{ scale: 1.02 }}
369
  whileTap={{ scale: 0.98 }}
370
  onClick={() => setShowResetInlineConfirm(true)}
 
384
  >
385
  <div className="flex items-center gap-2 mb-2">
386
  <div className="i-ph:key-duotone w-5 h-5 text-purple-500" />
387
+ <h3 className="text-lg font-medium text-gray-900 dark:text-white">API Keys Management</h3>
388
  </div>
389
+ <p className="text-sm text-gray-600 dark:text-gray-400 mb-4">
390
  Import API keys from a JSON file or download a template to fill in your keys.
391
  </p>
392
  <div className="flex gap-4">
 
405
  disabled={isDownloadingTemplate}
406
  >
407
  {isDownloadingTemplate ? (
408
+ <div className="i-ph:spinner-gap-bold animate-spin w-4 h-4" />
409
  ) : (
410
  <div className="i-ph:download-simple w-4 h-4" />
411
  )}
app/components/settings/debug/DebugTab.tsx CHANGED
@@ -92,10 +92,12 @@ interface WebAppInfo {
92
  nodeVersion: string;
93
  dependencies: { [key: string]: string };
94
  devDependencies: { [key: string]: string };
 
95
  // Build Info
96
  buildTime?: string;
97
  buildNumber?: string;
98
  environment?: string;
 
99
  // Git Info
100
  gitInfo?: {
101
  branch: string;
@@ -104,6 +106,7 @@ interface WebAppInfo {
104
  author: string;
105
  remoteUrl: string;
106
  };
 
107
  // GitHub Repository Info
108
  repoInfo?: {
109
  name: string;
@@ -121,6 +124,39 @@ interface WebAppInfo {
121
  };
122
  }
123
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
124
  export default function DebugTab() {
125
  const [systemInfo, setSystemInfo] = useState<SystemInfo | null>(null);
126
  const [webAppInfo, setWebAppInfo] = useState<WebAppInfo | null>(null);
@@ -328,23 +364,27 @@ export default function DebugTab() {
328
 
329
  // Fetch local app info
330
  const appInfoResponse = await fetch('/api/system/app-info');
 
331
  if (!appInfoResponse.ok) {
332
  throw new Error('Failed to fetch webapp info');
333
  }
334
- const appData = await appInfoResponse.json();
 
335
 
336
  // Fetch git info
337
  const gitInfoResponse = await fetch('/api/system/git-info');
338
- let gitInfo = null;
 
339
  if (gitInfoResponse.ok) {
340
- gitInfo = await gitInfoResponse.json();
341
  }
342
 
343
  // Fetch GitHub repository info
344
  const repoInfoResponse = await fetch('https://api.github.com/repos/stackblitz-labs/bolt.diy');
345
- let repoInfo = null;
 
346
  if (repoInfoResponse.ok) {
347
- const repoData = await repoInfoResponse.json();
348
  repoInfo = {
349
  name: repoData.name,
350
  fullName: repoData.full_name,
@@ -396,21 +436,6 @@ export default function DebugTab() {
396
  return `${Math.round(size)} ${units[unitIndex]}`;
397
  };
398
 
399
- const handleLogSystemInfo = () => {
400
- if (!systemInfo) {
401
- return;
402
- }
403
-
404
- logStore.logSystem('System Information', {
405
- os: systemInfo.os,
406
- arch: systemInfo.arch,
407
- cpus: systemInfo.cpus,
408
- memory: systemInfo.memory,
409
- node: systemInfo.node,
410
- });
411
- toast.success('System information logged');
412
- };
413
-
414
  const handleLogPerformance = () => {
415
  try {
416
  setLoading((prev) => ({ ...prev, performance: true }));
@@ -625,6 +650,26 @@ export default function DebugTab() {
625
  Check Errors
626
  </button>
627
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
628
  <button
629
  onClick={exportDebugInfo}
630
  className={classNames(
@@ -640,67 +685,11 @@ export default function DebugTab() {
640
  </button>
641
  </div>
642
 
643
- {/* Error Log Display */}
644
- {errorLog.errors.length > 0 && (
645
- <div className="mt-4">
646
- <h3 className="text-lg font-semibold mb-2">Error Log</h3>
647
- <div className="bg-gray-50 rounded-lg p-4 max-h-96 overflow-y-auto">
648
- {errorLog.errors.map((error, index) => (
649
- <div key={index} className="mb-4 last:mb-0 p-3 bg-white rounded border border-red-200">
650
- <div className="flex items-center gap-2 text-sm text-gray-600">
651
- <span className="font-medium">Type:</span> {error.type}
652
- <span className="font-medium ml-4">Time:</span>
653
- {new Date(error.timestamp).toLocaleString()}
654
- </div>
655
- <div className="mt-2 text-red-600">{error.message}</div>
656
- {error.filename && (
657
- <div className="mt-1 text-sm text-gray-500">
658
- File: {error.filename} (Line: {error.lineNumber}, Column: {error.columnNumber})
659
- </div>
660
- )}
661
- </div>
662
- ))}
663
- </div>
664
- </div>
665
- )}
666
-
667
  {/* System Information */}
668
  <div className="p-6 rounded-xl bg-white dark:bg-[#0A0A0A] border border-[#E5E5E5] dark:border-[#1A1A1A]">
669
- <div className="flex items-center justify-between mb-4">
670
- <div className="flex items-center gap-3">
671
- <div className="i-ph:cpu text-purple-500 w-5 h-5" />
672
- <h3 className="text-base font-medium text-bolt-elements-textPrimary">System Information</h3>
673
- </div>
674
- <div className="flex items-center gap-2">
675
- <button
676
- onClick={handleLogSystemInfo}
677
- className={classNames(
678
- 'flex items-center gap-2 px-3 py-2 rounded-lg text-sm',
679
- 'bg-[#F5F5F5] hover:bg-purple-500/10 hover:text-purple-500',
680
- 'dark:bg-[#1A1A1A] dark:hover:bg-purple-500/20',
681
- 'text-bolt-elements-textPrimary dark:hover:text-purple-500',
682
- 'transition-colors duration-200',
683
- )}
684
- >
685
- <div className="i-ph:note text-bolt-elements-textSecondary w-4 h-4" />
686
- Log
687
- </button>
688
- <button
689
- onClick={getSystemInfo}
690
- className={classNames(
691
- 'flex items-center gap-2 px-3 py-2 rounded-lg text-sm',
692
- 'bg-[#F5F5F5] hover:bg-purple-500/10 hover:text-purple-500',
693
- 'dark:bg-[#1A1A1A] dark:hover:bg-purple-500/20',
694
- 'text-bolt-elements-textPrimary dark:hover:text-purple-500',
695
- 'transition-colors duration-200',
696
- { 'opacity-50 cursor-not-allowed': loading.systemInfo },
697
- )}
698
- disabled={loading.systemInfo}
699
- >
700
- <div className={classNames('i-ph:arrows-clockwise w-4 h-4', loading.systemInfo ? 'animate-spin' : '')} />
701
- Refresh
702
- </button>
703
- </div>
704
  </div>
705
  {systemInfo ? (
706
  <div className="grid grid-cols-2 gap-6">
@@ -826,26 +815,9 @@ export default function DebugTab() {
826
 
827
  {/* Performance Metrics */}
828
  <div className="p-6 rounded-xl bg-white dark:bg-[#0A0A0A] border border-[#E5E5E5] dark:border-[#1A1A1A]">
829
- <div className="flex items-center justify-between mb-4">
830
- <div className="flex items-center gap-3">
831
- <div className="i-ph:chart-line text-purple-500 w-5 h-5" />
832
- <h3 className="text-base font-medium text-bolt-elements-textPrimary">Performance Metrics</h3>
833
- </div>
834
- <button
835
- onClick={handleLogPerformance}
836
- className={classNames(
837
- 'flex items-center gap-2 px-3 py-2 rounded-lg text-sm',
838
- 'bg-[#F5F5F5] hover:bg-purple-500/10 hover:text-purple-500',
839
- 'dark:bg-[#1A1A1A] dark:hover:bg-purple-500/20',
840
- 'text-bolt-elements-textPrimary dark:hover:text-purple-500',
841
- 'focus:outline-none focus:ring-2 focus:ring-purple-500 focus:ring-offset-2 dark:focus:ring-offset-[#0A0A0A]',
842
- { 'opacity-50 cursor-not-allowed': loading.performance },
843
- )}
844
- disabled={loading.performance}
845
- >
846
- <div className={classNames('i-ph:note w-4 h-4', loading.performance ? 'animate-spin' : '')} />
847
- Log Performance
848
- </button>
849
  </div>
850
  {systemInfo && (
851
  <div className="grid grid-cols-2 gap-4">
@@ -914,26 +886,9 @@ export default function DebugTab() {
914
 
915
  {/* WebApp Information */}
916
  <div className="p-6 rounded-xl bg-white dark:bg-[#0A0A0A] border border-[#E5E5E5] dark:border-[#1A1A1A]">
917
- <div className="flex items-center justify-between mb-4">
918
- <div className="flex items-center gap-3">
919
- <div className="i-ph:info text-blue-500 w-5 h-5" />
920
- <h3 className="text-base font-medium text-bolt-elements-textPrimary">WebApp Information</h3>
921
- </div>
922
- <button
923
- onClick={getWebAppInfo}
924
- className={classNames(
925
- 'flex items-center gap-2 px-3 py-2 rounded-lg text-sm',
926
- 'bg-[#F5F5F5] hover:bg-purple-500/10 hover:text-purple-500',
927
- 'dark:bg-[#1A1A1A] dark:hover:bg-purple-500/20',
928
- 'text-bolt-elements-textPrimary dark:hover:text-purple-500',
929
- 'focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 dark:focus:ring-offset-[#0A0A0A]',
930
- { 'opacity-50 cursor-not-allowed': loading.webAppInfo },
931
- )}
932
- disabled={loading.webAppInfo}
933
- >
934
- <div className={classNames('i-ph:arrows-clockwise w-4 h-4', loading.webAppInfo ? 'animate-spin' : '')} />
935
- Refresh
936
- </button>
937
  </div>
938
  {webAppInfo ? (
939
  <div className="grid grid-cols-2 gap-4">
@@ -1008,18 +963,12 @@ export default function DebugTab() {
1008
  <span className="text-bolt-elements-textSecondary">Git Info:</span>
1009
  </div>
1010
  <div className="pl-6 space-y-1">
1011
- <div className="text-xs text-bolt-elements-textPrimary">
1012
- Branch: {webAppInfo.gitInfo.branch}
1013
- </div>
1014
- <div className="text-xs text-bolt-elements-textPrimary">
1015
- Commit: {webAppInfo.gitInfo.commit}
1016
- </div>
1017
  <div className="text-xs text-bolt-elements-textPrimary">
1018
  Commit Time: {webAppInfo.gitInfo.commitTime}
1019
  </div>
1020
- <div className="text-xs text-bolt-elements-textPrimary">
1021
- Author: {webAppInfo.gitInfo.author}
1022
- </div>
1023
  <div className="text-xs text-bolt-elements-textPrimary">
1024
  Remote URL: {webAppInfo.gitInfo.remoteUrl}
1025
  </div>
@@ -1033,21 +982,15 @@ export default function DebugTab() {
1033
  <span className="text-bolt-elements-textSecondary">GitHub Repository:</span>
1034
  </div>
1035
  <div className="pl-6 space-y-1">
1036
- <div className="text-xs text-bolt-elements-textPrimary">
1037
- Name: {webAppInfo.repoInfo.name}
1038
- </div>
1039
  <div className="text-xs text-bolt-elements-textPrimary">
1040
  Full Name: {webAppInfo.repoInfo.fullName}
1041
  </div>
1042
  <div className="text-xs text-bolt-elements-textPrimary">
1043
  Description: {webAppInfo.repoInfo.description}
1044
  </div>
1045
- <div className="text-xs text-bolt-elements-textPrimary">
1046
- Stars: {webAppInfo.repoInfo.stars}
1047
- </div>
1048
- <div className="text-xs text-bolt-elements-textPrimary">
1049
- Forks: {webAppInfo.repoInfo.forks}
1050
- </div>
1051
  <div className="text-xs text-bolt-elements-textPrimary">
1052
  Open Issues: {webAppInfo.repoInfo.openIssues}
1053
  </div>
@@ -1077,26 +1020,9 @@ export default function DebugTab() {
1077
 
1078
  {/* Error Check */}
1079
  <div className="p-6 rounded-xl bg-white dark:bg-[#0A0A0A] border border-[#E5E5E5] dark:border-[#1A1A1A]">
1080
- <div className="flex items-center justify-between mb-4">
1081
- <div className="flex items-center gap-3">
1082
- <div className="i-ph:warning text-purple-500 w-5 h-5" />
1083
- <h3 className="text-base font-medium text-bolt-elements-textPrimary">Error Check</h3>
1084
- </div>
1085
- <button
1086
- onClick={checkErrors}
1087
- className={classNames(
1088
- 'flex items-center gap-2 px-3 py-2 rounded-lg text-sm',
1089
- 'bg-[#F5F5F5] hover:bg-purple-500/10 hover:text-purple-500',
1090
- 'dark:bg-[#1A1A1A] dark:hover:bg-purple-500/20',
1091
- 'text-bolt-elements-textPrimary dark:hover:text-purple-500',
1092
- 'focus:outline-none focus:ring-2 focus:ring-purple-500 focus:ring-offset-2 dark:focus:ring-offset-[#0A0A0A]',
1093
- { 'opacity-50 cursor-not-allowed': loading.errors },
1094
- )}
1095
- disabled={loading.errors}
1096
- >
1097
- <div className={classNames('i-ph:magnifying-glass w-4 h-4', loading.errors ? 'animate-spin' : '')} />
1098
- Check for Errors
1099
- </button>
1100
  </div>
1101
  <div className="space-y-4">
1102
  <div className="text-sm text-bolt-elements-textSecondary">
 
92
  nodeVersion: string;
93
  dependencies: { [key: string]: string };
94
  devDependencies: { [key: string]: string };
95
+
96
  // Build Info
97
  buildTime?: string;
98
  buildNumber?: string;
99
  environment?: string;
100
+
101
  // Git Info
102
  gitInfo?: {
103
  branch: string;
 
106
  author: string;
107
  remoteUrl: string;
108
  };
109
+
110
  // GitHub Repository Info
111
  repoInfo?: {
112
  name: string;
 
124
  };
125
  }
126
 
127
+ interface GitInfo {
128
+ branch: string;
129
+ commit: string;
130
+ commitTime: string;
131
+ author: string;
132
+ remoteUrl: string;
133
+ }
134
+
135
+ interface RepoData {
136
+ name: string;
137
+ full_name: string;
138
+ description: string;
139
+ stargazers_count: number;
140
+ forks_count: number;
141
+ open_issues_count: number;
142
+ default_branch: string;
143
+ updated_at: string;
144
+ owner: {
145
+ login: string;
146
+ avatar_url: string;
147
+ };
148
+ }
149
+
150
+ interface AppData {
151
+ name: string;
152
+ version: string;
153
+ description: string;
154
+ license: string;
155
+ nodeVersion: string;
156
+ dependencies: { [key: string]: string };
157
+ devDependencies: { [key: string]: string };
158
+ }
159
+
160
  export default function DebugTab() {
161
  const [systemInfo, setSystemInfo] = useState<SystemInfo | null>(null);
162
  const [webAppInfo, setWebAppInfo] = useState<WebAppInfo | null>(null);
 
364
 
365
  // Fetch local app info
366
  const appInfoResponse = await fetch('/api/system/app-info');
367
+
368
  if (!appInfoResponse.ok) {
369
  throw new Error('Failed to fetch webapp info');
370
  }
371
+
372
+ const appData = (await appInfoResponse.json()) as AppData;
373
 
374
  // Fetch git info
375
  const gitInfoResponse = await fetch('/api/system/git-info');
376
+ let gitInfo: GitInfo | undefined;
377
+
378
  if (gitInfoResponse.ok) {
379
+ gitInfo = (await gitInfoResponse.json()) as GitInfo;
380
  }
381
 
382
  // Fetch GitHub repository info
383
  const repoInfoResponse = await fetch('https://api.github.com/repos/stackblitz-labs/bolt.diy');
384
+ let repoInfo: WebAppInfo['repoInfo'] | undefined;
385
+
386
  if (repoInfoResponse.ok) {
387
+ const repoData = (await repoInfoResponse.json()) as RepoData;
388
  repoInfo = {
389
  name: repoData.name,
390
  fullName: repoData.full_name,
 
436
  return `${Math.round(size)} ${units[unitIndex]}`;
437
  };
438
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
439
  const handleLogPerformance = () => {
440
  try {
441
  setLoading((prev) => ({ ...prev, performance: true }));
 
650
  Check Errors
651
  </button>
652
 
653
+ <button
654
+ onClick={getWebAppInfo}
655
+ disabled={loading.webAppInfo}
656
+ className={classNames(
657
+ 'flex items-center gap-2 px-4 py-2 text-sm font-medium rounded-lg transition-colors',
658
+ 'bg-[#F5F5F5] hover:bg-purple-500/10 hover:text-purple-500',
659
+ 'dark:bg-[#1A1A1A] dark:hover:bg-purple-500/20',
660
+ 'text-bolt-elements-textPrimary dark:hover:text-purple-500',
661
+ 'focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 dark:focus:ring-offset-[#0A0A0A]',
662
+ { 'opacity-50 cursor-not-allowed': loading.webAppInfo },
663
+ )}
664
+ >
665
+ {loading.webAppInfo ? (
666
+ <div className="i-ph:spinner-gap w-4 h-4 animate-spin" />
667
+ ) : (
668
+ <div className="i-ph:info w-4 h-4" />
669
+ )}
670
+ Fetch WebApp Info
671
+ </button>
672
+
673
  <button
674
  onClick={exportDebugInfo}
675
  className={classNames(
 
685
  </button>
686
  </div>
687
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
688
  {/* System Information */}
689
  <div className="p-6 rounded-xl bg-white dark:bg-[#0A0A0A] border border-[#E5E5E5] dark:border-[#1A1A1A]">
690
+ <div className="flex items-center gap-3 mb-4">
691
+ <div className="i-ph:cpu text-purple-500 w-5 h-5" />
692
+ <h3 className="text-base font-medium text-bolt-elements-textPrimary">System Information</h3>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
693
  </div>
694
  {systemInfo ? (
695
  <div className="grid grid-cols-2 gap-6">
 
815
 
816
  {/* Performance Metrics */}
817
  <div className="p-6 rounded-xl bg-white dark:bg-[#0A0A0A] border border-[#E5E5E5] dark:border-[#1A1A1A]">
818
+ <div className="flex items-center gap-3 mb-4">
819
+ <div className="i-ph:chart-line text-purple-500 w-5 h-5" />
820
+ <h3 className="text-base font-medium text-bolt-elements-textPrimary">Performance Metrics</h3>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
821
  </div>
822
  {systemInfo && (
823
  <div className="grid grid-cols-2 gap-4">
 
886
 
887
  {/* WebApp Information */}
888
  <div className="p-6 rounded-xl bg-white dark:bg-[#0A0A0A] border border-[#E5E5E5] dark:border-[#1A1A1A]">
889
+ <div className="flex items-center gap-3 mb-4">
890
+ <div className="i-ph:info text-blue-500 w-5 h-5" />
891
+ <h3 className="text-base font-medium text-bolt-elements-textPrimary">WebApp Information</h3>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
892
  </div>
893
  {webAppInfo ? (
894
  <div className="grid grid-cols-2 gap-4">
 
963
  <span className="text-bolt-elements-textSecondary">Git Info:</span>
964
  </div>
965
  <div className="pl-6 space-y-1">
966
+ <div className="text-xs text-bolt-elements-textPrimary">Branch: {webAppInfo.gitInfo.branch}</div>
967
+ <div className="text-xs text-bolt-elements-textPrimary">Commit: {webAppInfo.gitInfo.commit}</div>
 
 
 
 
968
  <div className="text-xs text-bolt-elements-textPrimary">
969
  Commit Time: {webAppInfo.gitInfo.commitTime}
970
  </div>
971
+ <div className="text-xs text-bolt-elements-textPrimary">Author: {webAppInfo.gitInfo.author}</div>
 
 
972
  <div className="text-xs text-bolt-elements-textPrimary">
973
  Remote URL: {webAppInfo.gitInfo.remoteUrl}
974
  </div>
 
982
  <span className="text-bolt-elements-textSecondary">GitHub Repository:</span>
983
  </div>
984
  <div className="pl-6 space-y-1">
985
+ <div className="text-xs text-bolt-elements-textPrimary">Name: {webAppInfo.repoInfo.name}</div>
 
 
986
  <div className="text-xs text-bolt-elements-textPrimary">
987
  Full Name: {webAppInfo.repoInfo.fullName}
988
  </div>
989
  <div className="text-xs text-bolt-elements-textPrimary">
990
  Description: {webAppInfo.repoInfo.description}
991
  </div>
992
+ <div className="text-xs text-bolt-elements-textPrimary">Stars: {webAppInfo.repoInfo.stars}</div>
993
+ <div className="text-xs text-bolt-elements-textPrimary">Forks: {webAppInfo.repoInfo.forks}</div>
 
 
 
 
994
  <div className="text-xs text-bolt-elements-textPrimary">
995
  Open Issues: {webAppInfo.repoInfo.openIssues}
996
  </div>
 
1020
 
1021
  {/* Error Check */}
1022
  <div className="p-6 rounded-xl bg-white dark:bg-[#0A0A0A] border border-[#E5E5E5] dark:border-[#1A1A1A]">
1023
+ <div className="flex items-center gap-3 mb-4">
1024
+ <div className="i-ph:warning text-purple-500 w-5 h-5" />
1025
+ <h3 className="text-base font-medium text-bolt-elements-textPrimary">Error Check</h3>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1026
  </div>
1027
  <div className="space-y-4">
1028
  <div className="text-sm text-bolt-elements-textSecondary">
app/components/settings/developer/DeveloperWindow.tsx CHANGED
@@ -1,12 +1,18 @@
1
  import * as RadixDialog from '@radix-ui/react-dialog';
2
  import { motion } from 'framer-motion';
3
- import { useState, useEffect } from 'react';
4
  import { classNames } from '~/utils/classNames';
5
  import { TabManagement } from './TabManagement';
6
  import { TabTile } from '~/components/settings/shared/TabTile';
7
  import { DialogTitle } from '~/components/ui/Dialog';
8
  import type { TabType, TabVisibilityConfig } from '~/components/settings/settings.types';
9
- import { tabConfigurationStore, updateTabConfiguration } from '~/lib/stores/settings';
 
 
 
 
 
 
10
  import { useStore } from '@nanostores/react';
11
  import { DndProvider, useDrag, useDrop } from 'react-dnd';
12
  import { HTML5Backend } from 'react-dnd-html5-backend';
@@ -24,6 +30,7 @@ import * as DropdownMenu from '@radix-ui/react-dropdown-menu';
24
  import CloudProvidersTab from '~/components/settings/providers/CloudProvidersTab';
25
  import LocalProvidersTab from '~/components/settings/providers/LocalProvidersTab';
26
  import TaskManagerTab from '~/components/settings/task-manager/TaskManagerTab';
 
27
 
28
  interface DraggableTabTileProps {
29
  tab: TabVisibilityConfig;
@@ -83,8 +90,14 @@ const DraggableTabTile = ({
83
  },
84
  });
85
 
 
 
 
 
 
 
86
  return (
87
- <div ref={(node) => drag(drop(node))} style={{ opacity: isDragging ? 0.5 : 1 }}>
88
  <TabTile
89
  tab={tab}
90
  onClick={onClick}
@@ -104,15 +117,32 @@ interface DeveloperWindowProps {
104
  }
105
 
106
  export const DeveloperWindow = ({ open, onClose }: DeveloperWindowProps) => {
107
- const tabConfiguration = useStore(tabConfigurationStore);
108
  const [activeTab, setActiveTab] = useState<TabType | null>(null);
109
- const [showTabManagement, setShowTabManagement] = useState(false);
110
  const [loadingTab, setLoadingTab] = useState<TabType | null>(null);
 
 
 
111
  const [profile, setProfile] = useState(() => {
112
  const saved = localStorage.getItem('bolt_user_profile');
113
  return saved ? JSON.parse(saved) : { avatar: null, notifications: true };
114
  });
115
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
116
  // Listen for profile changes
117
  useEffect(() => {
118
  const handleStorageChange = (e: StorageEvent) => {
@@ -134,6 +164,38 @@ export const DeveloperWindow = ({ open, onClose }: DeveloperWindowProps) => {
134
  const { hasConnectionIssues, currentIssue, acknowledgeIssue } = useConnectionStatus();
135
  const { hasActiveWarnings, activeIssues, acknowledgeAllIssues } = useDebugStatus();
136
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
137
  const handleBack = () => {
138
  if (showTabManagement) {
139
  setShowTabManagement(false);
@@ -143,21 +205,55 @@ export const DeveloperWindow = ({ open, onClose }: DeveloperWindowProps) => {
143
  };
144
 
145
  // Only show tabs that are assigned to the developer window AND are visible
146
- const visibleDeveloperTabs = tabConfiguration.developerTabs
147
- .filter((tab) => {
148
- // Hide notifications tab if notifications are disabled
149
- if (tab.id === 'notifications' && !profile.notifications) {
150
- return false;
151
- }
152
 
153
- return tab.visible;
154
- })
155
- .sort((a: TabVisibilityConfig, b: TabVisibilityConfig) => (a.order || 0) - (b.order || 0));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
156
 
157
  const moveTab = (dragIndex: number, hoverIndex: number) => {
158
  const draggedTab = visibleDeveloperTabs[dragIndex];
159
  const targetTab = visibleDeveloperTabs[hoverIndex];
160
 
 
 
161
  // Update the order of the dragged and target tabs
162
  const updatedDraggedTab = { ...draggedTab, order: targetTab.order };
163
  const updatedTargetTab = { ...targetTab, order: draggedTab.order };
@@ -278,7 +374,10 @@ export const DeveloperWindow = ({ open, onClose }: DeveloperWindowProps) => {
278
  <DndProvider backend={HTML5Backend}>
279
  <RadixDialog.Root open={open}>
280
  <RadixDialog.Portal>
281
- <div className="fixed inset-0 flex items-center justify-center z-[60]">
 
 
 
282
  <RadixDialog.Overlay className="fixed inset-0">
283
  <motion.div
284
  className="absolute inset-0 bg-black/50 backdrop-blur-sm"
@@ -299,7 +398,7 @@ export const DeveloperWindow = ({ open, onClose }: DeveloperWindowProps) => {
299
  'flex flex-col overflow-hidden',
300
  )}
301
  initial={{ opacity: 0, scale: 0.95, y: 20 }}
302
- animate={{ opacity: 1, scale: 1, y: 0 }}
303
  exit={{ opacity: 0, scale: 0.95, y: 20 }}
304
  transition={{ duration: 0.2 }}
305
  >
@@ -346,6 +445,16 @@ export const DeveloperWindow = ({ open, onClose }: DeveloperWindowProps) => {
346
  </motion.button>
347
  )}
348
 
 
 
 
 
 
 
 
 
 
 
349
  <div className="relative">
350
  <DropdownMenu.Root>
351
  <DropdownMenu.Trigger asChild>
 
1
  import * as RadixDialog from '@radix-ui/react-dialog';
2
  import { motion } from 'framer-motion';
3
+ import { useState, useEffect, useMemo } from 'react';
4
  import { classNames } from '~/utils/classNames';
5
  import { TabManagement } from './TabManagement';
6
  import { TabTile } from '~/components/settings/shared/TabTile';
7
  import { DialogTitle } from '~/components/ui/Dialog';
8
  import type { TabType, TabVisibilityConfig } from '~/components/settings/settings.types';
9
+ import {
10
+ tabConfigurationStore,
11
+ resetTabConfiguration,
12
+ updateTabConfiguration,
13
+ developerModeStore,
14
+ setDeveloperMode,
15
+ } from '~/lib/stores/settings';
16
  import { useStore } from '@nanostores/react';
17
  import { DndProvider, useDrag, useDrop } from 'react-dnd';
18
  import { HTML5Backend } from 'react-dnd-html5-backend';
 
30
  import CloudProvidersTab from '~/components/settings/providers/CloudProvidersTab';
31
  import LocalProvidersTab from '~/components/settings/providers/LocalProvidersTab';
32
  import TaskManagerTab from '~/components/settings/task-manager/TaskManagerTab';
33
+ import { Switch } from '~/components/ui/Switch';
34
 
35
  interface DraggableTabTileProps {
36
  tab: TabVisibilityConfig;
 
90
  },
91
  });
92
 
93
+ const dragDropRef = (node: HTMLDivElement | null) => {
94
+ if (node) {
95
+ drag(drop(node));
96
+ }
97
+ };
98
+
99
  return (
100
+ <div ref={dragDropRef} style={{ opacity: isDragging ? 0.5 : 1 }}>
101
  <TabTile
102
  tab={tab}
103
  onClick={onClick}
 
117
  }
118
 
119
  export const DeveloperWindow = ({ open, onClose }: DeveloperWindowProps) => {
 
120
  const [activeTab, setActiveTab] = useState<TabType | null>(null);
 
121
  const [loadingTab, setLoadingTab] = useState<TabType | null>(null);
122
+ const tabConfiguration = useStore(tabConfigurationStore);
123
+ const [showTabManagement, setShowTabManagement] = useState(false);
124
+ const developerMode = useStore(developerModeStore);
125
  const [profile, setProfile] = useState(() => {
126
  const saved = localStorage.getItem('bolt_user_profile');
127
  return saved ? JSON.parse(saved) : { avatar: null, notifications: true };
128
  });
129
 
130
+ // Handle developer mode change
131
+ const handleDeveloperModeChange = (checked: boolean) => {
132
+ setDeveloperMode(checked);
133
+
134
+ if (!checked) {
135
+ onClose();
136
+ }
137
+ };
138
+
139
+ // Ensure developer mode is true when window is opened
140
+ useEffect(() => {
141
+ if (open) {
142
+ setDeveloperMode(true);
143
+ }
144
+ }, [open]);
145
+
146
  // Listen for profile changes
147
  useEffect(() => {
148
  const handleStorageChange = (e: StorageEvent) => {
 
164
  const { hasConnectionIssues, currentIssue, acknowledgeIssue } = useConnectionStatus();
165
  const { hasActiveWarnings, activeIssues, acknowledgeAllIssues } = useDebugStatus();
166
 
167
+ // Ensure tab configuration is properly initialized
168
+ useEffect(() => {
169
+ if (!tabConfiguration || !tabConfiguration.userTabs || !tabConfiguration.developerTabs) {
170
+ console.warn('Tab configuration is invalid in DeveloperWindow, resetting to defaults');
171
+ resetTabConfiguration();
172
+ } else {
173
+ // Validate tab configuration structure
174
+ const isValid =
175
+ tabConfiguration.userTabs.every(
176
+ (tab) =>
177
+ tab &&
178
+ typeof tab.id === 'string' &&
179
+ typeof tab.visible === 'boolean' &&
180
+ typeof tab.window === 'string' &&
181
+ typeof tab.order === 'number',
182
+ ) &&
183
+ tabConfiguration.developerTabs.every(
184
+ (tab) =>
185
+ tab &&
186
+ typeof tab.id === 'string' &&
187
+ typeof tab.visible === 'boolean' &&
188
+ typeof tab.window === 'string' &&
189
+ typeof tab.order === 'number',
190
+ );
191
+
192
+ if (!isValid) {
193
+ console.warn('Tab configuration is malformed in DeveloperWindow, resetting to defaults');
194
+ resetTabConfiguration();
195
+ }
196
+ }
197
+ }, [tabConfiguration]);
198
+
199
  const handleBack = () => {
200
  if (showTabManagement) {
201
  setShowTabManagement(false);
 
205
  };
206
 
207
  // Only show tabs that are assigned to the developer window AND are visible
208
+ const visibleDeveloperTabs = useMemo(() => {
209
+ console.log('Filtering developer tabs with configuration:', tabConfiguration);
 
 
 
 
210
 
211
+ if (!tabConfiguration?.developerTabs || !Array.isArray(tabConfiguration.developerTabs)) {
212
+ console.warn('Invalid tab configuration, using empty array');
213
+ return [];
214
+ }
215
+
216
+ return tabConfiguration.developerTabs
217
+ .filter((tab) => {
218
+ if (!tab || typeof tab.id !== 'string') {
219
+ console.warn('Invalid tab entry:', tab);
220
+ return false;
221
+ }
222
+
223
+ // Hide notifications tab if notifications are disabled
224
+ if (tab.id === 'notifications' && !profile.notifications) {
225
+ console.log('Hiding notifications tab due to disabled notifications');
226
+ return false;
227
+ }
228
+
229
+ // Ensure the tab has the required properties
230
+ if (typeof tab.visible !== 'boolean' || typeof tab.window !== 'string' || typeof tab.order !== 'number') {
231
+ console.warn('Tab missing required properties:', tab);
232
+ return false;
233
+ }
234
+
235
+ // Only show tabs that are explicitly visible and assigned to the developer window
236
+ const isVisible = tab.visible && tab.window === 'developer';
237
+ console.log(`Tab ${tab.id} visibility:`, isVisible);
238
+
239
+ return isVisible;
240
+ })
241
+ .sort((a: TabVisibilityConfig, b: TabVisibilityConfig) => {
242
+ const orderA = typeof a.order === 'number' ? a.order : 0;
243
+ const orderB = typeof b.order === 'number' ? b.order : 0;
244
+
245
+ return orderA - orderB;
246
+ });
247
+ }, [tabConfiguration, profile.notifications]);
248
+
249
+ console.log('Filtered visible developer tabs:', visibleDeveloperTabs);
250
 
251
  const moveTab = (dragIndex: number, hoverIndex: number) => {
252
  const draggedTab = visibleDeveloperTabs[dragIndex];
253
  const targetTab = visibleDeveloperTabs[hoverIndex];
254
 
255
+ console.log('Moving developer tab:', { draggedTab, targetTab });
256
+
257
  // Update the order of the dragged and target tabs
258
  const updatedDraggedTab = { ...draggedTab, order: targetTab.order };
259
  const updatedTargetTab = { ...targetTab, order: draggedTab.order };
 
374
  <DndProvider backend={HTML5Backend}>
375
  <RadixDialog.Root open={open}>
376
  <RadixDialog.Portal>
377
+ <div
378
+ className="fixed inset-0 flex items-center justify-center z-[60]"
379
+ style={{ opacity: developerMode ? 1 : 0, transition: 'opacity 0.2s ease-in-out' }}
380
+ >
381
  <RadixDialog.Overlay className="fixed inset-0">
382
  <motion.div
383
  className="absolute inset-0 bg-black/50 backdrop-blur-sm"
 
398
  'flex flex-col overflow-hidden',
399
  )}
400
  initial={{ opacity: 0, scale: 0.95, y: 20 }}
401
+ animate={{ opacity: developerMode ? 1 : 0, scale: developerMode ? 1 : 0.95, y: developerMode ? 0 : 20 }}
402
  exit={{ opacity: 0, scale: 0.95, y: 20 }}
403
  transition={{ duration: 0.2 }}
404
  >
 
445
  </motion.button>
446
  )}
447
 
448
+ <div className="flex items-center gap-2">
449
+ <Switch
450
+ checked={developerMode}
451
+ onCheckedChange={handleDeveloperModeChange}
452
+ className="data-[state=checked]:bg-purple-500"
453
+ aria-label="Toggle developer mode"
454
+ />
455
+ <label className="text-sm text-gray-500 dark:text-gray-400">Switch to User Mode</label>
456
+ </div>
457
+
458
  <div className="relative">
459
  <DropdownMenu.Root>
460
  <DropdownMenu.Trigger asChild>
app/components/settings/developer/TabManagement.tsx CHANGED
@@ -37,7 +37,7 @@ const TabGroup = ({ title, description, tabs, onVisibilityChange, targetWindow }
37
  const hiddenTabs = tabs.filter((tab) => !tab.visible).sort((a, b) => (a.order || 0) - (b.order || 0));
38
 
39
  return (
40
- <div className="mb-8 rounded-xl bg-white/5 p-6 backdrop-blur-sm dark:bg-gray-800/30">
41
  <div className="mb-6">
42
  <h3 className="flex items-center gap-2 text-lg font-medium text-gray-900 dark:text-white">
43
  <span className="i-ph:layout-fill h-5 w-5 text-purple-500" />
 
37
  const hiddenTabs = tabs.filter((tab) => !tab.visible).sort((a, b) => (a.order || 0) - (b.order || 0));
38
 
39
  return (
40
+ <div className="mb-8 rounded-xl bg-white/5 p-6 dark:bg-gray-800/30">
41
  <div className="mb-6">
42
  <h3 className="flex items-center gap-2 text-lg font-medium text-gray-900 dark:text-white">
43
  <span className="i-ph:layout-fill h-5 w-5 text-purple-500" />
app/components/settings/providers/LocalProvidersTab.tsx CHANGED
@@ -10,8 +10,6 @@ import { settingsStyles } from '~/components/settings/settings.styles';
10
  import { toast } from 'react-toastify';
11
  import { BsBox, BsCodeSquare, BsRobot } from 'react-icons/bs';
12
  import type { IconType } from 'react-icons';
13
- import OllamaModelUpdater from './OllamaModelUpdater';
14
- import { DialogRoot, Dialog } from '~/components/ui/Dialog';
15
  import { BiChip } from 'react-icons/bi';
16
  import { TbBrandOpenai } from 'react-icons/tb';
17
  import { providerBaseUrlEnvKeys } from '~/utils/constants';
@@ -33,12 +31,33 @@ const PROVIDER_DESCRIPTIONS: Record<ProviderName, string> = {
33
  OpenAILike: 'Connect to OpenAI-compatible API endpoints',
34
  };
35
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
  const LocalProvidersTab = () => {
37
  const settings = useSettings();
38
  const [filteredProviders, setFilteredProviders] = useState<IProviderConfig[]>([]);
39
  const [categoryEnabled, setCategoryEnabled] = useState<boolean>(false);
40
- const [showOllamaUpdater, setShowOllamaUpdater] = useState(false);
41
  const [editingProvider, setEditingProvider] = useState<string | null>(null);
 
 
42
 
43
  // Effect to filter and sort providers
44
  useEffect(() => {
@@ -46,9 +65,32 @@ const LocalProvidersTab = () => {
46
  .filter(([key]) => [...LOCAL_PROVIDERS, 'OpenAILike'].includes(key))
47
  .map(([key, value]) => {
48
  const provider = value as IProviderConfig;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
  return {
50
  name: key,
51
- settings: provider.settings,
 
 
 
52
  staticModels: provider.staticModels || [],
53
  getDynamicModels: provider.getDynamicModels,
54
  getApiKeyLink: provider.getApiKeyLink,
@@ -57,16 +99,135 @@ const LocalProvidersTab = () => {
57
  } as IProviderConfig;
58
  });
59
 
60
- const sorted = newFilteredProviders.sort((a, b) => a.name.localeCompare(b.name));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
  setFilteredProviders(sorted);
62
  }, [settings.providers]);
63
 
 
 
 
 
 
 
64
  // Add effect to update category toggle state based on provider states
65
  useEffect(() => {
66
  const newCategoryState = filteredProviders.every((p) => p.settings.enabled);
67
  setCategoryEnabled(newCategoryState);
68
  }, [filteredProviders]);
69
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
70
  const handleToggleCategory = useCallback(
71
  (enabled: boolean) => {
72
  setCategoryEnabled(enabled);
@@ -106,6 +267,31 @@ const LocalProvidersTab = () => {
106
  setEditingProvider(null);
107
  };
108
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
109
  return (
110
  <div className="space-y-6">
111
  <motion.div
@@ -139,7 +325,7 @@ const LocalProvidersTab = () => {
139
  </div>
140
  </div>
141
 
142
- <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
143
  {filteredProviders.map((provider, index) => (
144
  <motion.div
145
  key={provider.name}
@@ -150,6 +336,12 @@ const LocalProvidersTab = () => {
150
  'transition-all duration-200',
151
  'relative overflow-hidden group',
152
  'flex flex-col',
 
 
 
 
 
 
153
  )}
154
  initial={{ opacity: 0, y: 20 }}
155
  animate={{ opacity: 1, y: 0 }}
@@ -253,21 +445,109 @@ const LocalProvidersTab = () => {
253
  </div>
254
  </div>
255
  )}
256
- </div>
257
 
258
- {providerBaseUrlEnvKeys[provider.name]?.baseUrlKey && (
259
- <div className="mt-2 text-xs text-green-500">
260
- <div className="flex items-center gap-1">
261
- <div className="i-ph:info" />
262
- <span>Environment URL set in .env file</span>
 
 
 
 
 
 
 
 
 
 
 
263
  </div>
264
- </div>
265
- )}
266
  </motion.div>
267
  )}
268
  </div>
269
  </div>
270
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
271
  <motion.div
272
  className="absolute inset-0 border-2 border-purple-500/0 rounded-lg pointer-events-none"
273
  animate={{
@@ -276,36 +556,10 @@ const LocalProvidersTab = () => {
276
  }}
277
  transition={{ duration: 0.2 }}
278
  />
279
-
280
- {provider.name === 'Ollama' && provider.settings.enabled && (
281
- <motion.button
282
- onClick={() => setShowOllamaUpdater(true)}
283
- className={classNames(
284
- settingsStyles.button.base,
285
- settingsStyles.button.secondary,
286
- 'ml-2',
287
- 'hover:bg-purple-500/10 hover:text-purple-500',
288
- 'dark:bg-[#1A1A1A] dark:hover:bg-purple-500/20 dark:text-bolt-elements-textPrimary dark:hover:text-purple-500',
289
- )}
290
- whileHover={{ scale: 1.02 }}
291
- whileTap={{ scale: 0.98 }}
292
- >
293
- <div className="i-ph:arrows-clockwise" />
294
- Update Models
295
- </motion.button>
296
- )}
297
  </motion.div>
298
  ))}
299
  </div>
300
  </motion.div>
301
-
302
- <DialogRoot open={showOllamaUpdater} onOpenChange={setShowOllamaUpdater}>
303
- <Dialog>
304
- <div className="p-6">
305
- <OllamaModelUpdater />
306
- </div>
307
- </Dialog>
308
- </DialogRoot>
309
  </div>
310
  );
311
  };
 
10
  import { toast } from 'react-toastify';
11
  import { BsBox, BsCodeSquare, BsRobot } from 'react-icons/bs';
12
  import type { IconType } from 'react-icons';
 
 
13
  import { BiChip } from 'react-icons/bi';
14
  import { TbBrandOpenai } from 'react-icons/tb';
15
  import { providerBaseUrlEnvKeys } from '~/utils/constants';
 
31
  OpenAILike: 'Connect to OpenAI-compatible API endpoints',
32
  };
33
 
34
+ interface OllamaModel {
35
+ name: string;
36
+ digest: string;
37
+ size: number;
38
+ modified_at: string;
39
+ details?: {
40
+ family: string;
41
+ parameter_size: string;
42
+ quantization_level: string;
43
+ };
44
+ status?: 'idle' | 'updating' | 'updated' | 'error' | 'checking';
45
+ error?: string;
46
+ newDigest?: string;
47
+ progress?: {
48
+ current: number;
49
+ total: number;
50
+ status: string;
51
+ };
52
+ }
53
+
54
  const LocalProvidersTab = () => {
55
  const settings = useSettings();
56
  const [filteredProviders, setFilteredProviders] = useState<IProviderConfig[]>([]);
57
  const [categoryEnabled, setCategoryEnabled] = useState<boolean>(false);
 
58
  const [editingProvider, setEditingProvider] = useState<string | null>(null);
59
+ const [ollamaModels, setOllamaModels] = useState<OllamaModel[]>([]);
60
+ const [isLoadingModels, setIsLoadingModels] = useState(false);
61
 
62
  // Effect to filter and sort providers
63
  useEffect(() => {
 
65
  .filter(([key]) => [...LOCAL_PROVIDERS, 'OpenAILike'].includes(key))
66
  .map(([key, value]) => {
67
  const provider = value as IProviderConfig;
68
+ const envKey = providerBaseUrlEnvKeys[key]?.baseUrlKey;
69
+
70
+ // Get environment URL safely
71
+ const envUrl = envKey ? (import.meta.env[envKey] as string | undefined) : undefined;
72
+
73
+ console.log(`Checking env URL for ${key}:`, {
74
+ envKey,
75
+ envUrl,
76
+ currentBaseUrl: provider.settings.baseUrl,
77
+ });
78
+
79
+ // If there's an environment URL and no base URL set, update it
80
+ if (envUrl && !provider.settings.baseUrl) {
81
+ console.log(`Setting base URL for ${key} from env:`, envUrl);
82
+ settings.updateProviderSettings(key, {
83
+ ...provider.settings,
84
+ baseUrl: envUrl,
85
+ });
86
+ }
87
+
88
  return {
89
  name: key,
90
+ settings: {
91
+ ...provider.settings,
92
+ baseUrl: provider.settings.baseUrl || envUrl,
93
+ },
94
  staticModels: provider.staticModels || [],
95
  getDynamicModels: provider.getDynamicModels,
96
  getApiKeyLink: provider.getApiKeyLink,
 
99
  } as IProviderConfig;
100
  });
101
 
102
+ // Custom sort function to ensure LMStudio appears before OpenAILike
103
+ const sorted = newFilteredProviders.sort((a, b) => {
104
+ if (a.name === 'LMStudio') {
105
+ return -1;
106
+ }
107
+
108
+ if (b.name === 'LMStudio') {
109
+ return 1;
110
+ }
111
+
112
+ if (a.name === 'OpenAILike') {
113
+ return 1;
114
+ }
115
+
116
+ if (b.name === 'OpenAILike') {
117
+ return -1;
118
+ }
119
+
120
+ return a.name.localeCompare(b.name);
121
+ });
122
  setFilteredProviders(sorted);
123
  }, [settings.providers]);
124
 
125
+ // Helper function to safely get environment URL
126
+ const getEnvUrl = (provider: IProviderConfig): string | undefined => {
127
+ const envKey = providerBaseUrlEnvKeys[provider.name]?.baseUrlKey;
128
+ return envKey ? (import.meta.env[envKey] as string | undefined) : undefined;
129
+ };
130
+
131
  // Add effect to update category toggle state based on provider states
132
  useEffect(() => {
133
  const newCategoryState = filteredProviders.every((p) => p.settings.enabled);
134
  setCategoryEnabled(newCategoryState);
135
  }, [filteredProviders]);
136
 
137
+ // Fetch Ollama models when enabled
138
+ useEffect(() => {
139
+ const ollamaProvider = filteredProviders.find((p) => p.name === 'Ollama');
140
+
141
+ if (ollamaProvider?.settings.enabled) {
142
+ fetchOllamaModels();
143
+ }
144
+ }, [filteredProviders]);
145
+
146
+ const fetchOllamaModels = async () => {
147
+ try {
148
+ setIsLoadingModels(true);
149
+
150
+ const response = await fetch('http://127.0.0.1:11434/api/tags');
151
+ const data = (await response.json()) as { models: OllamaModel[] };
152
+
153
+ setOllamaModels(
154
+ data.models.map((model) => ({
155
+ ...model,
156
+ status: 'idle' as const,
157
+ })),
158
+ );
159
+ } catch (error) {
160
+ console.error('Error fetching Ollama models:', error);
161
+ } finally {
162
+ setIsLoadingModels(false);
163
+ }
164
+ };
165
+
166
+ const updateOllamaModel = async (modelName: string): Promise<{ success: boolean; newDigest?: string }> => {
167
+ try {
168
+ const response = await fetch('http://127.0.0.1:11434/api/pull', {
169
+ method: 'POST',
170
+ headers: { 'Content-Type': 'application/json' },
171
+ body: JSON.stringify({ name: modelName }),
172
+ });
173
+
174
+ if (!response.ok) {
175
+ throw new Error(`Failed to update ${modelName}`);
176
+ }
177
+
178
+ const reader = response.body?.getReader();
179
+
180
+ if (!reader) {
181
+ throw new Error('No response reader available');
182
+ }
183
+
184
+ while (true) {
185
+ const { done, value } = await reader.read();
186
+
187
+ if (done) {
188
+ break;
189
+ }
190
+
191
+ const text = new TextDecoder().decode(value);
192
+ const lines = text.split('\n').filter(Boolean);
193
+
194
+ for (const line of lines) {
195
+ const data = JSON.parse(line) as {
196
+ status: string;
197
+ completed?: number;
198
+ total?: number;
199
+ digest?: string;
200
+ };
201
+
202
+ setOllamaModels((current) =>
203
+ current.map((m) =>
204
+ m.name === modelName
205
+ ? {
206
+ ...m,
207
+ progress: {
208
+ current: data.completed || 0,
209
+ total: data.total || 0,
210
+ status: data.status,
211
+ },
212
+ newDigest: data.digest,
213
+ }
214
+ : m,
215
+ ),
216
+ );
217
+ }
218
+ }
219
+
220
+ const updatedResponse = await fetch('http://127.0.0.1:11434/api/tags');
221
+ const updatedData = (await updatedResponse.json()) as { models: OllamaModel[] };
222
+ const updatedModel = updatedData.models.find((m) => m.name === modelName);
223
+
224
+ return { success: true, newDigest: updatedModel?.digest };
225
+ } catch (error) {
226
+ console.error(`Error updating ${modelName}:`, error);
227
+ return { success: false };
228
+ }
229
+ };
230
+
231
  const handleToggleCategory = useCallback(
232
  (enabled: boolean) => {
233
  setCategoryEnabled(enabled);
 
267
  setEditingProvider(null);
268
  };
269
 
270
+ const handleUpdateOllamaModel = async (modelName: string) => {
271
+ setOllamaModels((current) => current.map((m) => (m.name === modelName ? { ...m, status: 'updating' } : m)));
272
+
273
+ const { success, newDigest } = await updateOllamaModel(modelName);
274
+
275
+ setOllamaModels((current) =>
276
+ current.map((m) =>
277
+ m.name === modelName
278
+ ? {
279
+ ...m,
280
+ status: success ? 'updated' : 'error',
281
+ error: success ? undefined : 'Update failed',
282
+ newDigest,
283
+ }
284
+ : m,
285
+ ),
286
+ );
287
+
288
+ if (success) {
289
+ toast.success(`Updated ${modelName}`);
290
+ } else {
291
+ toast.error(`Failed to update ${modelName}`);
292
+ }
293
+ };
294
+
295
  return (
296
  <div className="space-y-6">
297
  <motion.div
 
325
  </div>
326
  </div>
327
 
328
+ <div className="grid grid-cols-2 gap-4">
329
  {filteredProviders.map((provider, index) => (
330
  <motion.div
331
  key={provider.name}
 
336
  'transition-all duration-200',
337
  'relative overflow-hidden group',
338
  'flex flex-col',
339
+
340
+ // Make Ollama span 2 rows
341
+ provider.name === 'Ollama' ? 'row-span-2' : '',
342
+
343
+ // Place Ollama in the second column
344
+ provider.name === 'Ollama' ? 'col-start-2' : 'col-start-1',
345
  )}
346
  initial={{ opacity: 0, y: 20 }}
347
  animate={{ opacity: 1, y: 0 }}
 
445
  </div>
446
  </div>
447
  )}
 
448
 
449
+ {providerBaseUrlEnvKeys[provider.name]?.baseUrlKey && (
450
+ <div className="mt-2 text-xs">
451
+ <div className="flex items-center gap-1">
452
+ <div
453
+ className={
454
+ getEnvUrl(provider)
455
+ ? 'i-ph:check-circle text-green-500'
456
+ : 'i-ph:warning-circle text-yellow-500'
457
+ }
458
+ />
459
+ <span className={getEnvUrl(provider) ? 'text-green-500' : 'text-yellow-500'}>
460
+ {getEnvUrl(provider)
461
+ ? 'Environment URL set in .env.local'
462
+ : 'Environment URL not set in .env.local'}
463
+ </span>
464
+ </div>
465
  </div>
466
+ )}
467
+ </div>
468
  </motion.div>
469
  )}
470
  </div>
471
  </div>
472
 
473
+ {provider.name === 'Ollama' && provider.settings.enabled && (
474
+ <div className="mt-4 space-y-2">
475
+ <div className="flex items-center justify-between">
476
+ <div className="flex items-center gap-2">
477
+ <div className="i-ph:cube-duotone text-purple-500" />
478
+ <span className="text-sm font-medium text-bolt-elements-textPrimary">Installed Models</span>
479
+ </div>
480
+ {isLoadingModels ? (
481
+ <div className="flex items-center gap-2 text-sm text-bolt-elements-textSecondary">
482
+ <div className="i-ph:spinner-gap-bold animate-spin w-4 h-4" />
483
+ Loading models...
484
+ </div>
485
+ ) : (
486
+ <span className="text-sm text-bolt-elements-textSecondary">
487
+ {ollamaModels.length} models available
488
+ </span>
489
+ )}
490
+ </div>
491
+
492
+ <div className="space-y-2">
493
+ {ollamaModels.map((model) => (
494
+ <div
495
+ key={model.name}
496
+ className="flex items-center justify-between p-2 rounded-lg bg-bolt-elements-background-depth-3"
497
+ >
498
+ <div className="flex flex-col gap-1">
499
+ <div className="flex items-center gap-2">
500
+ <span className="text-sm text-bolt-elements-textPrimary">{model.name}</span>
501
+ {model.status === 'updating' && (
502
+ <div className="i-ph:spinner-gap-bold animate-spin w-4 h-4 text-purple-500" />
503
+ )}
504
+ {model.status === 'updated' && <div className="i-ph:check-circle text-green-500" />}
505
+ {model.status === 'error' && <div className="i-ph:x-circle text-red-500" />}
506
+ </div>
507
+ <div className="flex items-center gap-2 text-xs text-bolt-elements-textSecondary">
508
+ <span>Version: {model.digest.substring(0, 7)}</span>
509
+ {model.status === 'updated' && model.newDigest && (
510
+ <>
511
+ <div className="i-ph:arrow-right w-3 h-3" />
512
+ <span className="text-green-500">{model.newDigest.substring(0, 7)}</span>
513
+ </>
514
+ )}
515
+ {model.progress && (
516
+ <span className="ml-2">
517
+ {model.progress.status}{' '}
518
+ {model.progress.total > 0 && (
519
+ <>({Math.round((model.progress.current / model.progress.total) * 100)}%)</>
520
+ )}
521
+ </span>
522
+ )}
523
+ {model.details && (
524
+ <span className="ml-2">
525
+ ({model.details.parameter_size}, {model.details.quantization_level})
526
+ </span>
527
+ )}
528
+ </div>
529
+ </div>
530
+ <motion.button
531
+ onClick={() => handleUpdateOllamaModel(model.name)}
532
+ disabled={model.status === 'updating'}
533
+ className={classNames(
534
+ settingsStyles.button.base,
535
+ settingsStyles.button.secondary,
536
+ 'hover:bg-purple-500/10 hover:text-purple-500',
537
+ 'dark:bg-[#1A1A1A] dark:hover:bg-purple-500/20 dark:text-bolt-elements-textPrimary dark:hover:text-purple-500',
538
+ )}
539
+ whileHover={{ scale: 1.02 }}
540
+ whileTap={{ scale: 0.98 }}
541
+ >
542
+ <div className="i-ph:arrows-clockwise" />
543
+ Update
544
+ </motion.button>
545
+ </div>
546
+ ))}
547
+ </div>
548
+ </div>
549
+ )}
550
+
551
  <motion.div
552
  className="absolute inset-0 border-2 border-purple-500/0 rounded-lg pointer-events-none"
553
  animate={{
 
556
  }}
557
  transition={{ duration: 0.2 }}
558
  />
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
559
  </motion.div>
560
  ))}
561
  </div>
562
  </motion.div>
 
 
 
 
 
 
 
 
563
  </div>
564
  );
565
  };
app/components/settings/settings/SettingsTab.tsx CHANGED
@@ -6,6 +6,8 @@ import { Switch } from '~/components/ui/Switch';
6
  import { themeStore, kTheme } from '~/lib/stores/theme';
7
  import type { UserProfile } from '~/components/settings/settings.types';
8
  import { settingsStyles } from '~/components/settings/settings.styles';
 
 
9
 
10
  export default function SettingsTab() {
11
  const [currentTimezone, setCurrentTimezone] = useState('');
@@ -212,6 +214,39 @@ export default function SettingsTab() {
212
  </select>
213
  </div>
214
  </motion.div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
215
  </div>
216
  );
217
  }
 
6
  import { themeStore, kTheme } from '~/lib/stores/theme';
7
  import type { UserProfile } from '~/components/settings/settings.types';
8
  import { settingsStyles } from '~/components/settings/settings.styles';
9
+ import { useStore } from '@nanostores/react';
10
+ import { shortcutsStore } from '~/lib/stores/settings';
11
 
12
  export default function SettingsTab() {
13
  const [currentTimezone, setCurrentTimezone] = useState('');
 
214
  </select>
215
  </div>
216
  </motion.div>
217
+
218
+ {/* Keyboard Shortcuts */}
219
+ <motion.div
220
+ className="bg-white dark:bg-[#0A0A0A] rounded-lg shadow-sm dark:shadow-none p-4"
221
+ initial={{ opacity: 0, y: 20 }}
222
+ animate={{ opacity: 1, y: 0 }}
223
+ transition={{ delay: 0.3 }}
224
+ >
225
+ <div className="flex items-center gap-2 mb-4">
226
+ <div className="i-ph:keyboard-fill w-4 h-4 text-purple-500" />
227
+ <span className="text-sm font-medium text-bolt-elements-textPrimary">Keyboard Shortcuts</span>
228
+ </div>
229
+
230
+ <div className="space-y-2">
231
+ {Object.entries(useStore(shortcutsStore)).map(([name, shortcut]) => (
232
+ <div key={name} className="flex items-center justify-between p-2 rounded-lg bg-[#FAFAFA] dark:bg-[#1A1A1A]">
233
+ <span className="text-sm text-bolt-elements-textPrimary capitalize">
234
+ {name.replace(/([A-Z])/g, ' $1').toLowerCase()}
235
+ </span>
236
+ <div className="flex items-center gap-1">
237
+ {shortcut.ctrlOrMetaKey && (
238
+ <kbd className="kdb">{navigator.platform.includes('Mac') ? '⌘' : 'Ctrl'}</kbd>
239
+ )}
240
+ {shortcut.ctrlKey && <kbd className="kdb">Ctrl</kbd>}
241
+ {shortcut.metaKey && <kbd className="kdb">⌘</kbd>}
242
+ {shortcut.shiftKey && <kbd className="kdb">⇧</kbd>}
243
+ {shortcut.altKey && <kbd className="kdb">⌥</kbd>}
244
+ <kbd className="kdb">{shortcut.key.toUpperCase()}</kbd>
245
+ </div>
246
+ </div>
247
+ ))}
248
+ </div>
249
+ </motion.div>
250
  </div>
251
  );
252
  }
app/components/settings/shared/DraggableTabList.tsx CHANGED
@@ -36,7 +36,7 @@ const DraggableTabItem = ({
36
  onWindowChange,
37
  onVisibilityChange,
38
  }: DraggableTabItemProps) => {
39
- const [{ isDragging }, drag] = useDrag({
40
  type: 'tab',
41
  item: { type: 'tab', index, id: tab.id },
42
  collect: (monitor) => ({
@@ -44,7 +44,7 @@ const DraggableTabItem = ({
44
  }),
45
  });
46
 
47
- const [, drop] = useDrop({
48
  accept: 'tab',
49
  hover: (item: DragItem, monitor) => {
50
  if (!monitor.isOver({ shallow: true })) {
@@ -64,9 +64,14 @@ const DraggableTabItem = ({
64
  },
65
  });
66
 
 
 
 
 
 
67
  return (
68
  <motion.div
69
- ref={(node) => drag(drop(node))}
70
  initial={false}
71
  animate={{
72
  scale: isDragging ? 1.02 : 1,
 
36
  onWindowChange,
37
  onVisibilityChange,
38
  }: DraggableTabItemProps) => {
39
+ const [{ isDragging }, dragRef] = useDrag({
40
  type: 'tab',
41
  item: { type: 'tab', index, id: tab.id },
42
  collect: (monitor) => ({
 
44
  }),
45
  });
46
 
47
+ const [, dropRef] = useDrop({
48
  accept: 'tab',
49
  hover: (item: DragItem, monitor) => {
50
  if (!monitor.isOver({ shallow: true })) {
 
64
  },
65
  });
66
 
67
+ const ref = (node: HTMLDivElement | null) => {
68
+ dragRef(node);
69
+ dropRef(node);
70
+ };
71
+
72
  return (
73
  <motion.div
74
+ ref={ref}
75
  initial={false}
76
  animate={{
77
  scale: isDragging ? 1.02 : 1,
app/components/settings/shared/TabTile.tsx CHANGED
@@ -55,7 +55,7 @@ export const TabTile = ({
55
  'border border-[#E5E5E5]/50 dark:border-[#333333]/50',
56
 
57
  // Shadow and glass effect
58
- 'shadow-sm backdrop-blur-sm',
59
  'dark:shadow-[0_0_15px_rgba(0,0,0,0.1)]',
60
  'dark:bg-opacity-50',
61
 
 
55
  'border border-[#E5E5E5]/50 dark:border-[#333333]/50',
56
 
57
  // Shadow and glass effect
58
+ 'shadow-sm',
59
  'dark:shadow-[0_0_15px_rgba(0,0,0,0.1)]',
60
  'dark:bg-opacity-50',
61
 
app/components/settings/user/UsersWindow.tsx CHANGED
@@ -1,7 +1,7 @@
1
  import * as RadixDialog from '@radix-ui/react-dialog';
2
  import * as DropdownMenu from '@radix-ui/react-dropdown-menu';
3
  import { motion } from 'framer-motion';
4
- import { useState, useEffect } from 'react';
5
  import { classNames } from '~/utils/classNames';
6
  import { DialogTitle } from '~/components/ui/Dialog';
7
  import { Switch } from '~/components/ui/Switch';
@@ -9,7 +9,6 @@ import type { TabType, TabVisibilityConfig } from '~/components/settings/setting
9
  import { TAB_LABELS } from '~/components/settings/settings.types';
10
  import { DeveloperWindow } from '~/components/settings/developer/DeveloperWindow';
11
  import { TabTile } from '~/components/settings/shared/TabTile';
12
- import { tabConfigurationStore, updateTabConfiguration } from '~/lib/stores/settings';
13
  import { useStore } from '@nanostores/react';
14
  import { DndProvider, useDrag, useDrop } from 'react-dnd';
15
  import { HTML5Backend } from 'react-dnd-html5-backend';
@@ -30,6 +29,13 @@ import { useDebugStatus } from '~/lib/hooks/useDebugStatus';
30
  import CloudProvidersTab from '~/components/settings/providers/CloudProvidersTab';
31
  import LocalProvidersTab from '~/components/settings/providers/LocalProvidersTab';
32
  import TaskManagerTab from '~/components/settings/task-manager/TaskManagerTab';
 
 
 
 
 
 
 
33
 
34
  interface DraggableTabTileProps {
35
  tab: TabVisibilityConfig;
@@ -89,8 +95,14 @@ const DraggableTabTile = ({
89
  },
90
  });
91
 
 
 
 
 
 
 
92
  return (
93
- <div ref={(node) => drag(drop(node))} style={{ opacity: isDragging ? 0.5 : 1 }}>
94
  <TabTile
95
  tab={tab}
96
  onClick={onClick}
@@ -110,10 +122,15 @@ interface UsersWindowProps {
110
  }
111
 
112
  export const UsersWindow = ({ open, onClose }: UsersWindowProps) => {
113
- const [developerMode, setDeveloperMode] = useState(false);
114
  const [activeTab, setActiveTab] = useState<TabType | null>(null);
115
  const [loadingTab, setLoadingTab] = useState<TabType | null>(null);
116
  const tabConfiguration = useStore(tabConfigurationStore);
 
 
 
 
 
 
117
 
118
  // Status hooks
119
  const { hasUpdate, currentVersion, acknowledgeUpdate } = useUpdateCheck();
@@ -122,11 +139,7 @@ export const UsersWindow = ({ open, onClose }: UsersWindowProps) => {
122
  const { hasConnectionIssues, currentIssue, acknowledgeIssue } = useConnectionStatus();
123
  const { hasActiveWarnings, activeIssues, acknowledgeAllIssues } = useDebugStatus();
124
 
125
- const [profile, setProfile] = useState(() => {
126
- const saved = localStorage.getItem('bolt_user_profile');
127
- return saved ? JSON.parse(saved) : { avatar: null, notifications: true };
128
- });
129
-
130
  useEffect(() => {
131
  const handleStorageChange = (e: StorageEvent) => {
132
  if (e.key === 'bolt_user_profile') {
@@ -140,8 +153,66 @@ export const UsersWindow = ({ open, onClose }: UsersWindowProps) => {
140
  return () => window.removeEventListener('storage', handleStorageChange);
141
  }, []);
142
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
143
  const handleDeveloperModeChange = (checked: boolean) => {
144
  setDeveloperMode(checked);
 
 
 
 
 
 
 
 
 
 
145
  };
146
 
147
  const handleBack = () => {
@@ -149,21 +220,55 @@ export const UsersWindow = ({ open, onClose }: UsersWindowProps) => {
149
  };
150
 
151
  // Only show tabs that are assigned to the user window AND are visible
152
- const visibleUserTabs = tabConfiguration.userTabs
153
- .filter((tab) => {
154
- // Hide notifications tab if notifications are disabled
155
- if (tab.id === 'notifications' && !profile.notifications) {
156
- return false;
157
- }
158
 
159
- return tab.visible;
160
- })
161
- .sort((a: TabVisibilityConfig, b: TabVisibilityConfig) => (a.order || 0) - (b.order || 0));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
162
 
163
  const moveTab = (dragIndex: number, hoverIndex: number) => {
164
  const draggedTab = visibleUserTabs[dragIndex];
165
  const targetTab = visibleUserTabs[hoverIndex];
166
 
 
 
167
  // Update the order of the dragged and target tabs
168
  const updatedDraggedTab = { ...draggedTab, order: targetTab.order };
169
  const updatedTargetTab = { ...targetTab, order: draggedTab.order };
@@ -310,7 +415,7 @@ export const UsersWindow = ({ open, onClose }: UsersWindowProps) => {
310
  className="data-[state=checked]:bg-purple-500"
311
  aria-label="Toggle developer mode"
312
  />
313
- <label className="text-sm text-gray-500 dark:text-gray-400">Developer Mode</label>
314
  </div>
315
 
316
  <DropdownMenu.Root>
@@ -412,9 +517,9 @@ export const UsersWindow = ({ open, onClose }: UsersWindowProps) => {
412
 
413
  return (
414
  <>
415
- <DeveloperWindow open={developerMode} onClose={() => setDeveloperMode(false)} />
416
  <DndProvider backend={HTML5Backend}>
417
- <RadixDialog.Root open={open}>
418
  <RadixDialog.Portal>
419
  <div className="fixed inset-0 flex items-center justify-center z-[50]">
420
  <RadixDialog.Overlay asChild>
 
1
  import * as RadixDialog from '@radix-ui/react-dialog';
2
  import * as DropdownMenu from '@radix-ui/react-dropdown-menu';
3
  import { motion } from 'framer-motion';
4
+ import React, { useState, useEffect, useMemo } from 'react';
5
  import { classNames } from '~/utils/classNames';
6
  import { DialogTitle } from '~/components/ui/Dialog';
7
  import { Switch } from '~/components/ui/Switch';
 
9
  import { TAB_LABELS } from '~/components/settings/settings.types';
10
  import { DeveloperWindow } from '~/components/settings/developer/DeveloperWindow';
11
  import { TabTile } from '~/components/settings/shared/TabTile';
 
12
  import { useStore } from '@nanostores/react';
13
  import { DndProvider, useDrag, useDrop } from 'react-dnd';
14
  import { HTML5Backend } from 'react-dnd-html5-backend';
 
29
  import CloudProvidersTab from '~/components/settings/providers/CloudProvidersTab';
30
  import LocalProvidersTab from '~/components/settings/providers/LocalProvidersTab';
31
  import TaskManagerTab from '~/components/settings/task-manager/TaskManagerTab';
32
+ import {
33
+ tabConfigurationStore,
34
+ resetTabConfiguration,
35
+ updateTabConfiguration,
36
+ developerModeStore,
37
+ setDeveloperMode,
38
+ } from '~/lib/stores/settings';
39
 
40
  interface DraggableTabTileProps {
41
  tab: TabVisibilityConfig;
 
95
  },
96
  });
97
 
98
+ const dragDropRef = (node: HTMLDivElement | null) => {
99
+ if (node) {
100
+ drag(drop(node));
101
+ }
102
+ };
103
+
104
  return (
105
+ <div ref={dragDropRef} style={{ opacity: isDragging ? 0.5 : 1 }}>
106
  <TabTile
107
  tab={tab}
108
  onClick={onClick}
 
122
  }
123
 
124
  export const UsersWindow = ({ open, onClose }: UsersWindowProps) => {
 
125
  const [activeTab, setActiveTab] = useState<TabType | null>(null);
126
  const [loadingTab, setLoadingTab] = useState<TabType | null>(null);
127
  const tabConfiguration = useStore(tabConfigurationStore);
128
+ const developerMode = useStore(developerModeStore);
129
+ const [showDeveloperWindow, setShowDeveloperWindow] = useState(false);
130
+ const [profile, setProfile] = useState(() => {
131
+ const saved = localStorage.getItem('bolt_user_profile');
132
+ return saved ? JSON.parse(saved) : { avatar: null, notifications: true };
133
+ });
134
 
135
  // Status hooks
136
  const { hasUpdate, currentVersion, acknowledgeUpdate } = useUpdateCheck();
 
139
  const { hasConnectionIssues, currentIssue, acknowledgeIssue } = useConnectionStatus();
140
  const { hasActiveWarnings, activeIssues, acknowledgeAllIssues } = useDebugStatus();
141
 
142
+ // Listen for profile changes
 
 
 
 
143
  useEffect(() => {
144
  const handleStorageChange = (e: StorageEvent) => {
145
  if (e.key === 'bolt_user_profile') {
 
153
  return () => window.removeEventListener('storage', handleStorageChange);
154
  }, []);
155
 
156
+ // Listen for settings toggle event
157
+ useEffect(() => {
158
+ const handleToggleSettings = () => {
159
+ if (!open) {
160
+ // Open settings panel
161
+ setActiveTab('settings');
162
+ onClose(); // Close any other open panels
163
+ }
164
+ };
165
+
166
+ document.addEventListener('toggle-settings', handleToggleSettings);
167
+
168
+ return () => document.removeEventListener('toggle-settings', handleToggleSettings);
169
+ }, [open, onClose]);
170
+
171
+ // Ensure tab configuration is properly initialized
172
+ useEffect(() => {
173
+ if (!tabConfiguration || !tabConfiguration.userTabs || !tabConfiguration.developerTabs) {
174
+ console.warn('Tab configuration is invalid, resetting to defaults');
175
+ resetTabConfiguration();
176
+ } else {
177
+ // Validate tab configuration structure
178
+ const isValid =
179
+ tabConfiguration.userTabs.every(
180
+ (tab) =>
181
+ tab &&
182
+ typeof tab.id === 'string' &&
183
+ typeof tab.visible === 'boolean' &&
184
+ typeof tab.window === 'string' &&
185
+ typeof tab.order === 'number',
186
+ ) &&
187
+ tabConfiguration.developerTabs.every(
188
+ (tab) =>
189
+ tab &&
190
+ typeof tab.id === 'string' &&
191
+ typeof tab.visible === 'boolean' &&
192
+ typeof tab.window === 'string' &&
193
+ typeof tab.order === 'number',
194
+ );
195
+
196
+ if (!isValid) {
197
+ console.warn('Tab configuration is malformed, resetting to defaults');
198
+ resetTabConfiguration();
199
+ }
200
+ }
201
+ }, [tabConfiguration]);
202
+
203
+ // Handle developer mode changes
204
  const handleDeveloperModeChange = (checked: boolean) => {
205
  setDeveloperMode(checked);
206
+
207
+ if (checked) {
208
+ setShowDeveloperWindow(true);
209
+ }
210
+ };
211
+
212
+ // Handle developer window close
213
+ const handleDeveloperWindowClose = () => {
214
+ setShowDeveloperWindow(false);
215
+ setDeveloperMode(false);
216
  };
217
 
218
  const handleBack = () => {
 
220
  };
221
 
222
  // Only show tabs that are assigned to the user window AND are visible
223
+ const visibleUserTabs = useMemo(() => {
224
+ console.log('Filtering user tabs with configuration:', tabConfiguration);
 
 
 
 
225
 
226
+ if (!tabConfiguration?.userTabs || !Array.isArray(tabConfiguration.userTabs)) {
227
+ console.warn('Invalid tab configuration, using empty array');
228
+ return [];
229
+ }
230
+
231
+ return tabConfiguration.userTabs
232
+ .filter((tab) => {
233
+ if (!tab || typeof tab.id !== 'string') {
234
+ console.warn('Invalid tab entry:', tab);
235
+ return false;
236
+ }
237
+
238
+ // Hide notifications tab if notifications are disabled
239
+ if (tab.id === 'notifications' && !profile.notifications) {
240
+ console.log('Hiding notifications tab due to disabled notifications');
241
+ return false;
242
+ }
243
+
244
+ // Ensure the tab has the required properties
245
+ if (typeof tab.visible !== 'boolean' || typeof tab.window !== 'string' || typeof tab.order !== 'number') {
246
+ console.warn('Tab missing required properties:', tab);
247
+ return false;
248
+ }
249
+
250
+ // Only show tabs that are explicitly visible and assigned to the user window
251
+ const isVisible = tab.visible && tab.window === 'user';
252
+ console.log(`Tab ${tab.id} visibility:`, isVisible);
253
+
254
+ return isVisible;
255
+ })
256
+ .sort((a: TabVisibilityConfig, b: TabVisibilityConfig) => {
257
+ const orderA = typeof a.order === 'number' ? a.order : 0;
258
+ const orderB = typeof b.order === 'number' ? b.order : 0;
259
+
260
+ return orderA - orderB;
261
+ });
262
+ }, [tabConfiguration, profile.notifications]);
263
+
264
+ console.log('Filtered visible user tabs:', visibleUserTabs);
265
 
266
  const moveTab = (dragIndex: number, hoverIndex: number) => {
267
  const draggedTab = visibleUserTabs[dragIndex];
268
  const targetTab = visibleUserTabs[hoverIndex];
269
 
270
+ console.log('Moving tab:', { draggedTab, targetTab });
271
+
272
  // Update the order of the dragged and target tabs
273
  const updatedDraggedTab = { ...draggedTab, order: targetTab.order };
274
  const updatedTargetTab = { ...targetTab, order: draggedTab.order };
 
415
  className="data-[state=checked]:bg-purple-500"
416
  aria-label="Toggle developer mode"
417
  />
418
+ <label className="text-sm text-gray-500 dark:text-gray-400">Switch to Developer Mode</label>
419
  </div>
420
 
421
  <DropdownMenu.Root>
 
517
 
518
  return (
519
  <>
520
+ <DeveloperWindow open={showDeveloperWindow} onClose={handleDeveloperWindowClose} />
521
  <DndProvider backend={HTML5Backend}>
522
+ <RadixDialog.Root open={open && !showDeveloperWindow}>
523
  <RadixDialog.Portal>
524
  <div className="fixed inset-0 flex items-center justify-center z-[50]">
525
  <RadixDialog.Overlay asChild>
app/components/workbench/FileBreadcrumb.tsx CHANGED
@@ -87,7 +87,9 @@ export const FileBreadcrumb = memo<FileBreadcrumbProps>(({ files, pathSegments =
87
  <DropdownMenu.Root open={isActive} modal={false}>
88
  <DropdownMenu.Trigger asChild>
89
  <span
90
- ref={(ref) => (segmentRefs.current[index] = ref)}
 
 
91
  className={classNames('flex items-center gap-1.5 cursor-pointer shrink-0', {
92
  'text-bolt-elements-textTertiary hover:text-bolt-elements-textPrimary': !isActive,
93
  'text-bolt-elements-textPrimary underline': isActive,
 
87
  <DropdownMenu.Root open={isActive} modal={false}>
88
  <DropdownMenu.Trigger asChild>
89
  <span
90
+ ref={(ref) => {
91
+ segmentRefs.current[index] = ref;
92
+ }}
93
  className={classNames('flex items-center gap-1.5 cursor-pointer shrink-0', {
94
  'text-bolt-elements-textTertiary hover:text-bolt-elements-textPrimary': !isActive,
95
  'text-bolt-elements-textPrimary underline': isActive,
app/lib/stores/settings.ts CHANGED
@@ -5,6 +5,8 @@ import type { IProviderConfig } from '~/types/model';
5
  import type { TabVisibilityConfig, TabWindowConfig } from '~/components/settings/settings.types';
6
  import { DEFAULT_TAB_CONFIG } from '~/components/settings/settings.types';
7
  import Cookies from 'js-cookie';
 
 
8
 
9
  export interface Shortcut {
10
  key: string;
@@ -18,6 +20,9 @@ export interface Shortcut {
18
 
19
  export interface Shortcuts {
20
  toggleTerminal: Shortcut;
 
 
 
21
  }
22
 
23
  export const URL_CONFIGURABLE_PROVIDERS = ['Ollama', 'LMStudio', 'OpenAILike'];
@@ -31,6 +36,25 @@ export const shortcutsStore = map<Shortcuts>({
31
  ctrlOrMetaKey: true,
32
  action: () => workbenchStore.toggleTerminal(),
33
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
  });
35
 
36
  const initialProviderSettings: ProviderSetting = {};
@@ -70,18 +94,69 @@ export const enableContextOptimizationStore = atom(false);
70
 
71
  // Initialize tab configuration from cookie or default
72
  const savedTabConfig = Cookies.get('tabConfiguration');
73
- const initialTabConfig: TabWindowConfig = savedTabConfig
74
- ? JSON.parse(savedTabConfig)
75
- : {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
  userTabs: DEFAULT_TAB_CONFIG.filter((tab) => tab.window === 'user'),
77
  developerTabs: DEFAULT_TAB_CONFIG.filter((tab) => tab.window === 'developer'),
78
  };
 
 
 
 
 
 
 
 
 
 
79
 
80
  export const tabConfigurationStore = map<TabWindowConfig>(initialTabConfig);
81
 
82
  // Helper function to update tab configuration
83
  export const updateTabConfiguration = (config: TabVisibilityConfig) => {
84
  const currentConfig = tabConfigurationStore.get();
 
 
85
  const isUserTab = config.window === 'user';
86
  const targetArray = isUserTab ? 'userTabs' : 'developerTabs';
87
 
@@ -99,16 +174,38 @@ export const updateTabConfiguration = (config: TabVisibilityConfig) => {
99
  [targetArray]: updatedTabs,
100
  };
101
 
 
 
102
  tabConfigurationStore.set(newConfig);
103
- Cookies.set('tabConfiguration', JSON.stringify(newConfig));
 
 
 
 
104
  };
105
 
106
  // Helper function to reset tab configuration
107
  export const resetTabConfiguration = () => {
 
 
108
  const defaultConfig: TabWindowConfig = {
109
  userTabs: DEFAULT_TAB_CONFIG.filter((tab) => tab.window === 'user'),
110
  developerTabs: DEFAULT_TAB_CONFIG.filter((tab) => tab.window === 'developer'),
111
  };
 
 
 
112
  tabConfigurationStore.set(defaultConfig);
113
- Cookies.set('tabConfiguration', JSON.stringify(defaultConfig));
 
 
 
 
 
 
 
 
 
 
 
114
  };
 
5
  import type { TabVisibilityConfig, TabWindowConfig } from '~/components/settings/settings.types';
6
  import { DEFAULT_TAB_CONFIG } from '~/components/settings/settings.types';
7
  import Cookies from 'js-cookie';
8
+ import { toggleTheme } from './theme';
9
+ import { chatStore } from './chat';
10
 
11
  export interface Shortcut {
12
  key: string;
 
20
 
21
  export interface Shortcuts {
22
  toggleTerminal: Shortcut;
23
+ toggleTheme: Shortcut;
24
+ toggleChat: Shortcut;
25
+ toggleSettings: Shortcut;
26
  }
27
 
28
  export const URL_CONFIGURABLE_PROVIDERS = ['Ollama', 'LMStudio', 'OpenAILike'];
 
36
  ctrlOrMetaKey: true,
37
  action: () => workbenchStore.toggleTerminal(),
38
  },
39
+ toggleTheme: {
40
+ key: 't',
41
+ ctrlOrMetaKey: true,
42
+ shiftKey: true,
43
+ action: () => toggleTheme(),
44
+ },
45
+ toggleChat: {
46
+ key: '/',
47
+ ctrlOrMetaKey: true,
48
+ action: () => chatStore.setKey('showChat', !chatStore.get().showChat),
49
+ },
50
+ toggleSettings: {
51
+ key: ',',
52
+ ctrlOrMetaKey: true,
53
+ action: () => {
54
+ // This will be connected to the settings panel toggle
55
+ document.dispatchEvent(new CustomEvent('toggle-settings'));
56
+ },
57
+ },
58
  });
59
 
60
  const initialProviderSettings: ProviderSetting = {};
 
94
 
95
  // Initialize tab configuration from cookie or default
96
  const savedTabConfig = Cookies.get('tabConfiguration');
97
+ console.log('Saved tab configuration:', savedTabConfig);
98
+
99
+ let initialTabConfig: TabWindowConfig;
100
+
101
+ try {
102
+ if (savedTabConfig) {
103
+ const parsedConfig = JSON.parse(savedTabConfig);
104
+
105
+ // Validate the parsed configuration
106
+ if (
107
+ parsedConfig &&
108
+ Array.isArray(parsedConfig.userTabs) &&
109
+ Array.isArray(parsedConfig.developerTabs) &&
110
+ parsedConfig.userTabs.every(
111
+ (tab: any) =>
112
+ tab &&
113
+ typeof tab.id === 'string' &&
114
+ typeof tab.visible === 'boolean' &&
115
+ typeof tab.window === 'string' &&
116
+ typeof tab.order === 'number',
117
+ ) &&
118
+ parsedConfig.developerTabs.every(
119
+ (tab: any) =>
120
+ tab &&
121
+ typeof tab.id === 'string' &&
122
+ typeof tab.visible === 'boolean' &&
123
+ typeof tab.window === 'string' &&
124
+ typeof tab.order === 'number',
125
+ )
126
+ ) {
127
+ initialTabConfig = parsedConfig;
128
+ console.log('Using saved tab configuration');
129
+ } else {
130
+ console.warn('Invalid saved tab configuration, using defaults');
131
+ initialTabConfig = {
132
+ userTabs: DEFAULT_TAB_CONFIG.filter((tab) => tab.window === 'user'),
133
+ developerTabs: DEFAULT_TAB_CONFIG.filter((tab) => tab.window === 'developer'),
134
+ };
135
+ }
136
+ } else {
137
+ console.log('No saved tab configuration found, using defaults');
138
+ initialTabConfig = {
139
  userTabs: DEFAULT_TAB_CONFIG.filter((tab) => tab.window === 'user'),
140
  developerTabs: DEFAULT_TAB_CONFIG.filter((tab) => tab.window === 'developer'),
141
  };
142
+ }
143
+ } catch (error) {
144
+ console.error('Error loading tab configuration:', error);
145
+ initialTabConfig = {
146
+ userTabs: DEFAULT_TAB_CONFIG.filter((tab) => tab.window === 'user'),
147
+ developerTabs: DEFAULT_TAB_CONFIG.filter((tab) => tab.window === 'developer'),
148
+ };
149
+ }
150
+
151
+ console.log('Initial tab configuration:', initialTabConfig);
152
 
153
  export const tabConfigurationStore = map<TabWindowConfig>(initialTabConfig);
154
 
155
  // Helper function to update tab configuration
156
  export const updateTabConfiguration = (config: TabVisibilityConfig) => {
157
  const currentConfig = tabConfigurationStore.get();
158
+ console.log('Current tab configuration before update:', currentConfig);
159
+
160
  const isUserTab = config.window === 'user';
161
  const targetArray = isUserTab ? 'userTabs' : 'developerTabs';
162
 
 
174
  [targetArray]: updatedTabs,
175
  };
176
 
177
+ console.log('New tab configuration after update:', newConfig);
178
+
179
  tabConfigurationStore.set(newConfig);
180
+ Cookies.set('tabConfiguration', JSON.stringify(newConfig), {
181
+ expires: 365, // Set cookie to expire in 1 year
182
+ path: '/',
183
+ sameSite: 'strict',
184
+ });
185
  };
186
 
187
  // Helper function to reset tab configuration
188
  export const resetTabConfiguration = () => {
189
+ console.log('Resetting tab configuration to defaults');
190
+
191
  const defaultConfig: TabWindowConfig = {
192
  userTabs: DEFAULT_TAB_CONFIG.filter((tab) => tab.window === 'user'),
193
  developerTabs: DEFAULT_TAB_CONFIG.filter((tab) => tab.window === 'developer'),
194
  };
195
+
196
+ console.log('Default tab configuration:', defaultConfig);
197
+
198
  tabConfigurationStore.set(defaultConfig);
199
+ Cookies.set('tabConfiguration', JSON.stringify(defaultConfig), {
200
+ expires: 365, // Set cookie to expire in 1 year
201
+ path: '/',
202
+ sameSite: 'strict',
203
+ });
204
+ };
205
+
206
+ // Developer mode store
207
+ export const developerModeStore = atom<boolean>(false);
208
+
209
+ export const setDeveloperMode = (value: boolean) => {
210
+ developerModeStore.set(value);
211
  };
app/routes/api.system.git-info.ts CHANGED
@@ -2,7 +2,7 @@ import { json } from '@remix-run/node';
2
  import type { LoaderFunctionArgs } from '@remix-run/node';
3
  import { execSync } from 'child_process';
4
 
5
- export async function loader({ request }: LoaderFunctionArgs) {
6
  try {
7
  const branch = execSync('git rev-parse --abbrev-ref HEAD').toString().trim();
8
  const commit = execSync('git rev-parse --short HEAD').toString().trim();
 
2
  import type { LoaderFunctionArgs } from '@remix-run/node';
3
  import { execSync } from 'child_process';
4
 
5
+ export async function loader({ request: _request }: LoaderFunctionArgs) {
6
  try {
7
  const branch = execSync('git rev-parse --abbrev-ref HEAD').toString().trim();
8
  const commit = execSync('git rev-parse --short HEAD').toString().trim();
package.json CHANGED
@@ -59,16 +59,17 @@
59
  "@octokit/rest": "^21.0.2",
60
  "@octokit/types": "^13.6.2",
61
  "@openrouter/ai-sdk-provider": "^0.0.5",
 
62
  "@radix-ui/react-context-menu": "^2.2.2",
63
  "@radix-ui/react-dialog": "^1.1.2",
64
  "@radix-ui/react-dropdown-menu": "^2.1.2",
65
  "@radix-ui/react-separator": "^1.1.0",
66
  "@radix-ui/react-switch": "^1.1.1",
67
  "@radix-ui/react-tooltip": "^1.1.4",
68
- "@remix-run/cloudflare": "^2.15.0",
69
- "@remix-run/cloudflare-pages": "^2.15.0",
70
  "@remix-run/node": "^2.15.2",
71
- "@remix-run/react": "^2.15.0",
72
  "@uiw/codemirror-theme-vscode": "^4.23.6",
73
  "@unocss/reset": "^0.61.9",
74
  "@webcontainer/api": "1.3.0-internal.10",
@@ -118,7 +119,7 @@
118
  "@cloudflare/workers-types": "^4.20241127.0",
119
  "@iconify-json/ph": "^1.2.1",
120
  "@iconify/types": "^2.0.0",
121
- "@remix-run/dev": "^2.15.0",
122
  "@types/diff": "^5.2.3",
123
  "@types/dom-speech-recognition": "^0.0.4",
124
  "@types/file-saver": "^2.0.7",
 
59
  "@octokit/rest": "^21.0.2",
60
  "@octokit/types": "^13.6.2",
61
  "@openrouter/ai-sdk-provider": "^0.0.5",
62
+ "@phosphor-icons/react": "^2.1.7",
63
  "@radix-ui/react-context-menu": "^2.2.2",
64
  "@radix-ui/react-dialog": "^1.1.2",
65
  "@radix-ui/react-dropdown-menu": "^2.1.2",
66
  "@radix-ui/react-separator": "^1.1.0",
67
  "@radix-ui/react-switch": "^1.1.1",
68
  "@radix-ui/react-tooltip": "^1.1.4",
69
+ "@remix-run/cloudflare": "^2.15.2",
70
+ "@remix-run/cloudflare-pages": "^2.15.2",
71
  "@remix-run/node": "^2.15.2",
72
+ "@remix-run/react": "^2.15.2",
73
  "@uiw/codemirror-theme-vscode": "^4.23.6",
74
  "@unocss/reset": "^0.61.9",
75
  "@webcontainer/api": "1.3.0-internal.10",
 
119
  "@cloudflare/workers-types": "^4.20241127.0",
120
  "@iconify-json/ph": "^1.2.1",
121
  "@iconify/types": "^2.0.0",
122
+ "@remix-run/dev": "^2.15.2",
123
  "@types/diff": "^5.2.3",
124
  "@types/dom-speech-recognition": "^0.0.4",
125
  "@types/file-saver": "^2.0.7",
pages/api/system/git-info.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { NextApiRequest, NextApiResponse } from 'next';
2
  import { execSync } from 'child_process';
3
 
4
  export default async function handler(req: NextApiRequest, res: NextApiResponse) {
 
1
+ import type { NextApiRequest, NextApiResponse } from 'next';
2
  import { execSync } from 'child_process';
3
 
4
  export default async function handler(req: NextApiRequest, res: NextApiResponse) {
pnpm-lock.yaml CHANGED
@@ -98,6 +98,9 @@ importers:
98
  '@openrouter/ai-sdk-provider':
99
  specifier: ^0.0.5
100
  version: 0.0.5([email protected])
 
 
 
101
  '@radix-ui/react-context-menu':
102
  specifier: ^2.2.2
103
@@ -117,17 +120,17 @@ importers:
117
  specifier: ^1.1.4
118
119
  '@remix-run/cloudflare':
120
- specifier: ^2.15.0
121
- version: 2.15.0(@cloudflare/[email protected])([email protected])
122
  '@remix-run/cloudflare-pages':
123
- specifier: ^2.15.0
124
- version: 2.15.0(@cloudflare/[email protected])([email protected])
125
  '@remix-run/node':
126
  specifier: ^2.15.2
127
  version: 2.15.2([email protected])
128
  '@remix-run/react':
129
- specifier: ^2.15.0
130
131
  '@uiw/codemirror-theme-vscode':
132
  specifier: ^4.23.6
133
  version: 4.23.6(@codemirror/[email protected])(@codemirror/[email protected])(@codemirror/[email protected])
@@ -211,7 +214,7 @@ importers:
211
212
  react-dnd:
213
  specifier: ^16.0.1
214
- version: 16.0.1(@types/[email protected].1)(@types/[email protected])([email protected])
215
  react-dnd-html5-backend:
216
  specifier: ^16.0.1
217
  version: 16.0.1
@@ -244,10 +247,10 @@ importers:
244
  version: 4.0.0
245
  remix-island:
246
  specifier: ^0.2.0
247
248
  remix-utils:
249
  specifier: ^7.7.0
250
251
  shiki:
252
  specifier: ^1.24.0
253
  version: 1.24.0
@@ -260,7 +263,7 @@ importers:
260
  devDependencies:
261
  '@blitz/eslint-plugin':
262
  specifier: 0.1.0
263
264
  '@cloudflare/workers-types':
265
  specifier: ^4.20241127.0
266
  version: 4.20241127.0
@@ -271,8 +274,8 @@ importers:
271
  specifier: ^2.0.0
272
  version: 2.0.0
273
  '@remix-run/dev':
274
- specifier: ^2.15.0
275
276
  '@types/diff':
277
  specifier: ^5.2.3
278
  version: 5.2.3
@@ -320,22 +323,22 @@ importers:
320
  version: 11.0.5
321
  unocss:
322
  specifier: ^0.61.9
323
- version: 0.61.9(postcss@8.4.49)([email protected])([email protected](@types/[email protected].1)([email protected]))
324
  vite:
325
  specifier: ^5.4.11
326
- version: 5.4.11(@types/[email protected].1)([email protected])
327
  vite-plugin-node-polyfills:
328
  specifier: ^0.22.0
329
330
  vite-plugin-optimize-css-modules:
331
  specifier: ^1.1.0
332
333
  vite-tsconfig-paths:
334
  specifier: ^4.3.2
335
336
  vitest:
337
  specifier: ^2.1.7
338
- version: 2.1.8(@types/[email protected].1)([email protected])
339
  wrangler:
340
  specifier: ^3.91.0
341
  version: 3.91.0(@cloudflare/[email protected])
@@ -627,6 +630,10 @@ packages:
627
  resolution: {integrity: sha512-zevQbhbau95nkoxSq3f/DC/SC+EEOUZd3DYqfSkMhY2/wfSeaHV1Ew4vk8e+x8lja31IbyuUa2uQ3JONqKbysw==}
628
  engines: {node: '>=6.9.0'}
629
 
 
 
 
 
630
  '@babel/[email protected]':
631
  resolution: {integrity: sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==}
632
  engines: {node: '>=6.9.0'}
@@ -663,6 +670,10 @@ packages:
663
  resolution: {integrity: sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==}
664
  engines: {node: '>=6.9.0'}
665
 
 
 
 
 
666
  '@babel/[email protected]':
667
  resolution: {integrity: sha512-IiDqTOTBQy0sWyeXyGSC5TBJpGFXBkRynjBeXsvbhQFKj2viwJC76Epz35YLU1fpe/Am6Vppb7W7zM4fPQzLsQ==}
668
  engines: {node: '>=6.9.0'}
@@ -698,6 +709,11 @@ packages:
698
  engines: {node: '>=6.0.0'}
699
  hasBin: true
700
 
 
 
 
 
 
701
  '@babel/[email protected]':
702
  resolution: {integrity: sha512-ryzI0McXUPJnRCvMo4lumIKZUzhYUO/ScI+Mz4YVaTLt04DHNSjEUjKVvbzQjZFLuod/cYEc07mJWhzl6v4DPg==}
703
  engines: {node: '>=6.9.0'}
@@ -746,10 +762,18 @@ packages:
746
  resolution: {integrity: sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==}
747
  engines: {node: '>=6.9.0'}
748
 
 
 
 
 
749
  '@babel/[email protected]':
750
  resolution: {integrity: sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==}
751
  engines: {node: '>=6.9.0'}
752
 
 
 
 
 
753
  '@blitz/[email protected]':
754
  resolution: {integrity: sha512-mGEAFWCI5AQ4nrePhjp2WzvRen+UWR+SF4MvH70icIBClR08Gm3dT9MRa2jszOpfY00NyIYfm7/1CFZ37GvW4g==}
755
  engines: {node: ^18.0.0 || ^20.0.0}
@@ -1634,6 +1658,10 @@ packages:
1634
  resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==}
1635
  engines: {node: '>=6.0.0'}
1636
 
 
 
 
 
1637
  '@jridgewell/[email protected]':
1638
  resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
1639
  engines: {node: '>=6.0.0'}
@@ -1841,6 +1869,13 @@ packages:
1841
  resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==}
1842
  engines: {node: '>=8.0.0'}
1843
 
 
 
 
 
 
 
 
1844
  '@pkgjs/[email protected]':
1845
  resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
1846
  engines: {node: '>=14'}
@@ -2248,8 +2283,8 @@ packages:
2248
  peerDependencies:
2249
  react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1
2250
 
2251
- '@remix-run/[email protected].0':
2252
- resolution: {integrity: sha512-3FjiON0BmEH3fwGdmP6eEf9TL5BejCt9LOMnszefDGdwY7kgXCodJNr8TAYseor6m7LlC4xgSkgkgj/YRIZTGA==}
2253
  engines: {node: '>=18.0.0'}
2254
  peerDependencies:
2255
  '@cloudflare/workers-types': ^4.0.0
@@ -2258,8 +2293,8 @@ packages:
2258
  typescript:
2259
  optional: true
2260
 
2261
- '@remix-run/[email protected].0':
2262
- resolution: {integrity: sha512-X8Z3EDdlh/8Gjpu27gnJenN06Q9BtkxMEFt5op3y/qahCt0FH9A64DZQ5N47+WnFhySy6mOpzFwCAzPmGIuIeQ==}
2263
  engines: {node: '>=18.0.0'}
2264
  peerDependencies:
2265
  '@cloudflare/workers-types': ^4.0.0
@@ -2268,13 +2303,13 @@ packages:
2268
  typescript:
2269
  optional: true
2270
 
2271
- '@remix-run/[email protected].0':
2272
- resolution: {integrity: sha512-iXV6u9PBwFc7KriDpVcjqLGJzZZd6ZOrxewen7hoH0OBzGwjkhtm46BTQEJrZ/e/dzlU1IU/0ylH29tN9BZoyg==}
2273
  engines: {node: '>=18.0.0'}
2274
  hasBin: true
2275
  peerDependencies:
2276
- '@remix-run/react': ^2.15.0
2277
- '@remix-run/serve': ^2.15.0
2278
  typescript: ^5.1.0
2279
  vite: ^5.1.0
2280
  wrangler: ^3.28.2
@@ -2288,15 +2323,6 @@ packages:
2288
  wrangler:
2289
  optional: true
2290
 
2291
- '@remix-run/[email protected]':
2292
- resolution: {integrity: sha512-tWbR7pQ6gwj+MkGf6WVIYnjgfGfpdU8EOIa6xsCIRlrm0p3BtMz4jA3GvBWEpOuEnN5MV7CarVzhduaRzkZ0SQ==}
2293
- engines: {node: '>=18.0.0'}
2294
- peerDependencies:
2295
- typescript: ^5.1.0
2296
- peerDependenciesMeta:
2297
- typescript:
2298
- optional: true
2299
-
2300
  '@remix-run/[email protected]':
2301
  resolution: {integrity: sha512-NS/h5uxje7DYCNgcKqKAiUhf0r2HVnoYUBWLyIIMmCUP1ddWurBP6xTPcWzGhEvV/EvguniYi1wJZ5+X8sonWw==}
2302
  engines: {node: '>=18.0.0'}
@@ -2306,8 +2332,8 @@ packages:
2306
  typescript:
2307
  optional: true
2308
 
2309
- '@remix-run/[email protected].0':
2310
- resolution: {integrity: sha512-puqDbi9N/WfaUhzDnw2pACXtCB7ukrtFJ9ILwpEuhlaTBpjefifJ89igokW+tt1ePphIFMivAm/YspcbZdCQsA==}
2311
  engines: {node: '>=18.0.0'}
2312
  peerDependencies:
2313
  react: ^18.0.0
@@ -2321,15 +2347,6 @@ packages:
2321
  resolution: {integrity: sha512-xfSkCAchbdG5PnbrKqFWwia4Bi61nH+wm8wLEqfHDyp7Y3dZzgqS2itV8i4gAq9pC2HsTpwyBC6Ds8VHZ96JlA==}
2322
  engines: {node: '>=14.0.0'}
2323
 
2324
- '@remix-run/[email protected]':
2325
- resolution: {integrity: sha512-FuM8vAg1sPskf4wn0ivbuj/7s9Qdh2wnKu+sVXqYz0a95gH5b73TuMzk6n3NMSkFVKKc6+UmlG1WLYre7L2LTg==}
2326
- engines: {node: '>=18.0.0'}
2327
- peerDependencies:
2328
- typescript: ^5.1.0
2329
- peerDependenciesMeta:
2330
- typescript:
2331
- optional: true
2332
-
2333
  '@remix-run/[email protected]':
2334
  resolution: {integrity: sha512-OqiPcvEnnU88B8b1LIWHHkQ3Tz2GDAmQ1RihFNQsbrFKpDsQLkw0lJlnfgKA/uHd0CEEacpfV7C9qqJT3V6Z2g==}
2335
  engines: {node: '>=18.0.0'}
@@ -2742,6 +2759,9 @@ packages:
2742
  '@types/[email protected]':
2743
  resolution: {integrity: sha512-qKgsUwfHZV2WCWLAnVP1JqnpE6Im6h3Y0+fYgMTasNQ7V++CBX5OT1as0g0f+OyubbFqhf6XVNIsmN4IIhEgGQ==}
2744
 
 
 
 
2745
  '@types/[email protected]':
2746
  resolution: {integrity: sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==}
2747
 
@@ -2921,11 +2941,11 @@ packages:
2921
  peerDependencies:
2922
  vite: ^2.9.0 || ^3.0.0-0 || ^4.0.0 || ^5.0.0-0
2923
 
2924
- '@vanilla-extract/babel-plugin-debug-ids@1.1.0':
2925
- resolution: {integrity: sha512-Zy9bKjaL2P5zsrFYQJ8IjWGlFODmZrpvFmjFE0Zv8om55Pz1JtpJtL6DvlxlWUxbVaP1HKCqsmEfFOZN8fX/ZQ==}
2926
 
2927
- '@vanilla-extract/css@1.16.1':
2928
- resolution: {integrity: sha512-3jKxH5ty/ZjmGoLAx8liY7e87FRCIJfnuufX/K9fQklu0YHP3ClrNisU++LkZuD+GZleqMSAQMF0r8Otln+OPQ==}
2929
 
2930
  '@vanilla-extract/[email protected]':
2931
  resolution: {integrity: sha512-E2YcfO8vA+vs+ua+gpvy1HRqvgWbI+MTlUpxA8FvatOvybuNcWAY0CKwQ/Gpj7rswYKtC6C7+xw33emM6/ImdQ==}
@@ -3202,10 +3222,18 @@ packages:
3202
  resolution: {integrity: sha512-/aJwG2l3ZMJ1xNAnqbMpA40of9dj/pIH3QfiuQSqjfPJF747VR0J/bHn+/KdNnHKc6XQcWt/AfRSBft82W1d2A==}
3203
  engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
3204
 
 
 
 
 
3205
3206
  resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==}
3207
  engines: {node: '>= 0.4'}
3208
 
 
 
 
 
3209
3210
  resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
3211
  engines: {node: '>=6'}
@@ -3454,6 +3482,15 @@ packages:
3454
  supports-color:
3455
  optional: true
3456
 
 
 
 
 
 
 
 
 
 
3457
3458
  resolution: {integrity: sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==}
3459
 
@@ -3549,6 +3586,10 @@ packages:
3549
  resolution: {integrity: sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==}
3550
  engines: {node: '>=12'}
3551
 
 
 
 
 
3552
3553
  resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==}
3554
 
@@ -3602,6 +3643,10 @@ packages:
3602
  resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==}
3603
  engines: {node: '>= 0.4'}
3604
 
 
 
 
 
3605
3606
  resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
3607
  engines: {node: '>= 0.4'}
@@ -3609,6 +3654,13 @@ packages:
3609
3610
  resolution: {integrity: sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==}
3611
 
 
 
 
 
 
 
 
3612
3613
  resolution: {integrity: sha512-bRB4qbgUDWrdY1eMk123KiaCSW9VzQ+QLZrmU7D//cCFkmksPd9mUMpmWoFK/rxjIeTfTSOpKCoGoimlvI+AWw==}
3614
  engines: {node: '>=14.0.0'}
@@ -3812,8 +3864,8 @@ packages:
3812
  resolution: {integrity: sha512-bFi65yM+xZgk+u/KRIpekdSYkTB5W1pEf0Lt8Q8Msh7b+eQ7LXVtIB1Bkm4fvclDEL1b2CZkMhv2mOeF8tMdkA==}
3813
  engines: {node: '>=12.0.0'}
3814
 
3815
3816
- resolution: {integrity: sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==}
3817
  engines: {node: '>= 0.10.0'}
3818
 
3819
@@ -3946,6 +3998,10 @@ packages:
3946
  resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==}
3947
  engines: {node: '>= 0.4'}
3948
 
 
 
 
 
3949
3950
  resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==}
3951
  engines: {node: '>=6'}
@@ -3954,6 +4010,10 @@ packages:
3954
  resolution: {integrity: sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==}
3955
  engines: {node: '>=8'}
3956
 
 
 
 
 
3957
3958
  resolution: {integrity: sha512-X5+4+iD+HoSeEED+uwrQ07BOQr0kEDFMVqqpBuI+RaZBpBpHCuXxo70bjar6f0b0u/DQJsJ7ssurpP0V60Az+w==}
3959
 
@@ -3998,6 +4058,10 @@ packages:
3998
  resolution: {integrity: sha512-FQoVQnqcdk4hVM4JN1eromaun4iuS34oStkdlLENLdpULsuQcTyXj8w7ayhuUfPwEYZ1ZOooOTT6fdA9Vmx/RA==}
3999
  engines: {node: '>= 0.4'}
4000
 
 
 
 
 
4001
4002
  resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
4003
 
@@ -4198,6 +4262,10 @@ packages:
4198
  resolution: {integrity: sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==}
4199
  engines: {node: '>= 0.4'}
4200
 
 
 
 
 
4201
4202
  resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==}
4203
 
@@ -4294,8 +4362,8 @@ packages:
4294
4295
  resolution: {integrity: sha512-JVAfqNPTvNq3sB/VHQJAFxN/sPgKnsKrCwyRt15zwNCdrMMJDdcEOdubuy+DuJYYdm0ox1J4uzEuYKkN+9yhVg==}
4296
 
4297
4298
- resolution: {integrity: sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==}
4299
  hasBin: true
4300
 
4301
@@ -4374,8 +4442,8 @@ packages:
4374
4375
  resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==}
4376
 
4377
4378
- resolution: {integrity: sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==}
4379
  engines: {node: '>=14'}
4380
 
4381
@@ -4443,6 +4511,10 @@ packages:
4443
4444
  resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==}
4445
 
 
 
 
 
4446
4447
  resolution: {integrity: sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==}
4448
 
@@ -4821,6 +4893,9 @@ packages:
4821
4822
  resolution: {integrity: sha512-xUsx5n/mN0uQf4V548PKQ+YShA4/IW0KI1dZhrNrPCLG+xizETbHTkOa1f8/xut9JRPp8kQuMnz0oqwkTiLo/A==}
4823
 
 
 
 
4824
4825
  resolution: {integrity: sha512-sEKPVl2rM+MNVkGQt3ChdmD8YsigmXdn5NifZn6jiwn9LRJpWm8F3guhaqrJT/JOat6pwpbXEk6kv+b9DMIjsQ==}
4826
 
@@ -5032,6 +5107,9 @@ packages:
5032
5033
  resolution: {integrity: sha512-SWzvYcSJh4d/SGLIOQfZ/CoNv6BTlI6YEQ7Nj82oDVnRpwe/Z/F1EMx42x3JAOwGBlCjeCH0BRJQbQ/opHL17w==}
5034
 
 
 
 
5035
5036
  resolution: {integrity: sha512-kHt7kzLoS9VBZfUsiKjv43mr91ea+U05EyKkEtqp7vNbHxmaVuEqN7XxeEVnGrMtYOAxGrDElSi96K7EgO1zCA==}
5037
  engines: {node: '>=6'}
@@ -5064,8 +5142,8 @@ packages:
5064
  resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==}
5065
  engines: {node: '>=16 || 14 >=14.18'}
5066
 
5067
5068
- resolution: {integrity: sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==}
5069
 
5070
5071
  resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==}
@@ -5073,6 +5151,9 @@ packages:
5073
5074
  resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==}
5075
 
 
 
 
5076
5077
  resolution: {integrity: sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==}
5078
  engines: {node: '>= 14.16'}
@@ -5117,6 +5198,9 @@ packages:
5117
5118
  resolution: {integrity: sha512-sQoqa8alT3nHjGuTjuKgOnvjo4cljkufdtLMnO2LBP/wRwuDlo1tkaEdMxCRhyGRPacv/ztlZgDPm2b7FAmEvw==}
5119
 
 
 
 
5120
5121
  resolution: {integrity: sha512-yBgLP75OS8oCyUI0cXiWtVKXQKbLrfGfp4JUJwQD6i8n1OHUagig9WyJtj3I6/0+5TMm2nICc3lOYgD88NGEqw==}
5122
  engines: {node: '>=18.12'}
@@ -5150,8 +5234,8 @@ packages:
5150
  peerDependencies:
5151
  postcss: ^8.1.0
5152
 
5153
- postcss-modules-local-by-default@4.1.0:
5154
- resolution: {integrity: sha512-rm0bdSv4jC3BDma3s9H19ZddW0aHX6EoqwDYU2IfZhRN+53QrufTRo2IdkAbRqLx4R2IYbZnbjKKxg4VN5oU9Q==}
5155
  engines: {node: ^10 || ^12 || >= 14}
5156
  peerDependencies:
5157
  postcss: ^8.1.0
@@ -5188,6 +5272,10 @@ packages:
5188
  resolution: {integrity: sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==}
5189
  engines: {node: ^10 || ^12 || >=14}
5190
 
 
 
 
 
5191
5192
  resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
5193
  engines: {node: '>= 0.8.0'}
@@ -5370,15 +5458,15 @@ packages:
5370
  react: ^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc
5371
  react-dom: ^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc
5372
 
5373
5374
- resolution: {integrity: sha512-kQ7Unsl5YdyOltsPGl31zOjLrDv+m2VcIEcIHqYYD3Lp0UppLjrzcfJqDJwXxFw3TH/yvapbnUvPlAj7Kx5nbg==}
5375
  engines: {node: '>=14.0.0'}
5376
  peerDependencies:
5377
  react: '>=16.8'
5378
  react-dom: '>=16.8'
5379
 
5380
5381
- resolution: {integrity: sha512-HrYdIFqdrnhDw0PqG/AKjAqEqM7AvxCz0DQ4h2W8k6nqmc5uRBYDag0SBxx9iYz5G8gnuNVLzUe13wl9eAsXXg==}
5382
  engines: {node: '>=14.0.0'}
5383
  peerDependencies:
5384
  react: '>=16.8'
@@ -5759,10 +5847,26 @@ packages:
5759
5760
  resolution: {integrity: sha512-qIneep7QRwxRd5oiHb8jaRzH15V/S8F3saCXOdjwRLgozZJr5x2yeBhQtqkO3FSzQDwYEFAYuifg4oHjpDghrg==}
5761
 
 
 
 
 
 
 
 
 
 
 
 
 
5762
5763
  resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==}
5764
  engines: {node: '>= 0.4'}
5765
 
 
 
 
 
5766
5767
  resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==}
5768
 
@@ -5817,8 +5921,8 @@ packages:
5817
5818
  resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==}
5819
 
5820
5821
- resolution: {integrity: sha512-jg25NiDV/1fLtSgEgyvVyDunvaNHbuwF9lfNV17gSmPFAlYzdfNBlLtLzXTevwkPj7DhGbmN9VnmJIgLnhvaBw==}
5822
 
5823
5824
  resolution: {integrity: sha512-MGrFH9Z4NP9Iyhqn16sDtBpRRNJ0Y2hNa6D65h736fVSaPCHr4DM4sWUNvVaSuC+0OBGhwsrydQwmgfg5LncqQ==}
@@ -5961,8 +6065,8 @@ packages:
5961
5962
  resolution: {integrity: sha512-P+Vu1qXfzediirmHOC3xKGAYeZtPcV9g76X+xg2FD4tYgR71ewMA35Y3sCz3zhiN/dwefRpJX0yBcgwi1fXNQA==}
5963
 
5964
5965
- resolution: {integrity: sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==}
5966
 
5967
5968
  resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==}
@@ -6470,8 +6574,8 @@ packages:
6470
6471
  resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
6472
 
6473
- yaml@2.6.1:
6474
- resolution: {integrity: sha512-7r0XPzioN/Q9kXBro/XPnA6kznR73DHq+GXh5ON7ZozRO6aMjbmiBuKste2wslTFkC5d1dw0GooOCepZXJ2SAg==}
6475
  engines: {node: '>= 14'}
6476
  hasBin: true
6477
 
@@ -7080,6 +7184,14 @@ snapshots:
7080
  '@jridgewell/trace-mapping': 0.3.25
7081
  jsesc: 3.0.2
7082
 
 
 
 
 
 
 
 
 
7083
  '@babel/[email protected]':
7084
  dependencies:
7085
  '@babel/types': 7.26.0
@@ -7134,6 +7246,8 @@ snapshots:
7134
 
7135
  '@babel/[email protected]': {}
7136
 
 
 
7137
  '@babel/[email protected](@babel/[email protected])':
7138
  dependencies:
7139
  '@babel/core': 7.26.0
@@ -7172,10 +7286,14 @@ snapshots:
7172
  dependencies:
7173
  '@babel/types': 7.26.0
7174
 
 
 
 
 
7175
  '@babel/[email protected](@babel/[email protected])':
7176
  dependencies:
7177
  '@babel/core': 7.26.0
7178
- '@babel/helper-plugin-utils': 7.25.9
7179
 
7180
  '@babel/[email protected](@babel/[email protected])':
7181
  dependencies:
@@ -7240,24 +7358,41 @@ snapshots:
7240
  transitivePeerDependencies:
7241
  - supports-color
7242
 
 
 
 
 
 
 
 
 
 
 
 
 
7243
  '@babel/[email protected]':
7244
  dependencies:
7245
  '@babel/helper-string-parser': 7.25.9
7246
  '@babel/helper-validator-identifier': 7.25.9
7247
 
7248
- '@blitz/[email protected](@types/eslint@8.56.10)([email protected])([email protected])(typescript@5.7.2)':
7249
  dependencies:
7250
- '@stylistic/eslint-plugin-ts': 2.11.0(eslint@9.16.0([email protected]))([email protected])
7251
- '@typescript-eslint/eslint-plugin': 8.17.0(@typescript-eslint/[email protected](eslint@9.16.0([email protected]))([email protected]))([email protected]([email protected]))([email protected])
7252
- '@typescript-eslint/parser': 8.17.0([email protected]([email protected]))([email protected])
7253
- '@typescript-eslint/utils': 8.17.0(eslint@9.16.0([email protected].6))([email protected])
 
 
 
 
 
7254
  common-tags: 1.8.2
7255
- eslint: 9.16.0([email protected].6)
7256
- eslint-config-prettier: 9.1.0([email protected]([email protected].6))
7257
- eslint-plugin-jsonc: 2.18.2([email protected]([email protected].6))
7258
7259
  globals: 15.13.0
7260
- typescript-eslint: 8.17.0([email protected]([email protected].6))([email protected])
7261
  transitivePeerDependencies:
7262
  - '@eslint/json'
7263
  - '@types/eslint'
@@ -7723,9 +7858,9 @@ snapshots:
7723
  '@esbuild/[email protected]':
7724
  optional: true
7725
 
7726
7727
  dependencies:
7728
- eslint: 9.16.0([email protected].6)
7729
  eslint-visitor-keys: 3.4.3
7730
 
7731
  '@eslint-community/[email protected]': {}
@@ -7923,6 +8058,12 @@ snapshots:
7923
  '@jridgewell/sourcemap-codec': 1.5.0
7924
  '@jridgewell/trace-mapping': 0.3.25
7925
 
 
 
 
 
 
 
7926
  '@jridgewell/[email protected]': {}
7927
 
7928
  '@jridgewell/[email protected]': {}
@@ -8167,6 +8308,11 @@ snapshots:
8167
 
8168
  '@opentelemetry/[email protected]': {}
8169
 
 
 
 
 
 
8170
  '@pkgjs/[email protected]':
8171
  optional: true
8172
 
@@ -8556,51 +8702,51 @@ snapshots:
8556
  dependencies:
8557
  react: 18.3.1
8558
 
8559
- '@remix-run/[email protected].0(@cloudflare/[email protected])([email protected])':
8560
  dependencies:
8561
  '@cloudflare/workers-types': 4.20241127.0
8562
- '@remix-run/cloudflare': 2.15.0(@cloudflare/[email protected])([email protected])
8563
  optionalDependencies:
8564
  typescript: 5.7.2
8565
 
8566
- '@remix-run/[email protected].0(@cloudflare/[email protected])([email protected])':
8567
  dependencies:
8568
  '@cloudflare/kv-asset-handler': 0.1.3
8569
  '@cloudflare/workers-types': 4.20241127.0
8570
- '@remix-run/server-runtime': 2.15.0([email protected])
8571
  optionalDependencies:
8572
  typescript: 5.7.2
8573
 
8574
8575
  dependencies:
8576
  '@babel/core': 7.26.0
8577
- '@babel/generator': 7.26.2
8578
- '@babel/parser': 7.26.2
8579
  '@babel/plugin-syntax-decorators': 7.25.9(@babel/[email protected])
8580
  '@babel/plugin-syntax-jsx': 7.25.9(@babel/[email protected])
8581
  '@babel/preset-typescript': 7.26.0(@babel/[email protected])
8582
- '@babel/traverse': 7.25.9
8583
- '@babel/types': 7.26.0
8584
  '@mdx-js/mdx': 2.3.0
8585
  '@npmcli/package-json': 4.0.1
8586
- '@remix-run/node': 2.15.0([email protected])
8587
8588
  '@remix-run/router': 1.21.0
8589
- '@remix-run/server-runtime': 2.15.0([email protected])
8590
  '@types/mdx': 2.0.13
8591
- '@vanilla-extract/integration': 6.5.0(@types/[email protected].1)([email protected])
8592
  arg: 5.0.2
8593
  cacache: 17.1.4
8594
  chalk: 4.1.2
8595
  chokidar: 3.6.0
8596
  cross-spawn: 7.0.6
8597
  dotenv: 16.4.7
8598
- es-module-lexer: 1.5.4
8599
  esbuild: 0.17.6
8600
  esbuild-plugins-node-modules-polyfill: 1.6.8([email protected])
8601
  execa: 5.1.1
8602
  exit-hook: 2.2.1
8603
- express: 4.21.1
8604
  fs-extra: 10.1.0
8605
  get-port: 5.1.1
8606
  gunzip-maybe: 1.4.2
@@ -8613,10 +8759,10 @@ snapshots:
8613
  picocolors: 1.1.1
8614
  picomatch: 2.3.1
8615
  pidtree: 0.6.0
8616
- postcss: 8.4.49
8617
- postcss-discard-duplicates: 5.1.0(postcss@8.4.49)
8618
- postcss-load-config: 4.0.2(postcss@8.4.49)
8619
- postcss-modules: 6.0.1(postcss@8.4.49)
8620
  prettier: 2.8.8
8621
  pretty-ms: 7.0.1
8622
  react-refresh: 0.14.2
@@ -8624,14 +8770,14 @@ snapshots:
8624
  remark-mdx-frontmatter: 1.1.1
8625
  semver: 7.6.3
8626
  set-cookie-parser: 2.7.1
8627
- tar-fs: 2.1.1
8628
  tsconfig-paths: 4.2.0
8629
  valibot: 0.41.0([email protected])
8630
- vite-node: 1.6.0(@types/[email protected].1)([email protected])
8631
  ws: 7.5.10
8632
  optionalDependencies:
8633
  typescript: 5.7.2
8634
- vite: 5.4.11(@types/[email protected].1)([email protected])
8635
  wrangler: 3.91.0(@cloudflare/[email protected])
8636
  transitivePeerDependencies:
8637
  - '@types/node'
@@ -8649,18 +8795,6 @@ snapshots:
8649
  - ts-node
8650
  - utf-8-validate
8651
 
8652
8653
- dependencies:
8654
- '@remix-run/server-runtime': 2.15.0([email protected])
8655
- '@remix-run/web-fetch': 4.4.2
8656
- '@web3-storage/multipart-parser': 1.0.0
8657
- cookie-signature: 1.2.2
8658
- source-map-support: 0.5.21
8659
- stream-slice: 0.1.2
8660
- undici: 6.21.0
8661
- optionalDependencies:
8662
- typescript: 5.7.2
8663
-
8664
8665
  dependencies:
8666
  '@remix-run/server-runtime': 2.15.2([email protected])
@@ -8673,32 +8807,20 @@ snapshots:
8673
  optionalDependencies:
8674
  typescript: 5.7.2
8675
 
8676
8677
  dependencies:
8678
  '@remix-run/router': 1.21.0
8679
- '@remix-run/server-runtime': 2.15.0([email protected])
8680
  react: 18.3.1
8681
  react-dom: 18.3.1([email protected])
8682
- react-router: 6.28.0([email protected])
8683
8684
  turbo-stream: 2.4.0
8685
  optionalDependencies:
8686
  typescript: 5.7.2
8687
 
8688
  '@remix-run/[email protected]': {}
8689
 
8690
8691
- dependencies:
8692
- '@remix-run/router': 1.21.0
8693
- '@types/cookie': 0.6.0
8694
- '@web3-storage/multipart-parser': 1.0.0
8695
- cookie: 0.6.0
8696
- set-cookie-parser: 2.7.1
8697
- source-map: 0.7.4
8698
- turbo-stream: 2.4.0
8699
- optionalDependencies:
8700
- typescript: 5.7.2
8701
-
8702
8703
  dependencies:
8704
  '@remix-run/router': 1.21.0
@@ -9133,10 +9255,10 @@ snapshots:
9133
  '@smithy/util-buffer-from': 3.0.0
9134
  tslib: 2.8.1
9135
 
9136
9137
  dependencies:
9138
- '@typescript-eslint/utils': 8.17.0([email protected]([email protected].6))([email protected])
9139
- eslint: 9.16.0([email protected].6)
9140
  eslint-visitor-keys: 4.2.0
9141
  espree: 10.3.0
9142
  transitivePeerDependencies:
@@ -9219,6 +9341,10 @@ snapshots:
9219
  dependencies:
9220
  undici-types: 6.20.0
9221
 
 
 
 
 
9222
  '@types/[email protected]': {}
9223
 
9224
  '@types/[email protected]':
@@ -9236,15 +9362,15 @@ snapshots:
9236
 
9237
  '@types/[email protected]': {}
9238
 
9239
9240
  dependencies:
9241
  '@eslint-community/regexpp': 4.12.1
9242
- '@typescript-eslint/parser': 8.17.0([email protected]([email protected].6))([email protected])
9243
  '@typescript-eslint/scope-manager': 8.17.0
9244
- '@typescript-eslint/type-utils': 8.17.0([email protected]([email protected].6))([email protected])
9245
- '@typescript-eslint/utils': 8.17.0([email protected]([email protected].6))([email protected])
9246
  '@typescript-eslint/visitor-keys': 8.17.0
9247
- eslint: 9.16.0([email protected].6)
9248
  graphemer: 1.4.0
9249
  ignore: 5.3.2
9250
  natural-compare: 1.4.0
@@ -9254,14 +9380,14 @@ snapshots:
9254
  transitivePeerDependencies:
9255
  - supports-color
9256
 
9257
9258
  dependencies:
9259
  '@typescript-eslint/scope-manager': 8.17.0
9260
  '@typescript-eslint/types': 8.17.0
9261
  '@typescript-eslint/typescript-estree': 8.17.0([email protected])
9262
  '@typescript-eslint/visitor-keys': 8.17.0
9263
  debug: 4.3.7
9264
- eslint: 9.16.0([email protected].6)
9265
  optionalDependencies:
9266
  typescript: 5.7.2
9267
  transitivePeerDependencies:
@@ -9272,12 +9398,12 @@ snapshots:
9272
  '@typescript-eslint/types': 8.17.0
9273
  '@typescript-eslint/visitor-keys': 8.17.0
9274
 
9275
9276
  dependencies:
9277
  '@typescript-eslint/typescript-estree': 8.17.0([email protected])
9278
- '@typescript-eslint/utils': 8.17.0([email protected]([email protected].6))([email protected])
9279
  debug: 4.3.7
9280
- eslint: 9.16.0([email protected].6)
9281
  ts-api-utils: 1.4.3([email protected])
9282
  optionalDependencies:
9283
  typescript: 5.7.2
@@ -9301,13 +9427,13 @@ snapshots:
9301
  transitivePeerDependencies:
9302
  - supports-color
9303
 
9304
9305
  dependencies:
9306
- '@eslint-community/eslint-utils': 4.4.1([email protected]([email protected].6))
9307
  '@typescript-eslint/scope-manager': 8.17.0
9308
  '@typescript-eslint/types': 8.17.0
9309
  '@typescript-eslint/typescript-estree': 8.17.0([email protected])
9310
- eslint: 9.16.0([email protected].6)
9311
  optionalDependencies:
9312
  typescript: 5.7.2
9313
  transitivePeerDependencies:
@@ -9334,13 +9460,13 @@ snapshots:
9334
 
9335
  '@ungap/[email protected]': {}
9336
 
9337
9338
  dependencies:
9339
  '@unocss/core': 0.61.9
9340
  '@unocss/reset': 0.61.9
9341
9342
  optionalDependencies:
9343
- vite: 5.4.11(@types/[email protected].1)([email protected])
9344
  transitivePeerDependencies:
9345
  - rollup
9346
  - supports-color
@@ -9384,7 +9510,7 @@ snapshots:
9384
  gzip-size: 6.0.0
9385
  sirv: 2.0.4
9386
 
9387
- '@unocss/[email protected](postcss@8.4.49)':
9388
  dependencies:
9389
  '@unocss/config': 0.61.9
9390
  '@unocss/core': 0.61.9
@@ -9392,7 +9518,7 @@ snapshots:
9392
  css-tree: 2.3.1
9393
  fast-glob: 3.3.2
9394
  magic-string: 0.30.14
9395
- postcss: 8.4.49
9396
  transitivePeerDependencies:
9397
  - supports-color
9398
 
@@ -9477,7 +9603,7 @@ snapshots:
9477
  dependencies:
9478
  '@unocss/core': 0.61.9
9479
 
9480
9481
  dependencies:
9482
  '@ampproject/remapping': 2.3.0
9483
  '@rollup/pluginutils': 5.1.3([email protected])
@@ -9489,18 +9615,18 @@ snapshots:
9489
  chokidar: 3.6.0
9490
  fast-glob: 3.3.2
9491
  magic-string: 0.30.14
9492
- vite: 5.4.11(@types/[email protected].1)([email protected])
9493
  transitivePeerDependencies:
9494
  - rollup
9495
  - supports-color
9496
 
9497
- '@vanilla-extract/babel-plugin-debug-ids@1.1.0':
9498
  dependencies:
9499
  '@babel/core': 7.26.0
9500
  transitivePeerDependencies:
9501
  - supports-color
9502
 
9503
- '@vanilla-extract/css@1.16.1':
9504
  dependencies:
9505
  '@emotion/hash': 0.9.2
9506
  '@vanilla-extract/private': 1.0.6
@@ -9517,21 +9643,21 @@ snapshots:
9517
  transitivePeerDependencies:
9518
  - babel-plugin-macros
9519
 
9520
- '@vanilla-extract/[email protected](@types/[email protected].1)([email protected])':
9521
  dependencies:
9522
  '@babel/core': 7.26.0
9523
  '@babel/plugin-syntax-typescript': 7.25.9(@babel/[email protected])
9524
- '@vanilla-extract/babel-plugin-debug-ids': 1.1.0
9525
- '@vanilla-extract/css': 1.16.1
9526
- esbuild: 0.17.19
9527
  eval: 0.1.8
9528
  find-up: 5.0.0
9529
  javascript-stringify: 2.1.0
9530
  lodash: 4.17.21
9531
- mlly: 1.7.3
9532
  outdent: 0.8.0
9533
- vite: 5.4.11(@types/[email protected].1)([email protected])
9534
- vite-node: 1.6.0(@types/[email protected].1)([email protected])
9535
  transitivePeerDependencies:
9536
  - '@types/node'
9537
  - babel-plugin-macros
@@ -9553,13 +9679,13 @@ snapshots:
9553
  chai: 5.1.2
9554
  tinyrainbow: 1.2.0
9555
 
9556
9557
  dependencies:
9558
  '@vitest/spy': 2.1.8
9559
  estree-walker: 3.0.3
9560
  magic-string: 0.30.14
9561
  optionalDependencies:
9562
- vite: 5.4.11(@types/[email protected].1)([email protected])
9563
 
9564
  '@vitest/[email protected]':
9565
  dependencies:
@@ -9861,6 +9987,11 @@ snapshots:
9861
  tar: 6.2.1
9862
  unique-filename: 3.0.0
9863
 
 
 
 
 
 
9864
9865
  dependencies:
9866
  es-define-property: 1.0.0
@@ -9869,6 +10000,11 @@ snapshots:
9869
  get-intrinsic: 1.2.4
9870
  set-function-length: 1.2.2
9871
 
 
 
 
 
 
9872
9873
 
9874
@@ -10088,6 +10224,10 @@ snapshots:
10088
  dependencies:
10089
  ms: 2.1.3
10090
 
 
 
 
 
10091
10092
  dependencies:
10093
  character-entities: 2.0.2
@@ -10168,6 +10308,12 @@ snapshots:
10168
 
10169
10170
 
 
 
 
 
 
 
10171
10172
 
10173
@@ -10219,10 +10365,18 @@ snapshots:
10219
  dependencies:
10220
  get-intrinsic: 1.2.4
10221
 
 
 
10222
10223
 
10224
10225
 
 
 
 
 
 
 
10226
10227
  dependencies:
10228
  '@jspm/core': 2.0.1
@@ -10341,27 +10495,27 @@ snapshots:
10341
 
10342
10343
 
10344
10345
  dependencies:
10346
- eslint: 9.16.0([email protected].6)
10347
  semver: 7.6.3
10348
 
10349
10350
  dependencies:
10351
- eslint: 9.16.0([email protected].6)
10352
 
10353
10354
  dependencies:
10355
- eslint: 9.16.0([email protected].6)
10356
  esquery: 1.6.0
10357
  jsonc-eslint-parser: 2.4.0
10358
 
10359
10360
  dependencies:
10361
- '@eslint-community/eslint-utils': 4.4.1([email protected]([email protected].6))
10362
- eslint: 9.16.0([email protected].6)
10363
- eslint-compat-utils: 0.6.4([email protected]([email protected].6))
10364
- eslint-json-compat-utils: 0.2.1([email protected]([email protected].6))([email protected])
10365
  espree: 9.6.1
10366
  graphemer: 1.4.0
10367
  jsonc-eslint-parser: 2.4.0
@@ -10370,15 +10524,15 @@ snapshots:
10370
  transitivePeerDependencies:
10371
  - '@eslint/json'
10372
 
10373
10374
  dependencies:
10375
- eslint: 9.16.0([email protected].6)
10376
  prettier: 3.4.1
10377
  prettier-linter-helpers: 1.0.0
10378
  synckit: 0.9.2
10379
  optionalDependencies:
10380
  '@types/eslint': 8.56.10
10381
- eslint-config-prettier: 9.1.0([email protected]([email protected].6))
10382
 
10383
10384
  dependencies:
@@ -10389,9 +10543,9 @@ snapshots:
10389
 
10390
10391
 
10392
10393
  dependencies:
10394
- '@eslint-community/eslint-utils': 4.4.1([email protected]([email protected].6))
10395
  '@eslint-community/regexpp': 4.12.1
10396
  '@eslint/config-array': 0.19.0
10397
  '@eslint/core': 0.9.0
@@ -10426,7 +10580,7 @@ snapshots:
10426
  natural-compare: 1.4.0
10427
  optionator: 0.9.4
10428
  optionalDependencies:
10429
- jiti: 1.21.6
10430
  transitivePeerDependencies:
10431
  - supports-color
10432
 
@@ -10497,7 +10651,7 @@ snapshots:
10497
 
10498
10499
  dependencies:
10500
- '@types/node': 22.10.1
10501
  require-like: 0.1.2
10502
 
10503
@@ -10529,7 +10683,7 @@ snapshots:
10529
 
10530
10531
 
10532
10533
  dependencies:
10534
  accepts: 1.3.8
10535
  array-flatten: 1.1.1
@@ -10550,7 +10704,7 @@ snapshots:
10550
  methods: 1.1.2
10551
  on-finished: 2.4.1
10552
  parseurl: 1.3.3
10553
- path-to-regexp: 0.1.10
10554
  proxy-addr: 2.0.7
10555
  qs: 6.13.0
10556
  range-parser: 1.2.1
@@ -10695,10 +10849,28 @@ snapshots:
10695
  has-symbols: 1.1.0
10696
  hasown: 2.0.2
10697
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10698
10699
 
10700
10701
 
 
 
 
 
 
10702
10703
  dependencies:
10704
  data-uri-to-buffer: 2.0.2
@@ -10741,6 +10913,8 @@ snapshots:
10741
  dependencies:
10742
  get-intrinsic: 1.2.4
10743
 
 
 
10744
10745
 
10746
@@ -10939,9 +11113,9 @@ snapshots:
10939
  dependencies:
10940
  safer-buffer: 2.1.2
10941
 
10942
- [email protected](postcss@8.4.49):
10943
  dependencies:
10944
- postcss: 8.4.49
10945
 
10946
10947
 
@@ -10964,7 +11138,7 @@ snapshots:
10964
  debug: 4.3.7
10965
  esbuild: 0.23.1
10966
  jiti: 2.0.0-beta.3
10967
- jiti-v1: [email protected].6
10968
  pathe: 1.1.2
10969
  tsx: 4.19.2
10970
  transitivePeerDependencies:
@@ -11017,6 +11191,10 @@ snapshots:
11017
  dependencies:
11018
  hasown: 2.0.2
11019
 
 
 
 
 
11020
11021
 
11022
@@ -11101,7 +11279,7 @@ snapshots:
11101
 
11102
11103
 
11104
11105
 
11106
11107
 
@@ -11172,7 +11350,7 @@ snapshots:
11172
  dependencies:
11173
  immediate: 3.0.6
11174
 
11175
11176
 
11177
11178
 
@@ -11228,6 +11406,8 @@ snapshots:
11228
 
11229
11230
 
 
 
11231
11232
  dependencies:
11233
  hash-base: 3.0.5
@@ -11374,7 +11554,7 @@ snapshots:
11374
  ccount: 2.0.1
11375
  mdast-util-from-markdown: 1.3.1
11376
  mdast-util-to-markdown: 1.5.0
11377
- parse-entities: 4.0.1
11378
  stringify-entities: 4.0.4
11379
  unist-util-remove-position: 4.0.2
11380
  unist-util-stringify-position: 3.0.3
@@ -11873,7 +12053,7 @@ snapshots:
11873
11874
  dependencies:
11875
  '@types/debug': 4.1.12
11876
- debug: 4.3.7
11877
  decode-named-character-reference: 1.0.2
11878
  micromark-core-commonmark: 1.1.0
11879
  micromark-factory-space: 1.1.0
@@ -12013,6 +12193,13 @@ snapshots:
12013
  pkg-types: 1.2.1
12014
  ufo: 1.5.4
12015
 
 
 
 
 
 
 
 
12016
12017
 
12018
@@ -12110,7 +12297,7 @@ snapshots:
12110
12111
  dependencies:
12112
  hosted-git-info: 6.1.3
12113
- is-core-module: 2.15.1
12114
  semver: 7.6.3
12115
  validate-npm-package-license: 3.0.4
12116
 
@@ -12259,6 +12446,16 @@ snapshots:
12259
  is-decimal: 2.0.1
12260
  is-hexadecimal: 2.0.1
12261
 
 
 
 
 
 
 
 
 
 
 
12262
12263
 
12264
@@ -12282,12 +12479,14 @@ snapshots:
12282
  lru-cache: 10.4.3
12283
  minipass: 7.1.2
12284
 
12285
12286
 
12287
12288
 
12289
12290
 
 
 
12291
12292
 
12293
@@ -12332,52 +12531,58 @@ snapshots:
12332
  mlly: 1.7.3
12333
  pathe: 1.1.2
12334
 
 
 
 
 
 
 
12335
12336
 
12337
12338
 
12339
- [email protected](postcss@8.4.49):
12340
  dependencies:
12341
- postcss: 8.4.49
12342
 
12343
- [email protected](postcss@8.4.49):
12344
  dependencies:
12345
- lilconfig: 3.1.2
12346
- yaml: 2.6.1
12347
  optionalDependencies:
12348
- postcss: 8.4.49
12349
 
12350
- [email protected](postcss@8.4.49):
12351
  dependencies:
12352
- postcss: 8.4.49
12353
 
12354
- postcss-modules-local-by-default@4.1.0(postcss@8.4.49):
12355
  dependencies:
12356
- icss-utils: 5.1.0(postcss@8.4.49)
12357
- postcss: 8.4.49
12358
  postcss-selector-parser: 7.0.0
12359
  postcss-value-parser: 4.2.0
12360
 
12361
- [email protected](postcss@8.4.49):
12362
  dependencies:
12363
- postcss: 8.4.49
12364
  postcss-selector-parser: 7.0.0
12365
 
12366
- [email protected](postcss@8.4.49):
12367
  dependencies:
12368
- icss-utils: 5.1.0(postcss@8.4.49)
12369
- postcss: 8.4.49
12370
 
12371
- [email protected](postcss@8.4.49):
12372
  dependencies:
12373
  generic-names: 4.0.0
12374
- icss-utils: 5.1.0(postcss@8.4.49)
12375
  lodash.camelcase: 4.3.0
12376
- postcss: 8.4.49
12377
- postcss-modules-extract-imports: 3.1.0(postcss@8.4.49)
12378
- postcss-modules-local-by-default: 4.1.0(postcss@8.4.49)
12379
- postcss-modules-scope: 3.2.1(postcss@8.4.49)
12380
- postcss-modules-values: 4.0.0(postcss@8.4.49)
12381
  string-hash: 1.1.3
12382
 
12383
@@ -12399,6 +12604,12 @@ snapshots:
12399
  picocolors: 1.1.1
12400
  source-map-js: 1.2.1
12401
 
 
 
 
 
 
 
12402
12403
 
12404
@@ -12466,7 +12677,7 @@ snapshots:
12466
 
12467
12468
  dependencies:
12469
- side-channel: 1.0.6
12470
 
12471
12472
  dependencies:
@@ -12503,7 +12714,7 @@ snapshots:
12503
  dependencies:
12504
  dnd-core: 16.0.1
12505
 
12506
12507
  dependencies:
12508
  '@react-dnd/invariant': 4.0.2
12509
  '@react-dnd/shallowequal': 4.0.2
@@ -12512,7 +12723,7 @@ snapshots:
12512
  hoist-non-react-statics: 3.3.2
12513
  react: 18.3.1
12514
  optionalDependencies:
12515
- '@types/node': 22.10.1
12516
  '@types/react': 18.3.12
12517
 
12518
@@ -12575,14 +12786,14 @@ snapshots:
12575
  react: 18.3.1
12576
  react-dom: 18.3.1([email protected])
12577
 
12578
12579
  dependencies:
12580
  '@remix-run/router': 1.21.0
12581
  react: 18.3.1
12582
  react-dom: 18.3.1([email protected])
12583
- react-router: 6.28.0([email protected])
12584
 
12585
12586
  dependencies:
12587
  '@remix-run/router': 1.21.0
12588
  react: 18.3.1
@@ -12725,20 +12936,20 @@ snapshots:
12725
  mdast-util-to-markdown: 2.1.2
12726
  unified: 11.0.5
12727
 
12728
12729
  dependencies:
12730
12731
  '@remix-run/server-runtime': 2.15.2([email protected])
12732
  react: 18.3.1
12733
  react-dom: 18.3.1([email protected])
12734
 
12735
12736
  dependencies:
12737
  type-fest: 4.30.0
12738
  optionalDependencies:
12739
- '@remix-run/cloudflare': 2.15.0(@cloudflare/[email protected])([email protected])
12740
  '@remix-run/node': 2.15.2([email protected])
12741
12742
  '@remix-run/router': 1.21.0
12743
  react: 18.3.1
12744
  zod: 3.23.8
@@ -13023,6 +13234,26 @@ snapshots:
13023
  '@shikijs/vscode-textmate': 9.3.0
13024
  '@types/hast': 3.0.4
13025
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13026
13027
  dependencies:
13028
  call-bind: 1.0.7
@@ -13030,6 +13261,14 @@ snapshots:
13030
  get-intrinsic: 1.2.4
13031
  object-inspect: 1.13.3
13032
 
 
 
 
 
 
 
 
 
13033
13034
 
13035
@@ -13073,16 +13312,16 @@ snapshots:
13073
13074
  dependencies:
13075
  spdx-expression-parse: 3.0.1
13076
- spdx-license-ids: 3.0.20
13077
 
13078
13079
 
13080
13081
  dependencies:
13082
  spdx-exceptions: 2.5.0
13083
- spdx-license-ids: 3.0.20
13084
 
13085
13086
 
13087
13088
  dependencies:
@@ -13214,7 +13453,7 @@ snapshots:
13214
 
13215
13216
 
13217
13218
  dependencies:
13219
  chownr: 1.1.4
13220
  mkdirp-classic: 0.5.3
@@ -13315,12 +13554,12 @@ snapshots:
13315
  media-typer: 0.3.0
13316
  mime-types: 2.1.35
13317
 
13318
13319
  dependencies:
13320
13321
- '@typescript-eslint/parser': 8.17.0([email protected]([email protected].6))([email protected])
13322
- '@typescript-eslint/utils': 8.17.0([email protected]([email protected].6))([email protected])
13323
- eslint: 9.16.0([email protected].6)
13324
  optionalDependencies:
13325
  typescript: 5.7.2
13326
  transitivePeerDependencies:
@@ -13442,13 +13681,13 @@ snapshots:
13442
 
13443
13444
 
13445
13446
  dependencies:
13447
13448
  '@unocss/cli': 0.61.9([email protected])
13449
  '@unocss/core': 0.61.9
13450
  '@unocss/extractor-arbitrary-variants': 0.61.9
13451
- '@unocss/postcss': 0.61.9(postcss@8.4.49)
13452
  '@unocss/preset-attributify': 0.61.9
13453
  '@unocss/preset-icons': 0.61.9
13454
  '@unocss/preset-mini': 0.61.9
@@ -13463,9 +13702,9 @@ snapshots:
13463
  '@unocss/transformer-compile-class': 0.61.9
13464
  '@unocss/transformer-directives': 0.61.9
13465
  '@unocss/transformer-variant-group': 0.61.9
13466
13467
  optionalDependencies:
13468
- vite: 5.4.11(@types/[email protected].1)([email protected])
13469
  transitivePeerDependencies:
13470
  - postcss
13471
  - rollup
@@ -13572,13 +13811,13 @@ snapshots:
13572
  '@types/unist': 3.0.3
13573
  vfile-message: 4.0.2
13574
 
13575
13576
  dependencies:
13577
  cac: 6.7.14
13578
- debug: 4.3.7
13579
  pathe: 1.1.2
13580
  picocolors: 1.1.1
13581
- vite: 5.4.11(@types/[email protected].1)([email protected])
13582
  transitivePeerDependencies:
13583
  - '@types/node'
13584
  - less
@@ -13590,13 +13829,13 @@ snapshots:
13590
  - supports-color
13591
  - terser
13592
 
13593
13594
  dependencies:
13595
  cac: 6.7.14
13596
  debug: 4.3.7
13597
  es-module-lexer: 1.5.4
13598
  pathe: 1.1.2
13599
- vite: 5.4.11(@types/[email protected].1)([email protected])
13600
  transitivePeerDependencies:
13601
  - '@types/node'
13602
  - less
@@ -13608,43 +13847,43 @@ snapshots:
13608
  - supports-color
13609
  - terser
13610
 
13611
13612
  dependencies:
13613
  '@rollup/plugin-inject': 5.0.5([email protected])
13614
  node-stdlib-browser: 1.3.0
13615
- vite: 5.4.11(@types/[email protected].1)([email protected])
13616
  transitivePeerDependencies:
13617
  - rollup
13618
 
13619
13620
  dependencies:
13621
- vite: 5.4.11(@types/[email protected].1)([email protected])
13622
 
13623
13624
  dependencies:
13625
  debug: 4.3.7
13626
  globrex: 0.1.2
13627
  tsconfck: 3.1.4([email protected])
13628
  optionalDependencies:
13629
- vite: 5.4.11(@types/[email protected].1)([email protected])
13630
  transitivePeerDependencies:
13631
  - supports-color
13632
  - typescript
13633
 
13634
13635
  dependencies:
13636
  esbuild: 0.21.5
13637
  postcss: 8.4.49
13638
  rollup: 4.28.0
13639
  optionalDependencies:
13640
- '@types/node': 22.10.1
13641
  fsevents: 2.3.3
13642
  sass-embedded: 1.81.0
13643
 
13644
13645
  dependencies:
13646
  '@vitest/expect': 2.1.8
13647
- '@vitest/mocker': 2.1.8([email protected](@types/[email protected].1)([email protected]))
13648
  '@vitest/pretty-format': 2.1.8
13649
  '@vitest/runner': 2.1.8
13650
  '@vitest/snapshot': 2.1.8
@@ -13660,11 +13899,11 @@ snapshots:
13660
  tinyexec: 0.3.1
13661
  tinypool: 1.0.2
13662
  tinyrainbow: 1.2.0
13663
- vite: 5.4.11(@types/[email protected].1)([email protected])
13664
- vite-node: 2.1.8(@types/[email protected].1)([email protected])
13665
  why-is-node-running: 2.3.0
13666
  optionalDependencies:
13667
- '@types/node': 22.10.1
13668
  transitivePeerDependencies:
13669
  - less
13670
  - lightningcss
@@ -13780,7 +14019,7 @@ snapshots:
13780
 
13781
13782
 
13783
- yaml@2.6.1: {}
13784
 
13785
13786
 
 
98
  '@openrouter/ai-sdk-provider':
99
  specifier: ^0.0.5
100
  version: 0.0.5([email protected])
101
+ '@phosphor-icons/react':
102
+ specifier: ^2.1.7
103
104
  '@radix-ui/react-context-menu':
105
  specifier: ^2.2.2
106
 
120
  specifier: ^1.1.4
121
122
  '@remix-run/cloudflare':
123
+ specifier: ^2.15.2
124
+ version: 2.15.2(@cloudflare/[email protected])([email protected])
125
  '@remix-run/cloudflare-pages':
126
+ specifier: ^2.15.2
127
+ version: 2.15.2(@cloudflare/[email protected])([email protected])
128
  '@remix-run/node':
129
  specifier: ^2.15.2
130
  version: 2.15.2([email protected])
131
  '@remix-run/react':
132
+ specifier: ^2.15.2
133
134
  '@uiw/codemirror-theme-vscode':
135
  specifier: ^4.23.6
136
  version: 4.23.6(@codemirror/[email protected])(@codemirror/[email protected])(@codemirror/[email protected])
 
214
215
  react-dnd:
216
  specifier: ^16.0.1
217
+ version: 16.0.1(@types/[email protected].10)(@types/[email protected])([email protected])
218
  react-dnd-html5-backend:
219
  specifier: ^16.0.1
220
  version: 16.0.1
 
247
  version: 4.0.0
248
  remix-island:
249
  specifier: ^0.2.0
250
251
  remix-utils:
252
  specifier: ^7.7.0
253
254
  shiki:
255
  specifier: ^1.24.0
256
  version: 1.24.0
 
263
  devDependencies:
264
  '@blitz/eslint-plugin':
265
  specifier: 0.1.0
266
267
  '@cloudflare/workers-types':
268
  specifier: ^4.20241127.0
269
  version: 4.20241127.0
 
274
  specifier: ^2.0.0
275
  version: 2.0.0
276
  '@remix-run/dev':
277
+ specifier: ^2.15.2
278
279
  '@types/diff':
280
  specifier: ^5.2.3
281
  version: 5.2.3
 
323
  version: 11.0.5
324
  unocss:
325
  specifier: ^0.61.9
326
+ version: 0.61.9(postcss@8.5.1)([email protected])([email protected](@types/[email protected].10)([email protected]))
327
  vite:
328
  specifier: ^5.4.11
329
+ version: 5.4.11(@types/[email protected].10)([email protected])
330
  vite-plugin-node-polyfills:
331
  specifier: ^0.22.0
332
333
  vite-plugin-optimize-css-modules:
334
  specifier: ^1.1.0
335
336
  vite-tsconfig-paths:
337
  specifier: ^4.3.2
338
339
  vitest:
340
  specifier: ^2.1.7
341
+ version: 2.1.8(@types/[email protected].10)([email protected])
342
  wrangler:
343
  specifier: ^3.91.0
344
  version: 3.91.0(@cloudflare/[email protected])
 
630
  resolution: {integrity: sha512-zevQbhbau95nkoxSq3f/DC/SC+EEOUZd3DYqfSkMhY2/wfSeaHV1Ew4vk8e+x8lja31IbyuUa2uQ3JONqKbysw==}
631
  engines: {node: '>=6.9.0'}
632
 
633
+ '@babel/[email protected]':
634
+ resolution: {integrity: sha512-2caSP6fN9I7HOe6nqhtft7V4g7/V/gfDsC3Ag4W7kEzzvRGKqiv0pu0HogPiZ3KaVSoNDhUws6IJjDjpfmYIXw==}
635
+ engines: {node: '>=6.9.0'}
636
+
637
  '@babel/[email protected]':
638
  resolution: {integrity: sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==}
639
  engines: {node: '>=6.9.0'}
 
670
  resolution: {integrity: sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==}
671
  engines: {node: '>=6.9.0'}
672
 
673
+ '@babel/[email protected]':
674
+ resolution: {integrity: sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==}
675
+ engines: {node: '>=6.9.0'}
676
+
677
  '@babel/[email protected]':
678
  resolution: {integrity: sha512-IiDqTOTBQy0sWyeXyGSC5TBJpGFXBkRynjBeXsvbhQFKj2viwJC76Epz35YLU1fpe/Am6Vppb7W7zM4fPQzLsQ==}
679
  engines: {node: '>=6.9.0'}
 
709
  engines: {node: '>=6.0.0'}
710
  hasBin: true
711
 
712
+ '@babel/[email protected]':
713
+ resolution: {integrity: sha512-SRJ4jYmXRqV1/Xc+TIVG84WjHBXKlxO9sHQnA2Pf12QQEAp1LOh6kDzNHXcUnbH1QI0FDoPPVOt+vyUDucxpaw==}
714
+ engines: {node: '>=6.0.0'}
715
+ hasBin: true
716
+
717
  '@babel/[email protected]':
718
  resolution: {integrity: sha512-ryzI0McXUPJnRCvMo4lumIKZUzhYUO/ScI+Mz4YVaTLt04DHNSjEUjKVvbzQjZFLuod/cYEc07mJWhzl6v4DPg==}
719
  engines: {node: '>=6.9.0'}
 
762
  resolution: {integrity: sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==}
763
  engines: {node: '>=6.9.0'}
764
 
765
+ '@babel/[email protected]':
766
+ resolution: {integrity: sha512-rkOSPOw+AXbgtwUga3U4u8RpoK9FEFWBNAlTpcnkLFjL5CT+oyHNuUUC/xx6XefEJ16r38r8Bc/lfp6rYuHeJQ==}
767
+ engines: {node: '>=6.9.0'}
768
+
769
  '@babel/[email protected]':
770
  resolution: {integrity: sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==}
771
  engines: {node: '>=6.9.0'}
772
 
773
+ '@babel/[email protected]':
774
+ resolution: {integrity: sha512-L6mZmwFDK6Cjh1nRCLXpa6no13ZIioJDz7mdkzHv399pThrTa/k0nUlNaenOeh2kWu/iaOQYElEpKPUswUa9Vg==}
775
+ engines: {node: '>=6.9.0'}
776
+
777
  '@blitz/[email protected]':
778
  resolution: {integrity: sha512-mGEAFWCI5AQ4nrePhjp2WzvRen+UWR+SF4MvH70icIBClR08Gm3dT9MRa2jszOpfY00NyIYfm7/1CFZ37GvW4g==}
779
  engines: {node: ^18.0.0 || ^20.0.0}
 
1658
  resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==}
1659
  engines: {node: '>=6.0.0'}
1660
 
1661
+ '@jridgewell/[email protected]':
1662
+ resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==}
1663
+ engines: {node: '>=6.0.0'}
1664
+
1665
  '@jridgewell/[email protected]':
1666
  resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
1667
  engines: {node: '>=6.0.0'}
 
1869
  resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==}
1870
  engines: {node: '>=8.0.0'}
1871
 
1872
+ '@phosphor-icons/[email protected]':
1873
+ resolution: {integrity: sha512-g2e2eVAn1XG2a+LI09QU3IORLhnFNAFkNbo2iwbX6NOKSLOwvEMmTa7CgOzEbgNWR47z8i8kwjdvYZ5fkGx1mQ==}
1874
+ engines: {node: '>=10'}
1875
+ peerDependencies:
1876
+ react: '>= 16.8'
1877
+ react-dom: '>= 16.8'
1878
+
1879
  '@pkgjs/[email protected]':
1880
  resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
1881
  engines: {node: '>=14'}
 
2283
  peerDependencies:
2284
  react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1
2285
 
2286
+ '@remix-run/[email protected].2':
2287
+ resolution: {integrity: sha512-gjq20Hs3tWwhhrIXu18hSXDyjWiJXopZUQVbT35uULy/ACEnEbhO1DnVGJzov7NdeMHI4x0O4O0rWg6ZXLtD/Q==}
2288
  engines: {node: '>=18.0.0'}
2289
  peerDependencies:
2290
  '@cloudflare/workers-types': ^4.0.0
 
2293
  typescript:
2294
  optional: true
2295
 
2296
+ '@remix-run/[email protected].2':
2297
+ resolution: {integrity: sha512-6D/WTx3IbQYCWQ/BVNRItXI2upgDvkcCVYwZhvIctF4o+5+IaF21ZA1HTekQEnBfmYTpffJ3Jko1sCkqoMeOdw==}
2298
  engines: {node: '>=18.0.0'}
2299
  peerDependencies:
2300
  '@cloudflare/workers-types': ^4.0.0
 
2303
  typescript:
2304
  optional: true
2305
 
2306
+ '@remix-run/[email protected].2':
2307
+ resolution: {integrity: sha512-o8lix8t4GBhtXjo/G1IzwtHVW5GRMs7amtFtBHiR1bhSyK7VyX5qGtTDmJyny5QDv83pxaLOCiE0dUng2BCoyQ==}
2308
  engines: {node: '>=18.0.0'}
2309
  hasBin: true
2310
  peerDependencies:
2311
+ '@remix-run/react': ^2.15.2
2312
+ '@remix-run/serve': ^2.15.2
2313
  typescript: ^5.1.0
2314
  vite: ^5.1.0
2315
  wrangler: ^3.28.2
 
2323
  wrangler:
2324
  optional: true
2325
 
 
 
 
 
 
 
 
 
 
2326
  '@remix-run/[email protected]':
2327
  resolution: {integrity: sha512-NS/h5uxje7DYCNgcKqKAiUhf0r2HVnoYUBWLyIIMmCUP1ddWurBP6xTPcWzGhEvV/EvguniYi1wJZ5+X8sonWw==}
2328
  engines: {node: '>=18.0.0'}
 
2332
  typescript:
2333
  optional: true
2334
 
2335
+ '@remix-run/[email protected].2':
2336
+ resolution: {integrity: sha512-NAAMsSgoC/sdOgovUewwRCE/RUm3F+MBxxZKfwu3POCNeHaplY5qGkH/y8PUXvdN1EBG7Z0Ko43dyzCfcEy5PA==}
2337
  engines: {node: '>=18.0.0'}
2338
  peerDependencies:
2339
  react: ^18.0.0
 
2347
  resolution: {integrity: sha512-xfSkCAchbdG5PnbrKqFWwia4Bi61nH+wm8wLEqfHDyp7Y3dZzgqS2itV8i4gAq9pC2HsTpwyBC6Ds8VHZ96JlA==}
2348
  engines: {node: '>=14.0.0'}
2349
 
 
 
 
 
 
 
 
 
 
2350
  '@remix-run/[email protected]':
2351
  resolution: {integrity: sha512-OqiPcvEnnU88B8b1LIWHHkQ3Tz2GDAmQ1RihFNQsbrFKpDsQLkw0lJlnfgKA/uHd0CEEacpfV7C9qqJT3V6Z2g==}
2352
  engines: {node: '>=18.0.0'}
 
2759
  '@types/[email protected]':
2760
  resolution: {integrity: sha512-qKgsUwfHZV2WCWLAnVP1JqnpE6Im6h3Y0+fYgMTasNQ7V++CBX5OT1as0g0f+OyubbFqhf6XVNIsmN4IIhEgGQ==}
2761
 
2762
+ '@types/[email protected]':
2763
+ resolution: {integrity: sha512-X47y/mPNzxviAGY5TcYPtYL8JsY3kAq2n8fMmKoRCxq/c4v4pyGNCzM2R6+M5/umG4ZfHuT+sgqDYqWc9rJ6ww==}
2764
+
2765
  '@types/[email protected]':
2766
  resolution: {integrity: sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==}
2767
 
 
2941
  peerDependencies:
2942
  vite: ^2.9.0 || ^3.0.0-0 || ^4.0.0 || ^5.0.0-0
2943
 
2944
+ '@vanilla-extract/babel-plugin-debug-ids@1.2.0':
2945
+ resolution: {integrity: sha512-z5nx2QBnOhvmlmBKeRX5sPVLz437wV30u+GJL+Hzj1rGiJYVNvgIIlzUpRNjVQ0MgAgiQIqIUbqPnmMc6HmDlQ==}
2946
 
2947
+ '@vanilla-extract/css@1.17.0':
2948
+ resolution: {integrity: sha512-W6FqVFDD+C71ZlKsuj0MxOXSvHb1tvQ9h/+79aYfi097wLsALrnnBzd0by8C///iurrpQ3S+SH74lXd7Lr9MvA==}
2949
 
2950
  '@vanilla-extract/[email protected]':
2951
  resolution: {integrity: sha512-E2YcfO8vA+vs+ua+gpvy1HRqvgWbI+MTlUpxA8FvatOvybuNcWAY0CKwQ/Gpj7rswYKtC6C7+xw33emM6/ImdQ==}
 
3222
  resolution: {integrity: sha512-/aJwG2l3ZMJ1xNAnqbMpA40of9dj/pIH3QfiuQSqjfPJF747VR0J/bHn+/KdNnHKc6XQcWt/AfRSBft82W1d2A==}
3223
  engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
3224
 
3225
3226
+ resolution: {integrity: sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==}
3227
+ engines: {node: '>= 0.4'}
3228
+
3229
3230
  resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==}
3231
  engines: {node: '>= 0.4'}
3232
 
3233
3234
+ resolution: {integrity: sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==}
3235
+ engines: {node: '>= 0.4'}
3236
+
3237
3238
  resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
3239
  engines: {node: '>=6'}
 
3482
  supports-color:
3483
  optional: true
3484
 
3485
3486
+ resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==}
3487
+ engines: {node: '>=6.0'}
3488
+ peerDependencies:
3489
+ supports-color: '*'
3490
+ peerDependenciesMeta:
3491
+ supports-color:
3492
+ optional: true
3493
+
3494
3495
  resolution: {integrity: sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==}
3496
 
 
3586
  resolution: {integrity: sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==}
3587
  engines: {node: '>=12'}
3588
 
3589
3590
+ resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
3591
+ engines: {node: '>= 0.4'}
3592
+
3593
3594
  resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==}
3595
 
 
3643
  resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==}
3644
  engines: {node: '>= 0.4'}
3645
 
3646
3647
+ resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==}
3648
+ engines: {node: '>= 0.4'}
3649
+
3650
3651
  resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
3652
  engines: {node: '>= 0.4'}
 
3654
3655
  resolution: {integrity: sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==}
3656
 
3657
3658
+ resolution: {integrity: sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==}
3659
+
3660
3661
+ resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==}
3662
+ engines: {node: '>= 0.4'}
3663
+
3664
3665
  resolution: {integrity: sha512-bRB4qbgUDWrdY1eMk123KiaCSW9VzQ+QLZrmU7D//cCFkmksPd9mUMpmWoFK/rxjIeTfTSOpKCoGoimlvI+AWw==}
3666
  engines: {node: '>=14.0.0'}
 
3864
  resolution: {integrity: sha512-bFi65yM+xZgk+u/KRIpekdSYkTB5W1pEf0Lt8Q8Msh7b+eQ7LXVtIB1Bkm4fvclDEL1b2CZkMhv2mOeF8tMdkA==}
3865
  engines: {node: '>=12.0.0'}
3866
 
3867
3868
+ resolution: {integrity: sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==}
3869
  engines: {node: '>= 0.10.0'}
3870
 
3871
 
3998
  resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==}
3999
  engines: {node: '>= 0.4'}
4000
 
4001
4002
+ resolution: {integrity: sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==}
4003
+ engines: {node: '>= 0.4'}
4004
+
4005
4006
  resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==}
4007
  engines: {node: '>=6'}
 
4010
  resolution: {integrity: sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==}
4011
  engines: {node: '>=8'}
4012
 
4013
4014
+ resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==}
4015
+ engines: {node: '>= 0.4'}
4016
+
4017
4018
  resolution: {integrity: sha512-X5+4+iD+HoSeEED+uwrQ07BOQr0kEDFMVqqpBuI+RaZBpBpHCuXxo70bjar6f0b0u/DQJsJ7ssurpP0V60Az+w==}
4019
 
 
4058
  resolution: {integrity: sha512-FQoVQnqcdk4hVM4JN1eromaun4iuS34oStkdlLENLdpULsuQcTyXj8w7ayhuUfPwEYZ1ZOooOTT6fdA9Vmx/RA==}
4059
  engines: {node: '>= 0.4'}
4060
 
4061
4062
+ resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==}
4063
+ engines: {node: '>= 0.4'}
4064
+
4065
4066
  resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
4067
 
 
4262
  resolution: {integrity: sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==}
4263
  engines: {node: '>= 0.4'}
4264
 
4265
4266
+ resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==}
4267
+ engines: {node: '>= 0.4'}
4268
+
4269
4270
  resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==}
4271
 
 
4362
4363
  resolution: {integrity: sha512-JVAfqNPTvNq3sB/VHQJAFxN/sPgKnsKrCwyRt15zwNCdrMMJDdcEOdubuy+DuJYYdm0ox1J4uzEuYKkN+9yhVg==}
4364
 
4365
4366
+ resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==}
4367
  hasBin: true
4368
 
4369
 
4442
4443
  resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==}
4444
 
4445
4446
+ resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==}
4447
  engines: {node: '>=14'}
4448
 
4449
 
4511
4512
  resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==}
4513
 
4514
4515
+ resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
4516
+ engines: {node: '>= 0.4'}
4517
+
4518
4519
  resolution: {integrity: sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==}
4520
 
 
4893
4894
  resolution: {integrity: sha512-xUsx5n/mN0uQf4V548PKQ+YShA4/IW0KI1dZhrNrPCLG+xizETbHTkOa1f8/xut9JRPp8kQuMnz0oqwkTiLo/A==}
4895
 
4896
4897
+ resolution: {integrity: sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==}
4898
+
4899
4900
  resolution: {integrity: sha512-sEKPVl2rM+MNVkGQt3ChdmD8YsigmXdn5NifZn6jiwn9LRJpWm8F3guhaqrJT/JOat6pwpbXEk6kv+b9DMIjsQ==}
4901
 
 
5107
5108
  resolution: {integrity: sha512-SWzvYcSJh4d/SGLIOQfZ/CoNv6BTlI6YEQ7Nj82oDVnRpwe/Z/F1EMx42x3JAOwGBlCjeCH0BRJQbQ/opHL17w==}
5109
 
5110
5111
+ resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==}
5112
+
5113
5114
  resolution: {integrity: sha512-kHt7kzLoS9VBZfUsiKjv43mr91ea+U05EyKkEtqp7vNbHxmaVuEqN7XxeEVnGrMtYOAxGrDElSi96K7EgO1zCA==}
5115
  engines: {node: '>=6'}
 
5142
  resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==}
5143
  engines: {node: '>=16 || 14 >=14.18'}
5144
 
5145
5146
+ resolution: {integrity: sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==}
5147
 
5148
5149
  resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==}
 
5151
5152
  resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==}
5153
 
5154
5155
+ resolution: {integrity: sha512-15Ztpk+nov8DR524R4BF7uEuzESgzUEAV4Ah7CUMNGXdE5ELuvxElxGXndBl32vMSsWa1jpNf22Z+Er3sKwq+w==}
5156
+
5157
5158
  resolution: {integrity: sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==}
5159
  engines: {node: '>= 14.16'}
 
5198
5199
  resolution: {integrity: sha512-sQoqa8alT3nHjGuTjuKgOnvjo4cljkufdtLMnO2LBP/wRwuDlo1tkaEdMxCRhyGRPacv/ztlZgDPm2b7FAmEvw==}
5200
 
5201
5202
+ resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==}
5203
+
5204
5205
  resolution: {integrity: sha512-yBgLP75OS8oCyUI0cXiWtVKXQKbLrfGfp4JUJwQD6i8n1OHUagig9WyJtj3I6/0+5TMm2nICc3lOYgD88NGEqw==}
5206
  engines: {node: '>=18.12'}
 
5234
  peerDependencies:
5235
  postcss: ^8.1.0
5236
 
5237
+ postcss-modules-local-by-default@4.2.0:
5238
+ resolution: {integrity: sha512-5kcJm/zk+GJDSfw+V/42fJ5fhjL5YbFDl8nVdXkJPLLW+Vf9mTD5Xe0wqIaDnLuL2U6cDNpTr+UQ+v2HWIBhzw==}
5239
  engines: {node: ^10 || ^12 || >= 14}
5240
  peerDependencies:
5241
  postcss: ^8.1.0
 
5272
  resolution: {integrity: sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==}
5273
  engines: {node: ^10 || ^12 || >=14}
5274
 
5275
5276
+ resolution: {integrity: sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ==}
5277
+ engines: {node: ^10 || ^12 || >=14}
5278
+
5279
5280
  resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
5281
  engines: {node: '>= 0.8.0'}
 
5458
  react: ^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc
5459
  react-dom: ^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc
5460
 
5461
5462
+ resolution: {integrity: sha512-YraE27C/RdjcZwl5UCqF/ffXnZDxpJdk9Q6jw38SZHjXs7NNdpViq2l2c7fO7+4uWaEfcwfGCv3RSg4e1By/fQ==}
5463
  engines: {node: '>=14.0.0'}
5464
  peerDependencies:
5465
  react: '>=16.8'
5466
  react-dom: '>=16.8'
5467
 
5468
5469
+ resolution: {integrity: sha512-2omQTA3rkMljmrvvo6WtewGdVh45SpL9hGiCI9uUrwGGfNFDIvGK4gYJsKlJoNVi6AQZcopSCballL+QGOm7fA==}
5470
  engines: {node: '>=14.0.0'}
5471
  peerDependencies:
5472
  react: '>=16.8'
 
5847
5848
  resolution: {integrity: sha512-qIneep7QRwxRd5oiHb8jaRzH15V/S8F3saCXOdjwRLgozZJr5x2yeBhQtqkO3FSzQDwYEFAYuifg4oHjpDghrg==}
5849
 
5850
5851
+ resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==}
5852
+ engines: {node: '>= 0.4'}
5853
+
5854
5855
+ resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==}
5856
+ engines: {node: '>= 0.4'}
5857
+
5858
5859
+ resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==}
5860
+ engines: {node: '>= 0.4'}
5861
+
5862
5863
  resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==}
5864
  engines: {node: '>= 0.4'}
5865
 
5866
5867
+ resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==}
5868
+ engines: {node: '>= 0.4'}
5869
+
5870
5871
  resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==}
5872
 
 
5921
5922
  resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==}
5923
 
5924
5925
+ resolution: {integrity: sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg==}
5926
 
5927
5928
  resolution: {integrity: sha512-MGrFH9Z4NP9Iyhqn16sDtBpRRNJ0Y2hNa6D65h736fVSaPCHr4DM4sWUNvVaSuC+0OBGhwsrydQwmgfg5LncqQ==}
 
6065
6066
  resolution: {integrity: sha512-P+Vu1qXfzediirmHOC3xKGAYeZtPcV9g76X+xg2FD4tYgR71ewMA35Y3sCz3zhiN/dwefRpJX0yBcgwi1fXNQA==}
6067
 
6068
6069
+ resolution: {integrity: sha512-EsaAXwxmx8UB7FRKqeozqEPop69DXcmYwTQwXvyAPF352HJsPdkVhvTaDPYqfNgruveJIJy3TA2l+2zj8LJIJA==}
6070
 
6071
6072
  resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==}
 
6574
6575
  resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
6576
 
6577
+ yaml@2.7.0:
6578
+ resolution: {integrity: sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==}
6579
  engines: {node: '>= 14'}
6580
  hasBin: true
6581
 
 
7184
  '@jridgewell/trace-mapping': 0.3.25
7185
  jsesc: 3.0.2
7186
 
7187
+ '@babel/[email protected]':
7188
+ dependencies:
7189
+ '@babel/parser': 7.26.5
7190
+ '@babel/types': 7.26.5
7191
+ '@jridgewell/gen-mapping': 0.3.8
7192
+ '@jridgewell/trace-mapping': 0.3.25
7193
+ jsesc: 3.0.2
7194
+
7195
  '@babel/[email protected]':
7196
  dependencies:
7197
  '@babel/types': 7.26.0
 
7246
 
7247
  '@babel/[email protected]': {}
7248
 
7249
+ '@babel/[email protected]': {}
7250
+
7251
  '@babel/[email protected](@babel/[email protected])':
7252
  dependencies:
7253
  '@babel/core': 7.26.0
 
7286
  dependencies:
7287
  '@babel/types': 7.26.0
7288
 
7289
+ '@babel/[email protected]':
7290
+ dependencies:
7291
+ '@babel/types': 7.26.5
7292
+
7293
  '@babel/[email protected](@babel/[email protected])':
7294
  dependencies:
7295
  '@babel/core': 7.26.0
7296
+ '@babel/helper-plugin-utils': 7.26.5
7297
 
7298
  '@babel/[email protected](@babel/[email protected])':
7299
  dependencies:
 
7358
  transitivePeerDependencies:
7359
  - supports-color
7360
 
7361
+ '@babel/[email protected]':
7362
+ dependencies:
7363
+ '@babel/code-frame': 7.26.2
7364
+ '@babel/generator': 7.26.5
7365
+ '@babel/parser': 7.26.5
7366
+ '@babel/template': 7.25.9
7367
+ '@babel/types': 7.26.5
7368
+ debug: 4.4.0
7369
+ globals: 11.12.0
7370
+ transitivePeerDependencies:
7371
+ - supports-color
7372
+
7373
  '@babel/[email protected]':
7374
  dependencies:
7375
  '@babel/helper-string-parser': 7.25.9
7376
  '@babel/helper-validator-identifier': 7.25.9
7377
 
7378
+ '@babel/types@7.26.5':
7379
  dependencies:
7380
+ '@babel/helper-string-parser': 7.25.9
7381
+ '@babel/helper-validator-identifier': 7.25.9
7382
+
7383
+ '@blitz/eslint-plugin@0.1.0(@types/eslint@8.56.10)([email protected].7)([email protected])([email protected])':
7384
+ dependencies:
7385
+ '@stylistic/eslint-plugin-ts': 2.11.0([email protected]([email protected]))([email protected])
7386
7387
+ '@typescript-eslint/parser': 8.17.0([email protected]([email protected]))([email protected])
7388
+ '@typescript-eslint/utils': 8.17.0([email protected]([email protected]))([email protected])
7389
  common-tags: 1.8.2
7390
+ eslint: 9.16.0([email protected].7)
7391
+ eslint-config-prettier: 9.1.0([email protected]([email protected].7))
7392
+ eslint-plugin-jsonc: 2.18.2([email protected]([email protected].7))
7393
7394
  globals: 15.13.0
7395
+ typescript-eslint: 8.17.0([email protected]([email protected].7))([email protected])
7396
  transitivePeerDependencies:
7397
  - '@eslint/json'
7398
  - '@types/eslint'
 
7858
  '@esbuild/[email protected]':
7859
  optional: true
7860
 
7861
7862
  dependencies:
7863
+ eslint: 9.16.0([email protected].7)
7864
  eslint-visitor-keys: 3.4.3
7865
 
7866
  '@eslint-community/[email protected]': {}
 
8058
  '@jridgewell/sourcemap-codec': 1.5.0
8059
  '@jridgewell/trace-mapping': 0.3.25
8060
 
8061
+ '@jridgewell/[email protected]':
8062
+ dependencies:
8063
+ '@jridgewell/set-array': 1.2.1
8064
+ '@jridgewell/sourcemap-codec': 1.5.0
8065
+ '@jridgewell/trace-mapping': 0.3.25
8066
+
8067
  '@jridgewell/[email protected]': {}
8068
 
8069
  '@jridgewell/[email protected]': {}
 
8308
 
8309
  '@opentelemetry/[email protected]': {}
8310
 
8311
8312
+ dependencies:
8313
+ react: 18.3.1
8314
+ react-dom: 18.3.1([email protected])
8315
+
8316
  '@pkgjs/[email protected]':
8317
  optional: true
8318
 
 
8702
  dependencies:
8703
  react: 18.3.1
8704
 
8705
+ '@remix-run/[email protected].2(@cloudflare/[email protected])([email protected])':
8706
  dependencies:
8707
  '@cloudflare/workers-types': 4.20241127.0
8708
+ '@remix-run/cloudflare': 2.15.2(@cloudflare/[email protected])([email protected])
8709
  optionalDependencies:
8710
  typescript: 5.7.2
8711
 
8712
+ '@remix-run/[email protected].2(@cloudflare/[email protected])([email protected])':
8713
  dependencies:
8714
  '@cloudflare/kv-asset-handler': 0.1.3
8715
  '@cloudflare/workers-types': 4.20241127.0
8716
+ '@remix-run/server-runtime': 2.15.2([email protected])
8717
  optionalDependencies:
8718
  typescript: 5.7.2
8719
 
8720
8721
  dependencies:
8722
  '@babel/core': 7.26.0
8723
+ '@babel/generator': 7.26.5
8724
+ '@babel/parser': 7.26.5
8725
  '@babel/plugin-syntax-decorators': 7.25.9(@babel/[email protected])
8726
  '@babel/plugin-syntax-jsx': 7.25.9(@babel/[email protected])
8727
  '@babel/preset-typescript': 7.26.0(@babel/[email protected])
8728
+ '@babel/traverse': 7.26.5
8729
+ '@babel/types': 7.26.5
8730
  '@mdx-js/mdx': 2.3.0
8731
  '@npmcli/package-json': 4.0.1
8732
+ '@remix-run/node': 2.15.2([email protected])
8733
8734
  '@remix-run/router': 1.21.0
8735
+ '@remix-run/server-runtime': 2.15.2([email protected])
8736
  '@types/mdx': 2.0.13
8737
+ '@vanilla-extract/integration': 6.5.0(@types/[email protected].10)([email protected])
8738
  arg: 5.0.2
8739
  cacache: 17.1.4
8740
  chalk: 4.1.2
8741
  chokidar: 3.6.0
8742
  cross-spawn: 7.0.6
8743
  dotenv: 16.4.7
8744
+ es-module-lexer: 1.6.0
8745
  esbuild: 0.17.6
8746
  esbuild-plugins-node-modules-polyfill: 1.6.8([email protected])
8747
  execa: 5.1.1
8748
  exit-hook: 2.2.1
8749
+ express: 4.21.2
8750
  fs-extra: 10.1.0
8751
  get-port: 5.1.1
8752
  gunzip-maybe: 1.4.2
 
8759
  picocolors: 1.1.1
8760
  picomatch: 2.3.1
8761
  pidtree: 0.6.0
8762
+ postcss: 8.5.1
8763
+ postcss-discard-duplicates: 5.1.0(postcss@8.5.1)
8764
+ postcss-load-config: 4.0.2(postcss@8.5.1)
8765
+ postcss-modules: 6.0.1(postcss@8.5.1)
8766
  prettier: 2.8.8
8767
  pretty-ms: 7.0.1
8768
  react-refresh: 0.14.2
 
8770
  remark-mdx-frontmatter: 1.1.1
8771
  semver: 7.6.3
8772
  set-cookie-parser: 2.7.1
8773
+ tar-fs: 2.1.2
8774
  tsconfig-paths: 4.2.0
8775
  valibot: 0.41.0([email protected])
8776
+ vite-node: 1.6.0(@types/[email protected].10)([email protected])
8777
  ws: 7.5.10
8778
  optionalDependencies:
8779
  typescript: 5.7.2
8780
+ vite: 5.4.11(@types/[email protected].10)([email protected])
8781
  wrangler: 3.91.0(@cloudflare/[email protected])
8782
  transitivePeerDependencies:
8783
  - '@types/node'
 
8795
  - ts-node
8796
  - utf-8-validate
8797
 
 
 
 
 
 
 
 
 
 
 
 
 
8798
8799
  dependencies:
8800
  '@remix-run/server-runtime': 2.15.2([email protected])
 
8807
  optionalDependencies:
8808
  typescript: 5.7.2
8809
 
8810
8811
  dependencies:
8812
  '@remix-run/router': 1.21.0
8813
+ '@remix-run/server-runtime': 2.15.2([email protected])
8814
  react: 18.3.1
8815
  react-dom: 18.3.1([email protected])
8816
+ react-router: 6.28.1([email protected])
8817
8818
  turbo-stream: 2.4.0
8819
  optionalDependencies:
8820
  typescript: 5.7.2
8821
 
8822
  '@remix-run/[email protected]': {}
8823
 
 
 
 
 
 
 
 
 
 
 
 
 
8824
8825
  dependencies:
8826
  '@remix-run/router': 1.21.0
 
9255
  '@smithy/util-buffer-from': 3.0.0
9256
  tslib: 2.8.1
9257
 
9258
9259
  dependencies:
9260
+ '@typescript-eslint/utils': 8.17.0([email protected]([email protected].7))([email protected])
9261
+ eslint: 9.16.0([email protected].7)
9262
  eslint-visitor-keys: 4.2.0
9263
  espree: 10.3.0
9264
  transitivePeerDependencies:
 
9341
  dependencies:
9342
  undici-types: 6.20.0
9343
 
9344
+ '@types/[email protected]':
9345
+ dependencies:
9346
+ undici-types: 6.20.0
9347
+
9348
  '@types/[email protected]': {}
9349
 
9350
  '@types/[email protected]':
 
9362
 
9363
  '@types/[email protected]': {}
9364
 
9365
9366
  dependencies:
9367
  '@eslint-community/regexpp': 4.12.1
9368
+ '@typescript-eslint/parser': 8.17.0([email protected]([email protected].7))([email protected])
9369
  '@typescript-eslint/scope-manager': 8.17.0
9370
+ '@typescript-eslint/type-utils': 8.17.0([email protected]([email protected].7))([email protected])
9371
+ '@typescript-eslint/utils': 8.17.0([email protected]([email protected].7))([email protected])
9372
  '@typescript-eslint/visitor-keys': 8.17.0
9373
+ eslint: 9.16.0([email protected].7)
9374
  graphemer: 1.4.0
9375
  ignore: 5.3.2
9376
  natural-compare: 1.4.0
 
9380
  transitivePeerDependencies:
9381
  - supports-color
9382
 
9383
9384
  dependencies:
9385
  '@typescript-eslint/scope-manager': 8.17.0
9386
  '@typescript-eslint/types': 8.17.0
9387
  '@typescript-eslint/typescript-estree': 8.17.0([email protected])
9388
  '@typescript-eslint/visitor-keys': 8.17.0
9389
  debug: 4.3.7
9390
+ eslint: 9.16.0([email protected].7)
9391
  optionalDependencies:
9392
  typescript: 5.7.2
9393
  transitivePeerDependencies:
 
9398
  '@typescript-eslint/types': 8.17.0
9399
  '@typescript-eslint/visitor-keys': 8.17.0
9400
 
9401
9402
  dependencies:
9403
  '@typescript-eslint/typescript-estree': 8.17.0([email protected])
9404
+ '@typescript-eslint/utils': 8.17.0([email protected]([email protected].7))([email protected])
9405
  debug: 4.3.7
9406
+ eslint: 9.16.0([email protected].7)
9407
  ts-api-utils: 1.4.3([email protected])
9408
  optionalDependencies:
9409
  typescript: 5.7.2
 
9427
  transitivePeerDependencies:
9428
  - supports-color
9429
 
9430
9431
  dependencies:
9432
+ '@eslint-community/eslint-utils': 4.4.1([email protected]([email protected].7))
9433
  '@typescript-eslint/scope-manager': 8.17.0
9434
  '@typescript-eslint/types': 8.17.0
9435
  '@typescript-eslint/typescript-estree': 8.17.0([email protected])
9436
+ eslint: 9.16.0([email protected].7)
9437
  optionalDependencies:
9438
  typescript: 5.7.2
9439
  transitivePeerDependencies:
 
9460
 
9461
  '@ungap/[email protected]': {}
9462
 
9463
9464
  dependencies:
9465
  '@unocss/core': 0.61.9
9466
  '@unocss/reset': 0.61.9
9467
9468
  optionalDependencies:
9469
+ vite: 5.4.11(@types/[email protected].10)([email protected])
9470
  transitivePeerDependencies:
9471
  - rollup
9472
  - supports-color
 
9510
  gzip-size: 6.0.0
9511
  sirv: 2.0.4
9512
 
9513
+ '@unocss/[email protected](postcss@8.5.1)':
9514
  dependencies:
9515
  '@unocss/config': 0.61.9
9516
  '@unocss/core': 0.61.9
 
9518
  css-tree: 2.3.1
9519
  fast-glob: 3.3.2
9520
  magic-string: 0.30.14
9521
+ postcss: 8.5.1
9522
  transitivePeerDependencies:
9523
  - supports-color
9524
 
 
9603
  dependencies:
9604
  '@unocss/core': 0.61.9
9605
 
9606
9607
  dependencies:
9608
  '@ampproject/remapping': 2.3.0
9609
  '@rollup/pluginutils': 5.1.3([email protected])
 
9615
  chokidar: 3.6.0
9616
  fast-glob: 3.3.2
9617
  magic-string: 0.30.14
9618
+ vite: 5.4.11(@types/[email protected].10)([email protected])
9619
  transitivePeerDependencies:
9620
  - rollup
9621
  - supports-color
9622
 
9623
+ '@vanilla-extract/babel-plugin-debug-ids@1.2.0':
9624
  dependencies:
9625
  '@babel/core': 7.26.0
9626
  transitivePeerDependencies:
9627
  - supports-color
9628
 
9629
+ '@vanilla-extract/css@1.17.0':
9630
  dependencies:
9631
  '@emotion/hash': 0.9.2
9632
  '@vanilla-extract/private': 1.0.6
 
9643
  transitivePeerDependencies:
9644
  - babel-plugin-macros
9645
 
9646
+ '@vanilla-extract/[email protected](@types/[email protected].10)([email protected])':
9647
  dependencies:
9648
  '@babel/core': 7.26.0
9649
  '@babel/plugin-syntax-typescript': 7.25.9(@babel/[email protected])
9650
+ '@vanilla-extract/babel-plugin-debug-ids': 1.2.0
9651
+ '@vanilla-extract/css': 1.17.0
9652
+ esbuild: 0.17.6
9653
  eval: 0.1.8
9654
  find-up: 5.0.0
9655
  javascript-stringify: 2.1.0
9656
  lodash: 4.17.21
9657
+ mlly: 1.7.4
9658
  outdent: 0.8.0
9659
+ vite: 5.4.11(@types/[email protected].10)([email protected])
9660
+ vite-node: 1.6.0(@types/[email protected].10)([email protected])
9661
  transitivePeerDependencies:
9662
  - '@types/node'
9663
  - babel-plugin-macros
 
9679
  chai: 5.1.2
9680
  tinyrainbow: 1.2.0
9681
 
9682
9683
  dependencies:
9684
  '@vitest/spy': 2.1.8
9685
  estree-walker: 3.0.3
9686
  magic-string: 0.30.14
9687
  optionalDependencies:
9688
+ vite: 5.4.11(@types/[email protected].10)([email protected])
9689
 
9690
  '@vitest/[email protected]':
9691
  dependencies:
 
9987
  tar: 6.2.1
9988
  unique-filename: 3.0.0
9989
 
9990
9991
+ dependencies:
9992
+ es-errors: 1.3.0
9993
+ function-bind: 1.1.2
9994
+
9995
9996
  dependencies:
9997
  es-define-property: 1.0.0
 
10000
  get-intrinsic: 1.2.4
10001
  set-function-length: 1.2.2
10002
 
10003
10004
+ dependencies:
10005
+ call-bind-apply-helpers: 1.0.1
10006
+ get-intrinsic: 1.2.7
10007
+
10008
10009
 
10010
 
10224
  dependencies:
10225
  ms: 2.1.3
10226
 
10227
10228
+ dependencies:
10229
+ ms: 2.1.3
10230
+
10231
10232
  dependencies:
10233
  character-entities: 2.0.2
 
10308
 
10309
10310
 
10311
10312
+ dependencies:
10313
+ call-bind-apply-helpers: 1.0.1
10314
+ es-errors: 1.3.0
10315
+ gopd: 1.2.0
10316
+
10317
10318
 
10319
 
10365
  dependencies:
10366
  get-intrinsic: 1.2.4
10367
 
10368
10369
+
10370
10371
 
10372
10373
 
10374
10375
+
10376
10377
+ dependencies:
10378
+ es-errors: 1.3.0
10379
+
10380
10381
  dependencies:
10382
  '@jspm/core': 2.0.1
 
10495
 
10496
10497
 
10498
10499
  dependencies:
10500
+ eslint: 9.16.0([email protected].7)
10501
  semver: 7.6.3
10502
 
10503
10504
  dependencies:
10505
+ eslint: 9.16.0([email protected].7)
10506
 
10507
10508
  dependencies:
10509
+ eslint: 9.16.0([email protected].7)
10510
  esquery: 1.6.0
10511
  jsonc-eslint-parser: 2.4.0
10512
 
10513
10514
  dependencies:
10515
+ '@eslint-community/eslint-utils': 4.4.1([email protected]([email protected].7))
10516
+ eslint: 9.16.0([email protected].7)
10517
+ eslint-compat-utils: 0.6.4([email protected]([email protected].7))
10518
+ eslint-json-compat-utils: 0.2.1([email protected]([email protected].7))([email protected])
10519
  espree: 9.6.1
10520
  graphemer: 1.4.0
10521
  jsonc-eslint-parser: 2.4.0
 
10524
  transitivePeerDependencies:
10525
  - '@eslint/json'
10526
 
10527
10528
  dependencies:
10529
+ eslint: 9.16.0([email protected].7)
10530
  prettier: 3.4.1
10531
  prettier-linter-helpers: 1.0.0
10532
  synckit: 0.9.2
10533
  optionalDependencies:
10534
  '@types/eslint': 8.56.10
10535
+ eslint-config-prettier: 9.1.0([email protected]([email protected].7))
10536
 
10537
10538
  dependencies:
 
10543
 
10544
10545
 
10546
10547
  dependencies:
10548
+ '@eslint-community/eslint-utils': 4.4.1([email protected]([email protected].7))
10549
  '@eslint-community/regexpp': 4.12.1
10550
  '@eslint/config-array': 0.19.0
10551
  '@eslint/core': 0.9.0
 
10580
  natural-compare: 1.4.0
10581
  optionator: 0.9.4
10582
  optionalDependencies:
10583
+ jiti: 1.21.7
10584
  transitivePeerDependencies:
10585
  - supports-color
10586
 
 
10651
 
10652
10653
  dependencies:
10654
+ '@types/node': 22.10.10
10655
  require-like: 0.1.2
10656
 
10657
 
10683
 
10684
10685
 
10686
10687
  dependencies:
10688
  accepts: 1.3.8
10689
  array-flatten: 1.1.1
 
10704
  methods: 1.1.2
10705
  on-finished: 2.4.1
10706
  parseurl: 1.3.3
10707
+ path-to-regexp: 0.1.12
10708
  proxy-addr: 2.0.7
10709
  qs: 6.13.0
10710
  range-parser: 1.2.1
 
10849
  has-symbols: 1.1.0
10850
  hasown: 2.0.2
10851
 
10852
10853
+ dependencies:
10854
+ call-bind-apply-helpers: 1.0.1
10855
+ es-define-property: 1.0.1
10856
+ es-errors: 1.3.0
10857
+ es-object-atoms: 1.1.1
10858
+ function-bind: 1.1.2
10859
+ get-proto: 1.0.1
10860
+ gopd: 1.2.0
10861
+ has-symbols: 1.1.0
10862
+ hasown: 2.0.2
10863
+ math-intrinsics: 1.1.0
10864
+
10865
10866
 
10867
10868
 
10869
10870
+ dependencies:
10871
+ dunder-proto: 1.0.1
10872
+ es-object-atoms: 1.1.1
10873
+
10874
10875
  dependencies:
10876
  data-uri-to-buffer: 2.0.2
 
10913
  dependencies:
10914
  get-intrinsic: 1.2.4
10915
 
10916
10917
+
10918
10919
 
10920
 
11113
  dependencies:
11114
  safer-buffer: 2.1.2
11115
 
11116
+ [email protected](postcss@8.5.1):
11117
  dependencies:
11118
+ postcss: 8.5.1
11119
 
11120
11121
 
 
11138
  debug: 4.3.7
11139
  esbuild: 0.23.1
11140
  jiti: 2.0.0-beta.3
11141
+ jiti-v1: [email protected].7
11142
  pathe: 1.1.2
11143
  tsx: 4.19.2
11144
  transitivePeerDependencies:
 
11191
  dependencies:
11192
  hasown: 2.0.2
11193
 
11194
11195
+ dependencies:
11196
+ hasown: 2.0.2
11197
+
11198
11199
 
11200
 
11279
 
11280
11281
 
11282
11283
 
11284
11285
 
 
11350
  dependencies:
11351
  immediate: 3.0.6
11352
 
11353
11354
 
11355
11356
 
 
11406
 
11407
11408
 
11409
11410
+
11411
11412
  dependencies:
11413
  hash-base: 3.0.5
 
11554
  ccount: 2.0.1
11555
  mdast-util-from-markdown: 1.3.1
11556
  mdast-util-to-markdown: 1.5.0
11557
+ parse-entities: 4.0.2
11558
  stringify-entities: 4.0.4
11559
  unist-util-remove-position: 4.0.2
11560
  unist-util-stringify-position: 3.0.3
 
12053
12054
  dependencies:
12055
  '@types/debug': 4.1.12
12056
+ debug: 4.4.0
12057
  decode-named-character-reference: 1.0.2
12058
  micromark-core-commonmark: 1.1.0
12059
  micromark-factory-space: 1.1.0
 
12193
  pkg-types: 1.2.1
12194
  ufo: 1.5.4
12195
 
12196
12197
+ dependencies:
12198
+ acorn: 8.14.0
12199
+ pathe: 2.0.2
12200
+ pkg-types: 1.3.1
12201
+ ufo: 1.5.4
12202
+
12203
12204
 
12205
 
12297
12298
  dependencies:
12299
  hosted-git-info: 6.1.3
12300
+ is-core-module: 2.16.1
12301
  semver: 7.6.3
12302
  validate-npm-package-license: 3.0.4
12303
 
 
12446
  is-decimal: 2.0.1
12447
  is-hexadecimal: 2.0.1
12448
 
12449
12450
+ dependencies:
12451
+ '@types/unist': 2.0.11
12452
+ character-entities-legacy: 3.0.0
12453
+ character-reference-invalid: 2.0.1
12454
+ decode-named-character-reference: 1.0.2
12455
+ is-alphanumerical: 2.0.1
12456
+ is-decimal: 2.0.1
12457
+ is-hexadecimal: 2.0.1
12458
+
12459
12460
 
12461
 
12479
  lru-cache: 10.4.3
12480
  minipass: 7.1.2
12481
 
12482
12483
 
12484
12485
 
12486
12487
 
12488
12489
+
12490
12491
 
12492
 
12531
  mlly: 1.7.3
12532
  pathe: 1.1.2
12533
 
12534
12535
+ dependencies:
12536
+ confbox: 0.1.8
12537
+ mlly: 1.7.4
12538
+ pathe: 2.0.2
12539
+
12540
12541
 
12542
12543
 
12544
+ [email protected](postcss@8.5.1):
12545
  dependencies:
12546
+ postcss: 8.5.1
12547
 
12548
+ [email protected](postcss@8.5.1):
12549
  dependencies:
12550
+ lilconfig: 3.1.3
12551
+ yaml: 2.7.0
12552
  optionalDependencies:
12553
+ postcss: 8.5.1
12554
 
12555
+ [email protected](postcss@8.5.1):
12556
  dependencies:
12557
+ postcss: 8.5.1
12558
 
12559
+ postcss-modules-local-by-default@4.2.0(postcss@8.5.1):
12560
  dependencies:
12561
+ icss-utils: 5.1.0(postcss@8.5.1)
12562
+ postcss: 8.5.1
12563
  postcss-selector-parser: 7.0.0
12564
  postcss-value-parser: 4.2.0
12565
 
12566
+ [email protected](postcss@8.5.1):
12567
  dependencies:
12568
+ postcss: 8.5.1
12569
  postcss-selector-parser: 7.0.0
12570
 
12571
+ [email protected](postcss@8.5.1):
12572
  dependencies:
12573
+ icss-utils: 5.1.0(postcss@8.5.1)
12574
+ postcss: 8.5.1
12575
 
12576
+ [email protected](postcss@8.5.1):
12577
  dependencies:
12578
  generic-names: 4.0.0
12579
+ icss-utils: 5.1.0(postcss@8.5.1)
12580
  lodash.camelcase: 4.3.0
12581
+ postcss: 8.5.1
12582
+ postcss-modules-extract-imports: 3.1.0(postcss@8.5.1)
12583
+ postcss-modules-local-by-default: 4.2.0(postcss@8.5.1)
12584
+ postcss-modules-scope: 3.2.1(postcss@8.5.1)
12585
+ postcss-modules-values: 4.0.0(postcss@8.5.1)
12586
  string-hash: 1.1.3
12587
 
12588
 
12604
  picocolors: 1.1.1
12605
  source-map-js: 1.2.1
12606
 
12607
12608
+ dependencies:
12609
+ nanoid: 3.3.8
12610
+ picocolors: 1.1.1
12611
+ source-map-js: 1.2.1
12612
+
12613
12614
 
12615
 
12677
 
12678
12679
  dependencies:
12680
+ side-channel: 1.1.0
12681
 
12682
12683
  dependencies:
 
12714
  dependencies:
12715
  dnd-core: 16.0.1
12716
 
12717
12718
  dependencies:
12719
  '@react-dnd/invariant': 4.0.2
12720
  '@react-dnd/shallowequal': 4.0.2
 
12723
  hoist-non-react-statics: 3.3.2
12724
  react: 18.3.1
12725
  optionalDependencies:
12726
+ '@types/node': 22.10.10
12727
  '@types/react': 18.3.12
12728
 
12729
 
12786
  react: 18.3.1
12787
  react-dom: 18.3.1([email protected])
12788
 
12789
12790
  dependencies:
12791
  '@remix-run/router': 1.21.0
12792
  react: 18.3.1
12793
  react-dom: 18.3.1([email protected])
12794
+ react-router: 6.28.1([email protected])
12795
 
12796
12797
  dependencies:
12798
  '@remix-run/router': 1.21.0
12799
  react: 18.3.1
 
12936
  mdast-util-to-markdown: 2.1.2
12937
  unified: 11.0.5
12938
 
12939
12940
  dependencies:
12941
12942
  '@remix-run/server-runtime': 2.15.2([email protected])
12943
  react: 18.3.1
12944
  react-dom: 18.3.1([email protected])
12945
 
12946
12947
  dependencies:
12948
  type-fest: 4.30.0
12949
  optionalDependencies:
12950
+ '@remix-run/cloudflare': 2.15.2(@cloudflare/[email protected])([email protected])
12951
  '@remix-run/node': 2.15.2([email protected])
12952
12953
  '@remix-run/router': 1.21.0
12954
  react: 18.3.1
12955
  zod: 3.23.8
 
13234
  '@shikijs/vscode-textmate': 9.3.0
13235
  '@types/hast': 3.0.4
13236
 
13237
13238
+ dependencies:
13239
+ es-errors: 1.3.0
13240
+ object-inspect: 1.13.3
13241
+
13242
13243
+ dependencies:
13244
+ call-bound: 1.0.3
13245
+ es-errors: 1.3.0
13246
+ get-intrinsic: 1.2.7
13247
+ object-inspect: 1.13.3
13248
+
13249
13250
+ dependencies:
13251
+ call-bound: 1.0.3
13252
+ es-errors: 1.3.0
13253
+ get-intrinsic: 1.2.7
13254
+ object-inspect: 1.13.3
13255
+ side-channel-map: 1.0.1
13256
+
13257
13258
  dependencies:
13259
  call-bind: 1.0.7
 
13261
  get-intrinsic: 1.2.4
13262
  object-inspect: 1.13.3
13263
 
13264
13265
+ dependencies:
13266
+ es-errors: 1.3.0
13267
+ object-inspect: 1.13.3
13268
+ side-channel-list: 1.0.0
13269
+ side-channel-map: 1.0.1
13270
+ side-channel-weakmap: 1.0.2
13271
+
13272
13273
 
13274
 
13312
13313
  dependencies:
13314
  spdx-expression-parse: 3.0.1
13315
+ spdx-license-ids: 3.0.21
13316
 
13317
13318
 
13319
13320
  dependencies:
13321
  spdx-exceptions: 2.5.0
13322
+ spdx-license-ids: 3.0.21
13323
 
13324
13325
 
13326
13327
  dependencies:
 
13453
 
13454
13455
 
13456
13457
  dependencies:
13458
  chownr: 1.1.4
13459
  mkdirp-classic: 0.5.3
 
13554
  media-typer: 0.3.0
13555
  mime-types: 2.1.35
13556
 
13557
13558
  dependencies:
13559
13560
+ '@typescript-eslint/parser': 8.17.0([email protected]([email protected].7))([email protected])
13561
+ '@typescript-eslint/utils': 8.17.0([email protected]([email protected].7))([email protected])
13562
+ eslint: 9.16.0([email protected].7)
13563
  optionalDependencies:
13564
  typescript: 5.7.2
13565
  transitivePeerDependencies:
 
13681
 
13682
13683
 
13684
13685
  dependencies:
13686
13687
  '@unocss/cli': 0.61.9([email protected])
13688
  '@unocss/core': 0.61.9
13689
  '@unocss/extractor-arbitrary-variants': 0.61.9
13690
+ '@unocss/postcss': 0.61.9(postcss@8.5.1)
13691
  '@unocss/preset-attributify': 0.61.9
13692
  '@unocss/preset-icons': 0.61.9
13693
  '@unocss/preset-mini': 0.61.9
 
13702
  '@unocss/transformer-compile-class': 0.61.9
13703
  '@unocss/transformer-directives': 0.61.9
13704
  '@unocss/transformer-variant-group': 0.61.9
13705
13706
  optionalDependencies:
13707
+ vite: 5.4.11(@types/[email protected].10)([email protected])
13708
  transitivePeerDependencies:
13709
  - postcss
13710
  - rollup
 
13811
  '@types/unist': 3.0.3
13812
  vfile-message: 4.0.2
13813
 
13814
13815
  dependencies:
13816
  cac: 6.7.14
13817
+ debug: 4.4.0
13818
  pathe: 1.1.2
13819
  picocolors: 1.1.1
13820
+ vite: 5.4.11(@types/[email protected].10)([email protected])
13821
  transitivePeerDependencies:
13822
  - '@types/node'
13823
  - less
 
13829
  - supports-color
13830
  - terser
13831
 
13832
13833
  dependencies:
13834
  cac: 6.7.14
13835
  debug: 4.3.7
13836
  es-module-lexer: 1.5.4
13837
  pathe: 1.1.2
13838
+ vite: 5.4.11(@types/[email protected].10)([email protected])
13839
  transitivePeerDependencies:
13840
  - '@types/node'
13841
  - less
 
13847
  - supports-color
13848
  - terser
13849
 
13850
13851
  dependencies:
13852
  '@rollup/plugin-inject': 5.0.5([email protected])
13853
  node-stdlib-browser: 1.3.0
13854
+ vite: 5.4.11(@types/[email protected].10)([email protected])
13855
  transitivePeerDependencies:
13856
  - rollup
13857
 
13858
13859
  dependencies:
13860
+ vite: 5.4.11(@types/[email protected].10)([email protected])
13861
 
13862
13863
  dependencies:
13864
  debug: 4.3.7
13865
  globrex: 0.1.2
13866
  tsconfck: 3.1.4([email protected])
13867
  optionalDependencies:
13868
+ vite: 5.4.11(@types/[email protected].10)([email protected])
13869
  transitivePeerDependencies:
13870
  - supports-color
13871
  - typescript
13872
 
13873
13874
  dependencies:
13875
  esbuild: 0.21.5
13876
  postcss: 8.4.49
13877
  rollup: 4.28.0
13878
  optionalDependencies:
13879
+ '@types/node': 22.10.10
13880
  fsevents: 2.3.3
13881
  sass-embedded: 1.81.0
13882
 
13883
13884
  dependencies:
13885
  '@vitest/expect': 2.1.8
13886
+ '@vitest/mocker': 2.1.8([email protected](@types/[email protected].10)([email protected]))
13887
  '@vitest/pretty-format': 2.1.8
13888
  '@vitest/runner': 2.1.8
13889
  '@vitest/snapshot': 2.1.8
 
13899
  tinyexec: 0.3.1
13900
  tinypool: 1.0.2
13901
  tinyrainbow: 1.2.0
13902
+ vite: 5.4.11(@types/[email protected].10)([email protected])
13903
+ vite-node: 2.1.8(@types/[email protected].10)([email protected])
13904
  why-is-node-running: 2.3.0
13905
  optionalDependencies:
13906
+ '@types/node': 22.10.10
13907
  transitivePeerDependencies:
13908
  - less
13909
  - lightningcss
 
14019
 
14020
14021
 
14022
+ yaml@2.7.0: {}
14023
 
14024
14025