Compare commits
15 Commits
v0.3.1-bet
...
v0.3.2-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
83d7a573c7 | ||
|
|
0fe82f67df | ||
|
|
4b9f2c377d | ||
|
|
95bd824259 | ||
|
|
252f178bbd | ||
|
|
7dcf505360 | ||
|
|
8fb93fa47e | ||
|
|
5ec373cd6a | ||
|
|
1eb5a6d00f | ||
|
|
cd5ebe083c | ||
|
|
2004c15dd7 | ||
|
|
9306152736 | ||
|
|
e15a034de5 | ||
|
|
3b6cc38ea0 | ||
|
|
80c11cab3f |
61
CHANGELOG.md
61
CHANGELOG.md
@@ -4,6 +4,67 @@ All notable changes to this project will be documented in this file.
|
|||||||
|
|
||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
||||||
|
|
||||||
|
## v0.3.0
|
||||||
|
|
||||||
|
### Changes since v0.2.1
|
||||||
|
|
||||||
|
- fix(terminal): resolve PTY shell exec error, simplify CLI, unify Config tabs, restore Studio CSS (0b22109)
|
||||||
|
- feat: add API key validation flow for AI provider config (7f67473)
|
||||||
|
- feat(studio): replace sidebar layout with unified execution feed styles (040e482)
|
||||||
|
- fix: guard against empty tabs array in closeTab (c8903ef)
|
||||||
|
- refactor: redesign Config as settings window with sidebar panels, remove system overview from Dashboard (f3cb306)
|
||||||
|
- feat: add multi-tab terminal with SSH support, config editing, and dashboard redesign (3cdcb22)
|
||||||
|
- feat(studio): add i18n keys and CSS for redesigned AI chat interface (ee18bbe)
|
||||||
|
- chore: bump version to 0.3.0 (b0b0e1d)
|
||||||
|
- chore: remove dead code (packages, functions, types, constants) (fc79810)
|
||||||
|
- docs: rewrite README and CHANGELOG for desktop app mode (f7222b0)
|
||||||
|
- feat(web): add i18n support with FR/EN locales and keyboard layout awareness (11417d3)
|
||||||
|
- refactor(web): redesign frontend for native web UX (3dc24ae)
|
||||||
|
- refactor: remove TUI, desktop web UI is now the default and only mode (aa0ff19)
|
||||||
|
- refactor: unify into single `muyue` binary with embedded desktop mode (3463605)
|
||||||
|
- fix(ci): add frontend build step before Go vet/test/build (097cf40)
|
||||||
|
- feat: add desktop app with React frontend, API backend, theme system (#2) (88d2a03)
|
||||||
|
- chore: update CHANGELOG for v0.2.1 (1830c18)
|
||||||
|
- feat: complete TUI redesign with cyberpunk theme (#1) (cb8e3d0)
|
||||||
|
|
||||||
|
### Downloads
|
||||||
|
|
||||||
|
| Platform | File |
|
||||||
|
|----------|------|
|
||||||
|
| Linux x86_64 | [muyue-linux-amd64.tar.gz](https://gitea.legion-muyue.fr/Muyue/MuyueWorkspace/releases/download/v0.3.0/muyue-linux-amd64.tar.gz) |
|
||||||
|
| Linux ARM64 | [muyue-linux-arm64.tar.gz](https://gitea.legion-muyue.fr/Muyue/MuyueWorkspace/releases/download/v0.3.0/muyue-linux-arm64.tar.gz) |
|
||||||
|
| macOS Intel | [muyue-darwin-amd64.tar.gz](https://gitea.legion-muyue.fr/Muyue/MuyueWorkspace/releases/download/v0.3.0/muyue-darwin-amd64.tar.gz) |
|
||||||
|
| macOS Apple Silicon | [muyue-darwin-arm64.tar.gz](https://gitea.legion-muyue.fr/Muyue/MuyueWorkspace/releases/download/v0.3.0/muyue-darwin-arm64.tar.gz) |
|
||||||
|
| Windows x86_64 | [muyue-windows-amd64.zip](https://gitea.legion-muyue.fr/Muyue/MuyueWorkspace/releases/download/v0.3.0/muyue-windows-amd64.zip) |
|
||||||
|
| Windows ARM64 | [muyue-windows-arm64.zip](https://gitea.legion-muyue.fr/Muyue/MuyueWorkspace/releases/download/v0.3.0/muyue-windows-arm64.zip) |
|
||||||
|
|
||||||
|
The binary includes both CLI and Desktop modes.
|
||||||
|
Run `muyue` for TUI, `muyue desktop` for web UI.
|
||||||
|
|
||||||
|
### Install
|
||||||
|
|
||||||
|
**Linux (x86_64)**
|
||||||
|
```bash
|
||||||
|
curl -sL https://gitea.legion-muyue.fr/Muyue/MuyueWorkspace/releases/download/v0.3.0/muyue-linux-amd64.tar.gz | tar xz
|
||||||
|
chmod +x muyue-linux-amd64
|
||||||
|
sudo mv muyue-linux-amd64 /usr/local/bin/muyue
|
||||||
|
```
|
||||||
|
|
||||||
|
**macOS (Apple Silicon)**
|
||||||
|
```bash
|
||||||
|
curl -sL https://gitea.legion-muyue.fr/Muyue/MuyueWorkspace/releases/download/v0.3.0/muyue-darwin-arm64.tar.gz | tar xz
|
||||||
|
chmod +x muyue-darwin-arm64
|
||||||
|
sudo mv muyue-darwin-arm64 /usr/local/bin/muyue
|
||||||
|
```
|
||||||
|
|
||||||
|
**Windows (x86_64)**
|
||||||
|
```powershell
|
||||||
|
Invoke-WebRequest -Uri "https://gitea.legion-muyue.fr/Muyue/MuyueWorkspace/releases/download/v0.3.0/muyue-windows-amd64.zip" -OutFile "muyue.zip"
|
||||||
|
Expand-Archive -Path "muyue.zip" -DestinationPath "."
|
||||||
|
Move-Item muyue-windows-amd64.exe C:\Windows\muyue.exe
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
### Security
|
### Security
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package version
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
Name = "muyue"
|
Name = "muyue"
|
||||||
Version = "0.3.1"
|
Version = "0.3.2"
|
||||||
Author = "La Légion de Muyue"
|
Author = "La Légion de Muyue"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useState, useEffect, useCallback } from 'react'
|
import { useState, useEffect, useCallback } from 'react'
|
||||||
import { User, Brain, RefreshCw, Globe, Wrench, Monitor } from 'lucide-react'
|
import { User, Brain, RefreshCw, Globe, Wrench } from 'lucide-react'
|
||||||
import { useI18n, LANGUAGES } from '../i18n'
|
import { useI18n, LANGUAGES } from '../i18n'
|
||||||
import { getLayoutList } from '../i18n/keyboards'
|
import { getLayoutList } from '../i18n/keyboards'
|
||||||
|
|
||||||
@@ -27,9 +27,7 @@ export default function Config({ api }) {
|
|||||||
const [profileForm, setProfileForm] = useState({})
|
const [profileForm, setProfileForm] = useState({})
|
||||||
const [providerForm, setProviderForm] = useState({})
|
const [providerForm, setProviderForm] = useState({})
|
||||||
const [toast, setToast] = useState(null)
|
const [toast, setToast] = useState(null)
|
||||||
const [terminalThemes, setTerminalThemes] = useState([])
|
|
||||||
const [terminalSettings, setTerminalSettings] = useState({ font_size: 14, font_family: '', theme: 'default' })
|
|
||||||
const [savingTerminal, setSavingTerminal] = useState(false)
|
|
||||||
|
|
||||||
const layouts = getLayoutList()
|
const layouts = getLayoutList()
|
||||||
|
|
||||||
@@ -43,19 +41,13 @@ export default function Config({ api }) {
|
|||||||
editor: d.profile?.preferences?.editor || '',
|
editor: d.profile?.preferences?.editor || '',
|
||||||
shell: d.profile?.preferences?.shell || '',
|
shell: d.profile?.preferences?.shell || '',
|
||||||
})
|
})
|
||||||
if (d.terminal) {
|
|
||||||
setTerminalSettings({
|
|
||||||
font_size: d.terminal.font_size || 14,
|
|
||||||
font_family: d.terminal.font_family || '',
|
|
||||||
theme: d.terminal.theme || 'default',
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}).catch(() => {})
|
}).catch(() => {})
|
||||||
api.getProviders().then(d => setProviders(d.providers || [])).catch(() => {})
|
api.getProviders().then(d => setProviders(d.providers || [])).catch(() => {})
|
||||||
api.getSkills().then(d => setSkillList(d.skills || [])).catch(() => {})
|
api.getSkills().then(d => setSkillList(d.skills || [])).catch(() => {})
|
||||||
api.getUpdates().then(d => setUpdates(d.updates || [])).catch(() => {})
|
api.getUpdates().then(d => setUpdates(d.updates || [])).catch(() => {})
|
||||||
api.getTools().then(d => setTools(d.tools || [])).catch(() => {})
|
api.getTools().then(d => setTools(d.tools || [])).catch(() => {})
|
||||||
api.getTerminalThemes().then(d => setTerminalThemes(d.themes || [])).catch(() => {})
|
|
||||||
}, [api])
|
}, [api])
|
||||||
|
|
||||||
useEffect(() => { loadData() }, [loadData])
|
useEffect(() => { loadData() }, [loadData])
|
||||||
@@ -126,18 +118,6 @@ export default function Config({ api }) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleSaveTerminalSettings = async () => {
|
|
||||||
setSavingTerminal(true)
|
|
||||||
try {
|
|
||||||
await api.saveTerminalSettings(terminalSettings)
|
|
||||||
showToast(t('config.saved'))
|
|
||||||
window.location.reload()
|
|
||||||
} catch (err) {
|
|
||||||
showToast(`${t('config.error')}: ${err.message}`)
|
|
||||||
}
|
|
||||||
setSavingTerminal(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
const openProviderEdit = (p) => {
|
const openProviderEdit = (p) => {
|
||||||
setProviderForm({
|
setProviderForm({
|
||||||
name: p.name,
|
name: p.name,
|
||||||
@@ -213,13 +193,7 @@ export default function Config({ api }) {
|
|||||||
{activePanel === 'skills' && (
|
{activePanel === 'skills' && (
|
||||||
<PanelSkills skillList={skillList} t={t} />
|
<PanelSkills skillList={skillList} t={t} />
|
||||||
)}
|
)}
|
||||||
{activePanel === 'terminal' && (
|
|
||||||
<PanelTerminal
|
|
||||||
settings={terminalSettings} setSettings={setTerminalSettings}
|
|
||||||
themes={terminalThemes} saving={savingTerminal}
|
|
||||||
onSave={handleSaveTerminalSettings} t={t}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -470,102 +444,6 @@ function PanelSkills({ skillList, t }) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function PanelTerminal({ settings, setSettings, themes, saving, onSave, t }) {
|
|
||||||
const previewTheme = {
|
|
||||||
background: settings.theme === 'default' ? '#0A0A0C' :
|
|
||||||
settings.theme === 'monokai' ? '#272822' :
|
|
||||||
settings.theme === 'gruvbox' ? '#282828' :
|
|
||||||
settings.theme === 'nord' ? '#2E3440' :
|
|
||||||
settings.theme === 'solarized-dark' ? '#002B36' :
|
|
||||||
settings.theme === 'dracula' ? '#282A36' : '#0A0A0C',
|
|
||||||
foreground: settings.theme === 'default' ? '#EAE0E2' :
|
|
||||||
settings.theme === 'monokai' ? '#F8F8F2' :
|
|
||||||
settings.theme === 'gruvbox' ? '#EBDBB2' :
|
|
||||||
settings.theme === 'nord' ? '#D8DEE9' :
|
|
||||||
settings.theme === 'solarized-dark' ? '#839496' :
|
|
||||||
settings.theme === 'dracula' ? '#F8F8F2' : '#EAE0E2',
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="config-card">
|
|
||||||
<div className="config-card-group">
|
|
||||||
<span className="config-card-group-label">{t('config.terminalTheme')}</span>
|
|
||||||
<div className="chip-row">
|
|
||||||
{themes.map(th => (
|
|
||||||
<div
|
|
||||||
key={th.id}
|
|
||||||
className={`chip ${settings.theme === th.id ? 'active' : ''}`}
|
|
||||||
onClick={() => setSettings(s => ({ ...s, theme: th.id }))}
|
|
||||||
>
|
|
||||||
{th.name}
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="config-card-group">
|
|
||||||
<span className="config-card-group-label">{t('config.fontSize')}</span>
|
|
||||||
<div className="chip-row">
|
|
||||||
{[12, 14, 16, 18, 20, 24].map(size => (
|
|
||||||
<div
|
|
||||||
key={size}
|
|
||||||
className={`chip ${settings.font_size === size ? 'active' : ''}`}
|
|
||||||
onClick={() => setSettings(s => ({ ...s, font_size: size }))}
|
|
||||||
>
|
|
||||||
{size}px
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="config-card-group">
|
|
||||||
<span className="config-card-group-label">{t('config.fontFamily')}</span>
|
|
||||||
<select
|
|
||||||
className="config-form-input"
|
|
||||||
value={settings.font_family}
|
|
||||||
onChange={e => setSettings(s => ({ ...s, font_family: e.target.value }))}
|
|
||||||
style={{ maxWidth: 300 }}
|
|
||||||
>
|
|
||||||
<option value="">Default (JetBrains Mono)</option>
|
|
||||||
<option value="'Fira Code', monospace">Fira Code</option>
|
|
||||||
<option value="'Cascadia Code', 'SF Mono', monospace">Cascadia Code</option>
|
|
||||||
<option value="'SF Mono', 'Menlo', monospace">SF Mono</option>
|
|
||||||
<option value="'Source Code Pro', monospace">Source Code Pro</option>
|
|
||||||
<option value="monospace">System Monospace</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="config-card-group">
|
|
||||||
<span className="config-card-group-label">{t('config.preview')}</span>
|
|
||||||
<div style={{
|
|
||||||
background: previewTheme.background,
|
|
||||||
color: previewTheme.foreground,
|
|
||||||
padding: '16px 20px',
|
|
||||||
borderRadius: 'var(--radius)',
|
|
||||||
fontFamily: settings.font_family || "'JetBrains Mono', monospace",
|
|
||||||
fontSize: settings.font_size || 14,
|
|
||||||
border: '1px solid var(--border)',
|
|
||||||
}}>
|
|
||||||
<span style={{ color: '#00E676' }}>➜</span> <span>~/projects</span>
|
|
||||||
<span style={{ color: '#448AFF' }}> git status</span>
|
|
||||||
<br />
|
|
||||||
<span>On branch </span>
|
|
||||||
<span style={{ color: '#FFD740' }}>main</span>
|
|
||||||
<br />
|
|
||||||
<span style={{ opacity: 0.6 }}>Type a command...</span>
|
|
||||||
<span style={{ animation: 'blink 1s step-end infinite' }}> ▋</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="config-card-actions" style={{ marginTop: 16 }}>
|
|
||||||
<button className="primary sm" onClick={onSave} disabled={saving}>
|
|
||||||
{saving ? t('config.saving') : t('config.save')}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function FormInput({ label, value, onChange, type = 'text' }) {
|
function FormInput({ label, value, onChange, type = 'text' }) {
|
||||||
return (
|
return (
|
||||||
<div className="config-form-field">
|
<div className="config-form-field">
|
||||||
|
|||||||
Reference in New Issue
Block a user