J.A.R.V.I.S-rust/resources/commands/stopwatch/ctl.lua
Bossiara13 dcee98bddf feat: 5 new packs + dotenvy + regen icon.ico + shortcuts redo
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).
2026-05-15 12:28:44 +03:00

53 lines
2.3 KiB
Lua
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

local lang = jarvis.context.language
local cmd_id = jarvis.context.command_id
local function speak(text)
local sapi = text:gsub("'", "''"):gsub("\r?\n", " ")
local ps = string.format(
[[Add-Type -AssemblyName System.Speech; $s = New-Object System.Speech.Synthesis.SpeechSynthesizer; foreach ($v in $s.GetInstalledVoices()) { if ($v.VoiceInfo.Culture.TwoLetterISOLanguageName -eq 'ru') { try { $s.SelectVoice($v.VoiceInfo.Name); break } catch {} } } $s.Speak('%s')]],
sapi
)
jarvis.system.exec(string.format('powershell -NoProfile -Command "%s"', ps:gsub('"', '\\"')))
end
local function format_elapsed(sec)
sec = math.floor(sec)
if sec < 60 then return sec .. (lang == "ru" and " секунд" or " seconds") end
if sec < 3600 then
local m = math.floor(sec / 60); local s = sec % 60
return string.format(lang == "ru" and "%d мин %d сек" or "%d min %d sec", m, s)
end
local h = math.floor(sec / 3600); local m = math.floor((sec % 3600) / 60); local s = sec % 60
return string.format(lang == "ru" and "%d ч %d мин %d сек" or "%d h %d m %d s", h, m, s)
end
if cmd_id == "stopwatch_start" then
jarvis.state.set("stopwatch_start_ts", jarvis.context.time.timestamp)
jarvis.system.notify("Stopwatch", lang == "ru" and "Старт" or "Started")
speak(lang == "ru" and "Секундомер запущен" or "Stopwatch started")
jarvis.audio.play_ok()
return { chain = false }
end
local started = jarvis.state.get("stopwatch_start_ts")
if not started then
jarvis.system.notify("Stopwatch", lang == "ru" and "Не запущен" or "Not running")
speak(lang == "ru" and "Секундомер не запущен" or "Stopwatch is not running")
jarvis.audio.play_not_found()
return { chain = false }
end
local elapsed = jarvis.context.time.timestamp - started
local human = format_elapsed(elapsed)
if cmd_id == "stopwatch_stop" then
jarvis.state.set("stopwatch_start_ts", nil)
jarvis.system.notify("Stopwatch", (lang == "ru" and "Прошло: " or "Elapsed: ") .. human)
speak((lang == "ru" and "Прошло " or "Elapsed ") .. human)
else
jarvis.system.notify("Stopwatch", (lang == "ru" and "Прошло: " or "Elapsed: ") .. human)
speak((lang == "ru" and "Прошло " or "Elapsed ") .. human)
end
jarvis.audio.play_ok()
return { chain = false }