diff --git a/src/components/dashboard/ProjectCard.tsx b/src/components/dashboard/ProjectCard.tsx
index 9d29d6d..3636503 100644
--- a/src/components/dashboard/ProjectCard.tsx
+++ b/src/components/dashboard/ProjectCard.tsx
@@ -12,6 +12,7 @@ import { MentorPanel } from "../mentor/MentorPanel";
import { UserTodoPanel } from "./UserTodoPanel";
import { ProjectServerPanel } from "./ProjectServerPanel";
import { ClaudeConfigModal } from "./ClaudeConfigModal";
+import { ProjectDevVariablesPanel } from "./ProjectDevVariablesPanel";
// ── 蓝图状态徽章 ──────────────────────────────────────────────────────────────
@@ -66,6 +67,7 @@ export function ProjectCard({ project: p }: Props) {
const [showBlueprintPrompt, setShowBlueprintPrompt] = useState(false);
const [showMentor, setShowMentor] = useState(false);
const [showClaudeConfig, setShowClaudeConfig] = useState(false);
+ const [showDevVariables, setShowDevVariables] = useState(false);
const [showTodos, setShowTodos] = useState(false);
const [showServers, setShowServers] = useState(false);
const [showBranchMenu, setShowBranchMenu] = useState(false);
@@ -613,6 +615,7 @@ export function ProjectCard({ project: p }: Props) {
{([
{ icon: "🤖", label: "Claude 自主性", action: () => setShowClaudeConfig(true) },
+ { icon: "🔑", label: "开发变量", action: () => setShowDevVariables(true) },
{ icon: "📝", label: showTodos ? "收起备忘" : "个人备忘", action: () => setShowTodos((v) => !v) },
{ icon: "🖥️", label: showServers ? "收起服务器" : "关联服务器", action: () => setShowServers((v) => !v) },
{ icon: "🚀", label: "CI/CD 控制台", action: () => setShowCicd(true) },
@@ -705,6 +708,14 @@ export function ProjectCard({ project: p }: Props) {
/>
)}
+ {showDevVariables && (
+
setShowDevVariables(false)}
+ />
+ )}
+
{/* 个人备忘 */}
{showTodos && }
diff --git a/src/components/dashboard/ProjectDevVariablesPanel.tsx b/src/components/dashboard/ProjectDevVariablesPanel.tsx
new file mode 100644
index 0000000..5056397
--- /dev/null
+++ b/src/components/dashboard/ProjectDevVariablesPanel.tsx
@@ -0,0 +1,119 @@
+import { useState } from "react";
+import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
+import {
+ listProjectDevVariables,
+ saveProjectDevVariable,
+ revokeProjectDevVariable,
+} from "../../lib/commands";
+import { useUIStore } from "../../store/ui";
+import { Dialog } from "../ui/Dialog";
+
+interface Props {
+ projectId: string;
+ projectName: string;
+ onClose: () => void;
+}
+
+export function ProjectDevVariablesPanel({ projectId, projectName, onClose }: Props) {
+ const queryClient = useQueryClient();
+ const showToast = useUIStore((state) => state.showToast);
+ const [editingName, setEditingName] = useState(null);
+ const [draftValue, setDraftValue] = useState("");
+ const [saving, setSaving] = useState(false);
+ const { data: variables = [], isPending, error } = useQuery({
+ queryKey: ["projectDevVariables", projectId],
+ queryFn: () => listProjectDevVariables(projectId),
+ retry: false,
+ });
+ const handleSave = async (name: string) => {
+ if (!draftValue || saving) return;
+ setSaving(true);
+ try {
+ await saveProjectDevVariable(projectId, name, draftValue);
+ setDraftValue("");
+ setEditingName(null);
+ queryClient.invalidateQueries({ queryKey: ["projectDevVariables", projectId] });
+ showToast("开发变量已保存");
+ } catch (cause) {
+ showToast(`保存失败:${cause}`);
+ } finally {
+ setSaving(false);
+ }
+ };
+ const revokeMutation = useMutation({
+ mutationFn: (name: string) => revokeProjectDevVariable(projectId, name),
+ onSuccess: () => {
+ queryClient.invalidateQueries({ queryKey: ["projectDevVariables", projectId] });
+ showToast("开发变量已撤销");
+ },
+ onError: (cause) => showToast(`撤销失败:${cause}`),
+ });
+
+ return (
+
+ );
+}
diff --git a/src/lib/commands.ts b/src/lib/commands.ts
index 9aeb4ba..f2a1e8e 100644
--- a/src/lib/commands.ts
+++ b/src/lib/commands.ts
@@ -1405,6 +1405,25 @@ export const deleteApiKey = (id: string) =>
export const revealApiKey = (id: string) =>
invoke("reveal_api_key", { id });
+// ── Project development variables ──────────────────────────────────────────
+
+export interface ProjectDevVariableStatus {
+ project_id: string;
+ name: string;
+ purpose: string;
+ configured: boolean;
+ updated_at: string;
+}
+
+export const listProjectDevVariables = (projectId: string) =>
+ invoke("list_project_dev_variables", { projectId });
+
+export const saveProjectDevVariable = (projectId: string, name: string, value: string) =>
+ invoke("save_project_dev_variable", { projectId, name, value });
+
+export const revokeProjectDevVariable = (projectId: string, name: string) =>
+ invoke("revoke_project_dev_variable", { projectId, name });
+
// ── SSH Config & VS Code Remote ──────────────────────────────────────────────
export interface SshConfigStatus {