feat(shell): dedicated System Analyst AI, no code execution, analyze system
All checks were successful
Beta Release / beta (push) Successful in 45s
All checks were successful
Beta Release / beta (push) Successful in 45s
- New ShellConvStore with persistent history (shell_conversation.json) - 100k token limit — input grays out, must /clear to continue - Commands limited to /clear and /help only - Shell AI has NO tools — read-only analysis, never executes code - "Analyste Système" panel with system analysis button - System analysis uses Studio AI to write system_analysis.md, prepended as context on every conversation start - Code blocks show "Copier" and "Terminal" buttons to copy or send code directly to the active terminal via WebSocket - Token bar shows usage with warning at 80% 💘 Generated with Crush Assisted-by: GLM-5.1 via Crush <crush@charm.land>
This commit is contained in:
@@ -564,30 +564,82 @@ function PanelLocale({ language, keyboard, layouts, api, t }) {
|
||||
}
|
||||
|
||||
function PanelSkills({ skillList, t }) {
|
||||
const [selected, setSelected] = useState(null)
|
||||
|
||||
if (skillList.length === 0) {
|
||||
return <div className="empty-state" style={{ color: 'var(--text-disabled)', padding: 40 }}>{t('config.noSkills')}</div>
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="config-card">
|
||||
{skillList.length === 0 ? (
|
||||
<div className="empty-state">
|
||||
{t('config.noSkills')}
|
||||
<span style={{ fontFamily: 'var(--font-mono)' }}>{t('config.runSkillsInit')}</span>
|
||||
</div>
|
||||
) : (
|
||||
skillList.map((s, i) => (
|
||||
<div key={i} className="config-skill-row">
|
||||
<span className="config-skill-name">{s.name}</span>
|
||||
<span className="badge neutral">{s.target || 'both'}</span>
|
||||
{s.version && <span className="badge" style={{ fontSize: 10 }}>{s.version}</span>}
|
||||
{s.category && <span className="badge" style={{ fontSize: 10, opacity: 0.7 }}>{s.category}</span>}
|
||||
<span className="config-skill-desc">{s.description}</span>
|
||||
{s.dependencies && s.dependencies.length > 0 && (
|
||||
<div style={{ marginTop: 4, fontSize: 10, color: 'var(--muted)' }}>
|
||||
deps: {s.dependencies.map(d => d.name).join(', ')}
|
||||
</div>
|
||||
)}
|
||||
<>
|
||||
<div className="skill-tiles">
|
||||
{skillList.map((s, i) => (
|
||||
<div key={i} className="skill-tile" onClick={() => setSelected(s)}>
|
||||
<div className="skill-tile-name">{s.name}</div>
|
||||
<div className="skill-tile-desc">{s.description}</div>
|
||||
<div className="skill-tile-tags">
|
||||
{s.target && <span className="badge neutral">{s.target}</span>}
|
||||
{s.version && <span className="badge">{s.version}</span>}
|
||||
{s.category && <span className="badge" style={{ opacity: 0.7 }}>{s.category}</span>}
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
))}
|
||||
</div>
|
||||
{selected && (
|
||||
<div className="skill-detail-overlay" onClick={() => setSelected(null)}>
|
||||
<div className="skill-detail-panel" onClick={e => e.stopPropagation()}>
|
||||
<div className="skill-detail-header">
|
||||
<span className="skill-detail-name">{selected.name}</span>
|
||||
<button className="ghost sm" onClick={() => setSelected(null)}>✕</button>
|
||||
</div>
|
||||
<div className="skill-detail-body">
|
||||
<div className="skill-detail-section">
|
||||
<div className="skill-detail-label">Description</div>
|
||||
<div style={{ fontSize: 13, color: 'var(--text-secondary)' }}>{selected.description}</div>
|
||||
</div>
|
||||
<div className="skill-detail-section">
|
||||
<div className="skill-detail-label">Métadonnées</div>
|
||||
<div className="skill-detail-meta">
|
||||
{selected.target && <span className="badge neutral">{selected.target}</span>}
|
||||
{selected.version && <span className="badge">{selected.version}</span>}
|
||||
{selected.category && <span className="badge">{selected.category}</span>}
|
||||
{selected.author && <span className="badge ghost">{selected.author}</span>}
|
||||
{selected.languages && selected.languages.map(l => <span key={l} className="badge ghost">{l}</span>)}
|
||||
</div>
|
||||
</div>
|
||||
{selected.tags && selected.tags.length > 0 && (
|
||||
<div className="skill-detail-section">
|
||||
<div className="skill-detail-label">Tags</div>
|
||||
<div className="chip-row">
|
||||
{selected.tags.map(tag => <span key={tag} className="badge">{tag}</span>)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{selected.content && (
|
||||
<div className="skill-detail-section">
|
||||
<div className="skill-detail-label">Contenu</div>
|
||||
<div className="skill-detail-content">{selected.content}</div>
|
||||
</div>
|
||||
)}
|
||||
{selected.dependencies && selected.dependencies.length > 0 && (
|
||||
<div className="skill-detail-section">
|
||||
<div className="skill-detail-label">Dépendances</div>
|
||||
<div className="skill-detail-deps">
|
||||
{selected.dependencies.map((d, i) => (
|
||||
<div key={i} className="skill-detail-dep">
|
||||
<span className="badge">{d.type}</span>
|
||||
<span>{d.name}</span>
|
||||
{d.required === false && <span style={{ fontSize: 11, color: 'var(--text-disabled)' }}>optionnel</span>}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user