feat: Wave 1 — 10 new packs (75 → 85 rust packs)
User picked from the fishki roadmap; this commit ships the 10 easy/medium
ones in one batch. No Rust core changes — all pure Lua + jarvis.* APIs.
Pack catalog
magic_8ball
- "ответь да или нет" / "магический шар" / "что скажешь"
- 15 канонических ответов, random pick. Pure fun.
github_issues (2 cmds)
- "какие issues" / "открытые issues" — gh issue list по сохранённому репо
- "мои issues" / "что мне назначено" — gh issue list --assignee @me
weather_extended (2 cmds, Open-Meteo, no key)
- "погода завтра" — temp min/max + conditions + rain note
- "прогноз на неделю" — общий диапазон температур
- Auto-detects location via ipinfo.io if not in memory; stores lat/lon/city.
rss_reader (3 cmds)
- "добавь rss <url>" — extracts URL, persists via memory под ключом "rss.<domain>"
- "что в ленте" — fetches first feed, parses <title> tags, speaks top 3
- "какие у меня rss" — lists subscribed feed domains
ics_event
- "добавь встречу завтра в 15:00 обсудить проект"
- Parses time (HH:MM или "в HH") + date keywords (сегодня/завтра/послезавтра)
- Writes valid iCalendar v2.0 file to ~/Documents/jarvis-events/
- jarvis.system.open → дефолтный handler (Outlook/Mail/whatever)
backup
- "сделай бекап" — PowerShell Compress-Archive всех state files из APPDATA/Jarvis
- Outputs to ~/Documents/jarvis-backup-<YYYYMMDD-HHMMSS>.zip
- Bundles: long_term_memory, schedule, macros, profiles/, active_profile, llm_backend, settings
clip_history (3 cmds, 20-slot rolling buffer)
- "запиши буфер" — push current clipboard onto memory keys clip.0..clip.19
- "что я копировал" — speak preview of last 3
- "верни первый/второй/третий буфер" — restore clip.N to clipboard
notif_queue (2 cmds)
- "что я пропустил" — enumerate memory keys "notif.*", speak last 5 by recency
- "очисти уведомления" — purge all notif.* keys
- Producers (scheduler/macros/llm) can later push to memory[notif.<ts>] = text
password_vault (3 cmds, Windows DPAPI)
- "сохрани пароль от GitHub" — encrypts current clipboard content via DPAPI
(CurrentUser scope), base64-stored in memory[vault.GitHub]. Clears clipboard.
Password is NEVER spoken or written to disk in plaintext.
- "пароль от GitHub" — decrypts via DPAPI, restores to clipboard for 30 sec,
schedules auto-clear via jarvis.scheduler. Speaks only "Пароль от X в буфере."
- "какие у меня пароли" — list of stored service names.
habit_streaks (2 cmds, integrates with habit_nudge)
- "сколько дней подряд" / "статистика привычек" — reads memory keys
"habit_streak.<habit>.<YYYY-MM-DD>", computes consecutive-day streak per habit.
- "я попил воды" / "отметь привычку" — marks today's check-in.
Maps voice to habit: воды→water, размял/зарядк→stretch, глаз→eyes.
Tests: 6 commands tests pass (auto-validate the 10 new packs).
This commit is contained in:
parent
4d3d664abd
commit
c4b22618f8
30 changed files with 1086 additions and 0 deletions
24
resources/commands/habit_streaks/checkin.lua
Normal file
24
resources/commands/habit_streaks/checkin.lua
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
-- Mark a habit done today.
|
||||
local phrase = (jarvis.context.phrase or ""):lower()
|
||||
|
||||
local habit = nil
|
||||
if phrase:find("воды") or phrase:find("воду") then habit = "water"
|
||||
elseif phrase:find("размял") or phrase:find("зарядк") then habit = "stretch"
|
||||
elseif phrase:find("глаз") then habit = "eyes"
|
||||
end
|
||||
|
||||
-- Fallback: pick first word after "выполнил"/"отметь"
|
||||
if not habit then
|
||||
habit = jarvis.text.strip_trigger(phrase, {
|
||||
"отметь привычку", "выполнил привычку", "выполнил", "отметь",
|
||||
"check in habit",
|
||||
}):gsub("^[%s,:%.]+", ""):gsub("%s+$", "")
|
||||
if habit == "" then habit = "general" end
|
||||
end
|
||||
|
||||
local t = jarvis.context.time
|
||||
local date_str = string.format("%04d-%02d-%02d", t.year, t.month, t.day)
|
||||
local key = "habit_streak." .. habit .. "." .. date_str
|
||||
|
||||
jarvis.memory.remember(key, "1")
|
||||
return jarvis.cmd.ok("Отметил " .. habit .. " за сегодня.")
|
||||
41
resources/commands/habit_streaks/command.toml
Normal file
41
resources/commands/habit_streaks/command.toml
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
# Habit streaks — track when habit_nudge tasks actually fire, view stats.
|
||||
# Producers (habit_nudge schedule firings) should call jarvis.memory.remember
|
||||
# "habit_streak.<habit>.<YYYY-MM-DD>" = "1" on each firing.
|
||||
|
||||
[[commands]]
|
||||
id = "habits.streak"
|
||||
type = "lua"
|
||||
script = "streak.lua"
|
||||
sandbox = "minimal"
|
||||
timeout = 3000
|
||||
|
||||
[commands.phrases]
|
||||
ru = [
|
||||
"сколько дней подряд",
|
||||
"мои привычки",
|
||||
"статистика привычек",
|
||||
"статистика по привычкам",
|
||||
"сколько дней пью воду",
|
||||
"трекинг привычек",
|
||||
]
|
||||
en = ["habit streaks", "my habits stats"]
|
||||
ua = ["моя статистика звичок"]
|
||||
|
||||
|
||||
[[commands]]
|
||||
id = "habits.checkin"
|
||||
type = "lua"
|
||||
script = "checkin.lua"
|
||||
sandbox = "standard"
|
||||
timeout = 3000
|
||||
|
||||
[commands.phrases]
|
||||
ru = [
|
||||
"отметь привычку",
|
||||
"выполнил привычку",
|
||||
"я попил воды",
|
||||
"я размялся",
|
||||
"я отдохнул глазам",
|
||||
]
|
||||
en = ["check in habit", "I did the habit"]
|
||||
ua = ["я виконав звичку"]
|
||||
66
resources/commands/habit_streaks/streak.lua
Normal file
66
resources/commands/habit_streaks/streak.lua
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
-- Reads memory keys "habit_streak.<habit>.<YYYY-MM-DD>" and computes streak per habit.
|
||||
local t = jarvis.context.time
|
||||
|
||||
local function date_offset(days_back)
|
||||
-- Simple naive backwards calc (no calendar arithmetic — close enough for streaks)
|
||||
local jd_today = t.year * 365 + math.floor(t.year / 4)
|
||||
+ ({0,31,59,90,120,151,181,212,243,273,304,334})[t.month]
|
||||
+ (t.day - 1)
|
||||
local target_jd = jd_today - days_back
|
||||
-- Convert back to YYYY-MM-DD (approximate)
|
||||
local y = math.floor(target_jd / 365.25)
|
||||
local doy = target_jd - math.floor(y * 365.25)
|
||||
local month_starts = {0,31,59,90,120,151,181,212,243,273,304,334}
|
||||
local mo = 12
|
||||
for i = 12, 1, -1 do
|
||||
if doy >= month_starts[i] then mo = i; doy = doy - month_starts[i]; break end
|
||||
end
|
||||
return string.format("%04d-%02d-%02d", y, mo, doy + 1)
|
||||
end
|
||||
|
||||
local all = jarvis.memory.all()
|
||||
|
||||
-- Group keys by habit name
|
||||
local by_habit = {}
|
||||
for _, rec in ipairs(all) do
|
||||
local habit, date = rec.key:match("^habit_streak%.([^%.]+)%.(.+)$")
|
||||
if habit and date then
|
||||
by_habit[habit] = by_habit[habit] or {}
|
||||
by_habit[habit][date] = true
|
||||
end
|
||||
end
|
||||
|
||||
if next(by_habit) == nil then
|
||||
return jarvis.cmd.not_found("Привычек ещё не отмечено. Скажи 'выполнил привычку' после события.")
|
||||
end
|
||||
|
||||
-- For each habit, count consecutive days back from today
|
||||
local results = {}
|
||||
for habit, dates in pairs(by_habit) do
|
||||
local streak = 0
|
||||
for d = 0, 30 do
|
||||
local key_date = date_offset(d)
|
||||
if dates[key_date] then
|
||||
streak = streak + 1
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
table.insert(results, { habit = habit, streak = streak })
|
||||
end
|
||||
|
||||
table.sort(results, function(a, b) return a.streak > b.streak end)
|
||||
|
||||
local sample = math.min(#results, 3)
|
||||
local lines = {}
|
||||
for i = 1, sample do
|
||||
local r = results[i]
|
||||
if r.streak == 0 then
|
||||
table.insert(lines, r.habit .. " прервана")
|
||||
else
|
||||
local d = r.streak == 1 and "день" or (r.streak < 5 and "дня" or "дней")
|
||||
table.insert(lines, r.habit .. " " .. r.streak .. " " .. d)
|
||||
end
|
||||
end
|
||||
|
||||
return jarvis.cmd.ok("Стрики: " .. table.concat(lines, ", ") .. ".")
|
||||
Loading…
Add table
Add a link
Reference in a new issue