CI (.github/workflows/ci.yml):
- Three parallel jobs on push & PR: cargo test (jarvis-core), cargo
clippy (lint, warnings-as-errors), cargo check (workspace). Windows
runner, stable toolchain, rust-cache for fast incremental builds.
- Deliberately skips release build of jarvis-gui — that needs Node+npm
+Tauri bundler and would balloon CI to ~10min per push.
Drop Ukrainian:
- Delete ua.ftl, remove UA from SUPPORTED_LANGUAGES.
- config.rs: prune UA arms from get_wake_phrases / get_wake_grammar /
get_phrases_to_remove / get_llm_trigger_phrases / get_llm_system_prompt.
- stt/vosk.rs: drop UA → uk language mapping.
- tray menu: drop "Українська" entry.
- frontend: drop UA from Header.svelte language list, settings page
language map, i18n.ts fallback.
- 82 command.toml files stripped of every `ua = [...]` block (205
blocks total). Handled via subagent — TOML still parses, all 6 command
tests pass.
.gitignore: stop tracking dev.env / dll_probe*.py / imports_full.txt
which were sitting in working tree.
Tests: 128 pass (no regression). Workspace still compiles end-to-end.
Architecture — DRY at the Lua API surface:
lua/api/tts.rs (new): jarvis.speak(text, opts?). opts.lang = ISO
two-letter code (default "ru"); auto-picks first installed voice
matching the culture. opts.async = true|false (default true). The
9 packs that previously inlined a 60-character PS-SAPI string for
every spoken reply can now reduce to one line. Refactored fun/,
dice/, clipboard_read/ as proof — fun/ask.lua went from 75 lines
of HTTP+SAPI boilerplate to ~28 lines of intent code.
lua/api/llm.rs (new): jarvis.llm(messages, opts?). messages is a
list of {role, content} tables, opts.max_tokens / .temperature /
.top_p. Returns the assistant string or nil. Gated by sandbox
allows_http() (so Standard+ packs only). Internally uses the
existing jarvis_core::llm::LlmClient::complete_with, no duplicated
HTTP plumbing.
llm/client.rs: split complete() into complete_with(messages,
max_tokens, temperature, top_p) for the new caller; old complete()
is now a thin wrapper at temp=0.7 top_p=1.0 for backward compat.
GUI — /commands page rewrite:
Replaces the "Раздел в разработке" placeholder. Calls Tauri command
get_commands_list (already existed in tauri_commands/commands.rs,
was wired but unused). Renders a search-filterable card grid:
- cmd id (monospace)
- type badge with colour by kind (lua=blue, ahk=red, cli=grey,
voice=green, terminate=red, stop_chaining=violet)
- sandbox badge
- description line (if non-empty)
- all phrases for currentLanguage, fallback to en, fallback to
first available; each phrase in a small inline pill
Toolbar: text input with magnifier icon + reload button (↻).
Counter line shows visible/total + "Скажи Джарвис + любую фразу"
hint. Counts down as you type the filter.
New packs (3, total 33 → 36):
games/ — launch_game / list_games. Reads or creates
%USERPROFILE%\Documents\jarvis-games.json (the sample preloads dota,
cs2, elden ring, witcher 3, factorio + minecraft launcher path +
fortnite epic URI). Trigger-strip + fuzzy name/alias match, then
launches via steam://rungameid/N (Steam), epic:// (Epic Games), or
start "" "path" (anything else). list_games speaks the configured
library.
mouse/ — left/right/middle/double click + scroll up/down. Single
dispatch.lua + _mouse_helper.ps1. PS P/Invokes user32!mouse_event
with the right flag pair (LEFTDOWN+LEFTUP / etc.), 30ms gap, doubles
do two LEFT cycles with a 50ms gap, wheel uses ±360 ticks.
random_choice/ — "выбери из X или Y или Z". Strips the trigger,
splits on " или " / " or " / ", " / " либо " / " чи ", math.random
picks one, speaks "Я выбираю N".
cargo test commands::tests still 3/3. 36 packs verified via
jarvis-gui startup log.
Iron Man icon regenerated from resources/icons/icon.png at sizes
16/24/32/48/64/128/256 via Pillow (make_ico.py committed alongside);
icon.ico is now a clean 83 KB multi-res for sharp display at any
scale instead of whatever placeholder Tauri originally emitted.
dotenvy added to workspace deps. jarvis-app/main.rs and jarvis-gui/
main.rs both walk up from current_exe() looking for dev.env (up to
5 parent levels), so the Desktop shortcut can launch the exe
directly without a wrapper .bat to pre-set GROQ_TOKEN. Falls back
to dotenvy::dotenv() (cwd lookup) if nothing found near the binary.
5 new portable Lua command packs. Bumps total from 21 to 26.
cargo test -p jarvis-core --lib commands::tests still passes 3/3.
reminders/ — set_reminder. Parses "напомни через N (секунд|минут|
часов) <body>" or English equivalents; understands one Russian word
numerals (один, две, пять, десять, пятнадцать, ...) for the count
when speech recognition returns words instead of digits. Defaults to
5 minutes if number/unit missing. Spawns a detached PowerShell that
Start-Sleeps then fires: BurntToast if installed, System.Speech
SAPI (ru-RU voice preference), and a WScript.Shell.Popup as the
guaranteed-visible last resort.
date_query/ — today / tomorrow / yesterday. Single answer.lua keyed
by command_id, computes the offset via PowerShell Get-Date.AddDays()
in ru-RU culture so the weekday/month come out in Russian, then
speaks via SAPI.
voice_type/ — type_text. Strips the trigger, drops the remainder to
clipboard via jarvis.system.clipboard.set, then synthesises Ctrl+V
through user32!keybd_event so it lands in whatever window currently
has focus. Works in any text field (note app, browser, IDE,
Telegram, etc.).
dice/ — coin_flip / roll_dice / random_number. Single roll.lua,
seeds math.random with os.time + jitter, speaks the result. "1-6"
for dice, "1-100" for random.
stopwatch/ — start / check / stop. Uses jarvis.state.get/set
(persisted via jarvis-core's settings DB) to remember the start
timestamp, computes elapsed via jarvis.context.time.timestamp,
formats as "X сек" / "X мин Y сек" / "X ч Y мин Z сек".
All new packs follow the established patterns (sandbox=full, PS-via-
exec helper where needed, USERPROFILE/SystemDrive everywhere, no
hardcoded paths).