J.A.R.V.I.S-rust/resources/commands/birthdays/add.lua
Bossiara13 05b75feee4
Some checks failed
Rust CI / cargo test (jarvis-core) (push) Has been cancelled
Rust CI / cargo clippy (push) Has been cancelled
Rust CI / cargo check (workspace) (push) Has been cancelled
feat: Wave 11 — birthdays tracker pack
resources/commands/birthdays/ (2 commands):
- birthdays.add  "запомни день рождения мама 15 марта" → memory key
  "birthday.мама" = "15.03". Accepts both DD.MM and "DD <month>"
  formats; recognises all 12 RU + 12 EN month names.
- birthdays.next "ближайший день рождения" → reads every "birthday.*"
  memory key, computes days-until each entry (with year wrap), speaks
  the nearest one in human form ("сегодня" / "завтра" / "через N дней").

Storage piggybacks on the existing long-term memory store, so
birthdays survive restart, sync to disk atomically, and don't need a
new persistence layer. Naming convention "birthday.<name>" keeps the
data discoverable in /memory GUI.

Pack count: 99 → 100 functional packs.
Tests: 140 rust, unchanged.
2026-05-16 14:59:50 +03:00

80 lines
2.8 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.

-- Voice "запомни день рождения мама 15 марта" → memory["birthday.мама"]="15.03"
-- We accept three date formats: "15.03", "15 марта", and "15 march".
local lang = jarvis.context.language
local raw = (jarvis.context.phrase or ""):lower()
local triggers = {
"запомни день рождения", "день рождения у", "добавь день рождения",
"запиши день рождения",
"remember birthday", "add birthday", "save birthday",
}
local rest = jarvis.text.strip_trigger(raw, triggers) or raw
rest = rest:gsub("^%s+", ""):gsub("%s+$", "")
-- Russian month names → "MM"
local months_ru = {
["января"]=1, ["январь"]=1,
["февраля"]=2, ["февраль"]=2,
["марта"]=3, ["март"]=3,
["апреля"]=4, ["апрель"]=4,
["мая"]=5, ["май"]=5,
["июня"]=6, ["июнь"]=6,
["июля"]=7, ["июль"]=7,
["августа"]=8, ["август"]=8,
["сентября"]=9, ["сентябрь"]=9,
["октября"]=10, ["октябрь"]=10,
["ноября"]=11, ["ноябрь"]=11,
["декабря"]=12, ["декабрь"]=12,
}
local months_en = {
january=1, february=2, march=3, april=4, may=5, june=6,
july=7, august=8, september=9, october=10, november=11, december=12,
}
-- Try patterns in order. Each pattern leaves `name` and `date` populated.
local name, date_str = nil, nil
-- 1. "<name> DD.MM"
local n, d, m = rest:match("^(.-)%s+(%d?%d)%.(%d?%d)")
if n and d and m then
name = n
date_str = string.format("%02d.%02d", tonumber(d), tonumber(m))
end
-- 2. "<name> DD <month_ru/en>"
if not name then
local n2, d2, mword = rest:match("^(.-)%s+(%d?%d)%s+(%S+)")
if n2 and d2 and mword then
local m_num = months_ru[mword] or months_en[mword]
if m_num then
name = n2
date_str = string.format("%02d.%02d", tonumber(d2), m_num)
end
end
end
if not name or not date_str then
return jarvis.cmd.not_found(lang == "ru"
and "Скажи в формате 'имя 15 марта' или 'имя 15.03'."
or "Say in the form 'name 15 march' or 'name 15.03'.")
end
name = name:gsub("^%s+", ""):gsub("%s+$", "")
if name == "" then
return jarvis.cmd.not_found(lang == "ru" and "Чьё именно?" or "Whose?")
end
-- Strip leading prepositions left from "у мамы" → "мамы"
name = name:gsub("^у%s+", ""):gsub("^of%s+", ""):gsub("^for%s+", "")
local ok, err = pcall(function()
jarvis.memory.remember("birthday." .. name, date_str)
end)
if not ok then
return jarvis.cmd.error(tostring(err))
end
return jarvis.cmd.ok(string.format(lang == "ru"
and "Запомнил: %s — %s."
or "Got it: %s — %s.", name, date_str))