@iola_adm/iola-cli 0.1.60 → 0.1.62
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -0
- package/package.json +1 -1
- package/src/cli.js +162 -3
- package/wiki/Daemon-RPC-/320/270-cron.md +6 -0
- package/wiki//320/232/320/276/320/274/320/260/320/275/320/264/321/213.md +5 -0
- package/wiki//320/237/320/276/320/264/320/272/320/273/321/216/321/207/320/265/320/275/320/270/320/265-/320/223/320/276/321/201/321/203/321/201/320/273/321/203/320/263.md +34 -0
package/README.md
CHANGED
|
@@ -89,6 +89,8 @@ iola gosuslugi connect
|
|
|
89
89
|
iola gosuslugi whoami
|
|
90
90
|
iola gosuslugi debt
|
|
91
91
|
iola gosuslugi notifications --unread
|
|
92
|
+
iola gosuslugi keepalive
|
|
93
|
+
iola gosuslugi install-keepalive
|
|
92
94
|
```
|
|
93
95
|
|
|
94
96
|
Локальная модель через Ollama:
|
|
@@ -138,6 +140,7 @@ iola version --check
|
|
|
138
140
|
- браузерный runtime через Playwright: чтение страниц, скриншоты, PDF, клики, ввод и eval;
|
|
139
141
|
- личное локальное подключение Госуслуг через отдельный браузерный профиль на ПК пользователя;
|
|
140
142
|
- read-only tools Госуслуг для агента: ФИО, дата рождения, задолженности и уведомления;
|
|
143
|
+
- keepalive-проверка сессии Госуслуг каждые 30 минут через Windows Task Scheduler без висящего окна терминала;
|
|
141
144
|
- управляемые локальные файловые операции с режимами `locked`, `read-only`, `workspace-write`, `full-access`;
|
|
142
145
|
- планы выполнения, traces, tasks, artifacts, snapshots и policy-профили;
|
|
143
146
|
- экспорт отчетов в Excel/Word-совместимые файлы;
|
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -290,6 +290,7 @@ const SLASH_COMMANDS = [
|
|
|
290
290
|
{ command: "/gosuslugi connect", description: "открыть личный вход Госуслуг" },
|
|
291
291
|
{ command: "/gosuslugi debt", description: "задолженности Госуслуг" },
|
|
292
292
|
{ command: "/gosuslugi notifications", description: "уведомления Госуслуг" },
|
|
293
|
+
{ command: "/gosuslugi keepalive", description: "проверка сессии каждые 30 минут" },
|
|
293
294
|
{ command: "/wiki", description: "ссылки на документацию" },
|
|
294
295
|
{ command: "/context list", description: "локальный контекст проекта" },
|
|
295
296
|
{ command: "/skills list", description: "skills" },
|
|
@@ -523,7 +524,7 @@ Usage:
|
|
|
523
524
|
iola fork SESSION_ID [TEXT]
|
|
524
525
|
iola features list|enable|disable
|
|
525
526
|
iola settings list|get|validate|doctor|init
|
|
526
|
-
iola gosuslugi terms|consent|status|connect|open|text|screenshot|whoami|debt|notifications|mark-read|logout|configure|login|userinfo
|
|
527
|
+
iola gosuslugi terms|consent|status|check|keepalive|install-keepalive|keepalive-status|uninstall-keepalive|connect|open|text|screenshot|whoami|debt|notifications|mark-read|logout|configure|login|userinfo
|
|
527
528
|
iola wiki [open|links]
|
|
528
529
|
iola context list|show|init
|
|
529
530
|
iola skills list|show|paths|enable|disable|bundles|bundle|doctor
|
|
@@ -2286,6 +2287,33 @@ async function handleGosuslugi(args) {
|
|
|
2286
2287
|
return;
|
|
2287
2288
|
}
|
|
2288
2289
|
|
|
2290
|
+
if (action === "check") {
|
|
2291
|
+
const result = await gosuslugiCheck(options);
|
|
2292
|
+
if (options.json) printJson(result);
|
|
2293
|
+
else printKeyValue(result);
|
|
2294
|
+
return;
|
|
2295
|
+
}
|
|
2296
|
+
|
|
2297
|
+
if (action === "keepalive") {
|
|
2298
|
+
await gosuslugiKeepalive(options);
|
|
2299
|
+
return;
|
|
2300
|
+
}
|
|
2301
|
+
|
|
2302
|
+
if (action === "install-keepalive") {
|
|
2303
|
+
await installGosuslugiKeepaliveTask(options);
|
|
2304
|
+
return;
|
|
2305
|
+
}
|
|
2306
|
+
|
|
2307
|
+
if (action === "uninstall-keepalive") {
|
|
2308
|
+
await uninstallGosuslugiKeepaliveTask(options);
|
|
2309
|
+
return;
|
|
2310
|
+
}
|
|
2311
|
+
|
|
2312
|
+
if (action === "keepalive-status") {
|
|
2313
|
+
await printGosuslugiKeepaliveTaskStatus(options);
|
|
2314
|
+
return;
|
|
2315
|
+
}
|
|
2316
|
+
|
|
2289
2317
|
if (action === "connect") {
|
|
2290
2318
|
await gosuslugiBrowserConnect(options);
|
|
2291
2319
|
return;
|
|
@@ -2389,7 +2417,7 @@ async function handleGosuslugi(args) {
|
|
|
2389
2417
|
return;
|
|
2390
2418
|
}
|
|
2391
2419
|
|
|
2392
|
-
throw new Error("Команды gosuslugi: terms, consent, status, connect, open, text, screenshot, whoami, debt, notifications, mark-read, logout, configure, login, userinfo.");
|
|
2420
|
+
throw new Error("Команды gosuslugi: terms, consent, status, check, keepalive, install-keepalive, keepalive-status, uninstall-keepalive, connect, open, text, screenshot, whoami, debt, notifications, mark-read, logout, configure, login, userinfo.");
|
|
2393
2421
|
}
|
|
2394
2422
|
|
|
2395
2423
|
function targetOrDefault(args, options = {}) {
|
|
@@ -5775,6 +5803,10 @@ function isCronDue(job) {
|
|
|
5775
5803
|
if (normalized.includes("каждый час") || normalized.includes("hourly")) {
|
|
5776
5804
|
return !lastRun || now.getTime() - lastRun.getTime() >= 60 * 60 * 1000;
|
|
5777
5805
|
}
|
|
5806
|
+
const everyMinutes = normalized.match(/кажд(?:ые|ую)\s+(\d+)\s*(?:мин|минут)/u) || normalized.match(/every\s+(\d+)\s*(?:m|min|minutes)/u);
|
|
5807
|
+
if (everyMinutes) {
|
|
5808
|
+
return !lastRun || now.getTime() - lastRun.getTime() >= Number(everyMinutes[1]) * 60 * 1000;
|
|
5809
|
+
}
|
|
5778
5810
|
if (normalized.includes("каждый день") || normalized.includes("daily")) {
|
|
5779
5811
|
return !lastRun || now.toISOString().slice(0, 10) !== lastRun.toISOString().slice(0, 10);
|
|
5780
5812
|
}
|
|
@@ -7150,7 +7182,7 @@ function parseOptions(args) {
|
|
|
7150
7182
|
|
|
7151
7183
|
for (let index = 0; index < args.length; index += 1) {
|
|
7152
7184
|
const arg = args[index];
|
|
7153
|
-
if (arg === "--json" || arg === "--yes" || arg === "--silent" || arg === "--events" || arg === "--stream-json" || arg === "--stdio" || arg === "--system" || arg === "--headed" || arg === "--headless" || arg === "--no-history" || arg === "--summary" || arg === "--all" || arg === "--full" || arg === "--unread" || arg === "--local" || arg === "--cache" || arg === "--tools" || arg === "--files" || arg === "--plan" || arg === "--trace" || arg === "--diff" || arg === "--stage" || arg === "--fts" || arg === "--bare" || arg === "--quiet" || arg === "--no-color" || arg === "--fail-on-empty" || arg === "--debug" || arg === "--fix" || arg === "--append") {
|
|
7185
|
+
if (arg === "--json" || arg === "--yes" || arg === "--silent" || arg === "--events" || arg === "--stream-json" || arg === "--stdio" || arg === "--system" || arg === "--headed" || arg === "--headless" || arg === "--no-history" || arg === "--summary" || arg === "--all" || arg === "--full" || arg === "--unread" || arg === "--once" || arg === "--local" || arg === "--cache" || arg === "--tools" || arg === "--files" || arg === "--plan" || arg === "--trace" || arg === "--diff" || arg === "--stage" || arg === "--fts" || arg === "--bare" || arg === "--quiet" || arg === "--no-color" || arg === "--fail-on-empty" || arg === "--debug" || arg === "--fix" || arg === "--append") {
|
|
7154
7186
|
result[arg.slice(2)] = true;
|
|
7155
7187
|
} else if (arg === "--check" || arg === "--upgrade-node") {
|
|
7156
7188
|
result.check = true;
|
|
@@ -7799,6 +7831,133 @@ async function gosuslugiMarkNotificationsRead(options = {}) {
|
|
|
7799
7831
|
console.log("Команда отметки прочитанным выполнена. Проверьте статус: iola gosuslugi notifications --unread");
|
|
7800
7832
|
}
|
|
7801
7833
|
|
|
7834
|
+
async function gosuslugiCheck(options = {}) {
|
|
7835
|
+
try {
|
|
7836
|
+
const result = await gosuslugiWhoami({ wait: options.wait || 2000 });
|
|
7837
|
+
return {
|
|
7838
|
+
status: "ok",
|
|
7839
|
+
authorized: "yes",
|
|
7840
|
+
fio: result.summary.fio,
|
|
7841
|
+
checkedAt: new Date().toISOString(),
|
|
7842
|
+
nextAction: "-",
|
|
7843
|
+
};
|
|
7844
|
+
} catch (error) {
|
|
7845
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
7846
|
+
const result = {
|
|
7847
|
+
status: "needs-login",
|
|
7848
|
+
authorized: "unknown",
|
|
7849
|
+
checkedAt: new Date().toISOString(),
|
|
7850
|
+
nextAction: "iola gosuslugi connect",
|
|
7851
|
+
error: message,
|
|
7852
|
+
};
|
|
7853
|
+
if (!options.silent) {
|
|
7854
|
+
console.error("Сессия Госуслуг недоступна или требует повторный вход.");
|
|
7855
|
+
console.error("Запустите: iola gosuslugi connect");
|
|
7856
|
+
}
|
|
7857
|
+
return result;
|
|
7858
|
+
}
|
|
7859
|
+
}
|
|
7860
|
+
|
|
7861
|
+
async function gosuslugiKeepalive(options = {}) {
|
|
7862
|
+
const intervalMs = parseDurationMs(options.interval || "30m");
|
|
7863
|
+
const once = Boolean(options.once);
|
|
7864
|
+
console.log(`Gosuslugi keepalive запущен. Интервал: ${Math.round(intervalMs / 60000)} мин.`);
|
|
7865
|
+
console.log("Остановить: Ctrl+C");
|
|
7866
|
+
while (true) {
|
|
7867
|
+
const result = await gosuslugiCheck({ silent: true });
|
|
7868
|
+
const line = result.status === "ok"
|
|
7869
|
+
? `[${result.checkedAt}] Госуслуги: сессия активна (${result.fio || "-"})`
|
|
7870
|
+
: `[${result.checkedAt}] Госуслуги: нужен повторный вход. Запустите: iola gosuslugi connect`;
|
|
7871
|
+
console.log(line);
|
|
7872
|
+
if (once) return;
|
|
7873
|
+
await sleep(intervalMs);
|
|
7874
|
+
}
|
|
7875
|
+
}
|
|
7876
|
+
|
|
7877
|
+
function gosuslugiKeepaliveTaskName() {
|
|
7878
|
+
return "iola-gosuslugi-keepalive";
|
|
7879
|
+
}
|
|
7880
|
+
|
|
7881
|
+
function gosuslugiKeepaliveLogFile() {
|
|
7882
|
+
return path.join(CONFIG_DIR, "gosuslugi-keepalive.log");
|
|
7883
|
+
}
|
|
7884
|
+
|
|
7885
|
+
function cliEntrypointFile() {
|
|
7886
|
+
return path.resolve(__dirname, "..", "bin", "iola.js");
|
|
7887
|
+
}
|
|
7888
|
+
|
|
7889
|
+
async function installGosuslugiKeepaliveTask(options = {}) {
|
|
7890
|
+
const intervalMinutes = Math.max(1, Math.round(parseDurationMs(options.interval || "30m") / 60000));
|
|
7891
|
+
if (process.platform === "win32") {
|
|
7892
|
+
await installWindowsGosuslugiKeepaliveTask(intervalMinutes);
|
|
7893
|
+
return;
|
|
7894
|
+
}
|
|
7895
|
+
const id = addCronJob(`каждые ${intervalMinutes} минут`, "gosuslugi check --silent");
|
|
7896
|
+
console.log(`Локальная cron-задача добавлена: ${id}`);
|
|
7897
|
+
console.log("Для автоматического выполнения настройте системный планировщик на запуск: iola cron tick");
|
|
7898
|
+
}
|
|
7899
|
+
|
|
7900
|
+
async function installWindowsGosuslugiKeepaliveTask(intervalMinutes) {
|
|
7901
|
+
await mkdir(CONFIG_DIR, { recursive: true });
|
|
7902
|
+
const taskName = gosuslugiKeepaliveTaskName();
|
|
7903
|
+
const logFile = gosuslugiKeepaliveLogFile();
|
|
7904
|
+
const script = path.join(CONFIG_DIR, "gosuslugi-keepalive-task.cmd");
|
|
7905
|
+
const command = `"${process.execPath}" --no-warnings "${cliEntrypointFile()}" gosuslugi check --silent >> "${logFile}" 2>&1`;
|
|
7906
|
+
await writeFile(script, `@echo off\r\n${command}\r\n`, "utf8");
|
|
7907
|
+
await runCommand("schtasks.exe", [
|
|
7908
|
+
"/Create",
|
|
7909
|
+
"/TN", taskName,
|
|
7910
|
+
"/SC", "MINUTE",
|
|
7911
|
+
"/MO", String(intervalMinutes),
|
|
7912
|
+
"/TR", script,
|
|
7913
|
+
"/F",
|
|
7914
|
+
]);
|
|
7915
|
+
console.log(`Windows Task Scheduler задача создана: ${taskName}`);
|
|
7916
|
+
console.log(`Интервал: ${intervalMinutes} мин.`);
|
|
7917
|
+
console.log(`Лог: ${logFile}`);
|
|
7918
|
+
console.log("Проверить: iola gosuslugi keepalive-status");
|
|
7919
|
+
}
|
|
7920
|
+
|
|
7921
|
+
async function uninstallGosuslugiKeepaliveTask() {
|
|
7922
|
+
if (process.platform === "win32") {
|
|
7923
|
+
await runCommand("schtasks.exe", ["/Delete", "/TN", gosuslugiKeepaliveTaskName(), "/F"]).catch(() => {});
|
|
7924
|
+
console.log(`Windows Task Scheduler задача удалена: ${gosuslugiKeepaliveTaskName()}`);
|
|
7925
|
+
return;
|
|
7926
|
+
}
|
|
7927
|
+
console.log("Для не-Windows удалите локальную cron-задачу вручную: iola cron list, затем iola cron delete ID.");
|
|
7928
|
+
}
|
|
7929
|
+
|
|
7930
|
+
async function printGosuslugiKeepaliveTaskStatus(options = {}) {
|
|
7931
|
+
if (process.platform === "win32") {
|
|
7932
|
+
try {
|
|
7933
|
+
const { stdout } = await runCommand("schtasks.exe", ["/Query", "/TN", gosuslugiKeepaliveTaskName(), "/FO", "LIST"]);
|
|
7934
|
+
console.log(stdout.trim());
|
|
7935
|
+
} catch {
|
|
7936
|
+
console.log(`Задача не найдена: ${gosuslugiKeepaliveTaskName()}`);
|
|
7937
|
+
}
|
|
7938
|
+
if (existsSync(gosuslugiKeepaliveLogFile())) {
|
|
7939
|
+
console.log("");
|
|
7940
|
+
console.log(`Лог: ${gosuslugiKeepaliveLogFile()}`);
|
|
7941
|
+
}
|
|
7942
|
+
return;
|
|
7943
|
+
}
|
|
7944
|
+
const rows = listCronJobs().filter((job) => String(job.command).includes("gosuslugi check"));
|
|
7945
|
+
if (options.json) printJson(rows);
|
|
7946
|
+
else printTable(rows, [["id", "ID"], ["enabled", "Вкл"], ["schedule_text", "Расписание"], ["command", "Команда"], ["last_run_at", "Последний запуск"]]);
|
|
7947
|
+
}
|
|
7948
|
+
|
|
7949
|
+
function parseDurationMs(value) {
|
|
7950
|
+
const text = String(value || "30m").trim().toLocaleLowerCase("ru-RU");
|
|
7951
|
+
const match = text.match(/^(\d+(?:[.,]\d+)?)(ms|s|m|h|мин|минут|час|часа|часов)?$/u);
|
|
7952
|
+
if (!match) throw new Error("Интервал задается как 30m, 1800s или 1h.");
|
|
7953
|
+
const amount = Number(match[1].replace(",", "."));
|
|
7954
|
+
const unit = match[2] || "m";
|
|
7955
|
+
if (unit === "ms") return Math.max(1000, amount);
|
|
7956
|
+
if (unit === "s") return Math.max(1000, amount * 1000);
|
|
7957
|
+
if (unit === "h" || unit.startsWith("час")) return Math.max(1000, amount * 60 * 60 * 1000);
|
|
7958
|
+
return Math.max(1000, amount * 60 * 1000);
|
|
7959
|
+
}
|
|
7960
|
+
|
|
7802
7961
|
function printGosuslugiDebt(result) {
|
|
7803
7962
|
printKeyValue({
|
|
7804
7963
|
total: result.total,
|
|
@@ -34,3 +34,9 @@ iola cron delete 1
|
|
|
34
34
|
|
|
35
35
|
`cron tick` проверяет задачи, которые пора выполнить. Его можно запускать вручную, через Windows Task Scheduler или другой планировщик.
|
|
36
36
|
|
|
37
|
+
Для Госуслуг на Windows лучше использовать готовую системную задачу без висящего окна терминала:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
iola gosuslugi install-keepalive
|
|
41
|
+
iola gosuslugi keepalive-status
|
|
42
|
+
```
|
|
@@ -95,6 +95,11 @@ iola context list
|
|
|
95
95
|
iola settings list
|
|
96
96
|
iola settings validate
|
|
97
97
|
iola gosuslugi status
|
|
98
|
+
iola gosuslugi check
|
|
99
|
+
iola gosuslugi keepalive
|
|
100
|
+
iola gosuslugi install-keepalive
|
|
101
|
+
iola gosuslugi keepalive-status
|
|
102
|
+
iola gosuslugi uninstall-keepalive
|
|
98
103
|
iola gosuslugi terms
|
|
99
104
|
iola gosuslugi consent
|
|
100
105
|
iola gosuslugi connect
|
|
@@ -78,10 +78,44 @@ AI-агент может использовать read-only tools Госуслу
|
|
|
78
78
|
|
|
79
79
|
```bash
|
|
80
80
|
iola gosuslugi status
|
|
81
|
+
iola gosuslugi check
|
|
81
82
|
```
|
|
82
83
|
|
|
83
84
|
Команда показывает, принято ли согласие, где лежит локальный профиль и когда он был создан.
|
|
84
85
|
|
|
86
|
+
## Keepalive
|
|
87
|
+
|
|
88
|
+
Сессию Госуслуг нельзя сделать вечной: портал сам управляет сроком жизни входа и может попросить повторную двухфакторную аутентификацию. CLI может только мягко проверять сохраненный профиль.
|
|
89
|
+
|
|
90
|
+
Запуск проверки каждые 30 минут:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
iola gosuslugi keepalive
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Однократная проверка:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
iola gosuslugi keepalive --once
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Полностью автоматический режим через системный планировщик Windows:
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
iola gosuslugi install-keepalive
|
|
106
|
+
iola gosuslugi keepalive-status
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
На Windows создается задача Task Scheduler `iola-gosuslugi-keepalive`, которая каждые 30 минут выполняет `iola gosuslugi check --silent` без постоянно открытого окна терминала.
|
|
110
|
+
|
|
111
|
+
Удалить задачу:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
iola gosuslugi uninstall-keepalive
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Если сессия протухла, CLI запишет это в лог и при следующей ручной команде попросит выполнить `iola gosuslugi connect`.
|
|
118
|
+
|
|
85
119
|
## Отключение
|
|
86
120
|
|
|
87
121
|
Удалить локальное подключение:
|