J.A.R.V.I.S-rust/resources/commands/file_search/search.lua
Bossiara13 54dcf7e564 feat(commands): add PC control packs — volume, apps, file_search, output_device
All four packs are pure Lua (sandbox=full) and call out to PowerShell helpers
where COM / native APIs are needed. No new Rust code, no rebuild required:
post_build.py --sync copies them under target/{debug,release}/resources/.

volume/
  - volume_up / volume_down: 5x VK_VOLUME_UP|DOWN via keybd_event
  - volume_mute: VK_VOLUME_MUTE
  - volume_max: 50x VK_VOLUME_UP (system clamps)
  Helper _volume_helper.ps1 P/Invokes user32!keybd_event.

apps/
  - open_browser  : start "" https://www.google.com (uses system default browser)
  - open_notepad  : notepad.exe
  - open_calculator: calc.exe
  - open_explorer : explorer.exe
  - open_terminal : wt.exe, falls back to powershell.exe
  - open_settings : ms-settings: protocol
  - open_task_manager: taskmgr.exe
  - lock_screen   : rundll32 user32.dll,LockWorkStation
  - screenshot    : System.Drawing capture to ~/Pictures/jarvis_screenshot_*.png

file_search/
  - find file <query> : recursive Get-ChildItem in Desktop/Documents/Downloads
    (depth 3, top 5 matches). Strips Russian/English/Ukrainian trigger
    prefixes from the recognized phrase, then opens explorer /select on the
    first hit and notifies with the total count.

output_device/
  - list_output_devices : enumerates active render endpoints via
    IMMDeviceEnumerator and notifies friendly names with indices
  - next_output_device  : cycles the system default render device via the
    undocumented IPolicyConfig::SetDefaultEndpoint (eConsole/Multimedia/
    Communications). Tested locally — listed 7 devices, current correctly
    identified at index 5.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 00:54:52 +03:00

78 lines
2.6 KiB
Lua
Raw 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.

local lang = jarvis.context.language
local phrase = (jarvis.context.phrase or ""):lower()
local triggers = {
"найди документ", "найди файл", "поиск файла", "ищи файл", "где файл",
"find file", "search file", "where is file", "locate file",
"знайди файл", "пошук файлу", "де файл",
}
local query = phrase
for _, t in ipairs(triggers) do
local start, finish = string.find(query, t, 1, true)
if start == 1 then
query = query:sub(finish + 1)
break
end
end
query = query:gsub("^%s+", ""):gsub("%s+$", "")
if query == "" then
jarvis.log("warn", "file_search: empty query (phrase=" .. phrase .. ")")
jarvis.system.notify(
lang == "ru" and "Поиск файлов" or "File search",
lang == "ru" and "Что искать?" or "What to search for?"
)
jarvis.audio.play_error()
return { chain = false }
end
local userprofile = jarvis.system.env("USERPROFILE") or "C:\\Users\\Public"
local roots = {
userprofile .. "\\Desktop",
userprofile .. "\\Documents",
userprofile .. "\\Downloads",
}
local escaped = query:gsub("'", "''")
local roots_arg = "'" .. table.concat(roots, "','") .. "'"
local ps = string.format(
[[$ErrorActionPreference='SilentlyContinue'; $r=@(%s); $q='*%s*'; $hits=Get-ChildItem -Path $r -Filter $q -Recurse -Depth 3 -File | Select-Object -First 5; foreach($h in $hits){ Write-Output $h.FullName }]],
roots_arg, escaped
)
local cmd = string.format('powershell -NoProfile -ExecutionPolicy Bypass -Command "%s"', ps:gsub('"', '\\"'))
jarvis.log("info", "file_search query='" .. query .. "'")
local res = jarvis.system.exec(cmd)
if not res.success then
jarvis.log("error", "file_search exec failed: " .. tostring(res.stderr))
jarvis.audio.play_error()
return { chain = false }
end
local stdout = res.stdout or ""
local lines = {}
for line in stdout:gmatch("[^\r\n]+") do
if line ~= "" then table.insert(lines, line) end
end
if #lines == 0 then
jarvis.system.notify(
lang == "ru" and "Поиск файлов" or "File search",
(lang == "ru" and "Не найдено: " or "Not found: ") .. query
)
jarvis.audio.play_not_found()
else
local first = lines[1]
local count = #lines
local title = lang == "ru" and "Найдено файлов: " or "Files found: "
jarvis.system.notify(title .. count, first)
jarvis.log("info", "file_search opening: " .. first)
jarvis.system.exec(string.format('explorer.exe /select,"%s"', first))
jarvis.audio.play_ok()
end
return { chain = false }