Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
84b3bc1
feat(workbench): implement center tab management and file preview fun…
iptoux May 22, 2026
1a73b0b
style: enhance layout and spacing for app preferences and harness com…
iptoux May 22, 2026
d3997fe
feat(i18n): add appearance category and headings to localization files
iptoux May 22, 2026
1b66656
feat(i18n): add API keys category and headings to localization files
iptoux May 22, 2026
1f5d818
feat(plans): add workspace color and terminal badge plan for sidebar …
iptoux May 22, 2026
e67c03a
feat(plans): introduce centralized API keys management plan
iptoux May 22, 2026
9ea5b12
refactor(plans): update centralized API keys management plan
iptoux May 22, 2026
5855e4c
feat(plans): add runtime review section and update tasks for API keys…
iptoux May 22, 2026
55a1ff7
feat(plans): enhance centralized API keys management with detailed UI…
iptoux May 22, 2026
861709d
feat: Implement centralized API keys management pane
iptoux May 22, 2026
04601cf
feat(i18n): add new API keys localization strings and update UI refer…
iptoux May 22, 2026
dbda405
fix(i18n): ensure status message is a string and improve environment …
iptoux May 22, 2026
d51031f
feat(workspace): add workspace settings pane and localization support
iptoux May 22, 2026
fa0fc34
feat(workspace): align workspace settings layout with API Keys pane
iptoux May 22, 2026
1b28bfb
style(workspace): update CSS for workspace and API Keys panes
iptoux May 22, 2026
b27e6ba
style(workspace): unify API Keys and Workspace settings layout
iptoux May 22, 2026
201c7ed
style(api_keys_pane): add margin to API keys row for improved spacing
iptoux May 22, 2026
959c9db
style(api_keys_pane): enhance API keys row layout with brand icons
iptoux May 22, 2026
23da52f
style(workbench): improve disabled button styles and update button at…
iptoux May 22, 2026
379e149
feat(api_keys_pane): add brand icons for various API services
iptoux May 22, 2026
3b60ecd
feat(api_keys_pane): replace Groq icon with Grok and update styles
iptoux May 22, 2026
a0787bf
feat(agent_provider_pane): add agent provider settings pane and local…
iptoux May 22, 2026
3b8125d
feat(tauri_bridge, harness_ui, agent_provider_pane): enhance data str…
iptoux May 22, 2026
7df4ecd
refactor(agent_provider_pane): simplify event handling in AgentModelP…
iptoux May 22, 2026
5e4824e
refactor(agent_provider_pane): streamline identifier usage in AgentMo…
iptoux May 22, 2026
23084bc
refactor(agent_provider_pane): optimize identifier handling in AgentM…
iptoux May 22, 2026
83a8a96
feat(i18n): add new localization keys for agent provider settings
iptoux May 22, 2026
3e89f87
feat(agent_model_picker): add AgentModelPicker component for model se…
iptoux May 22, 2026
b12d6a4
refactor(harness_image_pane): simplify CSS and enhance image provider…
iptoux May 22, 2026
aab3527
feat(image_settings): introduce image quality level feature and local…
iptoux May 22, 2026
cf1f0e2
feat(api_keys, image): add support for fal.ai and AWS Polly API keys
iptoux May 22, 2026
c0ba446
feat(voice_settings): integrate voice STT language and push-to-talk c…
iptoux May 22, 2026
37ee5c2
feat(locale): add ISO-639-1 mapping and locale picker for STT settings
iptoux May 22, 2026
a1c77e7
feat(agent_provider_pane): enhance layout and voice settings integration
iptoux May 22, 2026
27d2098
feat(harness-level-picker): implement new CSS styles and structure fo…
iptoux May 22, 2026
74efad0
refactor(harness_ui): remove unused select_str function
iptoux May 22, 2026
bd51122
feat(agent_provider_pane): add voice provider selection and styling
iptoux May 22, 2026
075c60d
fix(voice_settings): ensure voice provider updates on settings save
iptoux May 22, 2026
a2e12af
feat(agent_voice_column): enhance voice model management and layout
iptoux May 22, 2026
85fabd7
feat(voice_provider): add AWS support and localization updates
iptoux May 22, 2026
ca35c85
feat(voice_provider): remove model picker and enhance voice selection UI
iptoux May 22, 2026
0e651d4
refactor(voice_settings): streamline voice selection logic and remove…
iptoux May 22, 2026
9064fa4
refactor(agent_model_picker): simplify pricing display logic in agent…
iptoux May 22, 2026
7fde5eb
feat(voice_provider): update voice selection hints and enhance voice …
iptoux May 22, 2026
eb0e753
refactor(voice): remove unused voice provider functionality and strea…
iptoux May 22, 2026
896da7e
refactor(harness_ui, agent_provider): remove voice category and updat…
iptoux May 22, 2026
d916661
feat(category_colors): add category color management to workspace set…
iptoux May 22, 2026
8bc6580
docs: settings revamp changelog, user/dev guides, close api-keys plan
iptoux May 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .agents/plans/PLANS.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,5 @@ Persistent plans for multi-step work on **blxcode**. Individual plans live as Ma
| done | [coordinated-subagents.md](coordinated-subagents.md) | Coordinated Subagents fuer BLXCode Agent mit Rollen, i18n Live-Subcards, Provider-Reuse, Environment Detection, Shell/Git/Web Toolsets und scoped Toolgruppen |
| done | [better-harness.md](better-harness.md) | BetterHarness: Shrink system prompt by extracting tool docs into 6 embedded Core Skills; Skills tab gets Core/User sub-tabs |
| done | [agent-chat-maximize.md](agent-chat-maximize.md) | Agent-Tab: Chat-Maximize-Toggle vor Reset; Voice-Hero kompakt (`agent-hero--compact`), mehr Platz fuer Chat-Verlauf |
| planned | [workspace-color-terminal-badge.md](workspace-color-terminal-badge.md) | Workspace-Farbe persistent in Sidebar (Dot, farbiges Unread-Badge), Terminal-Slot-Zahl vor Name, aenderbar via Kontextmenue-Dialog |
| done | [api-keys-centralized.md](api-keys-centralized.md) | API-Schlüssel zentral unter Settings → API Keys; Backend-Katalog + resolve; Agent-Tab ohne Key-Felder; Coming-soon-Provider mit CRUD |
57 changes: 57 additions & 0 deletions .agents/plans/api-keys-centralized.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# API Keys zentralisieren

## Summary

Zentrale API-Schlüssel unter **Settings → API Keys**. UI folgt **App**- und **Workspace**-Harness-Stil; **ein** Speichern-Button für alle Keys. Backend: Katalog, Batch-`api_keys_apply`, zentraler `api_keys::resolve` als einzige Lookup-Quelle für Agent, Subagents, Image, Voice, Web und Model-Refresh.

## Decisions

### UI
- Design-Vorlage: `harness-pane`, `harness-subpane`, `harness-stack`, `workbench-plain-input`, Footer wie Workspace (`workbench-mini-btn--primary` + `LuSave` + `BtnSave`).
- **Kein Save pro Zeile**; optional „Key entfernen" pro Zeile → Draft, Ausführung mit globalem Save.
- **Draft-UX**: Discard-Button neben Save; Verlassen-Warnung bei Dirty-State (Pane-Wechsel / Tab-Schließen).

### Backend
- Batch-IPC: `api_keys_apply` (setzt/löscht Keys in einem Aufruf).
- Zentrale Resolve-Funktion: `api_keys::resolve(provider) -> Option<String>` (intern genutzt) plus `provider_key_pub` für IPC-Konsumenten.
- **Env-Precedence**: Store gewinnt. Env (z. B. `BLX_ANTHROPIC_API_KEY`) ist nur Fallback, wenn Store leer ist. UI zeigt „via env" als Hinweis, wenn Fallback aktiv.
- **Migration (one-shot, beim Start)**: Bestehende Pro-Provider-Eintr. aus dem alten `agent_api_key_set`-Store werden in den zentralen Katalog übernommen; alter Store wird danach geleert. Idempotent — mehrfacher Start überschreibt nichts.
- **Alte IPCs entfernen (selber PR)**: `agent_api_key_set`, `agent_api_key_delete` + Bridge-Wrapper raus. Kein Deprecate-Shim.

### Image / Voice / Web
- Key-Felder vollständig aus `image_settings`, Voice-Settings und Web-Settings entfernen (UI **und** Backend-Struct).
- Runtime liest ausschließlich über `api_keys::resolve` mit den **reused** Provider-IDs (OpenAI / OpenRouter / …).
- Fehlermeldungen verweisen auf **Settings → API Keys**, nicht mehr auf „Image-Einstellungen" o. ä.

### Cursor-Plan (inline)
> Folgende Abschnitte aus dem ursprünglichen Cursor-Plan müssen hier eingetragen werden, damit dieser Plan eigenständig review-/umsetzbar ist:
- **Keyring-Strategie**: OS-Keyring (Linux: secret-service, macOS: Keychain, Windows: Credential Manager) vs. Plaintext-Datei — Fallback-Policy, Speicherort, Verschlüsselung. _(TODO: Inhalte aus Cursor-Plan einfügen)_
- **Pfade**: Konkreter Pfad des zentralen Katalogs (z. B. `~/.config/blxcode/api_keys.json` oder Keyring-Eintragsname). _(TODO)_
- **Env-Vars**: Vollständige Liste der respektierten Env-Vars pro Provider. _(TODO)_
- **Coming-soon-Provider**: Welche Provider erscheinen als deaktivierte Zeilen im UI? _(TODO)_

## Runtime (Review)

**Heute**: Agent / Subagent / Image / Voice / Web haben jeweils eigenen Key-Pfad. Image-Fehler zeigt irreführend „Image-Einstellungen". Subagent macht separaten Lookup.

**Ziel**: Agent, Subagents (gleicher Turn-Key), Image / Voice (Reuse OpenAI/OpenRouter-IDs), Web, Model-Refresh → **alle** über `api_keys::resolve` / `provider_key_pub`. Subagents ohne separaten Lookup. Image-Fehler auf API Keys umgestellt.

## Tasks (in Ausführungsreihenfolge)

1. [x] **`api-keys-backend`** — Katalog-Struct, Storage (Keyring/Datei), `api_keys_apply`, `api_keys::resolve`, One-shot-Migration aus altem `agent_api_key_set`-Store, Env-Fallback-Logik.
2. [x] **`api-keys-bridge`** — `tauri_bridge.rs`: `api_keys_status` / `api_keys_apply`; alte per-provider key commands entfernt.
3. [x] **`settings-scaffold`** — Docked center settings tab + sidebar categories (`harness_ui.rs` / `SettingsDock`).
4. [x] **`api-keys-ui`** — `api_keys_pane/`: Save/Discard footer, draft state, per-row remove, „via env" hint, brand icons.
5. [x] **`runtime-wiring`** — Agent/Subagent/Image/Voice/Web/Model-Refresh über zentralen resolve; Image/Voice ohne eigene Key-Felder.
6. [x] **`agent-pane-trim`** — BLXCode Agent: nur Status-Hinweis → API Keys (Text/Image/Voice).
7. [x] **`i18n-docs`** — Locales + user/developer docs + CHANGELOG (PR #13 branch).

## Acceptance Criteria

- [x] Subagent läuft mit zentral gesetztem Key (kein separater Lookup-Pfad).
- [x] Image-Fehlermeldung verweist auf **Settings → API Keys** (nicht mehr „Image-Einstellungen").
- [x] Agent-Pane enthält kein Key-Eingabefeld mehr.
- [x] Migration-Smoke: Vorhandene Pro-Provider-Keys (alter Store) sind nach erstem Start im zentralen Katalog lesbar; alter Store geleert.
- [x] `agent_api_key_set` / `agent_api_key_delete` (Backend-Command + Bridge-Wrapper) sind aus dem Repo entfernt.
- [x] Env-Fallback: Bei leerem Store-Eintrag wird `BLX_*` env gelesen; UI zeigt „via env".
- [x] Discard-Button verwirft Draft; Dirty-State im Footer sichtbar.
76 changes: 76 additions & 0 deletions .agents/plans/workspace-color-terminal-badge.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# Workspace-Farbe und Terminal-Badge in der Sidebar

## Summary

Workspaces erhalten ein persistentes `color`-Feld (analog Memory-Kategorien), änderbar über den bestehenden Kontextmenü-Dialog. In der Sidebar erscheinen ein Farbpunkt links, eine Terminal-Slot-Zahl vor dem Namen (nur bei mehr als einem Slot) und ein farblich passendes Unread-Badge rechts. Persistenz über `workbench.json`; keine Backend-Änderungen.

## Decisions

- **Terminal-Zahl:** zählt Terminal-Slots (`slot_ids.len()`), nicht Split-Panes oder laufende PTY-Sessions.
- **Anzeige Terminal-Badge:** nur wenn `slot_ids.len() > 1` (bei einem Slot ausblenden).
- **Default-Farbe:** `stable_category_color(&storage_key)` für neue und backgefüllte Workspaces.
- **Farb-Presets:** bestehende `memory_color_presets()` wiederverwenden (kein neuer localStorage-Key).
- **Kontextmenü:** Rename-Dialog wird zu „Workspace bearbeiten" mit Name + Farbe (wie `MemoryCategoryEditDialog`).
- **Terminal-Badge-Farbe:** fest orange `#e8954a` (Mockup); Unread-Badge rechts nutzt Workspace-Farbe.

## Implementation Notes

### Datenmodell — [`src/workbench/state.rs`](../../src/workbench/state.rs)

- `WorkspaceEntry.color: String` mit `#[serde(default)]` (leer = noch nicht gesetzt).
- `workspace_effective_color(entry)` — gespeicherte Farbe oder `stable_category_color(&entry.storage_key)`.
- Backfill leerer `color`-Felder beim Laden (`backfill_workspace_colors()` oder in `backfill_storage_keys()`).
- `create_workspace`: initiale Farbe setzen.
- Setter: `set_workspace_display(id, title, color)` oder `rename_workspace` + `set_workspace_color` erweitern.
- `normalize_memory_color` aus [`memory_panel.rs`](../../src/workbench/memory_panel.rs) nach shared Modul (`state.rs` oder `color_util.rs`) verschieben.

### Kontextmenü & Dialog — [`src/workbench/sidebar.rs`](../../src/workbench/sidebar.rs)

- Rechtsklick-Menü: Eintrag „Bearbeiten" öffnet Dialog mit Name, `<input type="color">`, Hex-Feld, Swatches aus `wb.memory_color_presets()`.
- Speichern schreibt Titel + normalisierte Farbe → debounced Auto-Save in [`mod.rs`](../../src/workbench/mod.rs).

### Sidebar-Rendering — [`src/workbench/sidebar.rs`](../../src/workbench/sidebar.rs)

Zeilenlayout (expanded):

```mermaid
flowchart LR
dot[Farbpunkt] --> termBadge[Terminal-Zahl] --> name[Name] --> unreadBadge[Unread]
```

- Farbpunkt: `.workbench-sidebar__color-dot` mit `--workspace-color`.
- Terminal-Badge: `.workbench-sidebar__terminal-count` vor dem Namen.
- `▸`-Bullet entfernen oder durch Farbpunkt ersetzen.
- Unread-Badge: inline-style mit Workspace-Farbe statt festem Orange.
- Collapsed-Modus: Farbe am Icon-Rand oder als Hintergrund des Initialen-Kästchens.

### CSS — [`styles.css`](../../styles.css)

Neue/angepasste Klassen: `__color-dot`, `__terminal-count`, dynamisches `__badge--total`, optional `__row--active` mit `--workspace-color` für `border-left-color`.

### i18n — [`src/i18n/keys.rs`](../../src/i18n/keys.rs) + alle `locales/*.rs`

Neue Keys: `SbEditMenu`, `SbEditTitle`, `SbEditSubmit`, `SbColorLabel`, `SbTerminalCountAria`.

## Tests

- Neuer Workspace: Farbpunkt sichtbar, persistiert nach Neustart.
- Bestehende Workspaces ohne `color` in JSON: Backfill weist stabile Farbe zu.
- Kontextmenü → Bearbeiten → Farbe ändern → Neustart → Farbe bleibt.
- Terminal-Slots hinzufügen/entfernen: Zahl vor Name aktualisiert sich reaktiv.
- Unread-Badge rechts nutzt Workspace-Farbe.
- Collapsed-Sidebar: Farbe weiterhin erkennbar.

```bash
cargo check -p blxcode-ui --target wasm32-unknown-unknown
cargo test --workspace
```

## Tasks

- [ ] `model-color` - WorkspaceEntry.color, workspace_effective_color, Backfill und Setter in state.rs
- [ ] `shared-color-util` - normalize_hex_color aus memory_panel extrahieren und gemeinsam nutzen
- [ ] `edit-dialog` - Rename-Dialog in sidebar.rs zu Edit-Dialog mit Color-Picker und Presets erweitern
- [ ] `sidebar-ui` - Farbpunkt, Terminal-Slot-Badge und farbiges Unread-Badge rendern
- [ ] `css` - Neue Sidebar-Klassen in styles.css; Active-State mit Workspace-Farbe
- [ ] `i18n` - Neue I18nKeys in keys.rs und allen locales/*.rs
82 changes: 73 additions & 9 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Build release bundles on macOS and Windows (no Linux CI).
# macOS .app/.dmg require a macOS runner (Intel + Apple Silicon via universal target).
# Windows builds use the self-hosted runner (label: blxcode-win).
name: Release

permissions:
Expand All @@ -15,6 +16,14 @@ on:
tags: ["v*"]
workflow_dispatch:
inputs:
mode:
description: "testbuild = build only (workflow artifacts); release = draft GitHub release + upload"
type: choice
required: true
default: testbuild
options:
- testbuild
- release
platforms:
description: Build targets
type: choice
Expand Down Expand Up @@ -88,19 +97,49 @@ jobs:
}
core.setFailed("Unauthorized release actor");

build:
resolve:
needs: authorize
runs-on: ubuntu-latest
outputs:
mode: ${{ steps.mode.outputs.mode }}
matrix: ${{ steps.matrix.outputs.matrix }}
steps:
- id: mode
run: |
if [ "${{ github.event_name }}" = "push" ]; then
echo "mode=release" >> "$GITHUB_OUTPUT"
else
echo "mode=${{ inputs.mode }}" >> "$GITHUB_OUTPUT"
fi

- id: matrix
run: |
platforms="${{ inputs.platforms }}"
if [ "${{ github.event_name }}" = "push" ]; then
platforms="Alle"
fi

include="["
sep=""
if [ "$platforms" = "Alle" ] || [ "$platforms" = "Mac Universal" ]; then
include+="${sep}{\"platform\":\"macos-latest\",\"platform_id\":\"mac\",\"args\":\"--target universal-apple-darwin\"}"
sep=","
fi
if [ "$platforms" = "Alle" ] || [ "$platforms" = "Windows" ]; then
include+="${sep}{\"platform\":[\"self-hosted\",\"Windows\",\"blxcode-win\"],\"platform_id\":\"windows\",\"args\":\"\"}"
fi
include+="]"

echo "matrix={\"include\":${include}}" >> "$GITHUB_OUTPUT"

build:
needs: [authorize, resolve]
permissions:
contents: write
strategy:
fail-fast: false
max-parallel: 1
matrix:
include:
- platform: macos-latest
args: --target universal-apple-darwin
- platform: windows-latest
args: ""
matrix: ${{ fromJson(needs.resolve.outputs.matrix) }}

runs-on: ${{ matrix.platform }}
steps:
Expand All @@ -118,8 +157,11 @@ jobs:
cache: npm
cache-dependency-path: frontend-js/package-lock.json

- name: Install frontend dependencies
run: npm ci --prefix frontend-js

- name: Add macOS Rust targets
if: matrix.platform == 'macos-latest'
if: matrix.platform_id == 'mac'
run: |
rustup target add aarch64-apple-darwin x86_64-apple-darwin
echo "macOS universal build: Apple Silicon (aarch64) + Intel (x86_64)"
Expand All @@ -129,7 +171,28 @@ jobs:
cargo install trunk --locked
cargo install tauri-cli --version "^2" --locked

- name: Build bundles
- name: Build bundles (testbuild)
if: needs.resolve.outputs.mode == 'testbuild'
working-directory: src-tauri
env:
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
CI: true
CSC_IDENTITY_AUTO_DISCOVERY: false
APPLE_SIGNING_IDENTITY: "-"
run: cargo tauri build ${{ matrix.args }}

- name: Upload test build artifacts
if: needs.resolve.outputs.mode == 'testbuild'
uses: actions/upload-artifact@v4
with:
name: blxcode-${{ matrix.platform_id }}-${{ github.run_id }}
path: target/**/release/bundle/**/*
retention-days: 7
if-no-files-found: error

- name: Build bundles (release)
if: needs.resolve.outputs.mode == 'release'
uses: tauri-apps/tauri-action@v0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Expand All @@ -149,6 +212,7 @@ jobs:
args: ${{ matrix.args || '' }}

- name: Merge updater latest.json
if: needs.resolve.outputs.mode == 'release'
shell: bash
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Expand Down
Loading
Loading