dsh-telegram-multiagent 1.3.0 → 1.4.1
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 +157 -108
- package/cordis.patch.yml +9 -8
- package/package.json +9 -4
- package/src/client.js +0 -0
- package/src/index.js +379 -156
- package/test/extract.mjs +0 -0
- package/test/stend-imena.mjs +148 -0
- package/test/stend-pobudki.mjs +142 -0
- package/test/stend-yashchika-shiny.mjs +184 -0
- package/test/test-goal-control.mjs +16 -4
package/README.md
CHANGED
|
@@ -1,123 +1,172 @@
|
|
|
1
1
|
# dsh-telegram-multiagent
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
Канал Telegram для платформы DeepSeek Harness. Один модуль на машину обслуживает
|
|
4
|
+
несколько агентов: у каждого свой бот, свой файл токена и свой список тех, кому он
|
|
5
|
+
отвечает. Агенты не видят переписку друг друга.
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
plugin builds one out of the two ends the harness does give you:
|
|
7
|
+
## Установка
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
in: ctx.agents.create/resume(...) → agent.send(message)
|
|
11
|
-
out: ctx.on('session/event', ...) → send to Telegram
|
|
12
|
-
```
|
|
9
|
+
npm install dsh-telegram-multiagent
|
|
13
10
|
|
|
14
|
-
|
|
11
|
+
Строка подключения кладётся в пресет агента (см. «Куда класть строку» ниже):
|
|
15
12
|
|
|
16
|
-
|
|
13
|
+
# внутри каталога профиля ($DSH_HOME/profiles/<имя>)
|
|
17
14
|
|
|
18
|
-
|
|
19
|
-
# inside your profile directory ($DSH_HOME/profiles/<name>)
|
|
20
|
-
pnpm add dsh-telegram-multiagent
|
|
21
|
-
```
|
|
15
|
+
## Настройки
|
|
22
16
|
|
|
23
|
-
|
|
24
|
-
|
|
17
|
+
| Поле | Обязательно | Что делает |
|
|
18
|
+
|---|---|---|
|
|
19
|
+
| `tokenFile` | одно из трёх | Путь к файлу с токеном бота. Предпочтительно: секрет принадлежит машине, настройка несёт только путь. |
|
|
20
|
+
| `token` / `tokenEnv` | одно из трёх | Сам токен либо имя переменной окружения. Для отладки. |
|
|
21
|
+
| `appDir` | да | Каталог, где установлена платформа этого агента. Пакеты платформы разрешаются **отсюда**, а не от места самого плагина — см. «Почему `appDir`». |
|
|
22
|
+
| `agentName` | нет | Подпись в строках журнала. Полезно, когда на машине несколько ботов. |
|
|
23
|
+
| `allowedUsers` | нет | Числовые идентификаторы тех, кому можно говорить с агентом. **Пусто означает «всем»** — а у агента обычно есть настоящий доступ к машине, так что задайте. |
|
|
24
|
+
| `workspace` | нет | Рабочий каталог, передаваемый сессии агента. |
|
|
25
|
+
| `preset` | нет | Пресет агента для сессий, созданных этим каналом. |
|
|
26
|
+
| `provider` / `model` | нет | Запасной вариант, если в установке нет службы модели по умолчанию. |
|
|
27
|
+
| `a2aDir` | нет | Каталог файлового канала между агентами (`in/`, `out/`). Не задан — канала нет. |
|
|
28
|
+
| `a2aSession` | нет | Идентификатор сессии для этого канала. По умолчанию `a2a`. |
|
|
29
|
+
| `spoolDir` | нет | Системный почтовый ящик агента. Не задан — ящик не читается. |
|
|
30
|
+
| `transcribeCommand` | нет | Внешняя команда для голосовых: `<команда> <файл> auto` → расшифровка в stdout. Не задана — голос вежливо отклоняется. |
|
|
31
|
+
| `goalUsers` | нет | Кому можно ставить цель из Telegram. **Пусто — команда отвергается для всех.** Намеренно не наследуется от `allowedUsers`: говорить с агентом и запускать ему платный автономный цикл — разные права. |
|
|
32
|
+
| `goalA2ASenders` | нет | Кому можно ставить цель из канала между агентами. Отправитель называет себя первой строкой файла `From: <имя>`. Это учёт, а не удостоверение личности. |
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
🔴 **Предел: 3 постановки цели за скользящий час.** Считается по отметкам состоявшихся
|
|
36
|
+
постановок, отдельно на каждый канал. Исчерпан — команда отвергается со словами «зовите
|
|
37
|
+
человека». СНЯТИЕ цели при исчерпанном пределе разрешено: предел бережёт от разгона, а не
|
|
38
|
+
запирает возможность остановиться.
|
|
39
|
+
|
|
40
|
+
Предел не защищает от намеренного действия агента с правами администратора: такой агент
|
|
41
|
+
снимет и счётчик, и сам предел. Защита здесь от разгона и случайности, а не от намерения.
|
|
42
|
+
## Пять вещей, стоивших нам дня
|
|
43
|
+
|
|
44
|
+
Каждая из них отказывает **выглядя успехом**. В исходниках они помечены комментариями
|
|
45
|
+
рядом с местом; здесь короткая версия.
|
|
46
|
+
|
|
47
|
+
**1. Опрос принадлежит боту, а не монтажу.** Платформа монтирует композицию больше
|
|
48
|
+
одного раза на процесс и снимает лишний монтаж. С одним общим флагом «идёт» вы
|
|
49
|
+
получите два опроса, дерущихся за одного бота, и Telegram оборвёт оба с ошибкой
|
|
50
|
+
`Conflict`. С вежливым «новый монтаж просит старый посторониться» вы не получите
|
|
51
|
+
опроса вовсе — потому что снимут именно новый. Лечение — счёт ссылок: первый монтаж
|
|
52
|
+
запускает опрос, последний снятый его останавливает.
|
|
53
|
+
|
|
54
|
+
**2. Входящее письмо удаляется только после того, как дошло до агента.** Прочитать
|
|
55
|
+
файл и сразу удалить — значит терять сообщение всякий раз, когда передача не удалась.
|
|
56
|
+
А она не удастся, см. (3). Снаружи это неотличимо от «бот меня проигнорировал».
|
|
57
|
+
|
|
58
|
+
**3. Фабрика агентов появляется позже канала.** Первое сообщение может прийти раньше,
|
|
59
|
+
чем платформа её зарегистрировала, и вы получите `no agent factory registered`. Ждите
|
|
60
|
+
платформу, а не предполагайте, что она готова.
|
|
61
|
+
|
|
62
|
+
**4. Сессию, уже лежащую на диске, надо продолжать, а не создавать.** Вызов `create()`
|
|
63
|
+
с существующим идентификатором даёт новую пустую сессию, и переписка начинается с
|
|
64
|
+
чистого листа — при том, что старая цела и лежит рядом.
|
|
65
|
+
|
|
66
|
+
**5. Отказ незнакомцу должен быть громким.** Молчаливый отказ прячет событие
|
|
67
|
+
безопасности: владелец не узнает, что кто-то нашёл его бота.
|
|
68
|
+
|
|
69
|
+
## Куда класть строку
|
|
70
|
+
|
|
71
|
+
В профиле `web` инструменты общего плана **выключены намеренно**; набор приходит из
|
|
72
|
+
пресета агента. Строка плагина, положенная в слой патча профиля, соберётся без единой
|
|
73
|
+
ошибки, будет числиться смонтированной — и никогда не дойдёт до агента. Кладите строку
|
|
74
|
+
в пресет агента.
|
|
75
|
+
|
|
76
|
+
Пресет читается ещё и **при создании сессии**: правка файла не действует на уже идущую.
|
|
77
|
+
Перезапустите платформу либо смените пресет по умолчанию в настройках (перечитывается на
|
|
78
|
+
ходу, действует для следующей созданной сессии).
|
|
79
|
+
|
|
80
|
+
## Почему `appDir`
|
|
81
|
+
|
|
82
|
+
Плагин разрешает `@deepseek-ai/dsh-llm` и `@deepseek-ai/dsh-agent` из каталога, который
|
|
83
|
+
вы передали в `appDir`, а не от собственного расположения. Это сделано намеренно: модуль
|
|
84
|
+
должен лежать на машине один раз и обслуживать нескольких агентов, у каждого своя
|
|
85
|
+
установка платформы. Привяжи его жёстко к `node_modules` одного агента — и удаление
|
|
86
|
+
ЭТОГО агента сломает канал всем остальным.
|
|
87
|
+
|
|
88
|
+
## Заметки о безопасности
|
|
89
|
+
|
|
90
|
+
- Пустой `allowedUsers` означает, что любой нашедший бота говорит с агентом, у которого
|
|
91
|
+
обычно есть доступ к оболочке машины. Задайте его.
|
|
92
|
+
- Отвергнутый незнакомец попадает в журнал и в сообщение владельцу. Молчаливый отказ
|
|
93
|
+
прячет событие безопасности.
|
|
94
|
+
- Токен читается из файла при запуске; настройка несёт путь, а не секрет.
|
|
95
|
+
- Изоляция агентов держится на правах файлов токенов, а не на самом модуле: модуль
|
|
96
|
+
общий, разделяет их файловая система.
|
|
97
|
+
|
|
98
|
+
## Состояние
|
|
99
|
+
|
|
100
|
+
Написан для собственного парка агентов и работает в бою на нескольких. Платформа молодая
|
|
101
|
+
(`0.1.0-rc`), её интерфейс плагинов меняется — рассчитывайте подстраиваться. Комментарии
|
|
102
|
+
в исходниках русские: они несут причину каждой неочевидной строки.
|
|
25
103
|
|
|
26
|
-
|
|
27
|
-
- insert:
|
|
28
|
-
- name: dsh-telegram-multiagent
|
|
29
|
-
config:
|
|
30
|
-
agentName: my-agent # log label only
|
|
31
|
-
tokenFile: /etc/dsh/bot.token # preferred: a file readable by this agent
|
|
32
|
-
appDir: /opt/my-agent/app # where THIS agent's harness is installed
|
|
33
|
-
workspace: /opt/my-agent/work
|
|
34
|
-
allowedUsers: [123456789] # empty = everyone; you do not want that
|
|
35
|
-
```
|
|
104
|
+
MIT.
|
|
36
105
|
|
|
37
|
-
##
|
|
106
|
+
## 1.4.0 — причина сетевого отказа и чтение почтового ящика
|
|
38
107
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
| `tokenFile` | one of these | Path to a file holding the bot token. Preferred: the secret belongs to the machine, the config only carries a path. |
|
|
42
|
-
| `token` / `tokenEnv` | one of these | Literal token, or the name of an env var. For debugging. |
|
|
43
|
-
| `appDir` | yes | Directory where this agent's harness is installed. Platform packages are resolved from **here**, not from the plugin's own location — see "Why appDir" below. |
|
|
44
|
-
| `agentName` | no | Label in log lines. Useful when several bots run on one machine. |
|
|
45
|
-
| `allowedUsers` | no | Numeric user ids allowed to talk to the agent. **Empty means everyone** — an agent usually has real access to the machine, so set it. |
|
|
46
|
-
| `workspace` | no | Working directory handed to the agent session. |
|
|
47
|
-
| `preset` | no | Agent preset to mount for sessions created by this channel. |
|
|
48
|
-
| `provider` / `model` | no | Fallback if the deployment has no default model service. |
|
|
49
|
-
| `a2aDir` | no | Directory for a file-based agent-to-agent channel (`in/`, `out/`). Omit and no such channel exists. |
|
|
50
|
-
| `a2aSession` | no | Session id used for that channel. Default `a2a`. |
|
|
51
|
-
| `transcribeCommand` | no | External command for voice messages: `<cmd> <audio-file> auto` → transcript on stdout. Omit and voice is politely refused. |
|
|
52
|
-
| `goalUsers` | no | Telegram user ids allowed to run `/goal`. **Empty (default) = the command is refused for everyone.** Not inherited from `allowedUsers` on purpose: talking to an agent and starting a paid autonomous loop are different rights. |
|
|
53
|
-
| `goalA2ASenders` | no | Sender names allowed to run `/goal` from the agent-to-agent channel. The sender names itself in the first line of the file (`From: <name>`) — this is bookkeeping, not authentication; see 1.3.0 below. |
|
|
54
|
-
|
|
55
|
-
## Five things that cost us a day
|
|
56
|
-
|
|
57
|
-
Each of these fails **while looking like success**. They are commented inline in the source; this is
|
|
58
|
-
the short version.
|
|
59
|
-
|
|
60
|
-
**1. Polling belongs to the bot, not to the mount.** The harness mounts a composition more than once
|
|
61
|
-
per process and unmounts the extra one. With a single shared `running` flag you get two pollers
|
|
62
|
-
fighting over one bot and Telegram cuts both with `Conflict`. With a polite "new mount asks the old
|
|
63
|
-
one to step aside" you get *no* poller at all — because the new mount is the one that gets unmounted.
|
|
64
|
-
The fix is reference counting: the first mount starts polling, the last unmount stops it.
|
|
65
|
-
|
|
66
|
-
**2. Delete the incoming message only after it reached the agent.** Reading a file and unlinking it
|
|
67
|
-
immediately loses the message whenever the handoff fails — and the handoff *will* fail, see (3).
|
|
68
|
-
From the outside that is indistinguishable from "the bot ignored me".
|
|
69
|
-
|
|
70
|
-
**3. The agent factory appears later than the channel.** The first message can arrive before the
|
|
71
|
-
harness has registered it, and you get `no agent factory registered`. Wait for the platform instead
|
|
72
|
-
of assuming it is ready.
|
|
73
|
-
|
|
74
|
-
**4. A session already on disk must be resumed, not created.** Calling `create()` with an existing
|
|
75
|
-
session id makes the persistence layer abort *every* turn with an id-collision error. Externally:
|
|
76
|
-
"accepted the message and went quiet" — the turn honestly starts and dies in milliseconds. It works
|
|
77
|
-
until the first restart, which is what makes it nasty. Use `resume()` when the session exists.
|
|
78
|
-
|
|
79
|
-
**5. `ctx.get()` returns nothing *quietly* while a service is still starting.** cordis hands back
|
|
80
|
-
`undefined` without throwing until the provider's fiber is active, so "this service is not in the
|
|
81
|
-
build" and "this service is thirty milliseconds away" arrive as the same value. Code written as
|
|
82
|
-
`const x = ctx.get('x'); if (x) {...}` then takes the "feature absent" branch and says nothing — the
|
|
83
|
-
agent is assembled, answers, and never mentions what it lost. This bit us three times in three days:
|
|
84
|
-
the agent factory (3), session persistence (4, the whole resume block was skipped), and the agent
|
|
85
|
-
preset — where a neighbouring agent's toolset dropped from 33 tools to 3 with no error and no log
|
|
86
|
-
line. Wait for the service with a stated deadline, and when the deadline passes, say so *and name
|
|
87
|
-
the consequence*. One helper for all of them: a fix applied to the instance instead of the class
|
|
88
|
-
guarantees a relapse, and the relapse looks like a new illness.
|
|
89
|
-
|
|
90
|
-
## Where to put the row
|
|
91
|
-
|
|
92
|
-
In the `web` profile the common-plane tools are **disabled on purpose**; the toolset comes from the
|
|
93
|
-
agent preset. A plugin row placed in the profile patch layer composes without a single error, is
|
|
94
|
-
listed as mounted — and never reaches the agent. Put the row in the agent preset.
|
|
95
|
-
|
|
96
|
-
The preset is also picked up when a **session is created**: editing the file does not affect a
|
|
97
|
-
running session. Restart the platform, or change the default preset in settings (hot-reloaded, takes
|
|
98
|
-
effect for the next created session).
|
|
99
|
-
|
|
100
|
-
## Why `appDir`
|
|
101
|
-
|
|
102
|
-
The plugin resolves `@deepseek-ai/dsh-llm` and `@deepseek-ai/dsh-agent` from the directory you pass
|
|
103
|
-
in `appDir`, not from its own location. That is deliberate: the module is meant to live once on a
|
|
104
|
-
machine and serve several agents, each with its own harness installation. Hard-linking it to one
|
|
105
|
-
agent's `node_modules` would mean that removing *that* agent breaks the channel for everybody else.
|
|
106
|
-
|
|
107
|
-
## Security notes
|
|
108
|
-
|
|
109
|
-
- `allowedUsers` empty means anyone who finds the bot talks to an agent that usually has shell access
|
|
110
|
-
to the machine. Set it.
|
|
111
|
-
- A rejected stranger is logged and reported to the owner. A silent refusal hides a security event.
|
|
112
|
-
- The token is read from a file at startup; the config carries a path, not a secret.
|
|
113
|
-
|
|
114
|
-
## Status
|
|
115
|
-
|
|
116
|
-
Written for our own fleet and running in production on several agents. The harness is young
|
|
117
|
-
(`0.1.0-rc`) and its plugin API moves; expect to adapt. Inline comments are currently in Russian —
|
|
118
|
-
they carry the reasoning behind each non-obvious line, and a translation is welcome.
|
|
108
|
+
**Ломающих изменений НЕТ.** Проверено сравнением состава: из 1.3.0 не пропало ни одного
|
|
109
|
+
файла, добавилось два стенда. Пути внутри пакета прежние.
|
|
119
110
|
|
|
120
|
-
|
|
111
|
+
пропало: ничего
|
|
112
|
+
добавилось: test/stend-imena.mjs, test/stend-yashchika-shiny.mjs
|
|
113
|
+
изменилось: src/index.js, test/test-goal-control.mjs, cordis.patch.yml, README.md
|
|
114
|
+
|
|
115
|
+
**Причина сетевого отказа печатается рядом с сообщением.** Раньше `fetch failed` скрывал
|
|
116
|
+
причину: обрыв соединения, истёкшее ожидание и ненайденное имя выглядели одинаково, и по
|
|
117
|
+
журналу нельзя было понять, что чинить. Теперь рядом печатается `e.cause`. Если причины
|
|
118
|
+
нет — пишется «не указана», а не пустое место: пустое читается как «причины нет» и
|
|
119
|
+
возвращает ту же слепоту.
|
|
120
|
+
|
|
121
|
+
🔴 **У двух каналов РАЗНЫЕ способы назвать отправителя, и путать их дорого:**
|
|
122
|
+
|
|
123
|
+
канал a2a (каталог a2aDir) — отправитель из заголовка первой строки: From: <имя>
|
|
124
|
+
почтовый ящик (spoolDir) — отправитель из ИМЕНИ ФАЙЛА: ГГГГММДДTЧЧММССZ-<имя>-<хвост>
|
|
125
|
+
|
|
126
|
+
Положив в ящик письмо с заголовком `From:`, вы получите отправителем то, что стоит
|
|
127
|
+
в имени файла, а сам заголовок останется в тексте письма. Ошибки не будет, отказа
|
|
128
|
+
тоже — просто отправитель окажется не тем, кого вы назвали. Проверено пробой.
|
|
129
|
+
|
|
130
|
+
Причина разницы: в ящик кладёт посторонний процесс правами каталога, и имя файла —
|
|
131
|
+
единственное, что он не может подделать незаметно для владельца ящика. В канале a2a
|
|
132
|
+
файл пишет сам отправитель, там заголовок и есть его подпись. В обоих случаях это
|
|
133
|
+
учёт, а не удостоверение личности.
|
|
134
|
+
|
|
135
|
+
И третье следствие того же различия: **команды (`/goal`) из ящика не принимаются вовсе** —
|
|
136
|
+
они живут только в канале a2a, где отправитель подписывает файл сам. Положив `/goal` в
|
|
137
|
+
ящик, вы получите обычное письмо с этим текстом: ни выполнения, ни отказа. Право ставить
|
|
138
|
+
цель поимённое, и проверять его по имени файла, которое задаёт посторонний процесс,
|
|
139
|
+
означало бы раздать это право владельцу каталога.
|
|
140
|
+
|
|
141
|
+
**Чтение писем из системного почтового ящика** (`spoolDir`). Письмо старше 12 часов
|
|
142
|
+
подаётся с явной пометкой возраста — иначе двухсуточное письмо толкает отвечать на
|
|
143
|
+
устаревшее. Больше пяти писем подаются одной пачкой, а не по одному. Ящик не задан —
|
|
144
|
+
не читается, молчаливого умолчания нет.
|
|
145
|
+
|
|
146
|
+
**Блок управления целями появился в `cordis.patch.yml`.** Раньше `goalUsers` и
|
|
147
|
+
`goalA2ASenders` были описаны в README, но отсутствовали в патче монтажа — то есть
|
|
148
|
+
настройка была недоступна тому, кто ставил пакет по инструкции.
|
|
149
|
+
|
|
150
|
+
### Проверка, что работает
|
|
151
|
+
|
|
152
|
+
Стенды едут вместе с кодом:
|
|
153
|
+
|
|
154
|
+
node test/test-goal-control.mjs управление целями из канала
|
|
155
|
+
node test/stend-imena.mjs метки отправителя и обезличенность
|
|
156
|
+
node test/stend-yashchika-shiny.mjs чтение почтового ящика
|
|
157
|
+
|
|
158
|
+
Коды: 0 — сошлось, 1 — расхождение, 2 — проверить нечем (слепота).
|
|
159
|
+
🔴 Код 2 не означает «всё хорошо»: он означает, что часть проверок не состоялась. Чаще
|
|
160
|
+
всего это отсутствие необязательных зависимостей или файлов настроек, которых у только
|
|
161
|
+
что установленного модуля ещё нет.
|
|
162
|
+
|
|
163
|
+
### Чего 1.4.0 НЕ делает
|
|
164
|
+
|
|
165
|
+
- не хранит переписку — она живёт в журнале сессии платформы;
|
|
166
|
+
- не гарантирует доставку при недоступной сети: повторяет опрос и пишет причину отказа в
|
|
167
|
+
журнал, но письмо в этот момент не уходит;
|
|
168
|
+
- не проверяет, что пишущий в канал между агентами — тот, за кого себя выдаёт: метка
|
|
169
|
+
отправителя берётся из имени файла, а право положить файл раздаётся правами каталога.
|
|
121
170
|
|
|
122
171
|
## 1.1.0 — кто спросил, кому отвечено, и кто это видит
|
|
123
172
|
|
package/cordis.patch.yml
CHANGED
|
@@ -17,13 +17,14 @@
|
|
|
17
17
|
# Empty means everyone can talk to an agent that usually has shell
|
|
18
18
|
# access. Set it.
|
|
19
19
|
allowedUsers: []
|
|
20
|
-
#
|
|
21
|
-
#
|
|
22
|
-
#
|
|
23
|
-
#
|
|
24
|
-
#
|
|
20
|
+
# 🔴 УПРАВЛЕНИЕ ЦЕЛЯМИ ИЗ КАНАЛА. Оба списка пусты по умолчанию — это
|
|
21
|
+
# значит, что команда постановки цели отвергается для ВСЕХ. Так задумано:
|
|
22
|
+
# запуск автономного цикла стоит денег, поэтому право даётся поимённо и
|
|
23
|
+
# НИКОГДА не наследуется от allowedUsers. Говорить с агентом и запускать
|
|
24
|
+
# ему платный цикл — разные права.
|
|
25
|
+
# Кому можно ставить цель из Telegram (числовые идентификаторы):
|
|
25
26
|
goalUsers: []
|
|
26
|
-
#
|
|
27
|
-
#
|
|
28
|
-
#
|
|
27
|
+
# Кому можно ставить цель из служебного канала между агентами.
|
|
28
|
+
# Отправитель называет себя сам, первой строкой файла: "From: <имя>".
|
|
29
|
+
# Это учёт, а не удостоверение личности — см. README.
|
|
29
30
|
goalA2ASenders: []
|
package/package.json
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-telegram-multiagent",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "Telegram
|
|
3
|
+
"version": "1.4.1",
|
|
4
|
+
"description": "Канал Telegram для DeepSeek Harness: один модуль на машину обслуживает несколько агентов, у каждого свой бот, свой файл токена и свой список разрешённых. Метка отправителя неподделываема, память владельца и координатора слита в одну, режим доставки переключается файлом вне кода, цели управляются из канала.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
7
7
|
"files": [
|
|
8
|
-
"src",
|
|
9
|
-
"
|
|
8
|
+
"src/index.js",
|
|
9
|
+
"src/client.js",
|
|
10
|
+
"test/extract.mjs",
|
|
11
|
+
"test/stend-imena.mjs",
|
|
12
|
+
"test/stend-yashchika-shiny.mjs",
|
|
13
|
+
"test/test-goal-control.mjs",
|
|
14
|
+
"test/stend-pobudki.mjs",
|
|
10
15
|
"cordis.patch.yml",
|
|
11
16
|
"README.md"
|
|
12
17
|
],
|
package/src/client.js
CHANGED
|
File without changes
|