@iola_adm/iola-cli 0.1.32 → 0.1.33
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 +1 -1
- package/package.json +1 -1
- package/src/cli.js +63 -6
- package/wiki//320/232/320/276/320/274/320/260/320/275/320/264/321/213.md +2 -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 +40 -12
package/README.md
CHANGED
|
@@ -121,7 +121,7 @@ iola version --check
|
|
|
121
121
|
- subagents, skill bundles, layered settings, usage/budget accounting и trajectory export;
|
|
122
122
|
- полноценный локальный MCP server по stdio/http: tools, resources и prompts;
|
|
123
123
|
- браузерный runtime через Playwright: чтение страниц, скриншоты, PDF, клики, ввод и eval;
|
|
124
|
-
-
|
|
124
|
+
- личное локальное подключение Госуслуг с явным согласием пользователя и хранением доступа только на его ПК;
|
|
125
125
|
- управляемые локальные файловые операции с режимами `locked`, `read-only`, `workspace-write`, `full-access`;
|
|
126
126
|
- планы выполнения, traces, tasks, artifacts, snapshots и policy-профили;
|
|
127
127
|
- экспорт отчетов в Excel/Word-совместимые файлы;
|
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -31,6 +31,20 @@ const FILE_TOOLS = ["files_tree", "files_read", "files_search", "files_write", "
|
|
|
31
31
|
const ALL_LOCAL_TOOLS = [...LOCAL_TOOLS, ...FILE_TOOLS];
|
|
32
32
|
const HOOK_EVENTS = ["SessionStart", "BeforeTool", "AfterTool", "PreToolUse", "PostToolUse", "OnError", "AfterSync", "BeforeExport", "SessionEnd"];
|
|
33
33
|
const DAEMON_PORT = Number(process.env.IOLA_DAEMON_PORT || 18790);
|
|
34
|
+
const GOSUSLUGI_CONSENT_VERSION = "2026-05-26-personal-local-v1";
|
|
35
|
+
const GOSUSLUGI_CONSENT_TEXT = `Подключение личных Госуслуг
|
|
36
|
+
|
|
37
|
+
Вы подключаете личную учетную запись Госуслуг к локальному CLI-агенту iola-cli на этом компьютере.
|
|
38
|
+
|
|
39
|
+
Нажимая "Да", вы подтверждаете, что:
|
|
40
|
+
- используете собственную учетную запись Госуслуг;
|
|
41
|
+
- понимаете, что все действия, выполненные через CLI-агента после подключения, считаются действиями владельца этой учетной записи;
|
|
42
|
+
- разрешаете iola-cli локально сохранить данные доступа, необходимые для повторного входа или выполнения запросов от вашего имени;
|
|
43
|
+
- понимаете, что данные доступа хранятся только на этом компьютере в локальном хранилище пользователя и не передаются разработчикам CLI, администрации города или третьим лицам;
|
|
44
|
+
- обязуетесь не подключать чужие учетные записи и не передавать локальные файлы доступа другим лицам;
|
|
45
|
+
- понимаете, что перед юридически значимыми действиями, отправкой заявлений, оплатой, подписанием или изменением персональных данных CLI должен запросить отдельное подтверждение.
|
|
46
|
+
|
|
47
|
+
Продолжить подключение?`;
|
|
34
48
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
35
49
|
const BUILTIN_SKILLS_DIR = path.resolve(__dirname, "..", "skills");
|
|
36
50
|
const USER_SKILLS_DIR = path.join(CONFIG_DIR, "skills");
|
|
@@ -112,6 +126,7 @@ const DEFAULT_AI_CONFIG = {
|
|
|
112
126
|
},
|
|
113
127
|
gosuslugi: {
|
|
114
128
|
enabled: false,
|
|
129
|
+
mode: "personal-local",
|
|
115
130
|
authUrl: "",
|
|
116
131
|
tokenUrl: "",
|
|
117
132
|
userinfoUrl: "",
|
|
@@ -402,7 +417,7 @@ Usage:
|
|
|
402
417
|
iola fork SESSION_ID [TEXT]
|
|
403
418
|
iola features list|enable|disable
|
|
404
419
|
iola settings list|get|validate|doctor|init
|
|
405
|
-
iola gosuslugi configure|status|login|logout|userinfo
|
|
420
|
+
iola gosuslugi terms|consent|configure|status|login|logout|userinfo
|
|
406
421
|
iola wiki [open|links]
|
|
407
422
|
iola context list|show|init
|
|
408
423
|
iola skills list|show|paths|enable|disable|bundles|bundle|doctor
|
|
@@ -1726,13 +1741,27 @@ async function handleGosuslugi(args) {
|
|
|
1726
1741
|
const [action = "status", ...rest] = args;
|
|
1727
1742
|
const options = parseOptions(rest);
|
|
1728
1743
|
|
|
1744
|
+
if (action === "terms") {
|
|
1745
|
+
console.log(GOSUSLUGI_CONSENT_TEXT);
|
|
1746
|
+
return;
|
|
1747
|
+
}
|
|
1748
|
+
|
|
1749
|
+
if (action === "consent") {
|
|
1750
|
+
await acceptGosuslugiConsent(options);
|
|
1751
|
+
return;
|
|
1752
|
+
}
|
|
1753
|
+
|
|
1729
1754
|
if (action === "status") {
|
|
1730
1755
|
const config = await loadConfig();
|
|
1731
1756
|
const secrets = await loadSecrets();
|
|
1732
1757
|
const tokens = secrets.gosuslugi?.tokens || null;
|
|
1758
|
+
const consent = secrets.gosuslugiConsent || null;
|
|
1733
1759
|
printKeyValue({
|
|
1760
|
+
mode: config.gosuslugi?.mode || "personal-local",
|
|
1734
1761
|
enabled: config.gosuslugi?.enabled ? "yes" : "no",
|
|
1735
1762
|
configured: isGosuslugiConfigured(config) ? "yes" : "no",
|
|
1763
|
+
consent: consent?.version === GOSUSLUGI_CONSENT_VERSION ? "accepted" : "not accepted",
|
|
1764
|
+
consentAt: consent?.acceptedAt || "-",
|
|
1736
1765
|
clientId: config.gosuslugi?.clientId ? maskSecret(config.gosuslugi.clientId) : "-",
|
|
1737
1766
|
authUrl: config.gosuslugi?.authUrl || "-",
|
|
1738
1767
|
tokenUrl: config.gosuslugi?.tokenUrl || "-",
|
|
@@ -1750,6 +1779,7 @@ async function handleGosuslugi(args) {
|
|
|
1750
1779
|
const next = {
|
|
1751
1780
|
...(current.gosuslugi || {}),
|
|
1752
1781
|
enabled: true,
|
|
1782
|
+
mode: "personal-local",
|
|
1753
1783
|
authUrl: options["auth-url"] || current.gosuslugi?.authUrl || "",
|
|
1754
1784
|
tokenUrl: options["token-url"] || current.gosuslugi?.tokenUrl || "",
|
|
1755
1785
|
userinfoUrl: options["userinfo-url"] || current.gosuslugi?.userinfoUrl || "",
|
|
@@ -1761,7 +1791,7 @@ async function handleGosuslugi(args) {
|
|
|
1761
1791
|
redirectPath: options["redirect-path"] || current.gosuslugi?.redirectPath || "/gosuslugi/callback",
|
|
1762
1792
|
};
|
|
1763
1793
|
await saveConfig({ gosuslugi: next });
|
|
1764
|
-
console.log("Настройки подключения
|
|
1794
|
+
console.log("Настройки личного локального подключения Госуслуг сохранены.");
|
|
1765
1795
|
console.log(`Redirect URI: ${gosuslugiRedirectUri({ gosuslugi: next })}`);
|
|
1766
1796
|
return;
|
|
1767
1797
|
}
|
|
@@ -1787,7 +1817,7 @@ async function handleGosuslugi(args) {
|
|
|
1787
1817
|
return;
|
|
1788
1818
|
}
|
|
1789
1819
|
|
|
1790
|
-
throw new Error("Команды gosuslugi: configure, status, login, logout, userinfo.");
|
|
1820
|
+
throw new Error("Команды gosuslugi: terms, consent, configure, status, login, logout, userinfo.");
|
|
1791
1821
|
}
|
|
1792
1822
|
|
|
1793
1823
|
async function handleWiki(args) {
|
|
@@ -2734,8 +2764,9 @@ async function openUrl(url) {
|
|
|
2734
2764
|
async function gosuslugiLogin(options = {}) {
|
|
2735
2765
|
const config = await loadConfig();
|
|
2736
2766
|
if (!isGosuslugiConfigured(config)) {
|
|
2737
|
-
throw new Error("
|
|
2767
|
+
throw new Error("Личное подключение не настроено. Пример: iola gosuslugi configure --auth-url URL --token-url URL --client-id ID --scope openid");
|
|
2738
2768
|
}
|
|
2769
|
+
await ensureGosuslugiConsent(options);
|
|
2739
2770
|
|
|
2740
2771
|
const state = randomUrlSafe(24);
|
|
2741
2772
|
const codeVerifier = randomUrlSafe(64);
|
|
@@ -2751,8 +2782,8 @@ async function gosuslugiLogin(options = {}) {
|
|
|
2751
2782
|
authUrl.searchParams.set("code_challenge", codeChallenge);
|
|
2752
2783
|
authUrl.searchParams.set("code_challenge_method", "S256");
|
|
2753
2784
|
|
|
2754
|
-
console.log("Открываю
|
|
2755
|
-
console.log("После входа CLI примет callback на локальном адресе и сохранит
|
|
2785
|
+
console.log("Открываю экран входа Госуслуг в браузере для личного локального подключения.");
|
|
2786
|
+
console.log("После входа CLI примет callback на локальном адресе и сохранит данные доступа только на этом компьютере.");
|
|
2756
2787
|
await openUrl(authUrl.toString());
|
|
2757
2788
|
const params = await callback;
|
|
2758
2789
|
if (params.error) throw new Error(`Госуслуги вернули ошибку: ${params.error} ${params.error_description || ""}`.trim());
|
|
@@ -2781,6 +2812,31 @@ async function gosuslugiLogin(options = {}) {
|
|
|
2781
2812
|
};
|
|
2782
2813
|
}
|
|
2783
2814
|
|
|
2815
|
+
async function acceptGosuslugiConsent(options = {}) {
|
|
2816
|
+
console.log(GOSUSLUGI_CONSENT_TEXT);
|
|
2817
|
+
if (!options.yes) {
|
|
2818
|
+
const accepted = await confirm("Да, подключить личные Госуслуги к локальному iola-cli? [y/N] ");
|
|
2819
|
+
if (!accepted) {
|
|
2820
|
+
throw new Error("Подключение Госуслуг отменено пользователем.");
|
|
2821
|
+
}
|
|
2822
|
+
}
|
|
2823
|
+
const secrets = await loadSecrets();
|
|
2824
|
+
secrets.gosuslugiConsent = {
|
|
2825
|
+
version: GOSUSLUGI_CONSENT_VERSION,
|
|
2826
|
+
acceptedAt: new Date().toISOString(),
|
|
2827
|
+
user: os.userInfo().username,
|
|
2828
|
+
host: os.hostname(),
|
|
2829
|
+
};
|
|
2830
|
+
await saveSecrets(secrets);
|
|
2831
|
+
console.log("Согласие сохранено локально.");
|
|
2832
|
+
}
|
|
2833
|
+
|
|
2834
|
+
async function ensureGosuslugiConsent(options = {}) {
|
|
2835
|
+
const secrets = await loadSecrets();
|
|
2836
|
+
if (secrets.gosuslugiConsent?.version === GOSUSLUGI_CONSENT_VERSION) return;
|
|
2837
|
+
await acceptGosuslugiConsent(options);
|
|
2838
|
+
}
|
|
2839
|
+
|
|
2784
2840
|
function waitForOAuthCallback(settings, expectedState, timeoutMs) {
|
|
2785
2841
|
const host = settings.redirectHost || "127.0.0.1";
|
|
2786
2842
|
const port = Number(settings.redirectPort || 18791);
|
|
@@ -2826,6 +2882,7 @@ async function exchangeGosuslugiCode(config, { code, codeVerifier, redirectUri }
|
|
|
2826
2882
|
body.set("redirect_uri", redirectUri);
|
|
2827
2883
|
body.set("client_id", config.gosuslugi.clientId);
|
|
2828
2884
|
body.set("code_verifier", codeVerifier);
|
|
2885
|
+
body.set("client_mode", config.gosuslugi.mode || "personal-local");
|
|
2829
2886
|
if (config.gosuslugi.clientSecret) body.set("client_secret", config.gosuslugi.clientSecret);
|
|
2830
2887
|
|
|
2831
2888
|
const response = await fetch(config.gosuslugi.tokenUrl, {
|
|
@@ -93,6 +93,8 @@ iola context list
|
|
|
93
93
|
iola settings list
|
|
94
94
|
iola settings validate
|
|
95
95
|
iola gosuslugi status
|
|
96
|
+
iola gosuslugi terms
|
|
97
|
+
iola gosuslugi consent
|
|
96
98
|
iola gosuslugi configure --auth-url URL --token-url URL --client-id ID --scope openid
|
|
97
99
|
iola gosuslugi login
|
|
98
100
|
iola gosuslugi userinfo --json
|
|
@@ -1,19 +1,47 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Личное подключение Госуслуг
|
|
2
2
|
|
|
3
|
-
`iola-cli` поддерживает
|
|
3
|
+
`iola-cli` поддерживает локальное подключение личной учетной записи Госуслуг на компьютере пользователя.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Сценарий рассчитан именно на пользователя, который ставит CLI на свой ПК и подключает свою учетную запись. Ключи организации или администрации в публичный пакет не вшиваются.
|
|
6
|
+
|
|
7
|
+
## Согласие пользователя
|
|
8
|
+
|
|
9
|
+
Перед входом CLI показывает текст согласия:
|
|
10
|
+
|
|
11
|
+
```text
|
|
12
|
+
Вы подключаете личную учетную запись Госуслуг к локальному CLI-агенту iola-cli на этом компьютере.
|
|
13
|
+
|
|
14
|
+
Нажимая "Да", вы подтверждаете, что:
|
|
15
|
+
- используете собственную учетную запись Госуслуг;
|
|
16
|
+
- понимаете, что все действия, выполненные через CLI-агента после подключения, считаются действиями владельца этой учетной записи;
|
|
17
|
+
- разрешаете iola-cli локально сохранить данные доступа, необходимые для повторного входа или выполнения запросов от вашего имени;
|
|
18
|
+
- понимаете, что данные доступа хранятся только на этом компьютере в локальном хранилище пользователя и не передаются разработчикам CLI, администрации города или третьим лицам;
|
|
19
|
+
- обязуетесь не подключать чужие учетные записи и не передавать локальные файлы доступа другим лицам;
|
|
20
|
+
- понимаете, что перед юридически значимыми действиями, отправкой заявлений, оплатой, подписанием или изменением персональных данных CLI должен запросить отдельное подтверждение.
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Посмотреть текст:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
iola gosuslugi terms
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Принять заранее:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
iola gosuslugi consent
|
|
33
|
+
```
|
|
6
34
|
|
|
7
35
|
## Настройка
|
|
8
36
|
|
|
9
|
-
Для работы нужны параметры
|
|
37
|
+
Для работы нужны параметры пользовательского OAuth/OIDC-подключения:
|
|
10
38
|
|
|
11
39
|
- authorization endpoint;
|
|
12
40
|
- token endpoint;
|
|
13
41
|
- client ID;
|
|
14
42
|
- разрешенный redirect URI;
|
|
15
43
|
- scope;
|
|
16
|
-
-
|
|
44
|
+
- optional client secret, если он выдан именно пользователю или локальному приложению;
|
|
17
45
|
- optional userinfo endpoint.
|
|
18
46
|
|
|
19
47
|
Команда настройки:
|
|
@@ -34,7 +62,7 @@ CLI покажет redirect URI:
|
|
|
34
62
|
http://127.0.0.1:18791/gosuslugi/callback
|
|
35
63
|
```
|
|
36
64
|
|
|
37
|
-
Этот URI должен быть разрешен в настройках
|
|
65
|
+
Этот URI должен быть разрешен в настройках подключения.
|
|
38
66
|
|
|
39
67
|
## Вход
|
|
40
68
|
|
|
@@ -45,10 +73,11 @@ iola gosuslugi login
|
|
|
45
73
|
Что происходит:
|
|
46
74
|
|
|
47
75
|
1. CLI запускает локальный callback server на `127.0.0.1`.
|
|
48
|
-
2.
|
|
49
|
-
3.
|
|
50
|
-
4.
|
|
51
|
-
5.
|
|
76
|
+
2. Показывается и сохраняется согласие пользователя.
|
|
77
|
+
3. Открывается экран входа Госуслуг.
|
|
78
|
+
4. Пользователь сам вводит логин, пароль, SMS/2FA.
|
|
79
|
+
5. Госуслуги возвращают `authorization code` на локальный callback.
|
|
80
|
+
6. CLI обменивает code на токены и сохраняет их локально.
|
|
52
81
|
|
|
53
82
|
Токены хранятся в `~/.iola/secrets.json` на компьютере пользователя.
|
|
54
83
|
|
|
@@ -69,5 +98,4 @@ iola gosuslugi logout
|
|
|
69
98
|
|
|
70
99
|
## Ограничения
|
|
71
100
|
|
|
72
|
-
Без
|
|
73
|
-
|
|
101
|
+
Без параметров пользовательского подключения команда `login` не сможет завершить подключение. Все ключи, токены и настройки хранятся только локально у пользователя.
|