jettypod 4.4.118 → 4.4.121

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (240) hide show
  1. package/.env +4 -3
  2. package/Cargo.lock +6450 -0
  3. package/Cargo.toml +35 -0
  4. package/README.md +5 -1
  5. package/TAURI-MIGRATION-PLAN.md +840 -0
  6. package/apps/dashboard/app/connect-claude/page.tsx +5 -6
  7. package/apps/dashboard/app/decision/[id]/page.tsx +63 -58
  8. package/apps/dashboard/app/demo/gates/page.tsx +43 -45
  9. package/apps/dashboard/app/design-system/page.tsx +868 -0
  10. package/apps/dashboard/app/globals.css +80 -4
  11. package/apps/dashboard/app/install-claude/page.tsx +4 -6
  12. package/apps/dashboard/app/login/page.tsx +72 -54
  13. package/apps/dashboard/app/page.tsx +101 -48
  14. package/apps/dashboard/app/settings/page.tsx +61 -13
  15. package/apps/dashboard/app/signup/page.tsx +242 -0
  16. package/apps/dashboard/app/subscribe/page.tsx +0 -2
  17. package/apps/dashboard/app/tests/page.tsx +37 -4
  18. package/apps/dashboard/app/welcome/page.tsx +13 -16
  19. package/apps/dashboard/app/work/[id]/page.tsx +117 -118
  20. package/apps/dashboard/app/work/[id]/proof/page.tsx +1489 -0
  21. package/apps/dashboard/components/AppShell.tsx +92 -85
  22. package/apps/dashboard/components/CardMenu.tsx +45 -12
  23. package/apps/dashboard/components/ClaudePanel.tsx +771 -850
  24. package/apps/dashboard/components/ClaudePanelInput.tsx +43 -15
  25. package/apps/dashboard/components/ConnectClaudeScreen.tsx +17 -34
  26. package/apps/dashboard/components/CopyableId.tsx +3 -4
  27. package/apps/dashboard/components/DetailReviewActions.tsx +100 -0
  28. package/apps/dashboard/components/DragContext.tsx +134 -63
  29. package/apps/dashboard/components/DraggableCard.tsx +3 -5
  30. package/apps/dashboard/components/DropZone.tsx +6 -7
  31. package/apps/dashboard/components/EditableDetailDescription.tsx +7 -13
  32. package/apps/dashboard/components/EditableDetailTitle.tsx +6 -13
  33. package/apps/dashboard/components/EditableTitle.tsx +26 -7
  34. package/apps/dashboard/components/ElapsedTimer.tsx +66 -0
  35. package/apps/dashboard/components/EpicGroup.tsx +359 -0
  36. package/apps/dashboard/components/GateCard.tsx +79 -17
  37. package/apps/dashboard/components/GateChoiceCard.tsx +15 -18
  38. package/apps/dashboard/components/InstallClaudeScreen.tsx +15 -32
  39. package/apps/dashboard/components/JettyLoader.tsx +37 -0
  40. package/apps/dashboard/components/KanbanBoard.tsx +368 -958
  41. package/apps/dashboard/components/KanbanCard.tsx +740 -0
  42. package/apps/dashboard/components/LazyCard.tsx +62 -0
  43. package/apps/dashboard/components/LazyMarkdown.tsx +11 -0
  44. package/apps/dashboard/components/MainNav.tsx +38 -73
  45. package/apps/dashboard/components/MessageBlock.tsx +468 -0
  46. package/apps/dashboard/components/ModeStartCard.tsx +15 -16
  47. package/apps/dashboard/components/OnboardingWelcome.tsx +213 -0
  48. package/apps/dashboard/components/PlaceholderCard.tsx +3 -4
  49. package/apps/dashboard/components/ProjectSwitcher.tsx +30 -30
  50. package/apps/dashboard/components/PrototypeTimeline.tsx +72 -51
  51. package/apps/dashboard/components/RealTimeKanbanWrapper.tsx +406 -388
  52. package/apps/dashboard/components/RealTimeTestsWrapper.tsx +373 -235
  53. package/apps/dashboard/components/ReviewFooter.tsx +139 -0
  54. package/apps/dashboard/components/SessionList.tsx +19 -19
  55. package/apps/dashboard/components/SubscribeContent.tsx +91 -47
  56. package/apps/dashboard/components/TestTree.tsx +16 -16
  57. package/apps/dashboard/components/TipCard.tsx +16 -17
  58. package/apps/dashboard/components/Toast.tsx +5 -6
  59. package/apps/dashboard/components/TypeIcon.tsx +55 -0
  60. package/apps/dashboard/components/ViewModeToolbar.tsx +104 -0
  61. package/apps/dashboard/components/WaveCompletionAnimation.tsx +52 -65
  62. package/apps/dashboard/components/WelcomeScreen.tsx +19 -35
  63. package/apps/dashboard/components/WorkItemHeader.tsx +4 -5
  64. package/apps/dashboard/components/WorkItemTree.tsx +11 -32
  65. package/apps/dashboard/components/settings/AccountSection.tsx +55 -35
  66. package/apps/dashboard/components/settings/AiContextSection.tsx +89 -0
  67. package/apps/dashboard/components/settings/ContextDocumentsSection.tsx +317 -0
  68. package/apps/dashboard/components/settings/EnvVarsSection.tsx +74 -152
  69. package/apps/dashboard/components/settings/GeneralSection.tsx +162 -56
  70. package/apps/dashboard/components/settings/ProjectStackSection.tsx +948 -0
  71. package/apps/dashboard/components/settings/SettingsLayout.tsx +4 -5
  72. package/apps/dashboard/components/ui/Button.tsx +104 -0
  73. package/apps/dashboard/components/ui/Input.tsx +78 -0
  74. package/apps/dashboard/components.json +1 -1
  75. package/apps/dashboard/contexts/ClaudeSessionContext.tsx +711 -418
  76. package/apps/dashboard/contexts/ConnectionStatusContext.tsx +25 -5
  77. package/apps/dashboard/contexts/UsageContext.tsx +87 -32
  78. package/apps/dashboard/dev.sh +35 -0
  79. package/apps/dashboard/eslint.config.mjs +9 -9
  80. package/apps/dashboard/hooks/useKanbanAnimation.ts +29 -0
  81. package/apps/dashboard/hooks/useKanbanUndo.ts +83 -0
  82. package/apps/dashboard/hooks/useWebSocket.ts +138 -83
  83. package/apps/dashboard/index.html +73 -0
  84. package/apps/dashboard/lib/constants.ts +43 -0
  85. package/apps/dashboard/lib/data-bridge.ts +722 -0
  86. package/apps/dashboard/lib/db.ts +69 -1265
  87. package/apps/dashboard/lib/environment-config.ts +173 -0
  88. package/apps/dashboard/lib/environment-verification.ts +119 -0
  89. package/apps/dashboard/lib/kanban-utils.ts +270 -0
  90. package/apps/dashboard/lib/proof-run.ts +495 -0
  91. package/apps/dashboard/lib/proof-scenario-runner.ts +346 -0
  92. package/apps/dashboard/lib/run-migrations.js +27 -2
  93. package/apps/dashboard/lib/service-recovery.ts +326 -0
  94. package/apps/dashboard/lib/session-state-machine.ts +1 -0
  95. package/apps/dashboard/lib/session-state-utils.ts +0 -164
  96. package/apps/dashboard/lib/session-stream-manager.ts +308 -134
  97. package/apps/dashboard/lib/shadows.ts +7 -0
  98. package/apps/dashboard/lib/stream-manager-registry.ts +46 -6
  99. package/apps/dashboard/lib/tauri-bridge.ts +102 -0
  100. package/apps/dashboard/lib/tauri.ts +106 -0
  101. package/apps/dashboard/lib/utils.ts +6 -0
  102. package/apps/dashboard/next-env.d.ts +1 -1
  103. package/apps/dashboard/package.json +21 -32
  104. package/apps/dashboard/public/bug-icon.png +0 -0
  105. package/apps/dashboard/public/buoy-icon.png +0 -0
  106. package/apps/dashboard/public/fonts/Satoshi-Variable.woff2 +0 -0
  107. package/apps/dashboard/public/fonts/Satoshi-VariableItalic.woff2 +0 -0
  108. package/apps/dashboard/public/in-flight-seagull.png +0 -0
  109. package/apps/dashboard/public/jetty-icon-loading-alt.svg +11 -0
  110. package/apps/dashboard/public/jetty-icon-loading.svg +11 -0
  111. package/apps/dashboard/public/jettypod_logo.png +0 -0
  112. package/apps/dashboard/public/pier-icon.png +0 -0
  113. package/apps/dashboard/public/star-icon.png +0 -0
  114. package/apps/dashboard/public/wrench-icon.png +0 -0
  115. package/apps/dashboard/scripts/tauri-build.js +228 -0
  116. package/apps/dashboard/scripts/upload-tauri-to-r2.js +125 -0
  117. package/apps/dashboard/scripts/ws-server.js +191 -0
  118. package/apps/dashboard/src/main.tsx +12 -0
  119. package/apps/dashboard/src/router.tsx +107 -0
  120. package/apps/dashboard/src/vite-env.d.ts +1 -0
  121. package/apps/dashboard/tsconfig.json +7 -12
  122. package/apps/dashboard/tsconfig.tsbuildinfo +1 -1
  123. package/apps/dashboard/vite.config.ts +33 -0
  124. package/apps/update-server/src/index.ts +228 -80
  125. package/claude-hooks/global-guardrails.js +14 -13
  126. package/crates/jettypod-cli/Cargo.toml +19 -0
  127. package/crates/jettypod-cli/src/commands.rs +1249 -0
  128. package/crates/jettypod-cli/src/main.rs +595 -0
  129. package/crates/jettypod-core/Cargo.toml +26 -0
  130. package/crates/jettypod-core/build.rs +98 -0
  131. package/crates/jettypod-core/migrations/V1__baseline.sql +197 -0
  132. package/crates/jettypod-core/migrations/V2__work_items_indexes.sql +6 -0
  133. package/crates/jettypod-core/migrations/V3__qa_steps.sql +2 -0
  134. package/crates/jettypod-core/src/auth.rs +294 -0
  135. package/crates/jettypod-core/src/config.rs +397 -0
  136. package/crates/jettypod-core/src/db/mod.rs +507 -0
  137. package/crates/jettypod-core/src/db/recovery.rs +114 -0
  138. package/crates/jettypod-core/src/db/startup.rs +101 -0
  139. package/crates/jettypod-core/src/db/validate.rs +149 -0
  140. package/crates/jettypod-core/src/error.rs +76 -0
  141. package/crates/jettypod-core/src/git.rs +458 -0
  142. package/crates/jettypod-core/src/lib.rs +20 -0
  143. package/crates/jettypod-core/src/sessions.rs +625 -0
  144. package/crates/jettypod-core/src/skills.rs +556 -0
  145. package/crates/jettypod-core/src/work.rs +1086 -0
  146. package/crates/jettypod-core/src/worktree.rs +628 -0
  147. package/crates/jettypod-core/src/ws.rs +767 -0
  148. package/cucumber-test.cjs +6 -0
  149. package/cucumber.js +9 -3
  150. package/docs/COMMAND_REFERENCE.md +34 -0
  151. package/hooks/post-checkout +32 -75
  152. package/hooks/post-merge +111 -10
  153. package/jest.setup.js +1 -0
  154. package/jettypod.js +145 -116
  155. package/lib/bdd-preflight.js +96 -0
  156. package/lib/chore-taxonomy.js +33 -10
  157. package/lib/database.js +36 -16
  158. package/lib/db-watcher.js +1 -1
  159. package/lib/git-hooks/pre-commit +1 -1
  160. package/lib/jettypod-backup.js +27 -4
  161. package/lib/merge-lock.js +111 -253
  162. package/lib/migrations/027-plan-at-creation-column.js +3 -1
  163. package/lib/migrations/029-remove-autoincrement.js +307 -0
  164. package/lib/migrations/029-rename-corrupted-to-cleaned.js +149 -0
  165. package/lib/migrations/030-rejection-round-columns.js +54 -0
  166. package/lib/migrations/031-session-isolation-index.js +17 -0
  167. package/lib/migrations/index.js +47 -4
  168. package/lib/schema.js +10 -5
  169. package/lib/seed-onboarding.js +1 -1
  170. package/lib/update-command/index.js +9 -175
  171. package/lib/work-commands/index.js +144 -19
  172. package/lib/work-tracking/index.js +148 -27
  173. package/lib/worktree-diagnostics.js +16 -16
  174. package/lib/worktree-facade.js +1 -1
  175. package/lib/worktree-manager.js +8 -8
  176. package/lib/worktree-reconciler.js +5 -5
  177. package/package.json +9 -2
  178. package/scripts/ndjson-to-cucumber-json.js +152 -0
  179. package/scripts/postinstall.js +25 -0
  180. package/skills-templates/bug-mode/SKILL.md +79 -20
  181. package/skills-templates/bug-planning/SKILL.md +25 -29
  182. package/skills-templates/chore-mode/SKILL.md +171 -69
  183. package/skills-templates/chore-mode/verification.js +51 -10
  184. package/skills-templates/chore-planning/SKILL.md +47 -18
  185. package/skills-templates/design-system-selection/SKILL.md +273 -0
  186. package/skills-templates/epic-planning/SKILL.md +82 -48
  187. package/skills-templates/external-transition/SKILL.md +47 -47
  188. package/skills-templates/feature-planning/SKILL.md +173 -74
  189. package/skills-templates/production-mode/SKILL.md +69 -49
  190. package/skills-templates/request-routing/SKILL.md +4 -4
  191. package/skills-templates/simple-improvement/SKILL.md +74 -29
  192. package/skills-templates/speed-mode/SKILL.md +217 -141
  193. package/skills-templates/stable-mode/SKILL.md +148 -89
  194. package/apps/dashboard/README.md +0 -36
  195. package/apps/dashboard/app/api/claude/[workItemId]/message/route.ts +0 -386
  196. package/apps/dashboard/app/api/claude/[workItemId]/pin/route.ts +0 -24
  197. package/apps/dashboard/app/api/claude/[workItemId]/route.ts +0 -167
  198. package/apps/dashboard/app/api/claude/sessions/[sessionId]/content/route.ts +0 -52
  199. package/apps/dashboard/app/api/claude/sessions/[sessionId]/message/route.ts +0 -378
  200. package/apps/dashboard/app/api/claude/sessions/[sessionId]/pin/route.ts +0 -24
  201. package/apps/dashboard/app/api/claude/sessions/cleanup/route.ts +0 -34
  202. package/apps/dashboard/app/api/claude/sessions/route.ts +0 -184
  203. package/apps/dashboard/app/api/decisions/[id]/route.ts +0 -25
  204. package/apps/dashboard/app/api/internal/set-project/route.ts +0 -17
  205. package/apps/dashboard/app/api/kanban/route.ts +0 -15
  206. package/apps/dashboard/app/api/settings/env-vars/route.ts +0 -125
  207. package/apps/dashboard/app/api/settings/general/route.ts +0 -21
  208. package/apps/dashboard/app/api/tests/route.ts +0 -9
  209. package/apps/dashboard/app/api/tests/run/route.ts +0 -82
  210. package/apps/dashboard/app/api/tests/run/stream/route.ts +0 -71
  211. package/apps/dashboard/app/api/tests/undefined/route.ts +0 -9
  212. package/apps/dashboard/app/api/usage/route.ts +0 -17
  213. package/apps/dashboard/app/api/work/[id]/description/route.ts +0 -21
  214. package/apps/dashboard/app/api/work/[id]/epic/route.ts +0 -21
  215. package/apps/dashboard/app/api/work/[id]/order/route.ts +0 -21
  216. package/apps/dashboard/app/api/work/[id]/status/route.ts +0 -21
  217. package/apps/dashboard/app/api/work/[id]/title/route.ts +0 -21
  218. package/apps/dashboard/app/layout.tsx +0 -43
  219. package/apps/dashboard/components/UpgradeBanner.tsx +0 -29
  220. package/apps/dashboard/electron/ipc-handlers.js +0 -1028
  221. package/apps/dashboard/electron/main.js +0 -2124
  222. package/apps/dashboard/electron/preload.js +0 -123
  223. package/apps/dashboard/electron/session-manager.js +0 -141
  224. package/apps/dashboard/electron-builder.config.js +0 -357
  225. package/apps/dashboard/hooks/useClaudeSessions.ts +0 -299
  226. package/apps/dashboard/lib/claude-process-manager.ts +0 -492
  227. package/apps/dashboard/lib/db-bridge.ts +0 -282
  228. package/apps/dashboard/lib/prototypes.ts +0 -202
  229. package/apps/dashboard/lib/test-results-db.ts +0 -307
  230. package/apps/dashboard/lib/tests.ts +0 -282
  231. package/apps/dashboard/next.config.js +0 -50
  232. package/apps/dashboard/postcss.config.mjs +0 -7
  233. package/apps/dashboard/public/file.svg +0 -1
  234. package/apps/dashboard/public/globe.svg +0 -1
  235. package/apps/dashboard/public/next.svg +0 -1
  236. package/apps/dashboard/public/vercel.svg +0 -1
  237. package/apps/dashboard/public/window.svg +0 -1
  238. package/apps/dashboard/scripts/download-node.js +0 -104
  239. package/apps/dashboard/scripts/upload-to-r2.js +0 -89
  240. package/docs/bdd-guidance.md +0 -390
@@ -1,6 +1,9 @@
1
- 'use client';
2
1
 
3
2
  import { useState } from 'react';
3
+ import { invoke } from '@/lib/tauri';
4
+ import { Input } from '@/components/ui/Input';
5
+ import { Button } from '@/components/ui/Button';
6
+ import { dataBridge } from '@/lib/data-bridge';
4
7
 
5
8
  interface EnvVar {
6
9
  name: string;
@@ -41,22 +44,8 @@ export function EnvVarsSection({ initialEnvVars, envFiles: initialEnvFiles, sele
41
44
  setCurrentFile(filename);
42
45
  setErrorMessage(null);
43
46
  try {
44
- // Persist selection
45
- await fetch('/api/settings/env-vars', {
46
- method: 'POST',
47
- headers: { 'Content-Type': 'application/json' },
48
- body: JSON.stringify({ action: 'select', file: filename }),
49
- });
50
- // Load vars from selected file
51
- const res = await fetch(`/api/settings/env-vars?file=${encodeURIComponent(filename)}`);
52
- if (!res.ok) {
53
- const data = await res.json();
54
- setErrorMessage(data.error || 'Failed to load environment variables');
55
- setEnvVars([]);
56
- return;
57
- }
58
- const vars = await res.json();
59
- setEnvVars(vars);
47
+ const vars = await dataBridge.getEnvVars(filename);
48
+ setEnvVars(vars.map(v => ({ name: v.key, value: v.value })));
60
49
  } catch {
61
50
  setErrorMessage('Failed to load environment variables');
62
51
  setEnvVars([]);
@@ -65,22 +54,16 @@ export function EnvVarsSection({ initialEnvVars, envFiles: initialEnvFiles, sele
65
54
 
66
55
  const refreshFiles = async () => {
67
56
  try {
68
- const res = await fetch('/api/settings/env-vars?action=discover');
69
- if (res.ok) {
70
- const data = await res.json();
71
- setEnvFiles(data.files || []);
72
- // If selected file no longer exists, fall back
73
- if (currentFile && !data.files.includes(currentFile)) {
74
- const fallback = data.files[0] || null;
75
- setCurrentFile(fallback);
76
- if (fallback) {
77
- const varsRes = await fetch(`/api/settings/env-vars?file=${encodeURIComponent(fallback)}`);
78
- if (varsRes.ok) {
79
- setEnvVars(await varsRes.json());
80
- }
81
- } else {
82
- setEnvVars([]);
83
- }
57
+ const files = await dataBridge.discoverEnvFiles();
58
+ setEnvFiles(files);
59
+ if (currentFile && !files.includes(currentFile)) {
60
+ const fallback = files[0] || null;
61
+ setCurrentFile(fallback);
62
+ if (fallback) {
63
+ const vars = await dataBridge.getEnvVars(fallback);
64
+ setEnvVars(vars.map(v => ({ name: v.key, value: v.value })));
65
+ } else {
66
+ setEnvVars([]);
84
67
  }
85
68
  }
86
69
  } catch {
@@ -91,16 +74,9 @@ export function EnvVarsSection({ initialEnvVars, envFiles: initialEnvFiles, sele
91
74
  const handleCreateEnvFile = async () => {
92
75
  setErrorMessage(null);
93
76
  try {
94
- const res = await fetch('/api/settings/env-vars', {
95
- method: 'POST',
96
- headers: { 'Content-Type': 'application/json' },
97
- body: JSON.stringify({ action: 'create', file: '.env' }),
98
- });
99
- if (!res.ok) {
100
- setErrorMessage('Failed to create .env file');
101
- return;
102
- }
103
- setEnvFiles(['.env']);
77
+ await invoke('db_create_env_file', { filename: '.env' });
78
+ const files = await dataBridge.discoverEnvFiles();
79
+ setEnvFiles(files);
104
80
  setCurrentFile('.env');
105
81
  setEnvVars([]);
106
82
  showSuccess('.env file created');
@@ -126,16 +102,7 @@ export function EnvVarsSection({ initialEnvVars, envFiles: initialEnvFiles, sele
126
102
 
127
103
  setErrorMessage(null);
128
104
  try {
129
- const res = await fetch('/api/settings/env-vars', {
130
- method: 'POST',
131
- headers: { 'Content-Type': 'application/json' },
132
- body: JSON.stringify({ action: 'add', name: formName, value: formValue, file: currentFile }),
133
- });
134
- if (!res.ok) {
135
- const data = await res.json();
136
- setErrorMessage(data.error || 'Failed to add variable');
137
- return;
138
- }
105
+ await invoke('db_create_env_var', { file: currentFile, key: formName, value: formValue });
139
106
  setEnvVars([...envVars, { name: formName, value: formValue }]);
140
107
  setFormName('');
141
108
  setFormValue('');
@@ -150,16 +117,7 @@ export function EnvVarsSection({ initialEnvVars, envFiles: initialEnvFiles, sele
150
117
  if (!editingName) return;
151
118
  setErrorMessage(null);
152
119
  try {
153
- const res = await fetch('/api/settings/env-vars', {
154
- method: 'POST',
155
- headers: { 'Content-Type': 'application/json' },
156
- body: JSON.stringify({ name: editingName, value: formValue, file: currentFile }),
157
- });
158
- if (!res.ok) {
159
- const data = await res.json();
160
- setErrorMessage(data.error || 'Failed to update variable');
161
- return;
162
- }
120
+ await invoke('db_update_env_var', { file: currentFile, key: editingName, value: formValue });
163
121
  setEnvVars(envVars.map(v => v.name === editingName ? { ...v, value: formValue } : v));
164
122
  setFormValue('');
165
123
  setEditingName(null);
@@ -173,16 +131,7 @@ export function EnvVarsSection({ initialEnvVars, envFiles: initialEnvFiles, sele
173
131
  if (!deletingName) return;
174
132
  setErrorMessage(null);
175
133
  try {
176
- const res = await fetch('/api/settings/env-vars', {
177
- method: 'DELETE',
178
- headers: { 'Content-Type': 'application/json' },
179
- body: JSON.stringify({ name: deletingName, file: currentFile }),
180
- });
181
- if (!res.ok) {
182
- const data = await res.json();
183
- setErrorMessage(data.error || 'Failed to delete variable');
184
- return;
185
- }
134
+ await invoke('db_delete_env_var', { file: currentFile, key: deletingName });
186
135
  setEnvVars(envVars.filter(v => v.name !== deletingName));
187
136
  setDeletingName(null);
188
137
  showSuccess('Variable deleted successfully');
@@ -200,21 +149,18 @@ export function EnvVarsSection({ initialEnvVars, envFiles: initialEnvFiles, sele
200
149
  if (!hasFiles) {
201
150
  return (
202
151
  <section id="env-vars">
203
- <div className="flex items-center justify-between mb-4">
152
+ <div className="flex items-center justify-between mb-6">
204
153
  <h2 className="text-lg font-medium text-zinc-900 dark:text-zinc-100">
205
154
  Environment Variables
206
155
  </h2>
207
156
  </div>
208
157
  <div className="text-center py-8">
209
- <p className="text-sm text-zinc-500 dark:text-zinc-400 mb-4">
158
+ <p className="text-base text-zinc-500 dark:text-zinc-400 mb-6">
210
159
  No .env files found
211
160
  </p>
212
- <button
213
- onClick={handleCreateEnvFile}
214
- className="px-4 py-2 text-sm font-medium bg-blue-600 hover:bg-blue-500 text-white rounded transition-colors"
215
- >
161
+ <Button onClick={handleCreateEnvFile} size="sm">
216
162
  Create .env file
217
- </button>
163
+ </Button>
218
164
  </div>
219
165
  </section>
220
166
  );
@@ -222,28 +168,28 @@ export function EnvVarsSection({ initialEnvVars, envFiles: initialEnvFiles, sele
222
168
 
223
169
  return (
224
170
  <section id="env-vars">
225
- <div className="flex items-center justify-between mb-4">
171
+ <div className="flex items-center justify-between mb-6">
226
172
  <h2 className="text-lg font-medium text-zinc-900 dark:text-zinc-100">
227
173
  Environment Variables
228
174
  </h2>
229
- <button
175
+ <Button
230
176
  onClick={() => { setIsAdding(true); setFormName(''); setFormValue(''); setErrorMessage(null); }}
231
- className="px-3 py-1.5 text-sm font-medium bg-blue-600 hover:bg-blue-500 text-white rounded transition-colors"
177
+ size="sm"
232
178
  >
233
179
  Add Variable
234
- </button>
180
+ </Button>
235
181
  </div>
236
182
 
237
183
  {/* File Selector */}
238
184
  {envFiles.length > 0 && (
239
- <div className="mb-4">
240
- <label className="block text-sm font-medium text-zinc-700 dark:text-zinc-300 mb-1">
185
+ <div className="mb-6">
186
+ <label className="block text-base font-medium text-zinc-700 dark:text-zinc-300 mb-1.5">
241
187
  File
242
188
  </label>
243
189
  <select
244
190
  value={currentFile || ''}
245
191
  onChange={(e) => handleFileChange(e.target.value)}
246
- className="w-full px-3 py-2 border border-zinc-300 dark:border-zinc-600 rounded-lg bg-white dark:bg-zinc-800 text-zinc-900 dark:text-zinc-100 text-sm"
192
+ className="w-full px-4 py-3 border-2 border-zinc-300 dark:border-zinc-600 rounded-lg bg-white dark:bg-zinc-800 text-zinc-900 dark:text-zinc-100 text-base"
247
193
  >
248
194
  {envFiles.map((file) => (
249
195
  <option key={file} value={file}>
@@ -255,58 +201,52 @@ export function EnvVarsSection({ initialEnvVars, envFiles: initialEnvFiles, sele
255
201
  )}
256
202
 
257
203
  {successMessage && (
258
- <div className="mb-4 px-4 py-2 bg-green-50 dark:bg-green-900/20 text-green-700 dark:text-green-300 rounded-lg text-sm">
204
+ <div className="mb-6 px-6 py-3 bg-green-50 dark:bg-green-900/20 text-green-700 dark:text-green-300 rounded-lg text-base">
259
205
  {successMessage}
260
206
  </div>
261
207
  )}
262
208
 
263
209
  {errorMessage && (
264
- <div className="mb-4 px-4 py-2 bg-red-50 dark:bg-red-900/20 text-red-700 dark:text-red-300 rounded-lg text-sm">
210
+ <div className="mb-6 px-6 py-3 bg-red-50 dark:bg-red-900/20 text-red-700 dark:text-red-300 rounded-lg text-base">
265
211
  {errorMessage}
266
212
  </div>
267
213
  )}
268
214
 
269
215
  {/* Add Form */}
270
216
  {isAdding && (
271
- <div className="mb-4 p-4 bg-zinc-50 dark:bg-zinc-800/50 rounded-lg">
272
- <div className="space-y-3">
217
+ <div className="mb-6 p-6 bg-zinc-50 dark:bg-zinc-800/50 rounded-lg">
218
+ <div className="space-y-4">
273
219
  <div>
274
- <label className="block text-sm font-medium text-zinc-700 dark:text-zinc-300 mb-1">
220
+ <label className="block text-base font-medium text-zinc-700 dark:text-zinc-300 mb-1.5">
275
221
  Variable Name
276
222
  </label>
277
- <input
223
+ <Input
278
224
  type="text"
279
225
  value={formName}
280
226
  onChange={(e) => { setFormName(e.target.value); setErrorMessage(null); }}
281
- className="w-full px-3 py-2 border border-zinc-300 dark:border-zinc-600 rounded-lg bg-white dark:bg-zinc-800 text-zinc-900 dark:text-zinc-100"
227
+ size="sm"
282
228
  placeholder="API_KEY"
283
229
  />
284
230
  </div>
285
231
  <div>
286
- <label className="block text-sm font-medium text-zinc-700 dark:text-zinc-300 mb-1">
232
+ <label className="block text-base font-medium text-zinc-700 dark:text-zinc-300 mb-1.5">
287
233
  Value
288
234
  </label>
289
- <input
235
+ <Input
290
236
  type="text"
291
237
  value={formValue}
292
238
  onChange={(e) => { setFormValue(e.target.value); setErrorMessage(null); }}
293
- className="w-full px-3 py-2 border border-zinc-300 dark:border-zinc-600 rounded-lg bg-white dark:bg-zinc-800 text-zinc-900 dark:text-zinc-100"
239
+ size="sm"
294
240
  placeholder="your-secret-value"
295
241
  />
296
242
  </div>
297
- <div className="flex gap-2">
298
- <button
299
- onClick={handleAdd}
300
- className="px-3 py-1.5 text-sm font-medium bg-blue-600 hover:bg-blue-500 text-white rounded transition-colors"
301
- >
243
+ <div className="flex gap-3">
244
+ <Button onClick={handleAdd} size="sm">
302
245
  Save
303
- </button>
304
- <button
305
- onClick={() => { setIsAdding(false); setErrorMessage(null); }}
306
- className="px-3 py-1.5 text-sm font-medium text-zinc-600 hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-zinc-100 transition-colors"
307
- >
246
+ </Button>
247
+ <Button onClick={() => { setIsAdding(false); setErrorMessage(null); }} variant="ghost" size="sm">
308
248
  Cancel
309
- </button>
249
+ </Button>
310
250
  </div>
311
251
  </div>
312
252
  </div>
@@ -314,33 +254,27 @@ export function EnvVarsSection({ initialEnvVars, envFiles: initialEnvFiles, sele
314
254
 
315
255
  {/* Edit Form */}
316
256
  {editingName && (
317
- <div className="mb-4 p-4 bg-zinc-50 dark:bg-zinc-800/50 rounded-lg">
318
- <div className="space-y-3">
257
+ <div className="mb-6 p-6 bg-zinc-50 dark:bg-zinc-800/50 rounded-lg">
258
+ <div className="space-y-4">
319
259
  <div>
320
- <label className="block text-sm font-medium text-zinc-700 dark:text-zinc-300 mb-1">
260
+ <label className="block text-base font-medium text-zinc-700 dark:text-zinc-300 mb-1.5">
321
261
  Editing: {editingName}
322
262
  </label>
323
- <input
263
+ <Input
324
264
  type="text"
325
265
  value={formValue}
326
266
  onChange={(e) => setFormValue(e.target.value)}
327
- className="w-full px-3 py-2 border border-zinc-300 dark:border-zinc-600 rounded-lg bg-white dark:bg-zinc-800 text-zinc-900 dark:text-zinc-100"
267
+ size="sm"
328
268
  placeholder="new-value"
329
269
  />
330
270
  </div>
331
- <div className="flex gap-2">
332
- <button
333
- onClick={handleEdit}
334
- className="px-3 py-1.5 text-sm font-medium bg-blue-600 hover:bg-blue-500 text-white rounded transition-colors"
335
- >
271
+ <div className="flex gap-3">
272
+ <Button onClick={handleEdit} size="sm">
336
273
  Save
337
- </button>
338
- <button
339
- onClick={() => setEditingName(null)}
340
- className="px-3 py-1.5 text-sm font-medium text-zinc-600 hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-zinc-100 transition-colors"
341
- >
274
+ </Button>
275
+ <Button onClick={() => setEditingName(null)} variant="ghost" size="sm">
342
276
  Cancel
343
- </button>
277
+ </Button>
344
278
  </div>
345
279
  </div>
346
280
  </div>
@@ -348,30 +282,24 @@ export function EnvVarsSection({ initialEnvVars, envFiles: initialEnvFiles, sele
348
282
 
349
283
  {/* Delete Confirmation */}
350
284
  {deletingName && (
351
- <div className="mb-4 p-4 bg-red-50 dark:bg-red-900/20 rounded-lg">
352
- <p className="text-sm text-red-700 dark:text-red-300 mb-3">
285
+ <div className="mb-6 p-6 bg-red-50 dark:bg-red-900/20 rounded-lg">
286
+ <p className="text-base text-red-700 dark:text-red-300 mb-3">
353
287
  Are you sure you want to delete &quot;{deletingName}&quot;?
354
288
  </p>
355
- <div className="flex gap-2">
356
- <button
357
- onClick={handleDelete}
358
- className="px-3 py-1.5 text-sm font-medium bg-red-600 hover:bg-red-500 text-white rounded transition-colors"
359
- >
289
+ <div className="flex gap-3">
290
+ <Button onClick={handleDelete} variant="destructive" size="sm">
360
291
  Delete
361
- </button>
362
- <button
363
- onClick={() => setDeletingName(null)}
364
- className="px-3 py-1.5 text-sm font-medium text-zinc-600 hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-zinc-100 transition-colors"
365
- >
292
+ </Button>
293
+ <Button onClick={() => setDeletingName(null)} variant="ghost" size="sm">
366
294
  Cancel
367
- </button>
295
+ </Button>
368
296
  </div>
369
297
  </div>
370
298
  )}
371
299
 
372
300
  {/* Env Vars List */}
373
301
  {envVars.length === 0 ? (
374
- <p className="text-sm text-zinc-500 dark:text-zinc-400">
302
+ <p className="text-base text-zinc-500 dark:text-zinc-400">
375
303
  No environment variables in this file yet.
376
304
  </p>
377
305
  ) : (
@@ -379,30 +307,24 @@ export function EnvVarsSection({ initialEnvVars, envFiles: initialEnvFiles, sele
379
307
  {envVars.map((envVar) => (
380
308
  <div
381
309
  key={envVar.name}
382
- className="flex items-center justify-between p-3 bg-zinc-50 dark:bg-zinc-800/50 rounded-lg"
310
+ className="flex items-center justify-between p-4 bg-zinc-50 dark:bg-zinc-800/50 rounded-lg"
383
311
  >
384
312
  <div>
385
- <span className="font-mono text-sm font-medium text-zinc-900 dark:text-zinc-100">
313
+ <span className="font-mono text-base font-medium text-zinc-900 dark:text-zinc-100">
386
314
  {envVar.name}
387
315
  </span>
388
316
  <span className="mx-2 text-zinc-400">=</span>
389
- <span className="font-mono text-sm text-zinc-500 dark:text-zinc-400">
317
+ <span className="font-mono text-base text-zinc-500 dark:text-zinc-400">
390
318
  {maskValue(envVar.value)}
391
319
  </span>
392
320
  </div>
393
- <div className="flex gap-2">
394
- <button
395
- onClick={() => startEdit(envVar)}
396
- className="px-2 py-1 text-xs text-zinc-600 hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-zinc-100 transition-colors"
397
- >
321
+ <div className="flex gap-3">
322
+ <Button onClick={() => startEdit(envVar)} variant="ghost" size="sm">
398
323
  Edit
399
- </button>
400
- <button
401
- onClick={() => setDeletingName(envVar.name)}
402
- className="px-2 py-1 text-xs text-red-600 hover:text-red-700 dark:text-red-400 dark:hover:text-red-300 transition-colors"
403
- >
324
+ </Button>
325
+ <Button onClick={() => setDeletingName(envVar.name)} variant="destructive" size="sm">
404
326
  Delete
405
- </button>
327
+ </Button>
406
328
  </div>
407
329
  </div>
408
330
  ))}