@iola_adm/iola-cli 0.2.48 → 0.2.49
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
CHANGED
|
@@ -210,6 +210,7 @@ Yandex tools уже доступны: профиль Yandex ID, расширен
|
|
|
210
210
|
Мой домофон:
|
|
211
211
|
|
|
212
212
|
```bash
|
|
213
|
+
iola ufanet
|
|
213
214
|
iola ufanet setup
|
|
214
215
|
iola ufanet intercoms
|
|
215
216
|
iola ufanet open
|
|
@@ -223,7 +224,7 @@ iola dom_ru
|
|
|
223
224
|
iola rostelecom
|
|
224
225
|
```
|
|
225
226
|
|
|
226
|
-
Уфанет поддерживается как рабочий провайдер: список домофонов, открытие двери после подтверждения, история звонков, записи звонков, камеры/RTSP и уведомления о новых вызовах через опрос истории звонков, пока CLI открыт. Команда `открой домофон` открывает единственный домофон сразу; если домофонов несколько, CLI просит выбрать адрес цифрой. При уведомлении о вызове можно ответить `да`, `да открой` или `нет`. Дом.ру и Ростелеком добавлены как видимые направления `в разработке`.
|
|
227
|
+
`/ufanet` в интерактивном CLI открывает отдельное меню домофона с выбором действия цифрой. Уфанет поддерживается как рабочий провайдер: список домофонов, открытие двери после подтверждения, история звонков, записи звонков, камеры/RTSP и уведомления о новых вызовах через опрос истории звонков, пока CLI открыт. Команда `открой домофон` открывает единственный домофон сразу; если домофонов несколько, CLI просит выбрать адрес цифрой. При уведомлении о вызове можно ответить `да`, `да открой` или `нет`. Дом.ру и Ростелеком добавлены как видимые направления `в разработке`.
|
|
227
228
|
|
|
228
229
|
Инструкция: [Мой домофон](https://github.com/adm-iola/iola-cli/wiki/Мой-домофон).
|
|
229
230
|
|
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -1282,11 +1282,15 @@ async function startAgentRawInput() {
|
|
|
1282
1282
|
|
|
1283
1283
|
async function handleAgentLine(line, state) {
|
|
1284
1284
|
if (!line.startsWith("/")) {
|
|
1285
|
+
if (/^\d{1,2}$/u.test(line.trim()) && (state.pendingAction?.type === "ufanet_menu" || state.lastCommand?.command === "ufanet")) {
|
|
1286
|
+
state.pendingAction = state.pendingAction?.type === "ufanet_menu" ? state.pendingAction : buildUfanetMenuPendingAction();
|
|
1287
|
+
}
|
|
1285
1288
|
const pendingAnswer = await handlePendingAgentAction(line, state);
|
|
1286
1289
|
const answer = pendingAnswer || await aiAsk(state.rawMode ? [line, "--quiet"] : [line], { history: state.history, state });
|
|
1287
1290
|
state.history.push({ role: "user", content: line });
|
|
1288
1291
|
state.history.push({ role: "assistant", content: answer });
|
|
1289
1292
|
if (state.rawMode) state.pendingOutput = answer;
|
|
1293
|
+
else if (pendingAnswer) printAiAnswer(pendingAnswer);
|
|
1290
1294
|
return false;
|
|
1291
1295
|
}
|
|
1292
1296
|
|
|
@@ -1308,6 +1312,10 @@ async function handleAgentLine(line, state) {
|
|
|
1308
1312
|
}
|
|
1309
1313
|
|
|
1310
1314
|
if (command === "help") {
|
|
1315
|
+
if (state.pendingAction?.type === "ufanet_menu") {
|
|
1316
|
+
await printUfanetMenu({ agentState: state, pending: true });
|
|
1317
|
+
return false;
|
|
1318
|
+
}
|
|
1311
1319
|
printAgentHelp();
|
|
1312
1320
|
return false;
|
|
1313
1321
|
}
|
|
@@ -1942,6 +1950,21 @@ async function handlePendingAgentAction(line, state) {
|
|
|
1942
1950
|
const result = await ufanetOpenIntercom(action.id, { confirm: true });
|
|
1943
1951
|
return formatUfanetOpenResult(result, action);
|
|
1944
1952
|
}
|
|
1953
|
+
if (action.type === "ufanet_menu") {
|
|
1954
|
+
const number = Number(text.match(/^\s*(\d{1,2})\s*$/u)?.[1] || 0);
|
|
1955
|
+
if (number === 0) {
|
|
1956
|
+
state.pendingAction = null;
|
|
1957
|
+
return "Выход из меню домофона.";
|
|
1958
|
+
}
|
|
1959
|
+
if (!number || number < 0 || number > action.items.length) {
|
|
1960
|
+
state.pendingAction = buildUfanetMenuPendingAction();
|
|
1961
|
+
return await formatUfanetMenu({ compact: true });
|
|
1962
|
+
}
|
|
1963
|
+
const item = action.items[number - 1];
|
|
1964
|
+
state.pendingAction = null;
|
|
1965
|
+
const answer = await executeUfanetMenuItem(item, state);
|
|
1966
|
+
return answer || "";
|
|
1967
|
+
}
|
|
1945
1968
|
return "";
|
|
1946
1969
|
}
|
|
1947
1970
|
|
|
@@ -3714,8 +3737,25 @@ async function handleUfanet(args = [], agentState = null) {
|
|
|
3714
3737
|
const [action = process.stdin.isTTY ? "menu" : "status", target, ...rest] = args;
|
|
3715
3738
|
const options = parseOptions(rest);
|
|
3716
3739
|
|
|
3717
|
-
if (action === "menu" || action === "choose") {
|
|
3718
|
-
await printUfanetMenu();
|
|
3740
|
+
if (action === "menu" || action === "choose" || action === "help") {
|
|
3741
|
+
await printUfanetMenu({ agentState, pending: action !== "help" });
|
|
3742
|
+
return;
|
|
3743
|
+
}
|
|
3744
|
+
|
|
3745
|
+
if (/^\d{1,2}$/u.test(String(action))) {
|
|
3746
|
+
const number = Number(action);
|
|
3747
|
+
const items = getUfanetMenuItems();
|
|
3748
|
+
if (number === 0) {
|
|
3749
|
+
console.log("Выход из меню домофона.");
|
|
3750
|
+
return;
|
|
3751
|
+
}
|
|
3752
|
+
const item = items[number - 1];
|
|
3753
|
+
if (!item) {
|
|
3754
|
+
console.log(formatUfanetMenu({ compact: true }));
|
|
3755
|
+
return;
|
|
3756
|
+
}
|
|
3757
|
+
const answer = await executeUfanetMenuItem(item, agentState);
|
|
3758
|
+
if (answer) console.log(answer);
|
|
3719
3759
|
return;
|
|
3720
3760
|
}
|
|
3721
3761
|
|
|
@@ -3804,28 +3844,88 @@ async function handleUfanet(args = [], agentState = null) {
|
|
|
3804
3844
|
iola ufanet delete`);
|
|
3805
3845
|
}
|
|
3806
3846
|
|
|
3807
|
-
async function printUfanetMenu() {
|
|
3847
|
+
async function printUfanetMenu(options = {}) {
|
|
3848
|
+
if (options.agentState && options.pending) {
|
|
3849
|
+
options.agentState.pendingAction = buildUfanetMenuPendingAction();
|
|
3850
|
+
}
|
|
3851
|
+
console.log(await formatUfanetMenu());
|
|
3852
|
+
}
|
|
3853
|
+
|
|
3854
|
+
async function formatUfanetMenu(options = {}) {
|
|
3808
3855
|
const status = await getUfanetStatus();
|
|
3809
|
-
|
|
3810
|
-
|
|
3811
|
-
{
|
|
3812
|
-
|
|
3813
|
-
|
|
3814
|
-
|
|
3815
|
-
|
|
3816
|
-
|
|
3817
|
-
|
|
3818
|
-
|
|
3819
|
-
|
|
3820
|
-
|
|
3821
|
-
|
|
3822
|
-
|
|
3823
|
-
|
|
3824
|
-
|
|
3825
|
-
{
|
|
3826
|
-
{
|
|
3827
|
-
{
|
|
3828
|
-
|
|
3856
|
+
const lines = [
|
|
3857
|
+
"Мой домофон",
|
|
3858
|
+
`Уфанет: ${status.configured ? "готово" : "не настроено"}; уведомления: ${status.notifications}.`,
|
|
3859
|
+
"Дом.ру: в разработке. Ростелеком: в разработке.",
|
|
3860
|
+
"",
|
|
3861
|
+
"Выберите действие:",
|
|
3862
|
+
...getUfanetMenuItems().map((item) => `${item.number}. ${item.title}`),
|
|
3863
|
+
"0. Назад",
|
|
3864
|
+
"",
|
|
3865
|
+
"Введите цифру или команду вида `/ufanet 3`. Пока открыт этот раздел, `/help` показывает справку по домофону.",
|
|
3866
|
+
];
|
|
3867
|
+
return options.compact ? lines.slice(4).join("\n") : lines.join("\n");
|
|
3868
|
+
}
|
|
3869
|
+
|
|
3870
|
+
function getUfanetMenuItems() {
|
|
3871
|
+
return [
|
|
3872
|
+
{ number: 1, key: "open", title: "Открыть домофон" },
|
|
3873
|
+
{ number: 2, key: "intercoms", title: "Показать мои домофоны" },
|
|
3874
|
+
{ number: 3, key: "history", title: "История звонков" },
|
|
3875
|
+
{ number: 4, key: "notifications-on", title: "Включить уведомления о вызовах" },
|
|
3876
|
+
{ number: 5, key: "notifications-off", title: "Выключить уведомления" },
|
|
3877
|
+
{ number: 6, key: "notifications-status", title: "Статус уведомлений" },
|
|
3878
|
+
{ number: 7, key: "cameras", title: "Камеры" },
|
|
3879
|
+
{ number: 8, key: "status", title: "Статус подключения" },
|
|
3880
|
+
{ number: 9, key: "delete", title: "Удалить подключение Уфанет" },
|
|
3881
|
+
];
|
|
3882
|
+
}
|
|
3883
|
+
|
|
3884
|
+
function buildUfanetMenuPendingAction() {
|
|
3885
|
+
return { type: "ufanet_menu", items: getUfanetMenuItems(), createdAt: new Date().toISOString() };
|
|
3886
|
+
}
|
|
3887
|
+
|
|
3888
|
+
async function executeUfanetMenuItem(item, agentState = null) {
|
|
3889
|
+
if (!item) return "";
|
|
3890
|
+
if (item.key === "open") {
|
|
3891
|
+
const result = await ufanetOpenSmart({ state: agentState });
|
|
3892
|
+
return formatUfanetSmartOpenResult(result);
|
|
3893
|
+
}
|
|
3894
|
+
if (item.key === "intercoms") {
|
|
3895
|
+
const rows = await ufanetGetIntercoms();
|
|
3896
|
+
if (!rows.length) return "Доступные домофоны Уфанет не найдены.";
|
|
3897
|
+
return ["Домофоны Уфанет:", ...rows.map((row, index) => `${index + 1}. ${row.address || row.name || `Домофон #${row.id}`} — ID ${row.id}`)].join("\n");
|
|
3898
|
+
}
|
|
3899
|
+
if (item.key === "history") {
|
|
3900
|
+
const rows = await ufanetGetCallHistory({ page: 1, pageSize: 10 });
|
|
3901
|
+
if (!rows.results?.length) return "В истории Уфанет звонков не найдено.";
|
|
3902
|
+
return ["История звонков Уфанет:", ...rows.results.map((row, index) => `${index + 1}. ${row.calledAt || "-"} — ${row.address || "-"}${row.uuid ? `, UUID ${row.uuid}` : ""}`)].join("\n");
|
|
3903
|
+
}
|
|
3904
|
+
if (item.key === "notifications-on") {
|
|
3905
|
+
await setUfanetNotifications(true);
|
|
3906
|
+
return "Уведомления Уфанет включены. При новом вызове в CLI можно ответить `да` или `нет`.";
|
|
3907
|
+
}
|
|
3908
|
+
if (item.key === "notifications-off") {
|
|
3909
|
+
await setUfanetNotifications(false);
|
|
3910
|
+
return "Уведомления Уфанет выключены.";
|
|
3911
|
+
}
|
|
3912
|
+
if (item.key === "notifications-status") {
|
|
3913
|
+
const status = await getUfanetStatus();
|
|
3914
|
+
return `Уведомления Уфанет: ${status.notifications}, интервал ${status.intervalSeconds} сек.`;
|
|
3915
|
+
}
|
|
3916
|
+
if (item.key === "cameras") {
|
|
3917
|
+
const rows = await ufanetGetCameras();
|
|
3918
|
+
if (!rows.length) return "Камеры Уфанет не найдены.";
|
|
3919
|
+
return ["Камеры Уфанет:", ...rows.slice(0, 10).map((row, index) => `${index + 1}. ${row.title || row.number || "камера"} — ${row.address || "-"}${row.rtspUrl ? `, ${row.rtspUrl}` : ""}`)].join("\n");
|
|
3920
|
+
}
|
|
3921
|
+
if (item.key === "status") {
|
|
3922
|
+
const status = await getUfanetStatus();
|
|
3923
|
+
return `Уфанет: ${status.configured ? "настроен" : "не настроен"}, ${status.enabled ? "включен" : "выключен"}, уведомления ${status.notifications}.`;
|
|
3924
|
+
}
|
|
3925
|
+
if (item.key === "delete") {
|
|
3926
|
+
return "Удаление подключения выполняется явной командой: `/ufanet delete`.";
|
|
3927
|
+
}
|
|
3928
|
+
return "";
|
|
3829
3929
|
}
|
|
3830
3930
|
|
|
3831
3931
|
async function setupUfanetConnector() {
|
package/wiki//320/234/320/276/320/271-/320/264/320/276/320/274/320/276/321/204/320/276/320/275.md
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
Рабочий провайдер:
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
+
iola ufanet
|
|
10
11
|
iola ufanet setup
|
|
11
12
|
iola ufanet status
|
|
12
13
|
iola ufanet intercoms
|
|
@@ -22,6 +23,8 @@ iola ufanet notifications status
|
|
|
22
23
|
iola ufanet delete
|
|
23
24
|
```
|
|
24
25
|
|
|
26
|
+
В интерактивном CLI команда `/ufanet` открывает отдельное меню домофона. В нем можно выбрать действие цифрой: открыть домофон, посмотреть список, историю, уведомления, камеры или статус.
|
|
27
|
+
|
|
25
28
|
При настройке нужны:
|
|
26
29
|
|
|
27
30
|
- номер договора Уфанет;
|