Refactor: remove desktop/Tauri bundle, add i18n, CI/CD pipeline
Nightly Build / build (push) Failing after 6s
Nightly Build / build (push) Failing after 6s
- Remove desktop (Tauri) bundle: docs/desktop.md, icons/, tauri.conf.json, src/desktop/mod.rs, gen/schemas/ - Remove build.rs (no longer needed) - Add i18n system (crates/core-api, plugin-mobile-connector, web) - Refactor config system (src/config.rs, boot_format.rs) - Add mobile connector features (app, router, device pairing) - Plugin system improvements (skald-core) - Update dependencies (Cargo.lock, Cargo.toml) - CI/CD: Gitea Actions workflows (nightly + release), package.sh, verify-version.sh, builds.skaldagent.net config
This commit is contained in:
@@ -389,6 +389,7 @@ export class AppCopilot extends I18nMixin(ChatSession) {
|
||||
</div>
|
||||
|
||||
<div class="copilot-input-area">
|
||||
${this._renderNoModelsBanner()}
|
||||
<div class="copilot-composer"
|
||||
@dragover=${(e) => e.preventDefault()}
|
||||
@drop=${(e) => this._onDrop(e)}>
|
||||
@@ -416,6 +417,7 @@ export class AppCopilot extends I18nMixin(ChatSession) {
|
||||
<textarea
|
||||
class="copilot-textarea"
|
||||
rows="1"
|
||||
?disabled=${this._noModels}
|
||||
placeholder=${t('chat.placeholder')}
|
||||
@keydown=${this._composerKeydown}
|
||||
@input=${(e) => { this._autoResize(e.target); this._updateCmdMenu(e.target.value); }}
|
||||
@@ -469,7 +471,7 @@ export class AppCopilot extends I18nMixin(ChatSession) {
|
||||
<i class="bi bi-stop-fill"></i>
|
||||
</button>`
|
||||
: nothing}
|
||||
<button class="copilot-send-btn" @click=${() => this._send()} title=${t('chat.send')}>
|
||||
<button class="copilot-send-btn" ?disabled=${this._noModels} @click=${() => this._send()} title=${t('chat.send')}>
|
||||
<i class="bi bi-send-fill"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -139,6 +139,7 @@ export class ChatPage extends ChatSession {
|
||||
</div>
|
||||
|
||||
<div class="chat-page-input-area">
|
||||
${this._renderNoModelsBanner()}
|
||||
<div class="chat-page-composer"
|
||||
@dragover=${(e) => e.preventDefault()}
|
||||
@drop=${(e) => this._onDrop(e)}>
|
||||
@@ -153,6 +154,7 @@ export class ChatPage extends ChatSession {
|
||||
<textarea
|
||||
class="chat-page-textarea"
|
||||
rows="1"
|
||||
?disabled=${this._noModels}
|
||||
placeholder=${t('chat.mobile.placeholder')}
|
||||
@input=${(e) => this._autoResize(e.target)}
|
||||
@paste=${(e) => this._onPaste(e)}
|
||||
@@ -195,6 +197,7 @@ export class ChatPage extends ChatSession {
|
||||
: nothing}
|
||||
<button
|
||||
class="chat-page-send"
|
||||
?disabled=${this._noModels}
|
||||
@click=${() => this._send()}
|
||||
title=${t('chat.send')}
|
||||
><i class="bi bi-send-fill"></i></button>
|
||||
|
||||
@@ -6,6 +6,14 @@
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.chat-no-models {
|
||||
margin-bottom: 0.6rem;
|
||||
padding: 0.7rem 0.9rem;
|
||||
font-size: 0.82rem;
|
||||
}
|
||||
.chat-no-models .home-banner-icon { font-size: 1.2rem; }
|
||||
.chat-no-models a { color: var(--bs-danger); font-weight: 600; }
|
||||
|
||||
.copilot-composer {
|
||||
position: relative;
|
||||
display: flex;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { html, nothing } from 'lit';
|
||||
import { LightElement } from './base.js';
|
||||
import { t } from './i18n.js';
|
||||
|
||||
@@ -29,6 +30,7 @@ export class ChatSession extends LightElement {
|
||||
_expanded: { state: true },
|
||||
_providers: { state: true },
|
||||
_selectedClient: { state: true },
|
||||
_providersLoaded: { state: true },
|
||||
_rejectingId: { state: true },
|
||||
_rejectNote: { state: true },
|
||||
_clarificationAnswer: { state: true },
|
||||
@@ -54,6 +56,7 @@ export class ChatSession extends LightElement {
|
||||
this._ws = null;
|
||||
this._providers = [];
|
||||
this._selectedClient = null;
|
||||
this._providersLoaded = false;
|
||||
this._rejectingId = null;
|
||||
this._rejectNote = '';
|
||||
this._clarificationAnswer = '';
|
||||
@@ -116,9 +119,30 @@ export class ChatSession extends LightElement {
|
||||
this._selectedClient = def;
|
||||
} catch (e) {
|
||||
console.error('Failed to load LLM models:', e);
|
||||
} finally {
|
||||
this._providersLoaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
get _noModels() {
|
||||
return this._providersLoaded
|
||||
&& this._providers.filter(p => p !== 'auto').length === 0;
|
||||
}
|
||||
|
||||
_renderNoModelsBanner() {
|
||||
if (!this._noModels) return nothing;
|
||||
return html`
|
||||
<div class="home-banner home-banner--error chat-no-models">
|
||||
<div class="home-banner-icon"><i class="bi bi-cpu-fill"></i></div>
|
||||
<div class="home-banner-body">
|
||||
<strong>${t('dashboard.banner.no_models.title')}</strong>
|
||||
${t('dashboard.banner.no_models.desc')}
|
||||
<a href="#llm-providers">${t('dashboard.banner.no_models.action')}</a>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
async _loadHistory() {
|
||||
try {
|
||||
const res = await fetch(`/api/${this._source}/messages`);
|
||||
|
||||
@@ -23,6 +23,22 @@ export function t(key, params) {
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge additional strings into the dictionaries — the registration seam for
|
||||
* plugin page fragments, which ship their own `{ en, it, fr }` table and call
|
||||
* this at module-load time (before their first render). Keys MUST be namespaced
|
||||
* (`plugin.<id>.<key>`) so a plugin never clobbers a core key or another
|
||||
* plugin's. Unknown locales are created on demand; missing keys still fall back
|
||||
* through `t()` (locale → en → key). Merging alone does not re-render — the
|
||||
* fragment registers before it mounts, and later `locale-changed` events drive
|
||||
* updates as usual via `I18nMixin`.
|
||||
*/
|
||||
export function addStrings(dicts) {
|
||||
for (const [loc, map] of Object.entries(dicts || {})) {
|
||||
DICTS[loc] = { ...(DICTS[loc] || {}), ...map };
|
||||
}
|
||||
}
|
||||
|
||||
export function getLocale() { return _locale; }
|
||||
|
||||
export function setLocale(locale, { persist = false } = {}) {
|
||||
|
||||
Reference in New Issue
Block a user