feat(launcher-ui): rebuild config UI with Bulma and offline CodeMirror
- migrate launcher UI to a Bulma-based layout with responsive sidebar/topbar panels\n- split logic into index.js and move locale strings to i18n.json\n- add multi-language handling with browser language default and language selector\n- switch raw JSON editor to offline CodeMirror (local vendor bundle) with live highlight/format/validation\n- improve process/auth/models UX, including persistent actionable error notice for missing picoclaw binary\n- embed new static assets (index.js, i18n.json, vendor/*) in launcher binary\n\nValidated with: go test ./cmd/picoclaw-launcher/...
This commit is contained in:
parent
8207c1c7e6
commit
46f4198874
5 changed files with 3179 additions and 1900 deletions
734
cmd/picoclaw-launcher/internal/ui/i18n.json
Normal file
734
cmd/picoclaw-launcher/internal/ui/i18n.json
Normal file
|
|
@ -0,0 +1,734 @@
|
||||||
|
{
|
||||||
|
"en": {
|
||||||
|
"start": "Start",
|
||||||
|
"stop": "Stop",
|
||||||
|
"save": "Save",
|
||||||
|
"cancel": "Cancel",
|
||||||
|
"edit": "Edit",
|
||||||
|
"delete": "Delete",
|
||||||
|
"enabled": "Enabled",
|
||||||
|
"comingSoon": "Coming soon",
|
||||||
|
"sidebar.providers": "Providers",
|
||||||
|
"sidebar.models": "Models",
|
||||||
|
"sidebar.auth": "Auth",
|
||||||
|
"sidebar.channels": "Channels",
|
||||||
|
"sidebar.feishu": "Feishu",
|
||||||
|
"channel.telegram": "Telegram",
|
||||||
|
"channel.discord": "Discord",
|
||||||
|
"channel.slack": "Slack",
|
||||||
|
"channel.wecom": "WeCom",
|
||||||
|
"channel.wecom_app": "WeCom App",
|
||||||
|
"channel.dingtalk": "DingTalk",
|
||||||
|
"channel.feishu": "Feishu",
|
||||||
|
"channel.line": "LINE",
|
||||||
|
"channel.whatsapp": "WhatsApp",
|
||||||
|
"channel.qq": "QQ",
|
||||||
|
"channel.onebot": "OneBot",
|
||||||
|
"channel.maixcam": "MaixCAM",
|
||||||
|
"sidebar.logs": "Logs",
|
||||||
|
"sidebar.rawjson": "Raw JSON",
|
||||||
|
"models.title": "Models",
|
||||||
|
"models.desc": "Manage LLM model configurations. Models without an API key are grayed out. Only available models can be set as primary.",
|
||||||
|
"models.add": "+ Add Custom Model",
|
||||||
|
"models.noModels": "No models configured.",
|
||||||
|
"models.primary": "Primary",
|
||||||
|
"models.noKey": "No Key",
|
||||||
|
"models.setPrimary": "Set Primary",
|
||||||
|
"models.editModel": "Edit Model",
|
||||||
|
"models.addModel": "Add Model",
|
||||||
|
"models.advancedOptions": "Advanced Options",
|
||||||
|
"models.deleteConfirm": "Delete model \"{name}\"?",
|
||||||
|
"models.requiredFields": "Model Name and Model ID are required",
|
||||||
|
"field.modelName": "Model Name",
|
||||||
|
"field.modelId": "Model ID",
|
||||||
|
"field.modelIdHint": "Format: protocol/model-id",
|
||||||
|
"field.apiKey": "API Key",
|
||||||
|
"field.apiBase": "API Base",
|
||||||
|
"field.proxy": "Proxy",
|
||||||
|
"field.authMethod": "Auth Method",
|
||||||
|
"field.connectMode": "Connect Mode",
|
||||||
|
"field.workspace": "Workspace",
|
||||||
|
"field.rpm": "RPM Limit",
|
||||||
|
"field.requestTimeout": "Request Timeout (s)",
|
||||||
|
"auth.title": "Provider Authentication",
|
||||||
|
"auth.desc": "Login to providers using OAuth or API tokens. Credentials are stored locally in <code style=\"font-family:'JetBrains Mono',monospace;font-size:12px;background:var(--bg-elevated);padding:2px 6px;border-radius:4px;\">~/.picoclaw/auth.json</code>.",
|
||||||
|
"auth.notLoggedIn": "Not logged in",
|
||||||
|
"auth.active": "Active",
|
||||||
|
"auth.expired": "Expired",
|
||||||
|
"auth.needsRefresh": "Needs Refresh",
|
||||||
|
"auth.authenticating": "Authenticating...",
|
||||||
|
"auth.loginDevice": "Login (Device Code)",
|
||||||
|
"auth.loginToken": "Login (API Token)",
|
||||||
|
"auth.loginOAuth": "Login (Browser OAuth)",
|
||||||
|
"auth.logout": "Logout",
|
||||||
|
"auth.retry": "Retry",
|
||||||
|
"auth.waiting": "Waiting...",
|
||||||
|
"auth.pasteKey": "Paste your API key here...",
|
||||||
|
"auth.step1": "Step 1: Click the link below",
|
||||||
|
"auth.step2": "Step 2: Enter this code",
|
||||||
|
"auth.step3": "Step 3: Complete auth in browser, this page updates automatically",
|
||||||
|
"auth.method": "Method",
|
||||||
|
"auth.email": "Email",
|
||||||
|
"auth.account": "Account",
|
||||||
|
"auth.project": "Project",
|
||||||
|
"auth.expires": "Expires",
|
||||||
|
"ch.configure": "Configure {name} channel settings.",
|
||||||
|
"ch.docLink": "Configuration Guide",
|
||||||
|
"ch.accessControl": "Access Control",
|
||||||
|
"ch.allowFrom": "Allow From (User IDs)",
|
||||||
|
"ch.addItem": "+ Add",
|
||||||
|
"ch.mentionOnly": "Mention Only",
|
||||||
|
"ch.mentionOnlyHint": "Only respond when mentioned",
|
||||||
|
"ch.groupTrigger": "Group Trigger Prefixes",
|
||||||
|
"logs.title": "Gateway Logs",
|
||||||
|
"logs.desc": "Real-time output from the gateway process.",
|
||||||
|
"logs.clear": "Clear Display",
|
||||||
|
"logs.autoScroll": "Auto-scroll",
|
||||||
|
"logs.noLogs": "No logs available. Start the gateway to see output here.",
|
||||||
|
"logs.noCapture": "Logs are not available. The gateway was not started from this launcher.",
|
||||||
|
"raw.title": "Raw JSON",
|
||||||
|
"raw.desc": "Directly edit the configuration file.",
|
||||||
|
"raw.reload": "Reload",
|
||||||
|
"raw.format": "Format",
|
||||||
|
"status.configLoaded": "Config loaded",
|
||||||
|
"status.configSaved": "Config saved",
|
||||||
|
"status.loadFailed": "Load failed",
|
||||||
|
"status.saveFailed": "Save failed",
|
||||||
|
"status.formatted": "Formatted",
|
||||||
|
"status.invalidJson": "Invalid JSON, please fix before saving",
|
||||||
|
"status.jsonValid": "JSON valid",
|
||||||
|
"status.jsonInvalid": "JSON invalid",
|
||||||
|
"status.saved": "{name} saved",
|
||||||
|
"status.tokenEmpty": "Token cannot be empty",
|
||||||
|
"status.tokenSaved": "Token saved for {name}",
|
||||||
|
"status.loggedOut": "Logged out from {name}",
|
||||||
|
"status.loginFailed": "Login failed",
|
||||||
|
"status.logoutFailed": "Logout failed",
|
||||||
|
"status.openingBrowser": "Opening browser for authentication...",
|
||||||
|
"status.loginStarted": "Login started...",
|
||||||
|
"status.loginSuccess": "Login successful!",
|
||||||
|
"process.running": "Service running",
|
||||||
|
"process.notRunning": "Service not running",
|
||||||
|
"process.starting": "Starting gateway...",
|
||||||
|
"process.started": "Gateway started",
|
||||||
|
"process.startFailed": "Failed to start gateway",
|
||||||
|
"process.stopping": "Stopping gateway...",
|
||||||
|
"process.stopped": "Gateway stopped",
|
||||||
|
"process.stopFailed": "Failed to stop gateway",
|
||||||
|
"process.needModel": "At least one model with API key is required",
|
||||||
|
"process.needChannel": "At least one channel must be enabled",
|
||||||
|
"process.checkLogs": "Check Logs for details",
|
||||||
|
"process.needBoth": "Need model with API key and enabled channel to start",
|
||||||
|
"process.picoclawNotFoundHint": "Hint: put picoclaw-launcher and the picoclaw executable in the same directory, or add picoclaw's directory to PATH."
|
||||||
|
},
|
||||||
|
"zh": {
|
||||||
|
"start": "启动",
|
||||||
|
"stop": "停止",
|
||||||
|
"save": "保存",
|
||||||
|
"cancel": "取消",
|
||||||
|
"edit": "编辑",
|
||||||
|
"delete": "删除",
|
||||||
|
"enabled": "启用",
|
||||||
|
"comingSoon": "即将推出",
|
||||||
|
"sidebar.providers": "提供商",
|
||||||
|
"sidebar.models": "模型",
|
||||||
|
"sidebar.auth": "认证",
|
||||||
|
"sidebar.channels": "通道",
|
||||||
|
"sidebar.feishu": "飞书",
|
||||||
|
"channel.telegram": "Telegram",
|
||||||
|
"channel.discord": "Discord",
|
||||||
|
"channel.slack": "Slack",
|
||||||
|
"channel.wecom": "企业微信机器人",
|
||||||
|
"channel.wecom_app": "企业微信应用",
|
||||||
|
"channel.dingtalk": "钉钉",
|
||||||
|
"channel.feishu": "飞书",
|
||||||
|
"channel.line": "LINE",
|
||||||
|
"channel.whatsapp": "WhatsApp",
|
||||||
|
"channel.qq": "QQ",
|
||||||
|
"channel.onebot": "OneBot",
|
||||||
|
"channel.maixcam": "MaixCAM",
|
||||||
|
"sidebar.logs": "日志",
|
||||||
|
"sidebar.rawjson": "原始 JSON",
|
||||||
|
"models.title": "模型",
|
||||||
|
"models.desc": "管理 LLM 模型配置。没有 API Key 的模型会灰显。只有可用模型才能设为主模型。",
|
||||||
|
"models.add": "+ 添加自定义模型",
|
||||||
|
"models.noModels": "暂无模型配置。",
|
||||||
|
"models.primary": "主模型",
|
||||||
|
"models.noKey": "无 Key",
|
||||||
|
"models.setPrimary": "设为主模型",
|
||||||
|
"models.editModel": "编辑模型",
|
||||||
|
"models.addModel": "添加模型",
|
||||||
|
"models.advancedOptions": "高级选项",
|
||||||
|
"models.deleteConfirm": "确定删除模型“{name}”?",
|
||||||
|
"models.requiredFields": "模型名称和模型 ID 为必填项",
|
||||||
|
"field.modelName": "模型名称",
|
||||||
|
"field.modelId": "模型 ID",
|
||||||
|
"field.modelIdHint": "格式:协议/模型标识",
|
||||||
|
"field.apiKey": "API Key",
|
||||||
|
"field.apiBase": "API 地址",
|
||||||
|
"field.proxy": "代理",
|
||||||
|
"field.authMethod": "认证方式",
|
||||||
|
"field.connectMode": "连接模式",
|
||||||
|
"field.workspace": "工作区",
|
||||||
|
"field.rpm": "RPM 限制",
|
||||||
|
"field.requestTimeout": "请求超时(秒)",
|
||||||
|
"auth.title": "提供商认证",
|
||||||
|
"auth.desc": "通过 OAuth 或 API Token 登录提供商。凭证会保存在本地 <code style=\"font-family:'JetBrains Mono',monospace;font-size:12px;background:var(--bg-elevated);padding:2px 6px;border-radius:4px;\">~/.picoclaw/auth.json</code>。",
|
||||||
|
"auth.notLoggedIn": "未登录",
|
||||||
|
"auth.active": "已激活",
|
||||||
|
"auth.expired": "已过期",
|
||||||
|
"auth.needsRefresh": "需要刷新",
|
||||||
|
"auth.authenticating": "认证中...",
|
||||||
|
"auth.loginDevice": "登录(设备码)",
|
||||||
|
"auth.loginToken": "登录(API Token)",
|
||||||
|
"auth.loginOAuth": "登录(浏览器 OAuth)",
|
||||||
|
"auth.logout": "登出",
|
||||||
|
"auth.retry": "重试",
|
||||||
|
"auth.waiting": "等待中...",
|
||||||
|
"auth.pasteKey": "请粘贴 API Key...",
|
||||||
|
"auth.step1": "第 1 步:点击下方链接",
|
||||||
|
"auth.step2": "第 2 步:输入以下代码",
|
||||||
|
"auth.step3": "第 3 步:在浏览器完成认证后,本页会自动更新",
|
||||||
|
"auth.method": "方式",
|
||||||
|
"auth.email": "邮箱",
|
||||||
|
"auth.account": "账号",
|
||||||
|
"auth.project": "项目",
|
||||||
|
"auth.expires": "过期时间",
|
||||||
|
"ch.configure": "配置 {name} 通道设置。",
|
||||||
|
"ch.docLink": "配置指南",
|
||||||
|
"ch.accessControl": "访问控制",
|
||||||
|
"ch.allowFrom": "允许的用户 ID",
|
||||||
|
"ch.addItem": "+ 添加",
|
||||||
|
"ch.mentionOnly": "仅提及时响应",
|
||||||
|
"ch.mentionOnlyHint": "只在被 @ 提及时回复",
|
||||||
|
"ch.groupTrigger": "群聊触发前缀",
|
||||||
|
"logs.title": "Gateway 日志",
|
||||||
|
"logs.desc": "Gateway 进程的实时输出。",
|
||||||
|
"logs.clear": "清除显示",
|
||||||
|
"logs.autoScroll": "自动滚动",
|
||||||
|
"logs.noLogs": "暂无日志。启动 Gateway 后可在此查看输出。",
|
||||||
|
"logs.noCapture": "日志不可用。Gateway 不是通过此启动器启动的。",
|
||||||
|
"raw.title": "原始 JSON",
|
||||||
|
"raw.desc": "直接编辑配置文件。",
|
||||||
|
"raw.reload": "重新加载",
|
||||||
|
"raw.format": "格式化",
|
||||||
|
"status.configLoaded": "配置已加载",
|
||||||
|
"status.configSaved": "配置已保存",
|
||||||
|
"status.loadFailed": "加载失败",
|
||||||
|
"status.saveFailed": "保存失败",
|
||||||
|
"status.formatted": "已格式化",
|
||||||
|
"status.invalidJson": "JSON 格式无效,请修正后再保存",
|
||||||
|
"status.jsonValid": "JSON 有效",
|
||||||
|
"status.jsonInvalid": "JSON 无效",
|
||||||
|
"status.saved": "{name} 已保存",
|
||||||
|
"status.tokenEmpty": "Token 不能为空",
|
||||||
|
"status.tokenSaved": "已保存 {name} 的 Token",
|
||||||
|
"status.loggedOut": "已从 {name} 登出",
|
||||||
|
"status.loginFailed": "登录失败",
|
||||||
|
"status.logoutFailed": "登出失败",
|
||||||
|
"status.openingBrowser": "正在打开浏览器进行认证...",
|
||||||
|
"status.loginStarted": "登录已启动...",
|
||||||
|
"status.loginSuccess": "登录成功!",
|
||||||
|
"process.running": "服务已启动",
|
||||||
|
"process.notRunning": "服务未启动",
|
||||||
|
"process.starting": "正在启动 Gateway...",
|
||||||
|
"process.started": "Gateway 已启动",
|
||||||
|
"process.startFailed": "Gateway 启动失败",
|
||||||
|
"process.stopping": "正在停止 Gateway...",
|
||||||
|
"process.stopped": "Gateway 已停止",
|
||||||
|
"process.stopFailed": "Gateway 停止失败",
|
||||||
|
"process.needModel": "至少需要一个配置了 API Key 的模型",
|
||||||
|
"process.needChannel": "至少需要启用一个通道",
|
||||||
|
"process.checkLogs": "请查看日志了解详情",
|
||||||
|
"process.needBoth": "需要可用模型和启用通道后才能启动",
|
||||||
|
"process.picoclawNotFoundHint": "提示:请将 picoclaw-launcher 和 picoclaw 可执行文件放在同一目录,或把 picoclaw 所在目录加入 PATH。"
|
||||||
|
},
|
||||||
|
"ja": {
|
||||||
|
"start": "Start",
|
||||||
|
"stop": "Stop",
|
||||||
|
"save": "Save",
|
||||||
|
"cancel": "Cancel",
|
||||||
|
"edit": "Edit",
|
||||||
|
"delete": "Delete",
|
||||||
|
"enabled": "Enabled",
|
||||||
|
"comingSoon": "Coming soon",
|
||||||
|
"sidebar.providers": "Providers",
|
||||||
|
"sidebar.models": "Models",
|
||||||
|
"sidebar.auth": "Auth",
|
||||||
|
"sidebar.channels": "Channels",
|
||||||
|
"sidebar.feishu": "Feishu",
|
||||||
|
"channel.telegram": "Telegram",
|
||||||
|
"channel.discord": "Discord",
|
||||||
|
"channel.slack": "Slack",
|
||||||
|
"channel.wecom": "WeCom",
|
||||||
|
"channel.wecom_app": "WeCom App",
|
||||||
|
"channel.dingtalk": "DingTalk",
|
||||||
|
"channel.feishu": "Feishu",
|
||||||
|
"channel.line": "LINE",
|
||||||
|
"channel.whatsapp": "WhatsApp",
|
||||||
|
"channel.qq": "QQ",
|
||||||
|
"channel.onebot": "OneBot",
|
||||||
|
"channel.maixcam": "MaixCAM",
|
||||||
|
"sidebar.logs": "Logs",
|
||||||
|
"sidebar.rawjson": "Raw JSON",
|
||||||
|
"models.title": "Models",
|
||||||
|
"models.desc": "Manage LLM model configurations. Models without an API key are grayed out. Only available models can be set as primary.",
|
||||||
|
"models.add": "+ Add Custom Model",
|
||||||
|
"models.noModels": "No models configured.",
|
||||||
|
"models.primary": "Primary",
|
||||||
|
"models.noKey": "No Key",
|
||||||
|
"models.setPrimary": "Set Primary",
|
||||||
|
"models.editModel": "Edit Model",
|
||||||
|
"models.addModel": "Add Model",
|
||||||
|
"models.advancedOptions": "Advanced Options",
|
||||||
|
"models.deleteConfirm": "Delete model \"{name}\"?",
|
||||||
|
"models.requiredFields": "Model Name and Model ID are required",
|
||||||
|
"field.modelName": "Model Name",
|
||||||
|
"field.modelId": "Model ID",
|
||||||
|
"field.modelIdHint": "Format: protocol/model-id",
|
||||||
|
"field.apiKey": "API Key",
|
||||||
|
"field.apiBase": "API Base",
|
||||||
|
"field.proxy": "Proxy",
|
||||||
|
"field.authMethod": "Auth Method",
|
||||||
|
"field.connectMode": "Connect Mode",
|
||||||
|
"field.workspace": "Workspace",
|
||||||
|
"field.rpm": "RPM Limit",
|
||||||
|
"field.requestTimeout": "Request Timeout (s)",
|
||||||
|
"auth.title": "Provider Authentication",
|
||||||
|
"auth.desc": "Login to providers using OAuth or API tokens. Credentials are stored locally in <code style=\"font-family:'JetBrains Mono',monospace;font-size:12px;background:var(--bg-elevated);padding:2px 6px;border-radius:4px;\">~/.picoclaw/auth.json</code>.",
|
||||||
|
"auth.notLoggedIn": "Not logged in",
|
||||||
|
"auth.active": "Active",
|
||||||
|
"auth.expired": "Expired",
|
||||||
|
"auth.needsRefresh": "Needs Refresh",
|
||||||
|
"auth.authenticating": "Authenticating...",
|
||||||
|
"auth.loginDevice": "Login (Device Code)",
|
||||||
|
"auth.loginToken": "Login (API Token)",
|
||||||
|
"auth.loginOAuth": "Login (Browser OAuth)",
|
||||||
|
"auth.logout": "Logout",
|
||||||
|
"auth.retry": "Retry",
|
||||||
|
"auth.waiting": "Waiting...",
|
||||||
|
"auth.pasteKey": "Paste your API key here...",
|
||||||
|
"auth.step1": "Step 1: Click the link below",
|
||||||
|
"auth.step2": "Step 2: Enter this code",
|
||||||
|
"auth.step3": "Step 3: Complete auth in browser, this page updates automatically",
|
||||||
|
"auth.method": "Method",
|
||||||
|
"auth.email": "Email",
|
||||||
|
"auth.account": "Account",
|
||||||
|
"auth.project": "Project",
|
||||||
|
"auth.expires": "Expires",
|
||||||
|
"ch.configure": "Configure {name} channel settings.",
|
||||||
|
"ch.docLink": "Configuration Guide",
|
||||||
|
"ch.accessControl": "Access Control",
|
||||||
|
"ch.allowFrom": "Allow From (User IDs)",
|
||||||
|
"ch.addItem": "+ Add",
|
||||||
|
"ch.mentionOnly": "Mention Only",
|
||||||
|
"ch.mentionOnlyHint": "Only respond when mentioned",
|
||||||
|
"ch.groupTrigger": "Group Trigger Prefixes",
|
||||||
|
"logs.title": "Gateway Logs",
|
||||||
|
"logs.desc": "Real-time output from the gateway process.",
|
||||||
|
"logs.clear": "Clear Display",
|
||||||
|
"logs.autoScroll": "Auto-scroll",
|
||||||
|
"logs.noLogs": "No logs available. Start the gateway to see output here.",
|
||||||
|
"logs.noCapture": "Logs are not available. The gateway was not started from this launcher.",
|
||||||
|
"raw.title": "Raw JSON",
|
||||||
|
"raw.desc": "Directly edit the configuration file.",
|
||||||
|
"raw.reload": "Reload",
|
||||||
|
"raw.format": "Format",
|
||||||
|
"status.configLoaded": "Config loaded",
|
||||||
|
"status.configSaved": "Config saved",
|
||||||
|
"status.loadFailed": "Load failed",
|
||||||
|
"status.saveFailed": "Save failed",
|
||||||
|
"status.formatted": "Formatted",
|
||||||
|
"status.invalidJson": "Invalid JSON, please fix before saving",
|
||||||
|
"status.jsonValid": "JSON valid",
|
||||||
|
"status.jsonInvalid": "JSON invalid",
|
||||||
|
"status.saved": "{name} saved",
|
||||||
|
"status.tokenEmpty": "Token cannot be empty",
|
||||||
|
"status.tokenSaved": "Token saved for {name}",
|
||||||
|
"status.loggedOut": "Logged out from {name}",
|
||||||
|
"status.loginFailed": "Login failed",
|
||||||
|
"status.logoutFailed": "Logout failed",
|
||||||
|
"status.openingBrowser": "Opening browser for authentication...",
|
||||||
|
"status.loginStarted": "Login started...",
|
||||||
|
"status.loginSuccess": "Login successful!",
|
||||||
|
"process.running": "Service running",
|
||||||
|
"process.notRunning": "Service not running",
|
||||||
|
"process.starting": "Starting gateway...",
|
||||||
|
"process.started": "Gateway started",
|
||||||
|
"process.startFailed": "Failed to start gateway",
|
||||||
|
"process.stopping": "Stopping gateway...",
|
||||||
|
"process.stopped": "Gateway stopped",
|
||||||
|
"process.stopFailed": "Failed to stop gateway",
|
||||||
|
"process.needModel": "At least one model with API key is required",
|
||||||
|
"process.needChannel": "At least one channel must be enabled",
|
||||||
|
"process.checkLogs": "Check Logs for details",
|
||||||
|
"process.needBoth": "Need model with API key and enabled channel to start",
|
||||||
|
"process.picoclawNotFoundHint": "Hint: put picoclaw-launcher and the picoclaw executable in the same directory, or add picoclaw's directory to PATH."
|
||||||
|
},
|
||||||
|
"pt-br": {
|
||||||
|
"start": "Start",
|
||||||
|
"stop": "Stop",
|
||||||
|
"save": "Save",
|
||||||
|
"cancel": "Cancel",
|
||||||
|
"edit": "Edit",
|
||||||
|
"delete": "Delete",
|
||||||
|
"enabled": "Enabled",
|
||||||
|
"comingSoon": "Coming soon",
|
||||||
|
"sidebar.providers": "Providers",
|
||||||
|
"sidebar.models": "Models",
|
||||||
|
"sidebar.auth": "Auth",
|
||||||
|
"sidebar.channels": "Channels",
|
||||||
|
"sidebar.feishu": "Feishu",
|
||||||
|
"channel.telegram": "Telegram",
|
||||||
|
"channel.discord": "Discord",
|
||||||
|
"channel.slack": "Slack",
|
||||||
|
"channel.wecom": "WeCom",
|
||||||
|
"channel.wecom_app": "WeCom App",
|
||||||
|
"channel.dingtalk": "DingTalk",
|
||||||
|
"channel.feishu": "Feishu",
|
||||||
|
"channel.line": "LINE",
|
||||||
|
"channel.whatsapp": "WhatsApp",
|
||||||
|
"channel.qq": "QQ",
|
||||||
|
"channel.onebot": "OneBot",
|
||||||
|
"channel.maixcam": "MaixCAM",
|
||||||
|
"sidebar.logs": "Logs",
|
||||||
|
"sidebar.rawjson": "Raw JSON",
|
||||||
|
"models.title": "Models",
|
||||||
|
"models.desc": "Manage LLM model configurations. Models without an API key are grayed out. Only available models can be set as primary.",
|
||||||
|
"models.add": "+ Add Custom Model",
|
||||||
|
"models.noModels": "No models configured.",
|
||||||
|
"models.primary": "Primary",
|
||||||
|
"models.noKey": "No Key",
|
||||||
|
"models.setPrimary": "Set Primary",
|
||||||
|
"models.editModel": "Edit Model",
|
||||||
|
"models.addModel": "Add Model",
|
||||||
|
"models.advancedOptions": "Advanced Options",
|
||||||
|
"models.deleteConfirm": "Delete model \"{name}\"?",
|
||||||
|
"models.requiredFields": "Model Name and Model ID are required",
|
||||||
|
"field.modelName": "Model Name",
|
||||||
|
"field.modelId": "Model ID",
|
||||||
|
"field.modelIdHint": "Format: protocol/model-id",
|
||||||
|
"field.apiKey": "API Key",
|
||||||
|
"field.apiBase": "API Base",
|
||||||
|
"field.proxy": "Proxy",
|
||||||
|
"field.authMethod": "Auth Method",
|
||||||
|
"field.connectMode": "Connect Mode",
|
||||||
|
"field.workspace": "Workspace",
|
||||||
|
"field.rpm": "RPM Limit",
|
||||||
|
"field.requestTimeout": "Request Timeout (s)",
|
||||||
|
"auth.title": "Provider Authentication",
|
||||||
|
"auth.desc": "Login to providers using OAuth or API tokens. Credentials are stored locally in <code style=\"font-family:'JetBrains Mono',monospace;font-size:12px;background:var(--bg-elevated);padding:2px 6px;border-radius:4px;\">~/.picoclaw/auth.json</code>.",
|
||||||
|
"auth.notLoggedIn": "Not logged in",
|
||||||
|
"auth.active": "Active",
|
||||||
|
"auth.expired": "Expired",
|
||||||
|
"auth.needsRefresh": "Needs Refresh",
|
||||||
|
"auth.authenticating": "Authenticating...",
|
||||||
|
"auth.loginDevice": "Login (Device Code)",
|
||||||
|
"auth.loginToken": "Login (API Token)",
|
||||||
|
"auth.loginOAuth": "Login (Browser OAuth)",
|
||||||
|
"auth.logout": "Logout",
|
||||||
|
"auth.retry": "Retry",
|
||||||
|
"auth.waiting": "Waiting...",
|
||||||
|
"auth.pasteKey": "Paste your API key here...",
|
||||||
|
"auth.step1": "Step 1: Click the link below",
|
||||||
|
"auth.step2": "Step 2: Enter this code",
|
||||||
|
"auth.step3": "Step 3: Complete auth in browser, this page updates automatically",
|
||||||
|
"auth.method": "Method",
|
||||||
|
"auth.email": "Email",
|
||||||
|
"auth.account": "Account",
|
||||||
|
"auth.project": "Project",
|
||||||
|
"auth.expires": "Expires",
|
||||||
|
"ch.configure": "Configure {name} channel settings.",
|
||||||
|
"ch.docLink": "Configuration Guide",
|
||||||
|
"ch.accessControl": "Access Control",
|
||||||
|
"ch.allowFrom": "Allow From (User IDs)",
|
||||||
|
"ch.addItem": "+ Add",
|
||||||
|
"ch.mentionOnly": "Mention Only",
|
||||||
|
"ch.mentionOnlyHint": "Only respond when mentioned",
|
||||||
|
"ch.groupTrigger": "Group Trigger Prefixes",
|
||||||
|
"logs.title": "Gateway Logs",
|
||||||
|
"logs.desc": "Real-time output from the gateway process.",
|
||||||
|
"logs.clear": "Clear Display",
|
||||||
|
"logs.autoScroll": "Auto-scroll",
|
||||||
|
"logs.noLogs": "No logs available. Start the gateway to see output here.",
|
||||||
|
"logs.noCapture": "Logs are not available. The gateway was not started from this launcher.",
|
||||||
|
"raw.title": "Raw JSON",
|
||||||
|
"raw.desc": "Directly edit the configuration file.",
|
||||||
|
"raw.reload": "Reload",
|
||||||
|
"raw.format": "Format",
|
||||||
|
"status.configLoaded": "Config loaded",
|
||||||
|
"status.configSaved": "Config saved",
|
||||||
|
"status.loadFailed": "Load failed",
|
||||||
|
"status.saveFailed": "Save failed",
|
||||||
|
"status.formatted": "Formatted",
|
||||||
|
"status.invalidJson": "Invalid JSON, please fix before saving",
|
||||||
|
"status.jsonValid": "JSON valid",
|
||||||
|
"status.jsonInvalid": "JSON invalid",
|
||||||
|
"status.saved": "{name} saved",
|
||||||
|
"status.tokenEmpty": "Token cannot be empty",
|
||||||
|
"status.tokenSaved": "Token saved for {name}",
|
||||||
|
"status.loggedOut": "Logged out from {name}",
|
||||||
|
"status.loginFailed": "Login failed",
|
||||||
|
"status.logoutFailed": "Logout failed",
|
||||||
|
"status.openingBrowser": "Opening browser for authentication...",
|
||||||
|
"status.loginStarted": "Login started...",
|
||||||
|
"status.loginSuccess": "Login successful!",
|
||||||
|
"process.running": "Service running",
|
||||||
|
"process.notRunning": "Service not running",
|
||||||
|
"process.starting": "Starting gateway...",
|
||||||
|
"process.started": "Gateway started",
|
||||||
|
"process.startFailed": "Failed to start gateway",
|
||||||
|
"process.stopping": "Stopping gateway...",
|
||||||
|
"process.stopped": "Gateway stopped",
|
||||||
|
"process.stopFailed": "Failed to stop gateway",
|
||||||
|
"process.needModel": "At least one model with API key is required",
|
||||||
|
"process.needChannel": "At least one channel must be enabled",
|
||||||
|
"process.checkLogs": "Check Logs for details",
|
||||||
|
"process.needBoth": "Need model with API key and enabled channel to start",
|
||||||
|
"process.picoclawNotFoundHint": "Hint: put picoclaw-launcher and the picoclaw executable in the same directory, or add picoclaw's directory to PATH."
|
||||||
|
},
|
||||||
|
"vi": {
|
||||||
|
"start": "Start",
|
||||||
|
"stop": "Stop",
|
||||||
|
"save": "Save",
|
||||||
|
"cancel": "Cancel",
|
||||||
|
"edit": "Edit",
|
||||||
|
"delete": "Delete",
|
||||||
|
"enabled": "Enabled",
|
||||||
|
"comingSoon": "Coming soon",
|
||||||
|
"sidebar.providers": "Providers",
|
||||||
|
"sidebar.models": "Models",
|
||||||
|
"sidebar.auth": "Auth",
|
||||||
|
"sidebar.channels": "Channels",
|
||||||
|
"sidebar.feishu": "Feishu",
|
||||||
|
"channel.telegram": "Telegram",
|
||||||
|
"channel.discord": "Discord",
|
||||||
|
"channel.slack": "Slack",
|
||||||
|
"channel.wecom": "WeCom",
|
||||||
|
"channel.wecom_app": "WeCom App",
|
||||||
|
"channel.dingtalk": "DingTalk",
|
||||||
|
"channel.feishu": "Feishu",
|
||||||
|
"channel.line": "LINE",
|
||||||
|
"channel.whatsapp": "WhatsApp",
|
||||||
|
"channel.qq": "QQ",
|
||||||
|
"channel.onebot": "OneBot",
|
||||||
|
"channel.maixcam": "MaixCAM",
|
||||||
|
"sidebar.logs": "Logs",
|
||||||
|
"sidebar.rawjson": "Raw JSON",
|
||||||
|
"models.title": "Models",
|
||||||
|
"models.desc": "Manage LLM model configurations. Models without an API key are grayed out. Only available models can be set as primary.",
|
||||||
|
"models.add": "+ Add Custom Model",
|
||||||
|
"models.noModels": "No models configured.",
|
||||||
|
"models.primary": "Primary",
|
||||||
|
"models.noKey": "No Key",
|
||||||
|
"models.setPrimary": "Set Primary",
|
||||||
|
"models.editModel": "Edit Model",
|
||||||
|
"models.addModel": "Add Model",
|
||||||
|
"models.advancedOptions": "Advanced Options",
|
||||||
|
"models.deleteConfirm": "Delete model \"{name}\"?",
|
||||||
|
"models.requiredFields": "Model Name and Model ID are required",
|
||||||
|
"field.modelName": "Model Name",
|
||||||
|
"field.modelId": "Model ID",
|
||||||
|
"field.modelIdHint": "Format: protocol/model-id",
|
||||||
|
"field.apiKey": "API Key",
|
||||||
|
"field.apiBase": "API Base",
|
||||||
|
"field.proxy": "Proxy",
|
||||||
|
"field.authMethod": "Auth Method",
|
||||||
|
"field.connectMode": "Connect Mode",
|
||||||
|
"field.workspace": "Workspace",
|
||||||
|
"field.rpm": "RPM Limit",
|
||||||
|
"field.requestTimeout": "Request Timeout (s)",
|
||||||
|
"auth.title": "Provider Authentication",
|
||||||
|
"auth.desc": "Login to providers using OAuth or API tokens. Credentials are stored locally in <code style=\"font-family:'JetBrains Mono',monospace;font-size:12px;background:var(--bg-elevated);padding:2px 6px;border-radius:4px;\">~/.picoclaw/auth.json</code>.",
|
||||||
|
"auth.notLoggedIn": "Not logged in",
|
||||||
|
"auth.active": "Active",
|
||||||
|
"auth.expired": "Expired",
|
||||||
|
"auth.needsRefresh": "Needs Refresh",
|
||||||
|
"auth.authenticating": "Authenticating...",
|
||||||
|
"auth.loginDevice": "Login (Device Code)",
|
||||||
|
"auth.loginToken": "Login (API Token)",
|
||||||
|
"auth.loginOAuth": "Login (Browser OAuth)",
|
||||||
|
"auth.logout": "Logout",
|
||||||
|
"auth.retry": "Retry",
|
||||||
|
"auth.waiting": "Waiting...",
|
||||||
|
"auth.pasteKey": "Paste your API key here...",
|
||||||
|
"auth.step1": "Step 1: Click the link below",
|
||||||
|
"auth.step2": "Step 2: Enter this code",
|
||||||
|
"auth.step3": "Step 3: Complete auth in browser, this page updates automatically",
|
||||||
|
"auth.method": "Method",
|
||||||
|
"auth.email": "Email",
|
||||||
|
"auth.account": "Account",
|
||||||
|
"auth.project": "Project",
|
||||||
|
"auth.expires": "Expires",
|
||||||
|
"ch.configure": "Configure {name} channel settings.",
|
||||||
|
"ch.docLink": "Configuration Guide",
|
||||||
|
"ch.accessControl": "Access Control",
|
||||||
|
"ch.allowFrom": "Allow From (User IDs)",
|
||||||
|
"ch.addItem": "+ Add",
|
||||||
|
"ch.mentionOnly": "Mention Only",
|
||||||
|
"ch.mentionOnlyHint": "Only respond when mentioned",
|
||||||
|
"ch.groupTrigger": "Group Trigger Prefixes",
|
||||||
|
"logs.title": "Gateway Logs",
|
||||||
|
"logs.desc": "Real-time output from the gateway process.",
|
||||||
|
"logs.clear": "Clear Display",
|
||||||
|
"logs.autoScroll": "Auto-scroll",
|
||||||
|
"logs.noLogs": "No logs available. Start the gateway to see output here.",
|
||||||
|
"logs.noCapture": "Logs are not available. The gateway was not started from this launcher.",
|
||||||
|
"raw.title": "Raw JSON",
|
||||||
|
"raw.desc": "Directly edit the configuration file.",
|
||||||
|
"raw.reload": "Reload",
|
||||||
|
"raw.format": "Format",
|
||||||
|
"status.configLoaded": "Config loaded",
|
||||||
|
"status.configSaved": "Config saved",
|
||||||
|
"status.loadFailed": "Load failed",
|
||||||
|
"status.saveFailed": "Save failed",
|
||||||
|
"status.formatted": "Formatted",
|
||||||
|
"status.invalidJson": "Invalid JSON, please fix before saving",
|
||||||
|
"status.jsonValid": "JSON valid",
|
||||||
|
"status.jsonInvalid": "JSON invalid",
|
||||||
|
"status.saved": "{name} saved",
|
||||||
|
"status.tokenEmpty": "Token cannot be empty",
|
||||||
|
"status.tokenSaved": "Token saved for {name}",
|
||||||
|
"status.loggedOut": "Logged out from {name}",
|
||||||
|
"status.loginFailed": "Login failed",
|
||||||
|
"status.logoutFailed": "Logout failed",
|
||||||
|
"status.openingBrowser": "Opening browser for authentication...",
|
||||||
|
"status.loginStarted": "Login started...",
|
||||||
|
"status.loginSuccess": "Login successful!",
|
||||||
|
"process.running": "Service running",
|
||||||
|
"process.notRunning": "Service not running",
|
||||||
|
"process.starting": "Starting gateway...",
|
||||||
|
"process.started": "Gateway started",
|
||||||
|
"process.startFailed": "Failed to start gateway",
|
||||||
|
"process.stopping": "Stopping gateway...",
|
||||||
|
"process.stopped": "Gateway stopped",
|
||||||
|
"process.stopFailed": "Failed to stop gateway",
|
||||||
|
"process.needModel": "At least one model with API key is required",
|
||||||
|
"process.needChannel": "At least one channel must be enabled",
|
||||||
|
"process.checkLogs": "Check Logs for details",
|
||||||
|
"process.needBoth": "Need model with API key and enabled channel to start",
|
||||||
|
"process.picoclawNotFoundHint": "Hint: put picoclaw-launcher and the picoclaw executable in the same directory, or add picoclaw's directory to PATH."
|
||||||
|
},
|
||||||
|
"fr": {
|
||||||
|
"start": "Start",
|
||||||
|
"stop": "Stop",
|
||||||
|
"save": "Save",
|
||||||
|
"cancel": "Cancel",
|
||||||
|
"edit": "Edit",
|
||||||
|
"delete": "Delete",
|
||||||
|
"enabled": "Enabled",
|
||||||
|
"comingSoon": "Coming soon",
|
||||||
|
"sidebar.providers": "Providers",
|
||||||
|
"sidebar.models": "Models",
|
||||||
|
"sidebar.auth": "Auth",
|
||||||
|
"sidebar.channels": "Channels",
|
||||||
|
"sidebar.feishu": "Feishu",
|
||||||
|
"channel.telegram": "Telegram",
|
||||||
|
"channel.discord": "Discord",
|
||||||
|
"channel.slack": "Slack",
|
||||||
|
"channel.wecom": "WeCom",
|
||||||
|
"channel.wecom_app": "WeCom App",
|
||||||
|
"channel.dingtalk": "DingTalk",
|
||||||
|
"channel.feishu": "Feishu",
|
||||||
|
"channel.line": "LINE",
|
||||||
|
"channel.whatsapp": "WhatsApp",
|
||||||
|
"channel.qq": "QQ",
|
||||||
|
"channel.onebot": "OneBot",
|
||||||
|
"channel.maixcam": "MaixCAM",
|
||||||
|
"sidebar.logs": "Logs",
|
||||||
|
"sidebar.rawjson": "Raw JSON",
|
||||||
|
"models.title": "Models",
|
||||||
|
"models.desc": "Manage LLM model configurations. Models without an API key are grayed out. Only available models can be set as primary.",
|
||||||
|
"models.add": "+ Add Custom Model",
|
||||||
|
"models.noModels": "No models configured.",
|
||||||
|
"models.primary": "Primary",
|
||||||
|
"models.noKey": "No Key",
|
||||||
|
"models.setPrimary": "Set Primary",
|
||||||
|
"models.editModel": "Edit Model",
|
||||||
|
"models.addModel": "Add Model",
|
||||||
|
"models.advancedOptions": "Advanced Options",
|
||||||
|
"models.deleteConfirm": "Delete model \"{name}\"?",
|
||||||
|
"models.requiredFields": "Model Name and Model ID are required",
|
||||||
|
"field.modelName": "Model Name",
|
||||||
|
"field.modelId": "Model ID",
|
||||||
|
"field.modelIdHint": "Format: protocol/model-id",
|
||||||
|
"field.apiKey": "API Key",
|
||||||
|
"field.apiBase": "API Base",
|
||||||
|
"field.proxy": "Proxy",
|
||||||
|
"field.authMethod": "Auth Method",
|
||||||
|
"field.connectMode": "Connect Mode",
|
||||||
|
"field.workspace": "Workspace",
|
||||||
|
"field.rpm": "RPM Limit",
|
||||||
|
"field.requestTimeout": "Request Timeout (s)",
|
||||||
|
"auth.title": "Provider Authentication",
|
||||||
|
"auth.desc": "Login to providers using OAuth or API tokens. Credentials are stored locally in <code style=\"font-family:'JetBrains Mono',monospace;font-size:12px;background:var(--bg-elevated);padding:2px 6px;border-radius:4px;\">~/.picoclaw/auth.json</code>.",
|
||||||
|
"auth.notLoggedIn": "Not logged in",
|
||||||
|
"auth.active": "Active",
|
||||||
|
"auth.expired": "Expired",
|
||||||
|
"auth.needsRefresh": "Needs Refresh",
|
||||||
|
"auth.authenticating": "Authenticating...",
|
||||||
|
"auth.loginDevice": "Login (Device Code)",
|
||||||
|
"auth.loginToken": "Login (API Token)",
|
||||||
|
"auth.loginOAuth": "Login (Browser OAuth)",
|
||||||
|
"auth.logout": "Logout",
|
||||||
|
"auth.retry": "Retry",
|
||||||
|
"auth.waiting": "Waiting...",
|
||||||
|
"auth.pasteKey": "Paste your API key here...",
|
||||||
|
"auth.step1": "Step 1: Click the link below",
|
||||||
|
"auth.step2": "Step 2: Enter this code",
|
||||||
|
"auth.step3": "Step 3: Complete auth in browser, this page updates automatically",
|
||||||
|
"auth.method": "Method",
|
||||||
|
"auth.email": "Email",
|
||||||
|
"auth.account": "Account",
|
||||||
|
"auth.project": "Project",
|
||||||
|
"auth.expires": "Expires",
|
||||||
|
"ch.configure": "Configure {name} channel settings.",
|
||||||
|
"ch.docLink": "Configuration Guide",
|
||||||
|
"ch.accessControl": "Access Control",
|
||||||
|
"ch.allowFrom": "Allow From (User IDs)",
|
||||||
|
"ch.addItem": "+ Add",
|
||||||
|
"ch.mentionOnly": "Mention Only",
|
||||||
|
"ch.mentionOnlyHint": "Only respond when mentioned",
|
||||||
|
"ch.groupTrigger": "Group Trigger Prefixes",
|
||||||
|
"logs.title": "Gateway Logs",
|
||||||
|
"logs.desc": "Real-time output from the gateway process.",
|
||||||
|
"logs.clear": "Clear Display",
|
||||||
|
"logs.autoScroll": "Auto-scroll",
|
||||||
|
"logs.noLogs": "No logs available. Start the gateway to see output here.",
|
||||||
|
"logs.noCapture": "Logs are not available. The gateway was not started from this launcher.",
|
||||||
|
"raw.title": "Raw JSON",
|
||||||
|
"raw.desc": "Directly edit the configuration file.",
|
||||||
|
"raw.reload": "Reload",
|
||||||
|
"raw.format": "Format",
|
||||||
|
"status.configLoaded": "Config loaded",
|
||||||
|
"status.configSaved": "Config saved",
|
||||||
|
"status.loadFailed": "Load failed",
|
||||||
|
"status.saveFailed": "Save failed",
|
||||||
|
"status.formatted": "Formatted",
|
||||||
|
"status.invalidJson": "Invalid JSON, please fix before saving",
|
||||||
|
"status.jsonValid": "JSON valid",
|
||||||
|
"status.jsonInvalid": "JSON invalid",
|
||||||
|
"status.saved": "{name} saved",
|
||||||
|
"status.tokenEmpty": "Token cannot be empty",
|
||||||
|
"status.tokenSaved": "Token saved for {name}",
|
||||||
|
"status.loggedOut": "Logged out from {name}",
|
||||||
|
"status.loginFailed": "Login failed",
|
||||||
|
"status.logoutFailed": "Logout failed",
|
||||||
|
"status.openingBrowser": "Opening browser for authentication...",
|
||||||
|
"status.loginStarted": "Login started...",
|
||||||
|
"status.loginSuccess": "Login successful!",
|
||||||
|
"process.running": "Service running",
|
||||||
|
"process.notRunning": "Service not running",
|
||||||
|
"process.starting": "Starting gateway...",
|
||||||
|
"process.started": "Gateway started",
|
||||||
|
"process.startFailed": "Failed to start gateway",
|
||||||
|
"process.stopping": "Stopping gateway...",
|
||||||
|
"process.stopped": "Gateway stopped",
|
||||||
|
"process.stopFailed": "Failed to stop gateway",
|
||||||
|
"process.needModel": "At least one model with API key is required",
|
||||||
|
"process.needChannel": "At least one channel must be enabled",
|
||||||
|
"process.checkLogs": "Check Logs for details",
|
||||||
|
"process.needBoth": "Need model with API key and enabled channel to start",
|
||||||
|
"process.picoclawNotFoundHint": "Hint: put picoclaw-launcher and the picoclaw executable in the same directory, or add picoclaw's directory to PATH."
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load diff
1559
cmd/picoclaw-launcher/internal/ui/index.js
Normal file
1559
cmd/picoclaw-launcher/internal/ui/index.js
Normal file
File diff suppressed because it is too large
Load diff
56
cmd/picoclaw-launcher/internal/ui/vendor/codemirror.js
vendored
Normal file
56
cmd/picoclaw-launcher/internal/ui/vendor/codemirror.js
vendored
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -27,7 +27,7 @@ import (
|
||||||
"github.com/sipeed/picoclaw/cmd/picoclaw-launcher/internal/server"
|
"github.com/sipeed/picoclaw/cmd/picoclaw-launcher/internal/server"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:embed internal/ui/index.html
|
//go:embed internal/ui/index.html internal/ui/index.js internal/ui/i18n.json internal/ui/vendor/*
|
||||||
var staticFiles embed.FS
|
var staticFiles embed.FS
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue