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.
55 lines
1.6 KiB
Lua
55 lines
1.6 KiB
Lua
-- Read all "birthday.*" memory keys, find the next upcoming date.
|
|
|
|
local lang = jarvis.context.language
|
|
local now = jarvis.context.time
|
|
|
|
local entries = {}
|
|
for _, f in ipairs(jarvis.memory.all() or {}) do
|
|
if f.key and f.key:sub(1, 9) == "birthday." then
|
|
local d, m = f.value:match("^(%d?%d)%.(%d?%d)")
|
|
if d and m then
|
|
table.insert(entries, {
|
|
name = f.key:sub(10),
|
|
day = tonumber(d),
|
|
month = tonumber(m),
|
|
})
|
|
end
|
|
end
|
|
end
|
|
|
|
if #entries == 0 then
|
|
return jarvis.cmd.not_found(lang == "ru"
|
|
and "Дней рождения в памяти нет, сэр."
|
|
or "No birthdays stored, sir.")
|
|
end
|
|
|
|
-- Compute "days until" for each. Wrap to next year if month/day already passed.
|
|
local function days_until(e)
|
|
local today_idx = now.month * 31 + now.day
|
|
local their_idx = e.month * 31 + e.day
|
|
local delta = their_idx - today_idx
|
|
if delta < 0 then
|
|
delta = delta + 12 * 31 -- approximate "wrap to next year"
|
|
end
|
|
return delta
|
|
end
|
|
|
|
for _, e in ipairs(entries) do
|
|
e.delta = days_until(e)
|
|
end
|
|
table.sort(entries, function(a, b) return a.delta < b.delta end)
|
|
|
|
local nxt = entries[1]
|
|
local human
|
|
if nxt.delta == 0 then
|
|
human = lang == "ru" and "сегодня" or "today"
|
|
elseif nxt.delta == 1 then
|
|
human = lang == "ru" and "завтра" or "tomorrow"
|
|
else
|
|
human = string.format(lang == "ru" and "через %d дней" or "in %d days", nxt.delta)
|
|
end
|
|
|
|
return jarvis.cmd.ok(string.format(lang == "ru"
|
|
and "Ближайший — %s, %s (%02d.%02d)."
|
|
or "Next: %s, %s (%02d.%02d).",
|
|
nxt.name, human, nxt.day, nxt.month))
|