tijiao
This commit is contained in:
@@ -1,42 +1,285 @@
|
||||
@import url("https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap");
|
||||
|
||||
:root {
|
||||
--background: #ffffff;
|
||||
--foreground: #171717;
|
||||
}
|
||||
--bg-color: #0d1117;
|
||||
--bg-gradient: radial-gradient(circle at top right, #1a2333, #0d1117);
|
||||
--text-primary: #e6edf3;
|
||||
--text-secondary: #8b949e;
|
||||
--accent-color: #58a6ff;
|
||||
--accent-hover: #3182ce;
|
||||
--panel-bg: rgba(22, 27, 34, 0.65);
|
||||
--panel-border: rgba(48, 54, 61, 0.5);
|
||||
--input-bg: rgba(13, 17, 23, 0.7);
|
||||
--input-border: #30363d;
|
||||
--input-focus: #58a6ff;
|
||||
--success-color: #238636;
|
||||
--error-color: #f85149;
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--background: #0a0a0a;
|
||||
--foreground: #ededed;
|
||||
}
|
||||
}
|
||||
--glass-blur: blur(12px);
|
||||
--glass-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.37);
|
||||
|
||||
html,
|
||||
body {
|
||||
max-width: 100vw;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
body {
|
||||
color: var(--foreground);
|
||||
background: var(--background);
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
--transition-speed: 0.2s;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
body {
|
||||
font-family:
|
||||
"Inter",
|
||||
-apple-system,
|
||||
BlinkMacSystemFont,
|
||||
"Segoe UI",
|
||||
Roboto,
|
||||
Helvetica,
|
||||
Arial,
|
||||
sans-serif;
|
||||
background-color: var(--bg-color);
|
||||
background-image: var(--bg-gradient);
|
||||
color: var(--text-primary);
|
||||
min-height: 100vh;
|
||||
line-height: 1.5;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
html {
|
||||
color-scheme: dark;
|
||||
main {
|
||||
max-width: 1000px;
|
||||
margin: 0 auto;
|
||||
padding: 3rem 1.5rem;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 2.5rem;
|
||||
font-weight: 700;
|
||||
margin-bottom: 0.5rem;
|
||||
background: linear-gradient(135deg, #58a6ff 0%, #bc8cff 100%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
text-align: center;
|
||||
color: var(--text-secondary);
|
||||
font-size: 1.1rem;
|
||||
margin-bottom: 3rem;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
/* Glassmorphism Panel Container */
|
||||
.glass-panel {
|
||||
background: var(--panel-bg);
|
||||
backdrop-filter: var(--glass-blur);
|
||||
-webkit-backdrop-filter: var(--glass-blur);
|
||||
border: 1px solid var(--panel-border);
|
||||
border-radius: 16px;
|
||||
padding: 2.5rem;
|
||||
box-shadow: var(--glass-shadow);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2rem;
|
||||
animation: fadeIn 0.6s ease-out;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.glass-panel {
|
||||
flex-direction: row;
|
||||
align-items: stretch;
|
||||
}
|
||||
}
|
||||
|
||||
.form-section {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
.preview-section {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
border-radius: 12px;
|
||||
border: 1px solid var(--panel-border);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Form Controls */
|
||||
.form-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.form-group label {
|
||||
font-weight: 500;
|
||||
font-size: 0.95rem;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.form-group input[type="text"],
|
||||
.form-group input[type="number"],
|
||||
.form-group select {
|
||||
width: 100%;
|
||||
padding: 0.75rem 1rem;
|
||||
background: var(--input-bg);
|
||||
border: 1px solid var(--input-border);
|
||||
border-radius: 8px;
|
||||
color: var(--text-primary);
|
||||
font-size: 1rem;
|
||||
font-family: inherit;
|
||||
transition: all var(--transition-speed) ease;
|
||||
}
|
||||
|
||||
.form-group input:focus,
|
||||
.form-group select:focus {
|
||||
outline: none;
|
||||
border-color: var(--input-focus);
|
||||
box-shadow: 0 0 0 2px rgba(88, 166, 255, 0.2);
|
||||
}
|
||||
|
||||
.form-group select option {
|
||||
background-color: var(--bg-color);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.checkbox-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.checkbox-group input[type="checkbox"] {
|
||||
appearance: none;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border: 2px solid var(--input-border);
|
||||
border-radius: 4px;
|
||||
background: var(--input-bg);
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
transition: all var(--transition-speed);
|
||||
}
|
||||
|
||||
.checkbox-group input[type="checkbox"]:checked {
|
||||
background: var(--accent-color);
|
||||
border-color: var(--accent-color);
|
||||
}
|
||||
|
||||
.checkbox-group input[type="checkbox"]:checked::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
left: 6px;
|
||||
width: 5px;
|
||||
height: 10px;
|
||||
border: solid white;
|
||||
border-width: 0 2px 2px 0;
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
.form-text {
|
||||
font-size: 0.8rem;
|
||||
color: var(--text-secondary);
|
||||
margin-top: 0.25rem;
|
||||
}
|
||||
|
||||
/* Tabs */
|
||||
.tabs {
|
||||
display: flex;
|
||||
border-bottom: 1px solid var(--panel-border);
|
||||
background: rgba(13, 17, 23, 0.5);
|
||||
}
|
||||
|
||||
.tab-btn {
|
||||
flex: 1;
|
||||
background: none;
|
||||
border: none;
|
||||
padding: 1rem;
|
||||
color: var(--text-secondary);
|
||||
font-size: 0.95rem;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
transition: all var(--transition-speed);
|
||||
border-bottom: 2px solid transparent;
|
||||
}
|
||||
|
||||
.tab-btn:hover {
|
||||
color: var(--text-primary);
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
|
||||
.tab-btn.active {
|
||||
color: var(--accent-color);
|
||||
border-bottom-color: var(--accent-color);
|
||||
background: rgba(88, 166, 255, 0.1);
|
||||
}
|
||||
|
||||
/* Code Preview */
|
||||
.code-container {
|
||||
flex: 1;
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.code-container pre {
|
||||
margin: 0;
|
||||
padding: 1.5rem;
|
||||
overflow-x: auto;
|
||||
font-family:
|
||||
"ui-monospace", "SFMono-Regular", "Menlo", "Monaco", "Consolas", monospace;
|
||||
font-size: 0.9rem;
|
||||
color: #c9d1d9;
|
||||
line-height: 1.6;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-all;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.copy-btn {
|
||||
position: absolute;
|
||||
top: 1rem;
|
||||
right: 1rem;
|
||||
background: rgba(48, 54, 61, 0.8);
|
||||
border: 1px solid var(--input-border);
|
||||
color: var(--text-primary);
|
||||
padding: 0.5rem 1rem;
|
||||
border-radius: 6px;
|
||||
font-size: 0.85rem;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
transition: all var(--transition-speed);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
backdrop-filter: blur(4px);
|
||||
}
|
||||
|
||||
.copy-btn:hover {
|
||||
background: var(--input-border);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.copy-btn.copied {
|
||||
background: var(--success-color);
|
||||
border-color: var(--success-color);
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* Animations */
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,66 +1,14 @@
|
||||
import Image from "next/image";
|
||||
import styles from "./page.module.css";
|
||||
import ScriptGenerator from '@/components/ScriptGenerator';
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<div className={styles.page}>
|
||||
<main className={styles.main}>
|
||||
<Image
|
||||
className={styles.logo}
|
||||
src="/next.svg"
|
||||
alt="Next.js logo"
|
||||
width={100}
|
||||
height={20}
|
||||
priority
|
||||
/>
|
||||
<div className={styles.intro}>
|
||||
<h1>To get started, edit the page.tsx file.</h1>
|
||||
<p>
|
||||
Looking for a starting point or more instructions? Head over to{" "}
|
||||
<a
|
||||
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Templates
|
||||
</a>{" "}
|
||||
or the{" "}
|
||||
<a
|
||||
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Learning
|
||||
</a>{" "}
|
||||
center.
|
||||
</p>
|
||||
</div>
|
||||
<div className={styles.ctas}>
|
||||
<a
|
||||
className={styles.primary}
|
||||
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<Image
|
||||
className={styles.logo}
|
||||
src="/vercel.svg"
|
||||
alt="Vercel logomark"
|
||||
width={16}
|
||||
height={16}
|
||||
/>
|
||||
Deploy Now
|
||||
</a>
|
||||
<a
|
||||
className={styles.secondary}
|
||||
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Documentation
|
||||
</a>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
<main>
|
||||
<h1>OpenClaw 自动化脚本生成器</h1>
|
||||
<p className="subtitle">
|
||||
为您的 OpenClaw 快速生成可跨平台的静默安装与配置脚本。
|
||||
</p>
|
||||
|
||||
<ScriptGenerator />
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
201
src/components/ScriptGenerator.tsx
Normal file
201
src/components/ScriptGenerator.tsx
Normal file
@@ -0,0 +1,201 @@
|
||||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
import { generateScript, OpenClawConfig } from '../utils/generateScripts';
|
||||
|
||||
export default function ScriptGenerator() {
|
||||
const [config, setConfig] = useState<OpenClawConfig>({
|
||||
workspace: '',
|
||||
mode: 'local',
|
||||
flow: 'quickstart',
|
||||
nodeManager: 'npm',
|
||||
installDaemon: true,
|
||||
gatewayPort: '',
|
||||
gatewayBind: '',
|
||||
gatewayToken: '',
|
||||
aiProvider: 'skip',
|
||||
apiKey: '',
|
||||
defaultModel: ''
|
||||
});
|
||||
|
||||
const [activeTab, setActiveTab] = useState<'unix' | 'windows'>('unix');
|
||||
const [copied, setCopied] = useState(false);
|
||||
|
||||
const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement>) => {
|
||||
const { name, value, type } = e.target;
|
||||
setConfig(prev => ({
|
||||
...prev,
|
||||
[name]: type === 'checkbox' ? (e.target as HTMLInputElement).checked : value
|
||||
}));
|
||||
};
|
||||
|
||||
const currentScript = generateScript(config, activeTab);
|
||||
|
||||
const handleCopy = async () => {
|
||||
try {
|
||||
await navigator.clipboard.writeText(currentScript);
|
||||
setCopied(true);
|
||||
setTimeout(() => setCopied(false), 2000);
|
||||
} catch (err) {
|
||||
console.error('Failed to copy text: ', err);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="glass-panel">
|
||||
|
||||
{/* Configuration Form */}
|
||||
<div className="form-section">
|
||||
<h2 style={{ fontSize: '1.5rem', marginBottom: '1rem' }}>参数配置</h2>
|
||||
|
||||
<div className="form-group">
|
||||
<label htmlFor="workspace">工作区路径 (Workspace Path)</label>
|
||||
<input
|
||||
type="text"
|
||||
id="workspace"
|
||||
name="workspace"
|
||||
value={config.workspace}
|
||||
onChange={handleChange}
|
||||
placeholder="例如: /opt/openclaw 或 C:\openclaw"
|
||||
/>
|
||||
<span className="form-text">OpenClaw 存储其节点数据的目录路径。</span>
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'flex', gap: '1rem' }}>
|
||||
<div className="form-group" style={{ flex: 1 }}>
|
||||
<label htmlFor="mode">运行模式 (Mode)</label>
|
||||
<select name="mode" id="mode" value={config.mode} onChange={handleChange}>
|
||||
<option value="local">本地模式 (Local)</option>
|
||||
<option value="remote">中继模式 (Remote)</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div className="form-group" style={{ flex: 1 }}>
|
||||
<label htmlFor="flow">向导流程 (Flow)</label>
|
||||
<select name="flow" id="flow" value={config.flow} onChange={handleChange}>
|
||||
<option value="quickstart">快速开始 (Quickstart)</option>
|
||||
<option value="advanced">高级配置 (Advanced)</option>
|
||||
<option value="manual">手动 (Manual)</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="form-group">
|
||||
<label htmlFor="nodeManager">Node 包管理器</label>
|
||||
<select name="nodeManager" id="nodeManager" value={config.nodeManager} onChange={handleChange}>
|
||||
<option value="npm">NPM</option>
|
||||
<option value="pnpm">PNPM</option>
|
||||
<option value="bun">BUN</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div className="form-group" style={{ marginTop: '0.5rem' }}>
|
||||
<label className="checkbox-group">
|
||||
<input
|
||||
type="checkbox"
|
||||
name="installDaemon"
|
||||
checked={config.installDaemon}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
自动安装后台守护进程 (Daemon)
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<h3 style={{ fontSize: '1.1rem', marginTop: '1rem', borderBottom: '1px solid var(--panel-border)', paddingBottom: '0.5rem' }}>AI 模型配置</h3>
|
||||
|
||||
<div className="form-group">
|
||||
<label htmlFor="aiProvider">AI 服务提供商 (AI Provider)</label>
|
||||
<select name="aiProvider" id="aiProvider" value={config.aiProvider} onChange={handleChange}>
|
||||
<option value="skip">跳过交互式认证 (默认)</option>
|
||||
<option value="openai">OpenAI</option>
|
||||
<option value="anthropic">Anthropic</option>
|
||||
<option value="custom">自定义 (Custom)</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
{config.aiProvider !== 'skip' && (
|
||||
<div style={{ display: 'flex', gap: '1rem', flexWrap: 'wrap' }}>
|
||||
<div className="form-group" style={{ flex: '1 1 100%' }}>
|
||||
<label htmlFor="apiKey">API 密钥 (API Key)</label>
|
||||
<input
|
||||
type="text"
|
||||
name="apiKey"
|
||||
id="apiKey"
|
||||
placeholder="在此输入您的 API Key"
|
||||
value={config.apiKey}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</div>
|
||||
<div className="form-group" style={{ flex: '1 1 100%' }}>
|
||||
<label htmlFor="defaultModel">默认模型 (Default Model)</label>
|
||||
<input
|
||||
type="text"
|
||||
name="defaultModel"
|
||||
id="defaultModel"
|
||||
placeholder="例如: gpt-4o, claude-3-5-sonnet-latest"
|
||||
value={config.defaultModel}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<h3 style={{ fontSize: '1.1rem', marginTop: '1rem', borderBottom: '1px solid var(--panel-border)', paddingBottom: '0.5rem' }}>网关设置 (可选)</h3>
|
||||
|
||||
<div style={{ display: 'flex', gap: '1rem' }}>
|
||||
<div className="form-group" style={{ flex: 1 }}>
|
||||
<label htmlFor="gatewayPort">网关端口 (Port)</label>
|
||||
<input type="number" name="gatewayPort" id="gatewayPort" placeholder="8080" value={config.gatewayPort} onChange={handleChange} />
|
||||
</div>
|
||||
<div className="form-group" style={{ flex: 1 }}>
|
||||
<label htmlFor="gatewayBind">网关绑定地址 (Bind)</label>
|
||||
<input type="text" name="gatewayBind" id="gatewayBind" placeholder="0.0.0.0" value={config.gatewayBind} onChange={handleChange} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="form-group">
|
||||
<label htmlFor="gatewayToken">网关令牌 (Token)</label>
|
||||
<input type="text" name="gatewayToken" id="gatewayToken" placeholder="留空则由系统自动生成" value={config.gatewayToken} onChange={handleChange} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Script Preview */}
|
||||
<div className="preview-section">
|
||||
<div className="tabs">
|
||||
<button
|
||||
className={`tab-btn ${activeTab === 'unix' ? 'active' : ''}`}
|
||||
onClick={() => setActiveTab('unix')}
|
||||
>
|
||||
Linux / Mac (.sh)
|
||||
</button>
|
||||
<button
|
||||
className={`tab-btn ${activeTab === 'windows' ? 'active' : ''}`}
|
||||
onClick={() => setActiveTab('windows')}
|
||||
>
|
||||
Windows (.ps1)
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="code-container">
|
||||
<button className={`copy-btn ${copied ? 'copied' : ''}`} onClick={handleCopy}>
|
||||
{copied ? (
|
||||
<>
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><polyline points="20 6 9 17 4 12"></polyline></svg>
|
||||
已复制!
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>
|
||||
复制脚本
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
<pre>
|
||||
<code>{currentScript}</code>
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
97
src/utils/generateScripts.ts
Normal file
97
src/utils/generateScripts.ts
Normal file
@@ -0,0 +1,97 @@
|
||||
export interface OpenClawConfig {
|
||||
workspace: string;
|
||||
mode: 'local' | 'remote';
|
||||
flow: 'quickstart' | 'advanced' | 'manual';
|
||||
nodeManager: 'npm' | 'pnpm' | 'bun';
|
||||
installDaemon: boolean;
|
||||
gatewayPort: string;
|
||||
gatewayBind: string;
|
||||
gatewayToken: string;
|
||||
aiProvider: 'openai' | 'anthropic' | 'custom' | 'skip';
|
||||
apiKey: string;
|
||||
defaultModel: string;
|
||||
}
|
||||
|
||||
export const generateScript = (config: OpenClawConfig, platform: 'unix' | 'windows') => {
|
||||
const args: string[] = ['--non-interactive'];
|
||||
|
||||
if (config.workspace) args.push(`--workspace "${config.workspace}"`);
|
||||
if (config.mode) args.push(`--mode ${config.mode}`);
|
||||
if (config.flow) args.push(`--flow ${config.flow}`);
|
||||
if (config.nodeManager) args.push(`--node-manager ${config.nodeManager}`);
|
||||
|
||||
if (config.installDaemon) {
|
||||
args.push('--install-daemon');
|
||||
} else {
|
||||
args.push('--skip-daemon');
|
||||
}
|
||||
|
||||
if (config.gatewayPort) args.push(`--gateway-port ${config.gatewayPort}`);
|
||||
if (config.gatewayBind) args.push(`--gateway-bind ${config.gatewayBind}`);
|
||||
if (config.gatewayToken) args.push(`--gateway-token "${config.gatewayToken}"`);
|
||||
|
||||
if (config.aiProvider === 'skip') {
|
||||
args.push('--auth-choice skip');
|
||||
} else {
|
||||
args.push(`--auth-choice ${config.aiProvider}`);
|
||||
if (config.apiKey) {
|
||||
if (config.aiProvider === 'openai') args.push(`--openai-api-key "${config.apiKey}"`);
|
||||
else if (config.aiProvider === 'anthropic') args.push(`--anthropic-api-key "${config.apiKey}"`);
|
||||
else if (config.aiProvider === 'custom') args.push(`--custom-api-key "${config.apiKey}"`);
|
||||
}
|
||||
if (config.defaultModel) {
|
||||
args.push(`--default-model "${config.defaultModel}"`);
|
||||
}
|
||||
}
|
||||
|
||||
const joinedArgs = args.join(' ');
|
||||
|
||||
if (platform === 'unix') {
|
||||
return `#!/bin/bash
|
||||
|
||||
# 将代码包裹在函数中,避免直接复制粘贴运行失败时导致终端退出
|
||||
install_openclaw() {
|
||||
# 检查当前系统环境是否安装了所选的包管理器
|
||||
if ! command -v ${config.nodeManager} &> /dev/null
|
||||
then
|
||||
echo "错误: 未在您的系统中检测到 \`${config.nodeManager}\` 环境。"
|
||||
echo "请先安装 Node.js (https://nodejs.org) 或相应的包管理工具后再运行此脚本。"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "正在使用 ${config.nodeManager} 全局安装 OpenClaw 最新版..."
|
||||
${config.nodeManager === 'npm' ? 'npm install -g' : config.nodeManager === 'pnpm' ? 'pnpm add -g' : 'bun install -g'} openclaw@latest
|
||||
|
||||
echo "正在运行 OpenClaw 自动化配置向导..."
|
||||
openclaw onboard ${joinedArgs}
|
||||
|
||||
echo "安装与配置完成!"
|
||||
}
|
||||
|
||||
install_openclaw
|
||||
`;
|
||||
} else {
|
||||
return `# Windows PowerShell 自动化脚本 (建议以管理员身份运行)
|
||||
|
||||
# 将代码包裹在函数中,避免直接执行失败时导致终端异常
|
||||
function Install-OpenClaw {
|
||||
# 检查当前系统环境是否安装了所选的包管理器
|
||||
if (!(Get-Command ${config.nodeManager} -ErrorAction SilentlyContinue)) {
|
||||
Write-Host "错误: 未在您的系统中检测到 \`${config.nodeManager}\` 环境。" -ForegroundColor Red
|
||||
Write-Host "请先下载并安装 Node.js (https://nodejs.org) 或相应的包管理工具后再运行此脚本。" -ForegroundColor Yellow
|
||||
return
|
||||
}
|
||||
|
||||
Write-Host "正在使用 ${config.nodeManager} 全局安装 OpenClaw 最新版..."
|
||||
${config.nodeManager === 'npm' ? 'npm install -g' : config.nodeManager === 'pnpm' ? 'pnpm add -g' : 'bun install -g'} openclaw@latest
|
||||
|
||||
Write-Host "正在运行 OpenClaw 自动化配置向导..."
|
||||
openclaw onboard ${joinedArgs}
|
||||
|
||||
Write-Host "安装与配置完成!"
|
||||
}
|
||||
|
||||
Install-OpenClaw
|
||||
`;
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user