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).
67 lines
2.2 KiB
Lua
67 lines
2.2 KiB
Lua
-- "Пароль от GitHub" — decrypts via DPAPI, copies to clipboard for 30 seconds,
|
||
-- speaks ONLY the service name (never the password).
|
||
local phrase = (jarvis.context.phrase or ""):lower()
|
||
local name = jarvis.text.strip_trigger(phrase, {
|
||
"покажи пароль от",
|
||
"достань пароль от",
|
||
"пароль от",
|
||
"дай пароль",
|
||
"password for",
|
||
"get password",
|
||
"пароль від",
|
||
})
|
||
name = name:gsub("^[%s,:%.]+", ""):gsub("%s+$", "")
|
||
|
||
if name == "" then
|
||
return jarvis.cmd.error("От чего пароль?")
|
||
end
|
||
|
||
local b64 = jarvis.memory.recall("vault." .. name)
|
||
if not b64 or b64 == "" then
|
||
return jarvis.cmd.not_found("Пароля для " .. name .. " нет.")
|
||
end
|
||
|
||
local ps = string.format([[
|
||
Add-Type -AssemblyName System.Security;
|
||
$bytes = [Convert]::FromBase64String('%s');
|
||
try {
|
||
$dec = [System.Security.Cryptography.ProtectedData]::Unprotect($bytes, $null, [System.Security.Cryptography.DataProtectionScope]::CurrentUser);
|
||
$text = [System.Text.Encoding]::UTF8.GetString($dec);
|
||
Set-Clipboard -Value $text;
|
||
Write-Output 'OK'
|
||
} catch {
|
||
Write-Output 'ERR'
|
||
}
|
||
]], b64)
|
||
|
||
local res = jarvis.system.exec(string.format(
|
||
'powershell -NoProfile -Command "%s"', ps:gsub('"', '\\"'):gsub("\r?\n", "; ")
|
||
))
|
||
local out = res and (res.stdout or ""):gsub("%s+", "") or ""
|
||
if out ~= "OK" then
|
||
return jarvis.cmd.error("Не получилось расшифровать.")
|
||
end
|
||
|
||
-- Schedule clipboard clear in 30 seconds via the scheduler.
|
||
local cmd_path = jarvis.context.command_path
|
||
local clear_script = cmd_path .. "\\_clear_clip.lua"
|
||
clear_script = clear_script:gsub("/", "\\")
|
||
|
||
if not jarvis.fs.is_file(clear_script) then
|
||
jarvis.fs.write(clear_script, [[
|
||
jarvis.system.clipboard.set("")
|
||
return { chain = false }
|
||
]])
|
||
end
|
||
|
||
local ok, _ = pcall(function()
|
||
jarvis.scheduler.remove("vault_clip_clear")
|
||
jarvis.scheduler.add({
|
||
id = "vault_clip_clear",
|
||
name = "Clear clipboard after vault paste",
|
||
schedule = "in 30 seconds",
|
||
action = { type = "lua", script_path = clear_script },
|
||
})
|
||
end)
|
||
|
||
return jarvis.cmd.ok("Пароль от " .. name .. " в буфере на 30 секунд.")
|