feat: GUI /memory page + disk/date_math/sleep_timer packs (10 new commands)

GUI: Memory management completes the management trio (/macros + /scheduler + /memory).

Tauri commands (crates/jarvis-gui/src/tauri_commands/memory.rs)
  - memory_list             → Vec<MemoryFact{key, value, created_at, last_used_at, use_count}>
  - memory_remember(k, v)   → persist new fact (or overwrite)
  - memory_forget(key)      → delete by exact key
  - memory_search(q, limit) → substring search

GUI /memory page (frontend/src/routes/memory/index.svelte)
  - Top: add-fact form (key + value inputs + "+Добавить" button)
  - Substring filter input for the list
  - Per-card: key + use_count badge + value (highlighted box) + timestamps +
    "Забыть" button with confirm() guard
  - Auto-sorted by recency (last_used_at desc)
  - Empty state shows voice-hint: 'скажи Jarvis-у "запомни что я люблю чай улун"'

Header (frontend/src/components/Header.svelte)
  - New "Память" button between /scheduler and /settings.
  - i18n: header-memory in ru/en/ua FTL files.

New voice packs

resources/commands/disk/ (2 cmds)
  - disk.free      "сколько свободно на диске" / "сколько места на диске C"
                   PowerShell Get-PSDrive → speaks "Свободно X ГБ из Y, это N%"
  - disk.list      "какие у меня диски" → "C 120 ГБ, D 300 ГБ, E 50 ГБ"

resources/commands/date_math/ (2 cmds)
  - date.days_until    "сколько дней до нового года" / "сколько до 8 марта" /
                       "сколько до 15 марта" — recognises Russian months,
                       holidays (Новый год, Рождество, 8 марта, 9 мая).
                       Auto-rolls to next year if target already passed.
                       Russian-grammar pluralisation (день/дня/дней).
  - date.day_of_week   "какой сегодня день недели" — Zeller's congruence,
                       maps to ru day name.

resources/commands/sleep_timer/ (3 cmds)
  - sleep_timer.pause_in    "выключи музыку через 30 минут"
                            → scheduler one-shot lua action that fires media
                            VK_MEDIA_PLAY_PAUSE via the existing media_keys helper.
                            (Auto-generates _fire_pause.lua wrapper if missing.)
  - sleep_timer.shutdown_in "выключи компьютер через 1 час"
                            → shutdown.exe /s /t <secs>. Caps at 24 hours.
                            Speaks "Скажите 'отмени таймер' чтобы передумать."
  - sleep_timer.cancel      "отмени таймер выключения" / "не выключай компьютер"
                            → shutdown /a + scheduler.remove("sleep_timer_pause"),
                            idempotent.

Pack count: 64 → 67. Tests: 112/112 pass.
Build: cargo build --release -p jarvis-gui green.
This commit is contained in:
Bossiara13 2026-05-15 23:35:23 +03:00
parent 84d3b57ddc
commit d3180b7d78
18 changed files with 717 additions and 4 deletions

View file

@ -0,0 +1,36 @@
# Disk space — free GB on system drive, or named drive.
[[commands]]
id = "disk.free"
type = "lua"
script = "free.lua"
sandbox = "full"
timeout = 5000
[commands.phrases]
ru = [
"сколько свободного места",
"сколько места на диске",
"сколько свободно на диске",
"место на диске",
"свободное место",
]
en = ["disk space", "free space", "how much disk"]
ua = ["скільки місця на диску"]
[[commands]]
id = "disk.list"
type = "lua"
script = "list.lua"
sandbox = "full"
timeout = 5000
[commands.phrases]
ru = [
"какие у меня диски",
"список дисков",
"перечень дисков",
]
en = ["list drives", "what drives do I have"]
ua = ["які диски"]

View file

@ -0,0 +1,35 @@
-- "Сколько свободно на диске C" / "сколько места"
local phrase = (jarvis.context.phrase or ""):upper()
local letter = phrase:match("([A-Z])%s*ДИСК") or phrase:match("ДИСК%s*([A-Z])") or
phrase:match("DRIVE%s*([A-Z])") or "C"
local ps = string.format(
"$d = Get-PSDrive %s -ErrorAction SilentlyContinue; " ..
"if ($d) { '{0}|{1}' -f " ..
"[math]::Round($d.Free/1GB,1), " ..
"[math]::Round(($d.Free + $d.Used)/1GB,0) } else { 'NONE' }",
letter
)
local res = jarvis.system.exec(string.format(
'powershell -NoProfile -Command "%s"', ps:gsub('"', '\\"')
))
if not res.success then
return jarvis.cmd.error("Не получилось.")
end
local out = (res.stdout or ""):gsub("%s+", "")
if out == "NONE" or out == "" then
return jarvis.cmd.not_found("Диск " .. letter .. " не найден.")
end
local free_gb, total_gb = out:match("([%d%.]+)|(%d+)")
if not free_gb then
return jarvis.cmd.error("Не понял ответ системы.")
end
local pct = math.floor(tonumber(free_gb) / tonumber(total_gb) * 100 + 0.5)
return jarvis.cmd.ok(string.format(
"На диске %s свободно %s гигабайт из %s, это %d процентов.",
letter, free_gb, total_gb, pct
))

View file

@ -0,0 +1,30 @@
local ps =
"Get-PSDrive -PSProvider FileSystem | " ..
"Where-Object { $_.Used -ne $null -or $_.Free -ne $null } | " ..
"ForEach-Object { '{0}:{1}' -f $_.Name, [math]::Round($_.Free/1GB,0) } | " ..
"ForEach-Object { Write-Host -NoNewline ($_+' ') }"
local res = jarvis.system.exec(string.format(
'powershell -NoProfile -Command "%s"', ps:gsub('"', '\\"')
))
if not res.success then
return jarvis.cmd.error("Не получилось.")
end
local out = (res.stdout or ""):gsub("^%s+", ""):gsub("%s+$", "")
if out == "" then
return jarvis.cmd.not_found("Дисков не нашёл.")
end
-- "C:120 D:300 E:50" → "C 120 ГБ, D 300 ГБ, ..."
local parts = {}
for letter, gb in out:gmatch("([A-Z]):(%d+)") do
table.insert(parts, letter .. " " .. gb .. " гигабайт")
end
if #parts == 0 then
return jarvis.cmd.error("Не понял ответ системы.")
end
return jarvis.cmd.ok("Свободно: " .. table.concat(parts, ", ") .. ".")