feat: Wave 6 — focus mode, cooking timer, memory admin
Some checks are pending
Rust CI / cargo test (jarvis-core) (push) Waiting to run
Rust CI / cargo clippy (push) Waiting to run
Rust CI / cargo check (workspace) (push) Waiting to run

Focus mode (`focus/`):
- focus.start ("режим фокуса" / "focus mode"): three side-effects in one
  voice trigger:
    1. switch profile to "work" (silences fun/banter)
    2. enable Windows Focus Assist via registry tweak (QuietHours key)
    3. schedule a stretch reminder in 50 minutes through the persistent
       scheduler — so it survives daemon restart
- focus.stop: undoes all three, including cancelling pending stretch
  reminders by matching their scheduler name. Best-effort: any one
  failing doesn't block the others.

Cooking timer (`cooking/`):
- Recognises 16+ dish names (чай, кофе, омлет, яйца, макароны, паста,
  рис, гречка, картошка, курица, пицца, etc.) and starts a preset-
  duration scheduler reminder ("Сэр, чай готов.").
- Single Lua script, table-driven — adding a recipe is one line.
- EN phrases for the same dishes ("boiling pasta", "frying eggs", ...).

Memory admin (`memory_admin/`):
- memory_admin.count → speak fact count with full RU pluralisation.
- memory_admin.list → speak 5 most-recent + toast the rest.
- memory_admin.wipe → ONLY fires on "точно забудь все" prefix (not bare
  "забудь все") so we can't disaster-wipe by accident.
- Adds `long_term_memory::clear_all() -> usize` returning removed count
  + Lua binding `jarvis.memory.clear_all()`.
- One extra unit test for `clear_all`.

Tests: 139 → 140 (+1). Pack count: 92 → 95.
This commit is contained in:
Bossiara13 2026-05-16 14:39:55 +03:00
parent df799b6cd2
commit 8f46bd735a
11 changed files with 467 additions and 0 deletions

View file

@ -0,0 +1,66 @@
# Memory admin — voice-driven housekeeping for the long-term memory.
# - "сколько фактов помнишь" → speak count
# - "выгрузи список фактов" → notify with first ~10 keys
# - "забудь все" → wipe everything (with safety prefix "точно забудь все")
[[commands]]
id = "memory_admin.count"
type = "lua"
script = "count.lua"
sandbox = "minimal"
timeout = 2000
[commands.phrases]
ru = [
"сколько фактов помнишь",
"сколько ты помнишь",
"сколько у тебя в памяти",
"размер памяти",
]
en = [
"how many facts do you remember",
"how big is your memory",
"memory size",
]
[[commands]]
id = "memory_admin.list"
type = "lua"
script = "list.lua"
sandbox = "minimal"
timeout = 2000
[commands.phrases]
ru = [
"выгрузи список фактов",
"покажи что помнишь",
"перечисли что помнишь",
"что у тебя в памяти",
]
en = [
"list what you remember",
"show me your memory",
"what's in memory",
]
[[commands]]
id = "memory_admin.wipe"
type = "lua"
script = "wipe.lua"
sandbox = "minimal"
timeout = 2000
[commands.phrases]
ru = [
"точно забудь все",
"точно забудь всё",
"сотри всю память",
"wipe memory",
]
en = [
"wipe all memory",
"really forget everything",
"clear all memory",
]

View file

@ -0,0 +1,20 @@
local lang = jarvis.context.language
local facts = jarvis.memory.all() or {}
local n = #facts
local function ru_plural_facts(n)
local m100 = n % 100
if m100 >= 11 and m100 <= 14 then return "фактов" end
local m10 = n % 10
if m10 == 1 then return "факт" end
if m10 >= 2 and m10 <= 4 then return "факта" end
return "фактов"
end
local msg
if lang == "ru" then
msg = "В памяти " .. tostring(n) .. " " .. ru_plural_facts(n) .. ", сэр."
else
msg = "I remember " .. tostring(n) .. (n == 1 and " fact, sir." or " facts, sir.")
end
return jarvis.cmd.ok(msg)

View file

@ -0,0 +1,37 @@
-- Read out the first ~5 keys + value previews; the rest is just a count.
-- TTS doesn't handle long enumerations well, so we keep it short and notify
-- the full dump as a Windows toast for visual scan.
local lang = jarvis.context.language
local facts = jarvis.memory.all() or {}
if #facts == 0 then
return jarvis.cmd.not_found(lang == "ru"
and "Память пуста, сэр."
or "Memory is empty, sir.")
end
-- Sort by most-recently-used so the user hears what's actually fresh.
table.sort(facts, function(a, b) return (a.last_used_at or 0) > (b.last_used_at or 0) end)
local speak_lines = {}
local notify_lines = {}
for i, f in ipairs(facts) do
local v = (f.value or ""):sub(1, 60)
local line = f.key .. ": " .. v
table.insert(notify_lines, line)
if i <= 5 then
table.insert(speak_lines, f.key .. "" .. v)
end
end
jarvis.system.notify(
lang == "ru" and ("Память (" .. tostring(#facts) .. ")") or ("Memory (" .. tostring(#facts) .. ")"),
table.concat(notify_lines, "\n")
)
local preview = table.concat(speak_lines, ", ")
local extra = #facts > 5
and string.format(lang == "ru" and ". И ещё %d." or ". And %d more.", #facts - 5)
or "."
return jarvis.cmd.ok(preview .. extra)

View file

@ -0,0 +1,13 @@
-- Nuclear "forget everything" — guarded by the "точно" prefix in the toml
-- phrases so a stray "забудь" doesn't trigger it.
local lang = jarvis.context.language
local n = jarvis.memory.clear_all()
if n == 0 then
return jarvis.cmd.ok(lang == "ru" and "Память уже пуста, сэр."
or "Memory is already empty, sir.")
end
return jarvis.cmd.ok(string.format(lang == "ru"
and "Стёр %d записей. Память чиста."
or "Wiped %d records. Memory is clean.", n))