@pachca/cli 2026.10.2 → 2026.10.3
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/CHANGELOG.md +16 -0
- package/README.md +24 -24
- package/README.template.md +14 -23
- package/dist/base-command.js +1 -1
- package/dist/client.js +56 -32
- package/dist/commands/api.js +1 -1
- package/dist/commands/auth/logout.js +23 -12
- package/dist/commands/bots/create-token.js +0 -3
- package/dist/commands/bots/create.js +0 -4
- package/dist/commands/bots/delete.js +0 -3
- package/dist/commands/bots/get-stream.js +23 -0
- package/dist/commands/bots/list-company.js +0 -3
- package/dist/commands/bots/list-events.js +0 -3
- package/dist/commands/bots/list-scopes.js +0 -3
- package/dist/commands/bots/list.js +0 -3
- package/dist/commands/bots/recreate-token-self.js +0 -3
- package/dist/commands/bots/recreate-token.js +0 -3
- package/dist/commands/bots/reissue-token.js +0 -3
- package/dist/commands/bots/remove-event.js +0 -3
- package/dist/commands/bots/update-webhook.js +0 -3
- package/dist/commands/bots/update.js +0 -5
- package/dist/commands/chats/archive.js +0 -4
- package/dist/commands/chats/create.js +3 -6
- package/dist/commands/chats/download-export.js +0 -3
- package/dist/commands/chats/list-company.js +0 -3
- package/dist/commands/chats/list.js +1 -6
- package/dist/commands/chats/remove-avatar.js +0 -3
- package/dist/commands/chats/request-export.js +0 -3
- package/dist/commands/chats/unarchive.js +0 -3
- package/dist/commands/chats/update-avatar.js +0 -3
- package/dist/commands/chats/update.js +0 -3
- package/dist/commands/custom-properties/list.js +0 -3
- package/dist/commands/drafts/create.js +1 -4
- package/dist/commands/drafts/delete.js +0 -3
- package/dist/commands/drafts/update.js +1 -1
- package/dist/commands/files/uploads.js +0 -3
- package/dist/commands/group-tags/create.js +0 -3
- package/dist/commands/group-tags/list-users.js +0 -3
- package/dist/commands/group-tags/list.js +0 -3
- package/dist/commands/important-messages/create.js +64 -0
- package/dist/commands/important-messages/delete.js +42 -0
- package/dist/commands/important-messages/list.js +89 -0
- package/dist/commands/members/add.js +0 -5
- package/dist/commands/members/leave.js +0 -3
- package/dist/commands/members/list.js +0 -4
- package/dist/commands/members/remove.js +0 -3
- package/dist/commands/members/update.js +0 -3
- package/dist/commands/messages/create.js +3 -8
- package/dist/commands/messages/delete.js +0 -3
- package/dist/commands/messages/get.js +0 -5
- package/dist/commands/messages/list.js +1 -5
- package/dist/commands/messages/pin.js +0 -3
- package/dist/commands/messages/unfurl.js +0 -3
- package/dist/commands/messages/unpin.js +0 -3
- package/dist/commands/messages/update.js +2 -7
- package/dist/commands/oauth/token-info.js +0 -3
- package/dist/commands/profile/delete-avatar.js +0 -3
- package/dist/commands/profile/delete-status.js +0 -3
- package/dist/commands/profile/get.js +0 -4
- package/dist/commands/profile/update-avatar.js +0 -3
- package/dist/commands/profile/update-status.js +1 -4
- package/dist/commands/reactions/add.js +3 -6
- package/dist/commands/reactions/remove.js +3 -6
- package/dist/commands/read-member/list-readers.js +0 -3
- package/dist/commands/search/list-chats.js +0 -5
- package/dist/commands/search/list-messages.js +0 -3
- package/dist/commands/search/list-users.js +0 -5
- package/dist/commands/security/list.js +0 -5
- package/dist/commands/tasks/create.js +1 -6
- package/dist/commands/tasks/delete.js +0 -3
- package/dist/commands/tasks/get.js +0 -3
- package/dist/commands/tasks/list.js +0 -5
- package/dist/commands/tasks/update.js +2 -6
- package/dist/commands/threads/add.js +0 -4
- package/dist/commands/threads/list.js +0 -4
- package/dist/commands/users/create.js +0 -5
- package/dist/commands/users/delete.js +0 -3
- package/dist/commands/users/get-status.js +0 -3
- package/dist/commands/users/get.js +0 -3
- package/dist/commands/users/list.js +0 -5
- package/dist/commands/users/remove-avatar.js +0 -3
- package/dist/commands/users/remove-status.js +0 -3
- package/dist/commands/users/update-avatar.js +0 -3
- package/dist/commands/users/update-status.js +1 -4
- package/dist/commands/users/update.js +4 -4
- package/dist/commands/views/open.js +0 -5
- package/dist/commands/views/submit-response.js +0 -3
- package/dist/data/alternatives.json +5 -9
- package/dist/data/changelog.json +66 -0
- package/dist/data/endpoints.json +1 -1
- package/dist/help.js +0 -1
- package/dist/hooks/command-not-found.js +0 -1
- package/dist/hooks/init.js +5 -1
- package/dist/oauth.js +9 -4
- package/dist/token-refresh.js +61 -14
- package/oclif.manifest.json +1 -1
- package/package.json +1 -1
- package/dist/commands/guide.js +0 -90
- package/dist/data/workflows.json +0 -1058
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2026.10.3 (28 октября 2026)
|
|
4
|
+
|
|
5
|
+
- **Изменено** (guide): Команда убрана вместе со сценариями: как решать задачи в Пачке, агенту рассказывают скиллы (https://dev.pachca.com/guides/mcp/plugin), а флаги каждой команды показывает `pachca <команда> --help`
|
|
6
|
+
- **Изменено**: Из `--help` команд убран блок примеров со сценариями
|
|
7
|
+
- **Изменено** (api): `api ls` и справка `--describe`, `--spec`, `--docs` работают без токена: они читают встроенную спецификацию и в API не обращаются
|
|
8
|
+
- **Добавлено** (important-messages list, important-messages create, important-messages delete): Новые команды — раздел «Важное» владельца токена: список отмеченных сообщений, добавление сообщения и удаление из раздела
|
|
9
|
+
- **Добавлено** (bots get-stream): Новая команда — ссылка на поток событий бота
|
|
10
|
+
- **Добавлено** (users update): Значение `guest` у `--role` вместе с флагом `--chat-ids` переводит сотрудника в гости
|
|
11
|
+
- **Добавлено** (chats create): Команда предупреждает в stderr об идентификаторах из `--group-tag-ids`, которых нет среди тегов пространства
|
|
12
|
+
- **Добавлено**: В выводе команд с сообщениями появилось поле `important`: сообщение в разделе «Важное» владельца токена
|
|
13
|
+
- **Изменено** (auth logout): После входа через браузер команда закрывает вход на сервере и при истёкшем токене: сначала обновляет его, потом отзывает свежий
|
|
14
|
+
- **Изменено** (auth logout): `token_revoked: true` значит, что вход на сервере закрыт, в том числе если его закрыли раньше, а при `false` закрыть вход не удалось, и его нужно отозвать в списке «Токены CLI»
|
|
15
|
+
- **Изменено**: Ответы `500`, `502`, `503`, `504` и сетевую ошибку CLI повторяет до трёх раз только у запросов GET, PUT и DELETE, POST и PATCH после них не повторяются, а `504` с кодом `timeout` (поиск не уложился по времени) приходит ошибкой сразу
|
|
16
|
+
- **Изменено**: Подсказки при опечатке в команде предлагают только существующие команды, без `pachca skill …`
|
|
17
|
+
- **Исправлено**: Описание флага `--no-retry` уточнено: он отключает повторы после `429`, `5xx` и сетевой ошибки
|
|
18
|
+
|
|
3
19
|
## 2026.10.2 (21 октября 2026)
|
|
4
20
|
|
|
5
21
|
- **Добавлено** (security list): Флаг `--event-key` принимает события входа по QR-коду: `login_grant_created`, `login_grant_approved` и `login_grant_denied`
|
package/README.md
CHANGED
|
@@ -14,31 +14,33 @@ npx -y @pachca/cli users list
|
|
|
14
14
|
## Быстрый старт
|
|
15
15
|
|
|
16
16
|
```
|
|
17
|
-
pachca auth login #
|
|
17
|
+
pachca auth login # вход через браузер
|
|
18
18
|
pachca users list # список сотрудников
|
|
19
19
|
pachca messages create --entity-id 123 --content "Привет!"
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
Какой токен выбрать: https://dev.pachca.com/api/authorization
|
|
23
23
|
|
|
24
24
|
## Использование в агентах (Claude, Cursor и др.)
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
Вход запускает сотрудник в своём терминале командой `pachca auth login` и подтверждает в браузере. Агент проверяет вход командой `pachca auth status`. Токен в разговоре агенту не передают.
|
|
27
27
|
|
|
28
28
|
```
|
|
29
|
-
#
|
|
30
|
-
#
|
|
31
|
-
pachca
|
|
29
|
+
pachca auth status # есть ли вход и под кем
|
|
30
|
+
pachca api ls # справка по API без входа и без токена
|
|
31
|
+
pachca api POST /messages --describe
|
|
32
|
+
```
|
|
32
33
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
В CI и у агентов без сотрудника токен приходит из переменной окружения, `auth login` не нужен:
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
PACHCA_TOKEN=$TOKEN pachca users list --no-input
|
|
36
38
|
```
|
|
37
39
|
|
|
38
|
-
|
|
40
|
+
Готовый токен сохраняют через stdin, а не аргументом: аргумент остаётся в истории оболочки и в списке процессов.
|
|
39
41
|
|
|
40
42
|
```
|
|
41
|
-
|
|
43
|
+
pbpaste | pachca auth login --token -
|
|
42
44
|
```
|
|
43
45
|
|
|
44
46
|
## Профили (несколько токенов)
|
|
@@ -52,18 +54,7 @@ pachca auth list
|
|
|
52
54
|
pachca auth switch bot-notify
|
|
53
55
|
```
|
|
54
56
|
|
|
55
|
-
|
|
56
|
-
В CI — через переменную окружения PACHCA_TOKEN.
|
|
57
|
-
|
|
58
|
-
## Поиск по сценариям
|
|
59
|
-
|
|
60
|
-
Не знаете какую команду использовать? Поищите по задаче:
|
|
61
|
-
|
|
62
|
-
```
|
|
63
|
-
pachca guide "отправить файл"
|
|
64
|
-
pachca guide "создать беседу и добавить участников"
|
|
65
|
-
pachca guide # список всех сценариев
|
|
66
|
-
```
|
|
57
|
+
Токен хранится в хранилище ключей ОС, в `~/.config/pachca/config.toml` только имя, почта и права. Где хранилища нет, токен лежит в этом файле, CLI говорит об этом при входе.
|
|
67
58
|
|
|
68
59
|
<!-- AUTO:COMMANDS -->
|
|
69
60
|
## Команды
|
|
@@ -97,6 +88,7 @@ pachca guide # список всех сценариев
|
|
|
97
88
|
| `pachca bots reissue-token` | Перевыпуск токена бота |
|
|
98
89
|
| `pachca bots list-company` | Список ботов пространства |
|
|
99
90
|
| `pachca bots list-events` | История событий |
|
|
91
|
+
| `pachca bots get-stream` | Поток событий |
|
|
100
92
|
| `pachca bots remove-event` | Удаление события истории |
|
|
101
93
|
|
|
102
94
|
### chats
|
|
@@ -163,6 +155,14 @@ pachca guide # список всех сценариев
|
|
|
163
155
|
| `pachca group-tags delete` | Удаление тега |
|
|
164
156
|
| `pachca group-tags list-users` | Список сотрудников тега |
|
|
165
157
|
|
|
158
|
+
### important-messages
|
|
159
|
+
|
|
160
|
+
| Команда | Описание |
|
|
161
|
+
|---------|---------|
|
|
162
|
+
| `pachca important-messages list` | Список важных сообщений |
|
|
163
|
+
| `pachca important-messages create` | Добавление сообщения в важные |
|
|
164
|
+
| `pachca important-messages delete` | Удаление сообщения из важных |
|
|
165
|
+
|
|
166
166
|
### messages
|
|
167
167
|
|
|
168
168
|
| Команда | Описание |
|
|
@@ -275,7 +275,7 @@ pachca guide # список всех сценариев
|
|
|
275
275
|
| `--no-input` | | Отключить интерактивные промпты |
|
|
276
276
|
| `--dry-run` | | Показать запрос без отправки |
|
|
277
277
|
| `--timeout <value>` | | Таймаут запроса в секундах (по умолчанию 30) |
|
|
278
|
-
| `--no-retry` | | Отключить
|
|
278
|
+
| `--no-retry` | | Отключить автоповтор при 429, 5xx и сетевых ошибках |
|
|
279
279
|
| `--plain` | | Плоский вывод: TSV без заголовка, ID первым, без цвета (для скриптов) |
|
|
280
280
|
|
|
281
281
|
<!-- AUTO:FLAGS:END -->
|
package/README.template.md
CHANGED
|
@@ -14,31 +14,33 @@ npx -y @pachca/cli users list
|
|
|
14
14
|
## Быстрый старт
|
|
15
15
|
|
|
16
16
|
```
|
|
17
|
-
pachca auth login #
|
|
17
|
+
pachca auth login # вход через браузер
|
|
18
18
|
pachca users list # список сотрудников
|
|
19
19
|
pachca messages create --entity-id 123 --content "Привет!"
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
Какой токен выбрать: https://dev.pachca.com/api/authorization
|
|
23
23
|
|
|
24
24
|
## Использование в агентах (Claude, Cursor и др.)
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
Вход запускает сотрудник в своём терминале командой `pachca auth login` и подтверждает в браузере. Агент проверяет вход командой `pachca auth status`. Токен в разговоре агенту не передают.
|
|
27
27
|
|
|
28
28
|
```
|
|
29
|
-
#
|
|
30
|
-
#
|
|
31
|
-
pachca
|
|
29
|
+
pachca auth status # есть ли вход и под кем
|
|
30
|
+
pachca api ls # справка по API без входа и без токена
|
|
31
|
+
pachca api POST /messages --describe
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
В CI и у агентов без сотрудника токен приходит из переменной окружения, `auth login` не нужен:
|
|
32
35
|
|
|
33
|
-
|
|
34
|
-
pachca users list
|
|
35
|
-
pachca messages create --entity-id 123 --content "Привет!"
|
|
36
|
+
```
|
|
37
|
+
PACHCA_TOKEN=$TOKEN pachca users list --no-input
|
|
36
38
|
```
|
|
37
39
|
|
|
38
|
-
|
|
40
|
+
Готовый токен сохраняют через stdin, а не аргументом: аргумент остаётся в истории оболочки и в списке процессов.
|
|
39
41
|
|
|
40
42
|
```
|
|
41
|
-
|
|
43
|
+
pbpaste | pachca auth login --token -
|
|
42
44
|
```
|
|
43
45
|
|
|
44
46
|
## Профили (несколько токенов)
|
|
@@ -52,18 +54,7 @@ pachca auth list
|
|
|
52
54
|
pachca auth switch bot-notify
|
|
53
55
|
```
|
|
54
56
|
|
|
55
|
-
|
|
56
|
-
В CI — через переменную окружения PACHCA_TOKEN.
|
|
57
|
-
|
|
58
|
-
## Поиск по сценариям
|
|
59
|
-
|
|
60
|
-
Не знаете какую команду использовать? Поищите по задаче:
|
|
61
|
-
|
|
62
|
-
```
|
|
63
|
-
pachca guide "отправить файл"
|
|
64
|
-
pachca guide "создать беседу и добавить участников"
|
|
65
|
-
pachca guide # список всех сценариев
|
|
66
|
-
```
|
|
57
|
+
Токен хранится в хранилище ключей ОС, в `~/.config/pachca/config.toml` только имя, почта и права. Где хранилища нет, токен лежит в этом файле, CLI говорит об этом при входе.
|
|
67
58
|
|
|
68
59
|
<!-- AUTO:COMMANDS -->
|
|
69
60
|
<!-- AUTO:COMMANDS:END -->
|
package/dist/base-command.js
CHANGED
|
@@ -57,7 +57,7 @@ export class BaseCommand extends Command {
|
|
|
57
57
|
min: 1,
|
|
58
58
|
}),
|
|
59
59
|
'no-retry': Flags.boolean({
|
|
60
|
-
description: 'Disable auto-retry on 429
|
|
60
|
+
description: 'Disable auto-retry on 429, 5xx and network errors',
|
|
61
61
|
default: false,
|
|
62
62
|
}),
|
|
63
63
|
json: Flags.boolean({
|
package/dist/client.js
CHANGED
|
@@ -24,6 +24,11 @@ export function getBaseUrl() {
|
|
|
24
24
|
}
|
|
25
25
|
const MAX_RETRIES = 3;
|
|
26
26
|
const DEFAULT_TIMEOUT = 30;
|
|
27
|
+
const RETRYABLE_5XX = new Set([500, 502, 503, 504]);
|
|
28
|
+
// A 5xx says nothing about whether the server already applied the request, and
|
|
29
|
+
// the API has no idempotency key: a retried POST /messages sends the message
|
|
30
|
+
// twice. These methods are safe to repeat, the same set as in the SDKs.
|
|
31
|
+
const IDEMPOTENT_METHODS = new Set(['GET', 'HEAD', 'OPTIONS', 'PUT', 'DELETE']);
|
|
27
32
|
function buildUrl(apiPath, query) {
|
|
28
33
|
const base = apiPath.startsWith('http://') || apiPath.startsWith('https://')
|
|
29
34
|
? apiPath
|
|
@@ -101,9 +106,11 @@ export async function request(opts, clientFlags) {
|
|
|
101
106
|
// means by `--timeout 0`. The env var already ignored 0; make the flag agree.
|
|
102
107
|
const timeoutSeconds = requestedTimeout > 0 ? requestedTimeout : DEFAULT_TIMEOUT;
|
|
103
108
|
const noRetry = opts.noRetry ?? clientFlags?.['no-retry'] ?? false;
|
|
104
|
-
|
|
105
|
-
//
|
|
106
|
-
|
|
109
|
+
const method = opts.method.toUpperCase();
|
|
110
|
+
// The same set is retried after a 5xx and after a network error. A repeated
|
|
111
|
+
// DELETE whose first attempt went through answers 404, which the caller sees
|
|
112
|
+
// as an error, but it never deletes anything twice.
|
|
113
|
+
const idempotent = IDEMPOTENT_METHODS.has(method);
|
|
107
114
|
const fetchHeaders = {
|
|
108
115
|
...(opts.noAuth ? {} : { Authorization: `Bearer ${opts.token}` }),
|
|
109
116
|
Accept: 'application/json',
|
|
@@ -178,35 +185,32 @@ export async function request(opts, clientFlags) {
|
|
|
178
185
|
continue;
|
|
179
186
|
}
|
|
180
187
|
}
|
|
181
|
-
// Handle
|
|
182
|
-
// load balancer says nothing about whether the
|
|
183
|
-
// the write — retrying a POST there duplicates
|
|
184
|
-
|
|
185
|
-
const baseMs = 1000;
|
|
186
|
-
const waitMs = baseMs * Math.pow(2, attempt) + Math.random() * baseMs;
|
|
187
|
-
if (clientFlags?.verbose) {
|
|
188
|
-
process.stderr.write(`${ansis.dim(`⏳ Service unavailable, retrying in ${Math.round(waitMs)}ms...`)}\n`);
|
|
189
|
-
}
|
|
190
|
-
await sleep(waitMs);
|
|
191
|
-
continue;
|
|
192
|
-
}
|
|
193
|
-
// Parse response body
|
|
194
|
-
const contentType = response.headers.get('content-type') || '';
|
|
188
|
+
// Handle 5xx with backoff, for idempotent methods only. Unlike 429, a 5xx
|
|
189
|
+
// from a proxy or a draining load balancer says nothing about whether the
|
|
190
|
+
// backend already committed the write — retrying a POST there duplicates
|
|
191
|
+
// the message.
|
|
195
192
|
let data;
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
//
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
193
|
+
let bodyRead = false;
|
|
194
|
+
if (RETRYABLE_5XX.has(response.status) && idempotent && !noRetry && attempt < MAX_RETRIES) {
|
|
195
|
+
// A 504 with the code `timeout` is a search the server stopped because
|
|
196
|
+
// the query is too heavy: the same query would time out again, so it
|
|
197
|
+
// goes back to the caller at once. A 504 from a proxy has no such code.
|
|
198
|
+
if (response.status === 504) {
|
|
199
|
+
data = await readBody(response, opts.isBinary).catch(() => null);
|
|
200
|
+
bodyRead = true;
|
|
201
|
+
}
|
|
202
|
+
if (!isQueryTimeout(response.status, data)) {
|
|
203
|
+
const baseMs = 1000;
|
|
204
|
+
const waitMs = baseMs * Math.pow(2, attempt) + Math.random() * baseMs;
|
|
205
|
+
if (clientFlags?.verbose) {
|
|
206
|
+
process.stderr.write(`${ansis.dim(`⏳ Server error ${response.status}, retrying in ${Math.round(waitMs)}ms...`)}\n`);
|
|
207
|
+
}
|
|
208
|
+
await sleep(waitMs);
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
209
211
|
}
|
|
212
|
+
if (!bodyRead)
|
|
213
|
+
data = await readBody(response, opts.isBinary);
|
|
210
214
|
// Handle errors
|
|
211
215
|
if (!response.ok) {
|
|
212
216
|
s?.stop('');
|
|
@@ -231,8 +235,7 @@ export async function request(opts, clientFlags) {
|
|
|
231
235
|
});
|
|
232
236
|
}
|
|
233
237
|
lastError = error;
|
|
234
|
-
|
|
235
|
-
if (!safeMethod || noRetry || attempt >= MAX_RETRIES) {
|
|
238
|
+
if (!idempotent || noRetry || attempt >= MAX_RETRIES) {
|
|
236
239
|
break;
|
|
237
240
|
}
|
|
238
241
|
}
|
|
@@ -245,6 +248,27 @@ export async function request(opts, clientFlags) {
|
|
|
245
248
|
message: lastError?.message || 'Failed to connect to server',
|
|
246
249
|
});
|
|
247
250
|
}
|
|
251
|
+
async function readBody(response, isBinary) {
|
|
252
|
+
const contentType = response.headers.get('content-type') || '';
|
|
253
|
+
if (response.status === 204 || response.headers.get('content-length') === '0') {
|
|
254
|
+
return null;
|
|
255
|
+
}
|
|
256
|
+
if (isBinary && response.ok) {
|
|
257
|
+
// Тело файла нельзя читать как текст: любой байт вне UTF-8 портится
|
|
258
|
+
// при декодировании, и сохранённый файл оказывается битым.
|
|
259
|
+
return Buffer.from(await response.arrayBuffer());
|
|
260
|
+
}
|
|
261
|
+
if (contentType.includes('application/json')) {
|
|
262
|
+
return response.json();
|
|
263
|
+
}
|
|
264
|
+
return response.text();
|
|
265
|
+
}
|
|
266
|
+
function isQueryTimeout(status, body) {
|
|
267
|
+
return (status === 504 &&
|
|
268
|
+
isRecord(body) &&
|
|
269
|
+
Array.isArray(body.errors) &&
|
|
270
|
+
body.errors.some((error) => isRecord(error) && error.code === 'timeout'));
|
|
271
|
+
}
|
|
248
272
|
// Недостающий скоуп по RFC 6750 приходит в параметре scope заголовка
|
|
249
273
|
// WWW-Authenticate: Bearer error="insufficient_scope", …, scope="profile:read"
|
|
250
274
|
function scopeFromChallenge(header) {
|
package/dist/commands/api.js
CHANGED
|
@@ -160,7 +160,7 @@ export default class Api extends BaseCommand {
|
|
|
160
160
|
const { outputData } = await import('../output.js');
|
|
161
161
|
outputData(data, { ...this.getOutputOptions(), format: outFormat });
|
|
162
162
|
}
|
|
163
|
-
/** Load the build-time endpoint index
|
|
163
|
+
/** Load the build-time endpoint index. */
|
|
164
164
|
async loadEndpoints() {
|
|
165
165
|
try {
|
|
166
166
|
const data = await import('../data/endpoints.json', { with: { type: 'json' } });
|
|
@@ -2,7 +2,7 @@ import { Args } from '@oclif/core';
|
|
|
2
2
|
import * as clack from '@clack/prompts';
|
|
3
3
|
import { BaseCommand } from '../../base-command.js';
|
|
4
4
|
import { listProfiles, deleteProfile, getAuthMethod, getSecretStorage, getProfile } from '../../profiles.js';
|
|
5
|
-
import {
|
|
5
|
+
import { revokeSession } from '../../token-refresh.js';
|
|
6
6
|
import { outputError } from '../../output.js';
|
|
7
7
|
export default class AuthLogout extends BaseCommand {
|
|
8
8
|
static description = 'Удаление сохранённого профиля';
|
|
@@ -72,14 +72,14 @@ export default class AuthLogout extends BaseCommand {
|
|
|
72
72
|
}
|
|
73
73
|
const authMethod = getAuthMethod(profiles[profileName]);
|
|
74
74
|
const storage = getSecretStorage(profiles[profileName]);
|
|
75
|
-
//
|
|
76
|
-
//
|
|
77
|
-
// CLI
|
|
78
|
-
let
|
|
75
|
+
// Close the login server-side before dropping the profile — afterwards the
|
|
76
|
+
// secrets are gone and there is nothing left to revoke with. Only logins this
|
|
77
|
+
// CLI made can revoke themselves; a pasted token is not ours to cancel.
|
|
78
|
+
let session = 'open';
|
|
79
79
|
if (authMethod === 'oauth') {
|
|
80
|
-
const
|
|
81
|
-
if (
|
|
82
|
-
|
|
80
|
+
const profile = getProfile(profileName);
|
|
81
|
+
if (profile)
|
|
82
|
+
session = await revokeSession(profileName, profile);
|
|
83
83
|
}
|
|
84
84
|
deleteProfile(profileName);
|
|
85
85
|
if (format === 'json') {
|
|
@@ -87,7 +87,11 @@ export default class AuthLogout extends BaseCommand {
|
|
|
87
87
|
deleted_profile: profileName,
|
|
88
88
|
auth: authMethod,
|
|
89
89
|
storage,
|
|
90
|
-
|
|
90
|
+
// True when the server confirms the login is closed. The revoke endpoint
|
|
91
|
+
// answers 200 to a login closed earlier too, so the field reports the
|
|
92
|
+
// state on the server, not which call closed it. False means nothing
|
|
93
|
+
// confirms it: the login may still be alive in the «Токены CLI» list.
|
|
94
|
+
token_revoked: session !== 'open',
|
|
91
95
|
});
|
|
92
96
|
return;
|
|
93
97
|
}
|
|
@@ -96,9 +100,16 @@ export default class AuthLogout extends BaseCommand {
|
|
|
96
100
|
// token when it did not is worse than an extra line here.
|
|
97
101
|
if (!flags.quiet) {
|
|
98
102
|
if (authMethod === 'oauth') {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
103
|
+
if (session === 'revoked') {
|
|
104
|
+
process.stderr.write(` Вход закрыт на сервере, токен удалён с этой машины.\n`);
|
|
105
|
+
}
|
|
106
|
+
else if (session === 'closed') {
|
|
107
|
+
process.stderr.write(` Токен удалён с этой машины. Вход на сервере уже был закрыт.\n`);
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
process.stderr.write(` Токен удалён с этой машины, но закрыть вход на сервере не удалось.\n`);
|
|
111
|
+
process.stderr.write(` Отзовите его в Пачке: Интеграции > API, список «Токены CLI».\n`);
|
|
112
|
+
}
|
|
102
113
|
}
|
|
103
114
|
else {
|
|
104
115
|
process.stderr.write(` Токен удалён с этой машины, но продолжает действовать.\n`);
|
|
@@ -4,9 +4,6 @@ import { BaseCommand } from '../../base-command.js';
|
|
|
4
4
|
import * as clack from '@clack/prompts';
|
|
5
5
|
export default class BotsCreateToken extends BaseCommand {
|
|
6
6
|
static description = "Новый токен бота";
|
|
7
|
-
static examples = [
|
|
8
|
-
"Выпустить боту отдельный токен — Выпусти токен с именем и правами из каталога. Без `--scopes` токен выпускается без прав, право не из каталога отклоняется с `400`:\n $ pachca bots create-token"
|
|
9
|
-
];
|
|
10
7
|
static scope = "bots:write";
|
|
11
8
|
static apiMethod = "POST";
|
|
12
9
|
static apiPath = "/bots/{id}/tokens";
|
|
@@ -4,10 +4,6 @@ import { BaseCommand } from '../../base-command.js';
|
|
|
4
4
|
import * as clack from '@clack/prompts';
|
|
5
5
|
export default class BotsCreate extends BaseCommand {
|
|
6
6
|
static description = "Новый бот";
|
|
7
|
-
static examples = [
|
|
8
|
-
"Создать бота через API и получить токен — Создай бота. Только пользовательским токеном (не токеном бота); `nickname` обязан заканчиваться на `_bot`. Параметры вебхука (Webhook URL, события, команды) можно задать сразу или позже. Скоупы токена бота можно ограничить флагом `--scopes` (если не указать — бот получит набор по умолчанию):\n $ pachca bots create",
|
|
9
|
-
"Настроить бота с исходящим вебхуком — Создай бота, сразу указав Webhook URL и события в одном вызове (детали создания и работы с токеном — в сценарии «Создать бота через API и получить токен»):\n $ pachca bots create"
|
|
10
|
-
];
|
|
11
7
|
static scope = "bots:write";
|
|
12
8
|
static apiMethod = "POST";
|
|
13
9
|
static apiPath = "/bots";
|
|
@@ -4,9 +4,6 @@ import { BaseCommand } from '../../base-command.js';
|
|
|
4
4
|
import * as clack from '@clack/prompts';
|
|
5
5
|
export default class BotsDelete extends BaseCommand {
|
|
6
6
|
static description = "Удаление бота";
|
|
7
|
-
static examples = [
|
|
8
|
-
"Найти и удалить бота — Возьми `id` нужного бота из списка и удали его (скоуп `bots:write`). Доступно создателю бота и администратору, если бот открыт администраторам, — владельцы чатов удалять бота не могут. Все токены бота инвалидируются сразу, бот исключается из всех чатов, его вебхуки удаляются:\n $ pachca bots delete"
|
|
9
|
-
];
|
|
10
7
|
static scope = "bots:write";
|
|
11
8
|
static apiMethod = "DELETE";
|
|
12
9
|
static apiPath = "/bots/{id}";
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base-command.js';
|
|
2
|
+
export default class BotsGetStream extends BaseCommand {
|
|
3
|
+
static description = "Поток событий";
|
|
4
|
+
static scope = "webhooks:events:read";
|
|
5
|
+
static apiMethod = "GET";
|
|
6
|
+
static apiPath = "/webhooks/events/stream";
|
|
7
|
+
static defaultColumns = ["url", "expires_at"];
|
|
8
|
+
static args = {};
|
|
9
|
+
static flags = {
|
|
10
|
+
...BaseCommand.baseFlags,
|
|
11
|
+
};
|
|
12
|
+
async run() {
|
|
13
|
+
const { args, flags } = await this.parse(BotsGetStream);
|
|
14
|
+
this.parsedFlags = flags;
|
|
15
|
+
const { data } = await this.apiRequest({
|
|
16
|
+
method: 'GET',
|
|
17
|
+
path: '/webhooks/events/stream',
|
|
18
|
+
});
|
|
19
|
+
const responseBody = (data ?? {});
|
|
20
|
+
const result = responseBody.data ?? responseBody;
|
|
21
|
+
this.output(result);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -3,9 +3,6 @@ import { Flags } from '@oclif/core';
|
|
|
3
3
|
import { BaseCommand } from '../../base-command.js';
|
|
4
4
|
export default class BotsListCompany extends BaseCommand {
|
|
5
5
|
static description = "Список ботов пространства";
|
|
6
|
-
static examples = [
|
|
7
|
-
"Инвентаризация всех ботов пространства — Получи всех ботов пространства, а не только доступных для редактирования:\n $ pachca bots list-company"
|
|
8
|
-
];
|
|
9
6
|
static scope = "company_bots:read";
|
|
10
7
|
static plan = "corporation";
|
|
11
8
|
static apiMethod = "GET";
|
|
@@ -3,9 +3,6 @@ import { Flags } from '@oclif/core';
|
|
|
3
3
|
import { BaseCommand } from '../../base-command.js';
|
|
4
4
|
export default class BotsListEvents extends BaseCommand {
|
|
5
5
|
static description = "История событий";
|
|
6
|
-
static examples = [
|
|
7
|
-
"Обработка событий через историю (polling) — Получи накопленные события:\n $ pachca bots list-events"
|
|
8
|
-
];
|
|
9
6
|
static scope = "webhooks:events:read";
|
|
10
7
|
static apiMethod = "GET";
|
|
11
8
|
static apiPath = "/webhooks/events";
|
|
@@ -3,9 +3,6 @@ import { Args } from '@oclif/core';
|
|
|
3
3
|
import { BaseCommand } from '../../base-command.js';
|
|
4
4
|
export default class BotsListScopes extends BaseCommand {
|
|
5
5
|
static description = "Каталог прав бота";
|
|
6
|
-
static examples = [
|
|
7
|
-
"Выпустить боту отдельный токен — Пользовательским токеном (создатель бота или администратор, если бот открыт администраторам) получи каталог прав, которые можно выдать этому боту:\n $ pachca bots list-scopes"
|
|
8
|
-
];
|
|
9
6
|
static scope = "bots:read";
|
|
10
7
|
static apiMethod = "GET";
|
|
11
8
|
static apiPath = "/bots/{id}/scopes";
|
|
@@ -3,9 +3,6 @@ import { Flags } from '@oclif/core';
|
|
|
3
3
|
import { BaseCommand } from '../../base-command.js';
|
|
4
4
|
export default class BotsList extends BaseCommand {
|
|
5
5
|
static description = "Список ботов";
|
|
6
|
-
static examples = [
|
|
7
|
-
"Найти и удалить бота — Пользовательским токеном (скоуп `bots:read`) получи список ботов, доступных тебе для редактирования: созданных тобой и тех, чьи настройки открывают тебе доступ. Фильтруй по имени параметром `query`. Пока `meta.paginate.has_next` равен `true`, следующую страницу бери из `meta.paginate.next_page`:\n $ pachca bots list"
|
|
8
|
-
];
|
|
9
6
|
static scope = "bots:read";
|
|
10
7
|
static apiMethod = "GET";
|
|
11
8
|
static apiPath = "/bots";
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import { BaseCommand } from '../../base-command.js';
|
|
2
2
|
export default class BotsRecreateTokenSelf extends BaseCommand {
|
|
3
3
|
static description = "Ротация собственного токена бота";
|
|
4
|
-
static examples = [
|
|
5
|
-
"Ротация токена бота — Или: бот перевыпускает свой основной токен сам (скоуп `bot_self:write`). Если запрос сделан основным токеном, он инвалидируется сразу — обязательно сохрани новый `access_token` из ответа, иначе бот потеряет доступ к API:\n $ pachca bots recreate-token-self"
|
|
6
|
-
];
|
|
7
4
|
static scope = "bot_self:write";
|
|
8
5
|
static apiMethod = "POST";
|
|
9
6
|
static apiPath = "/bot/recreate_token";
|
|
@@ -3,9 +3,6 @@ import { Args } from '@oclif/core';
|
|
|
3
3
|
import { BaseCommand } from '../../base-command.js';
|
|
4
4
|
export default class BotsRecreateToken extends BaseCommand {
|
|
5
5
|
static description = "Ротация токена бота";
|
|
6
|
-
static examples = [
|
|
7
|
-
"Ротация токена бота — Пользовательским токеном (создатель бота или администратор, если бот открыт администраторам) — перевыпусти основной токен по `id` бота: тот, что без имени, а если такого нет, самый старый. Прежнее значение инвалидируется сразу:\n $ pachca bots recreate-token"
|
|
8
|
-
];
|
|
9
6
|
static scope = "bots:write";
|
|
10
7
|
static apiMethod = "POST";
|
|
11
8
|
static apiPath = "/bots/{id}/recreate_token";
|
|
@@ -3,9 +3,6 @@ import { Args } from '@oclif/core';
|
|
|
3
3
|
import { BaseCommand } from '../../base-command.js';
|
|
4
4
|
export default class BotsReissueToken extends BaseCommand {
|
|
5
5
|
static description = "Перевыпуск токена бота";
|
|
6
|
-
static examples = [
|
|
7
|
-
"Ротация токена бота — Отдельный токен бота перевыпускай по его `id` из `pachca bots list-tokens`: значение меняется, имя и права остаются:\n $ pachca bots reissue-token"
|
|
8
|
-
];
|
|
9
6
|
static scope = "bots:write";
|
|
10
7
|
static apiMethod = "POST";
|
|
11
8
|
static apiPath = "/bots/{id}/tokens/{token_id}/reissue";
|
|
@@ -4,9 +4,6 @@ import { BaseCommand } from '../../base-command.js';
|
|
|
4
4
|
import * as clack from '@clack/prompts';
|
|
5
5
|
export default class BotsRemoveEvent extends BaseCommand {
|
|
6
6
|
static description = "Удаление события истории";
|
|
7
|
-
static examples = [
|
|
8
|
-
"Обработка событий через историю (polling) — Удали обработанное событие:\n $ pachca bots remove-event"
|
|
9
|
-
];
|
|
10
7
|
static scope = "webhooks:events:delete";
|
|
11
8
|
static apiMethod = "DELETE";
|
|
12
9
|
static apiPath = "/webhooks/events/{id}";
|
|
@@ -4,9 +4,6 @@ import { BaseCommand } from '../../base-command.js';
|
|
|
4
4
|
import * as clack from '@clack/prompts';
|
|
5
5
|
export default class BotsUpdateWebhook extends BaseCommand {
|
|
6
6
|
static description = "Саморегистрация вебхука бота";
|
|
7
|
-
static examples = [
|
|
8
|
-
"Обновить Webhook URL бота — Или: бот сам обновляет свой webhook своим же токеном — без `id` и без участия администратора (нужен скоуп `bot_self:webhook:write`):\n $ pachca bots update-webhook"
|
|
9
|
-
];
|
|
10
7
|
static scope = "bot_self:webhook:write";
|
|
11
8
|
static apiMethod = "PUT";
|
|
12
9
|
static apiPath = "/bot/webhook";
|
|
@@ -3,11 +3,6 @@ import { Args, Flags } from '@oclif/core';
|
|
|
3
3
|
import { BaseCommand } from '../../base-command.js';
|
|
4
4
|
export default class BotsUpdate extends BaseCommand {
|
|
5
5
|
static description = "Редактирование бота";
|
|
6
|
-
static examples = [
|
|
7
|
-
"Обновить Webhook URL бота — Пользовательским токеном (с правом редактировать бота) — обнови URL по `id` бота. Пустая строка отключает вебхук:\n $ pachca bots update",
|
|
8
|
-
"Включить боту авторизацию от имени сотрудника — Пользовательским токеном (создатель бота или администратор, если бот открыт администраторам) включи авторизацию: где хранится секрет, адреса возврата и права, которые бот попросит у сотрудника. Права бери из `pachca bots list-scopes`:\n $ pachca bots update",
|
|
9
|
-
"Включить боту авторизацию от имени сотрудника — Чтобы бот появился в витрине, добавь описание и опубликуй страницу:\n $ pachca bots update"
|
|
10
|
-
];
|
|
11
6
|
static scope = "bots:write";
|
|
12
7
|
static apiMethod = "PUT";
|
|
13
8
|
static apiPath = "/bots/{id}";
|
|
@@ -3,10 +3,6 @@ import { Args } from '@oclif/core';
|
|
|
3
3
|
import { BaseCommand } from '../../base-command.js';
|
|
4
4
|
export default class ChatsArchive extends BaseCommand {
|
|
5
5
|
static description = "Архивация чата";
|
|
6
|
-
static examples = [
|
|
7
|
-
"Архивация и управление чатом — Архивировать чат:\n $ pachca chats archive",
|
|
8
|
-
"Найти и заархивировать неактивные чаты — Для каждого чата: архивируй:\n $ pachca chats archive"
|
|
9
|
-
];
|
|
10
6
|
static scope = "chats:archive";
|
|
11
7
|
static apiMethod = "PUT";
|
|
12
8
|
static apiPath = "/chats/{id}/archive";
|