update
This commit is contained in:
1 parent
f482f25856
commit
d126c4cf21
165 files changed
+123
-541297
No files matched your search
@@ -5,11 +5,13 @@ import {
|
||||
CheckCircle,
|
||||
Cpu,
|
||||
FolderOpen,
|
||||
GearSix,
|
||||
GlobeSimple,
|
||||
Lightning,
|
||||
Rocket,
|
||||
Target,
|
||||
WarningCircle,
|
||||
X,
|
||||
XCircle,
|
||||
} from "@phosphor-icons/react";
|
||||
import { getConnectorExecutionReadinessIssue, isConnectorExecutionReady } from "@shared/connector-policy";
|
||||
@@ -50,6 +52,11 @@ export function CompanyOnboarding({
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [launchSummary, setLaunchSummary] = useState<OnboardingBootstrapResult | null>(null);
|
||||
const [claudeSettingsOpen, setClaudeSettingsOpen] = useState(false);
|
||||
const [claudeApiKey, setClaudeApiKey] = useState("");
|
||||
const [claudeBaseUrl, setClaudeBaseUrl] = useState("");
|
||||
const [claudeModel, setClaudeModel] = useState("");
|
||||
const [claudeSettingsSaving, setClaudeSettingsSaving] = useState(false);
|
||||
|
||||
const executionReadyConnectors = useMemo(
|
||||
() => connectors.filter((connector) => isConnectorExecutionReady(connector)),
|
||||
@@ -70,6 +77,44 @@ export function CompanyOnboarding({
|
||||
}
|
||||
}, [executionReadyConnectors, selectedConnectorId]);
|
||||
|
||||
const openClaudeSettings = useCallback(() => {
|
||||
const claude = connectors.find((c) => c.id === "claude_local");
|
||||
if (!claude) return;
|
||||
const lines = claude.envBindingText.split(/\r?\n/);
|
||||
setClaudeApiKey(lines.find((l) => l.startsWith("ANTHROPIC_API_KEY="))?.split("=").slice(1).join("=") ?? "");
|
||||
setClaudeBaseUrl(lines.find((l) => l.startsWith("ANTHROPIC_BASE_URL="))?.split("=").slice(1).join("=") ?? "");
|
||||
setClaudeModel(claude.model ?? "");
|
||||
setClaudeSettingsOpen(true);
|
||||
}, [connectors]);
|
||||
|
||||
const saveClaudeSettings = useCallback(async () => {
|
||||
setClaudeSettingsSaving(true);
|
||||
try {
|
||||
const envLines: string[] = [];
|
||||
if (claudeApiKey.trim()) envLines.push(`ANTHROPIC_API_KEY=${claudeApiKey.trim()}`);
|
||||
if (claudeBaseUrl.trim()) envLines.push(`ANTHROPIC_BASE_URL=${claudeBaseUrl.trim()}`);
|
||||
const claude = connectors.find((c) => c.id === "claude_local");
|
||||
if (!claude) return;
|
||||
const existingLines = claude.envBindingText.split(/\r?\n/).filter((l) => {
|
||||
const key = l.split("=")[0]?.trim();
|
||||
return key && key !== "ANTHROPIC_API_KEY" && key !== "ANTHROPIC_BASE_URL" && l.trim();
|
||||
});
|
||||
const newEnvText = [...envLines, ...existingLines].join("\n");
|
||||
unwrap(await window.agentCompany.saveConnector({
|
||||
id: "claude_local",
|
||||
command: claude.command,
|
||||
model: claudeModel.trim() || null,
|
||||
envBindingText: newEnvText,
|
||||
notes: claude.notes,
|
||||
}));
|
||||
setClaudeSettingsOpen(false);
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : String(err));
|
||||
} finally {
|
||||
setClaudeSettingsSaving(false);
|
||||
}
|
||||
}, [claudeApiKey, claudeBaseUrl, claudeModel, connectors]);
|
||||
|
||||
const stepLabels = [
|
||||
{ label: t("onboarding.stepLabel1"), icon: Buildings },
|
||||
{ label: t("onboarding.stepLabel2"), icon: Target },
|
||||
@@ -221,7 +266,7 @@ export function CompanyOnboarding({
|
||||
) : (
|
||||
<WarningCircle size={16} weight="fill" className="shrink-0 text-[color:var(--warn)]" />
|
||||
)}
|
||||
<div className="min-w-0">
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className={isReady ? "font-medium text-[color:var(--text)]" : isChecking ? "text-[color:var(--text)]" : "text-[color:var(--muted)]"}>
|
||||
{connector.label}
|
||||
@@ -236,6 +281,16 @@ export function CompanyOnboarding({
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
{connector.id === "claude_local" ? (
|
||||
<button
|
||||
type="button"
|
||||
onClick={(e) => { e.stopPropagation(); openClaudeSettings(); }}
|
||||
className="shrink-0 rounded-[6px] p-1.5 text-[color:var(--muted)] transition hover:bg-[color:var(--panel-soft)] hover:text-[color:var(--text)]"
|
||||
title={currentLocale === "zh" ? "Claude Code 设置" : "Claude Code Settings"}
|
||||
>
|
||||
<GearSix size={14} />
|
||||
</button>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
@@ -569,6 +624,63 @@ export function CompanyOnboarding({
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{claudeSettingsOpen ? (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center bg-[color:var(--bg)]/72 backdrop-blur-sm" onClick={() => setClaudeSettingsOpen(false)}>
|
||||
<div className="w-full max-w-[420px] rounded-[12px] border border-[color:var(--line)] bg-[color:var(--panel)] p-6 shadow-lg" onClick={(e) => e.stopPropagation()}>
|
||||
<div className="mb-5 flex items-center justify-between">
|
||||
<h3 className="text-[16px] font-semibold text-[color:var(--text)]">Claude Code {currentLocale === "zh" ? "设置" : "Settings"}</h3>
|
||||
<button type="button" onClick={() => setClaudeSettingsOpen(false)} className="rounded-[6px] p-1 text-[color:var(--muted)] transition hover:text-[color:var(--text)]"><X size={16} /></button>
|
||||
</div>
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<label className="mb-1.5 block text-[12px] font-medium text-[color:var(--muted-strong)]">API Key</label>
|
||||
<input
|
||||
type="password"
|
||||
className="focus-ring w-full rounded-[8px] border border-[color:var(--line)] bg-[color:var(--panel)] px-3 py-2.5 text-[13px] text-[color:var(--text)] placeholder:text-[color:var(--muted)]"
|
||||
value={claudeApiKey}
|
||||
onChange={(e) => setClaudeApiKey(e.target.value)}
|
||||
placeholder="sk-ant-..."
|
||||
/>
|
||||
<div className="mt-1 text-[11px] text-[color:var(--muted)]">{currentLocale === "zh" ? "留空使用订阅认证" : "Leave empty to use subscription auth"}</div>
|
||||
</div>
|
||||
<div>
|
||||
<label className="mb-1.5 block text-[12px] font-medium text-[color:var(--muted-strong)]">Base URL</label>
|
||||
<input
|
||||
className="focus-ring w-full rounded-[8px] border border-[color:var(--line)] bg-[color:var(--panel)] px-3 py-2.5 text-[13px] text-[color:var(--text)] placeholder:text-[color:var(--muted)]"
|
||||
value={claudeBaseUrl}
|
||||
onChange={(e) => setClaudeBaseUrl(e.target.value)}
|
||||
placeholder="https://api.anthropic.com"
|
||||
/>
|
||||
<div className="mt-1 text-[11px] text-[color:var(--muted)]">{currentLocale === "zh" ? "留空使用默认端点" : "Leave empty for default endpoint"}</div>
|
||||
</div>
|
||||
<div>
|
||||
<label className="mb-1.5 block text-[12px] font-medium text-[color:var(--muted-strong)]">Model</label>
|
||||
<input
|
||||
className="focus-ring w-full rounded-[8px] border border-[color:var(--line)] bg-[color:var(--panel)] px-3 py-2.5 text-[13px] text-[color:var(--text)] placeholder:text-[color:var(--muted)]"
|
||||
value={claudeModel}
|
||||
onChange={(e) => setClaudeModel(e.target.value)}
|
||||
placeholder="claude-sonnet-4-20250514"
|
||||
/>
|
||||
<div className="mt-1 text-[11px] text-[color:var(--muted)]">{currentLocale === "zh" ? "留空使用连接器默认模型" : "Leave empty for connector default"}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-6 flex justify-end gap-3">
|
||||
<button type="button" onClick={() => setClaudeSettingsOpen(false)} className="rounded-[8px] px-4 py-2 text-[13px] font-medium text-[color:var(--muted)] transition hover:text-[color:var(--text)]">
|
||||
{currentLocale === "zh" ? "取消" : "Cancel"}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => void saveClaudeSettings()}
|
||||
disabled={claudeSettingsSaving}
|
||||
className="rounded-[8px] bg-[color:var(--accent)] px-4 py-2 text-[13px] font-medium text-white transition hover:opacity-90 disabled:opacity-50"
|
||||
>
|
||||
{claudeSettingsSaving ? (currentLocale === "zh" ? "保存中..." : "Saving...") : (currentLocale === "zh" ? "保存" : "Save")}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -19,24 +19,12 @@ function getAuthActionCopy(connector: ConnectorRecord) {
|
||||
message: "Claude Code is installed, but the local CLI is not authenticated for this desktop runtime.",
|
||||
buttonLabel: "Open Terminal To Sign In",
|
||||
};
|
||||
case "opencode_local":
|
||||
return {
|
||||
title: "OpenCode provider login required",
|
||||
message: "OpenCode is installed, but the provider login must be completed before runs can start.",
|
||||
buttonLabel: "Open Terminal To Sign In",
|
||||
};
|
||||
case "gemini_local":
|
||||
return {
|
||||
title: "Gemini authentication required",
|
||||
message: "Gemini CLI is available, but the runtime still needs an authenticated session. AgentCompany will open Gemini in a terminal and you can complete its interactive auth flow there.",
|
||||
buttonLabel: "Open Terminal",
|
||||
};
|
||||
case "kimi_local":
|
||||
return {
|
||||
title: "Kimi interactive login required",
|
||||
message: "Kimi Code is available in generic mode. AgentCompany can open the CLI in a terminal so you can complete the interactive login flow there if prompted.",
|
||||
buttonLabel: "Open Terminal",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,8 +43,8 @@ export function ConnectorEditor({ connector, onSaved }: { connector: ConnectorRe
|
||||
const authPollTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||
const authActionCopy = getAuthActionCopy(connector);
|
||||
const needsLogin = connector.authState === "required" || connector.status === "auth_required";
|
||||
const requiresExplicitModel = connector.id === "opencode_local";
|
||||
const shouldLoadModelOptions = connector.capabilityMatrix.modelDiscovery || connector.id === "opencode_local";
|
||||
const requiresExplicitModel = false;
|
||||
const shouldLoadModelOptions = connector.capabilityMatrix.modelDiscovery;
|
||||
|
||||
useEffect(() => {
|
||||
setModel(connector.model ?? "");
|
||||
|
||||
@@ -1176,8 +1176,6 @@ const adapterLabels: Record<string, string> = {
|
||||
claude_local: "Claude",
|
||||
codex_local: "Codex",
|
||||
gemini_local: "Gemini",
|
||||
opencode_local: "OpenCode",
|
||||
kimi_local: "Kimi",
|
||||
};
|
||||
|
||||
export function OrgChart({
|
||||
|
||||
Reference in new issue
Block a user