@pachca/cli 2026.10.0 → 2026.10.2

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.
Files changed (57) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +7 -5
  3. package/dist/base-command.js +12 -0
  4. package/dist/client.js +2 -1
  5. package/dist/commands/bots/create.js +1 -1
  6. package/dist/commands/bots/list-company.js +1 -1
  7. package/dist/commands/bots/list-events.js +1 -1
  8. package/dist/commands/bots/list-tokens.js +1 -1
  9. package/dist/commands/bots/list.js +2 -2
  10. package/dist/commands/bots/remove-avatar.js +42 -0
  11. package/dist/commands/bots/remove-event.js +1 -1
  12. package/dist/commands/bots/update-avatar.js +51 -0
  13. package/dist/commands/bots/update.js +4 -4
  14. package/dist/commands/chats/create.js +3 -2
  15. package/dist/commands/chats/download-export.js +1 -1
  16. package/dist/commands/chats/get.js +1 -1
  17. package/dist/commands/chats/list-company.js +1 -1
  18. package/dist/commands/chats/list.js +1 -1
  19. package/dist/commands/chats/mark-unread.js +1 -1
  20. package/dist/commands/chats/request-export.js +4 -2
  21. package/dist/commands/drafts/list.js +1 -1
  22. package/dist/commands/files/direct-url.js +8 -4
  23. package/dist/commands/group-tags/get.js +1 -1
  24. package/dist/commands/group-tags/list-users.js +2 -2
  25. package/dist/commands/group-tags/list.js +3 -3
  26. package/dist/commands/members/add.js +2 -2
  27. package/dist/commands/members/list.js +2 -2
  28. package/dist/commands/members/remove-group-tag.js +1 -1
  29. package/dist/commands/members/remove.js +1 -1
  30. package/dist/commands/members/update.js +1 -1
  31. package/dist/commands/messages/create.js +9 -10
  32. package/dist/commands/messages/get.js +1 -1
  33. package/dist/commands/messages/list.js +1 -1
  34. package/dist/commands/messages/update.js +1 -1
  35. package/dist/commands/profile/update-status.js +3 -32
  36. package/dist/commands/reactions/list.js +1 -1
  37. package/dist/commands/read-member/list-readers.js +1 -1
  38. package/dist/commands/search/list-chats.js +2 -2
  39. package/dist/commands/search/list-messages.js +6 -6
  40. package/dist/commands/search/list-users.js +4 -4
  41. package/dist/commands/security/list.js +2 -2
  42. package/dist/commands/tasks/get.js +1 -1
  43. package/dist/commands/tasks/list.js +5 -5
  44. package/dist/commands/threads/get.js +1 -1
  45. package/dist/commands/threads/list.js +2 -2
  46. package/dist/commands/upload.js +5 -2
  47. package/dist/commands/users/get.js +1 -1
  48. package/dist/commands/users/list.js +1 -1
  49. package/dist/commands/users/update-status.js +3 -32
  50. package/dist/commands/users/update.js +2 -2
  51. package/dist/commands/views/open.js +2 -2
  52. package/dist/data/alternatives.json +7 -5
  53. package/dist/data/changelog.json +52 -0
  54. package/dist/data/endpoints.json +1 -1
  55. package/dist/data/workflows.json +7 -7
  56. package/oclif.manifest.json +1 -1
  57. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## 2026.10.2 (21 октября 2026)
4
+
5
+ - **Добавлено** (security list): Флаг `--event-key` принимает события входа по QR-коду: `login_grant_created`, `login_grant_approved` и `login_grant_denied`
6
+
7
+ ## 2026.10.1 (20 октября 2026)
8
+
9
+ - **Изменено** (chats request-export): Команда выводит номер выгрузки `id`: с ним `pachca chats download-export` забирает архив, когда тот соберётся
10
+ - **Добавлено** (chats create): Команда предупреждает в stderr об идентификаторах из `--member-ids`, которых не удалось добавить в чат
11
+ - **Добавлено** (bots update-avatar, bots remove-avatar): Новые команды — аватар бота: загрузка файла флагом `--file` и удаление
12
+ - **Добавлено** (bots get): В `webhook` приходят адрес входящего вебхука `url`, секрет подписи `secret_token` и тело последнего запроса `last_request_body`, если у токена есть скоуп `bots:write` и вы можете управлять токенами бота
13
+ - **Изменено** (messages create): Сообщение уходит без `--content`, если к нему приложены файлы
14
+ - **Изменено** (profile update-status, users update-status): `--emoji` и `--title` нужны, только когда статуса ещё нет — продлить статус можно одним `--expires-at`
15
+ - **Изменено** (upload, files direct-url): `pachca upload` передаёт в форме загрузки `acl` и `bucket`, только если они пришли, а у `pachca files direct-url` флаг `--acl` необязателен и есть флаг `--bucket`: в части пространств метод `Получение подписи, ключа и других параметров` отдаёт `bucket` вместо `acl`
16
+
3
17
  ## 2026.10.0 (13 октября 2026)
4
18
 
5
19
  - **Добавлено** (bots list-tokens, bots create-token, bots update-token, bots reissue-token, bots delete-token): Новые команды — токены бота: у бота может быть несколько токенов, у каждого своё имя и права. Значение токена показывается один раз, при выпуске и перевыпуске.
package/README.md CHANGED
@@ -85,6 +85,8 @@ pachca guide # список всех сценариев
85
85
  | `pachca bots get` | Информация о боте |
86
86
  | `pachca bots update` | Редактирование бота |
87
87
  | `pachca bots delete` | Удаление бота |
88
+ | `pachca bots update-avatar` | Загрузка аватара бота |
89
+ | `pachca bots remove-avatar` | Удаление аватара бота |
88
90
  | `pachca bots recreate-token` | Ротация токена бота |
89
91
  | `pachca bots rotate-client-secret` | Ротация секрета клиента |
90
92
  | `pachca bots list-scopes` | Каталог прав бота |
@@ -95,7 +97,7 @@ pachca guide # список всех сценариев
95
97
  | `pachca bots reissue-token` | Перевыпуск токена бота |
96
98
  | `pachca bots list-company` | Список ботов пространства |
97
99
  | `pachca bots list-events` | История событий |
98
- | `pachca bots remove-event` | Удаление события |
100
+ | `pachca bots remove-event` | Удаление события истории |
99
101
 
100
102
  ### chats
101
103
 
@@ -119,12 +121,12 @@ pachca guide # список всех сценариев
119
121
  | Команда | Описание |
120
122
  |---------|---------|
121
123
  | `pachca members add-group-tags` | Добавление тегов |
122
- | `pachca members remove-group-tag` | Исключение тега |
124
+ | `pachca members remove-group-tag` | Исключение тега из чата |
123
125
  | `pachca members leave` | Выход из чата |
124
126
  | `pachca members list` | Список участников чата |
125
- | `pachca members add` | Добавление пользователей |
126
- | `pachca members remove` | Исключение пользователя |
127
- | `pachca members update` | Редактирование роли |
127
+ | `pachca members add` | Добавление участников |
128
+ | `pachca members remove` | Исключение участника |
129
+ | `pachca members update` | Редактирование роли участника |
128
130
 
129
131
  ### custom-properties
130
132
 
@@ -209,6 +209,18 @@ export class BaseCommand extends Command {
209
209
  }
210
210
  outputData(data, opts);
211
211
  }
212
+ /**
213
+ * Warn about a non-empty list from the response `meta` (e.g. `not_found_member_ids`).
214
+ *
215
+ * stdout keeps printing only `data`, so `-o json` output keeps its shape. The list
216
+ * goes to stderr in every output mode, like the other `⚠` notices.
217
+ */
218
+ warnMetaList(meta, field, message, hint) {
219
+ const value = meta && typeof meta === 'object' ? meta[field] : undefined;
220
+ if (!Array.isArray(value) || value.length === 0)
221
+ return;
222
+ process.stderr.write(`⚠ ${message}: ${value.join(', ')}.\n ${hint}\n`);
223
+ }
212
224
  /**
213
225
  * Output a success message to stderr.
214
226
  */
package/dist/client.js CHANGED
@@ -33,8 +33,9 @@ function buildUrl(apiPath, query) {
33
33
  for (const [key, value] of Object.entries(query)) {
34
34
  if (value !== undefined) {
35
35
  if (Array.isArray(value)) {
36
+ // The key already carries the form the spec declares, `name[]` for a list.
36
37
  for (const v of value) {
37
- url.searchParams.append(`${key}[]`, String(v));
38
+ url.searchParams.append(key, String(v));
38
39
  }
39
40
  }
40
41
  else {
@@ -41,7 +41,7 @@ export default class BotsCreate extends BaseCommand {
41
41
  description: "Шаблон форматирования входящего вебхука",
42
42
  }),
43
43
  'template-engine': Flags.string({
44
- description: "Шаблонизатор для обработки шаблона входящего вебхука",
44
+ description: "Шаблонизатор для обработки шаблона входящего вебхука. Без этого поля бот получает `liquid`, а пустой бот (`empty: true`) — `mustache`.",
45
45
  }),
46
46
  'challenge-key': Flags.string({
47
47
  description: "Название поля проверки для верификации входящего вебхука",
@@ -52,7 +52,7 @@ export default class BotsListCompany extends BaseCommand {
52
52
  const paginate = meta?.paginate;
53
53
  nextCursor = paginate?.next_page;
54
54
  pages++;
55
- // Условие конца: списочные методы — has_next === false; методы поиска и /users?query= (без has_next) — пустой data
55
+ // Условие конца: списочные методы и /users?query= — has_next === false; методы поиска (без has_next) — пустой data
56
56
  const hasNext = paginate?.has_next;
57
57
  if (typeof hasNext === 'boolean') {
58
58
  if (!hasNext)
@@ -47,7 +47,7 @@ export default class BotsListEvents extends BaseCommand {
47
47
  const paginate = meta?.paginate;
48
48
  nextCursor = paginate?.next_page;
49
49
  pages++;
50
- // Условие конца: списочные методы — has_next === false; методы поиска и /users?query= (без has_next) — пустой data
50
+ // Условие конца: списочные методы и /users?query= — has_next === false; методы поиска (без has_next) — пустой data
51
51
  const hasNext = paginate?.has_next;
52
52
  if (typeof hasNext === 'boolean') {
53
53
  if (!hasNext)
@@ -49,7 +49,7 @@ export default class BotsListTokens extends BaseCommand {
49
49
  const paginate = meta?.paginate;
50
50
  nextCursor = paginate?.next_page;
51
51
  pages++;
52
- // Условие конца: списочные методы — has_next === false; методы поиска и /users?query= (без has_next) — пустой data
52
+ // Условие конца: списочные методы и /users?query= — has_next === false; методы поиска (без has_next) — пустой data
53
53
  const hasNext = paginate?.has_next;
54
54
  if (typeof hasNext === 'boolean') {
55
55
  if (!hasNext)
@@ -4,7 +4,7 @@ import { BaseCommand } from '../../base-command.js';
4
4
  export default class BotsList extends BaseCommand {
5
5
  static description = "Список ботов";
6
6
  static examples = [
7
- "Найти и удалить бота — Пользовательским токеном (скоуп `bots:read`) получи список ботов, доступных тебе для редактирования: созданных тобой и тех, чьи настройки открывают тебе доступ. Фильтруй по имени параметром `query`, следующую страницу бери из `meta.paginate.next_page`:\n $ pachca bots list"
7
+ "Найти и удалить бота — Пользовательским токеном (скоуп `bots:read`) получи список ботов, доступных тебе для редактирования: созданных тобой и тех, чьи настройки открывают тебе доступ. Фильтруй по имени параметром `query`. Пока `meta.paginate.has_next` равен `true`, следующую страницу бери из `meta.paginate.next_page`:\n $ pachca bots list"
8
8
  ];
9
9
  static scope = "bots:read";
10
10
  static apiMethod = "GET";
@@ -51,7 +51,7 @@ export default class BotsList extends BaseCommand {
51
51
  const paginate = meta?.paginate;
52
52
  nextCursor = paginate?.next_page;
53
53
  pages++;
54
- // Условие конца: списочные методы — has_next === false; методы поиска и /users?query= (без has_next) — пустой data
54
+ // Условие конца: списочные методы и /users?query= — has_next === false; методы поиска (без has_next) — пустой data
55
55
  const hasNext = paginate?.has_next;
56
56
  if (typeof hasNext === 'boolean') {
57
57
  if (!hasNext)
@@ -0,0 +1,42 @@
1
+ // Auto-generated from openapi.yaml — DO NOT EDIT
2
+ import { Args, Flags } from '@oclif/core';
3
+ import { BaseCommand } from '../../base-command.js';
4
+ import * as clack from '@clack/prompts';
5
+ export default class BotsRemoveAvatar extends BaseCommand {
6
+ static description = "Удаление аватара бота";
7
+ static scope = "bots:write";
8
+ static apiMethod = "DELETE";
9
+ static apiPath = "/bots/{id}/avatar";
10
+ static args = {
11
+ id: Args.integer({
12
+ description: "Идентификатор бота (pachca bots list)",
13
+ required: true,
14
+ }),
15
+ };
16
+ static flags = {
17
+ ...BaseCommand.baseFlags,
18
+ force: Flags.boolean({
19
+ description: 'Пропустить подтверждение',
20
+ default: false,
21
+ }),
22
+ };
23
+ async run() {
24
+ const { args, flags } = await this.parse(BotsRemoveAvatar);
25
+ this.parsedFlags = flags;
26
+ if (!flags.force) {
27
+ if (!this.isInteractive()) {
28
+ this.validationError([{ message: 'Деструктивная операция требует флага --force', flag: 'force' }], { type: 'PACHCA_DESTRUCTIVE_OP_ERROR', hint: "pachca bots remove-avatar <id> --force" });
29
+ }
30
+ const confirm = await clack.confirm({ message: 'Вы уверены?' });
31
+ if (clack.isCancel(confirm) || !confirm) {
32
+ process.stderr.write('Отменено.\n');
33
+ this.exit(0);
34
+ }
35
+ }
36
+ const { data } = await this.apiRequest({
37
+ method: 'DELETE',
38
+ path: `/bots/${args.id}/avatar`,
39
+ });
40
+ this.success('Удалено');
41
+ }
42
+ }
@@ -3,7 +3,7 @@ import { Args, Flags } from '@oclif/core';
3
3
  import { BaseCommand } from '../../base-command.js';
4
4
  import * as clack from '@clack/prompts';
5
5
  export default class BotsRemoveEvent extends BaseCommand {
6
- static description = "Удаление события";
6
+ static description = "Удаление события истории";
7
7
  static examples = [
8
8
  "Обработка событий через историю (polling) — Удали обработанное событие:\n $ pachca bots remove-event"
9
9
  ];
@@ -0,0 +1,51 @@
1
+ // Auto-generated from openapi.yaml — DO NOT EDIT
2
+ import { Args, Flags } from '@oclif/core';
3
+ import { BaseCommand } from '../../base-command.js';
4
+ import * as fs from 'node:fs';
5
+ import * as path from 'node:path';
6
+ export default class BotsUpdateAvatar extends BaseCommand {
7
+ static description = "Загрузка аватара бота";
8
+ static scope = "bots:write";
9
+ static apiMethod = "PUT";
10
+ static apiPath = "/bots/{id}/avatar";
11
+ static defaultColumns = ["image_url"];
12
+ static args = {
13
+ id: Args.integer({
14
+ description: "Идентификатор бота (pachca bots list)",
15
+ required: true,
16
+ }),
17
+ };
18
+ static flags = {
19
+ ...BaseCommand.baseFlags,
20
+ file: Flags.string({
21
+ description: "Файл изображения для аватара",
22
+ }),
23
+ };
24
+ async run() {
25
+ const { args, flags } = await this.parse(BotsUpdateAvatar);
26
+ this.parsedFlags = flags;
27
+ let formData;
28
+ if (flags.file) {
29
+ formData = new FormData();
30
+ if (flags.file === '-') {
31
+ const chunks = [];
32
+ for await (const chunk of process.stdin)
33
+ chunks.push(chunk);
34
+ const blob = new Blob([Buffer.concat(chunks)]);
35
+ formData.append('image', blob, 'stdin');
36
+ }
37
+ else {
38
+ const blob = new Blob([fs.readFileSync(flags.file)]);
39
+ formData.append('image', blob, path.basename(flags.file));
40
+ }
41
+ }
42
+ const { data } = await this.apiRequest({
43
+ method: 'PUT',
44
+ path: `/bots/${args.id}/avatar`,
45
+ formData,
46
+ });
47
+ const responseBody = (data ?? {});
48
+ const result = responseBody.data ?? responseBody;
49
+ this.output(result);
50
+ }
51
+ }
@@ -30,7 +30,7 @@ export default class BotsUpdate extends BaseCommand {
30
30
  description: "URL исходящего вебхука",
31
31
  }),
32
32
  'events': Flags.string({
33
- description: "События, на которые подписан бот",
33
+ description: "События, на которые подписан бот. Список заменяется целиком.",
34
34
  }),
35
35
  'trigger-on': Flags.string({
36
36
  description: "Условие срабатывания исходящего вебхука",
@@ -66,7 +66,7 @@ export default class BotsUpdate extends BaseCommand {
66
66
  description: "Кто может добавлять бота в чаты",
67
67
  }),
68
68
  'can-edit': Flags.string({
69
- description: "Роли, которым, помимо создателя, разрешено редактировать настройки бота. Создатель может редактировать всегда. Пустой массив — редактировать может только создатель.",
69
+ description: "Роли, которым, помимо создателя, разрешено редактировать настройки бота. Создатель может редактировать всегда. Пустой массив — редактировать может только создатель. Список заменяется целиком.",
70
70
  }),
71
71
  'single-chat': Flags.boolean({
72
72
  description: "Ограничивает бота одной беседой или каналом: `true` — бота можно добавить только в один такой чат, `false` — в несколько. Личные чаты и треды в ограничение не входят.",
@@ -76,10 +76,10 @@ export default class BotsUpdate extends BaseCommand {
76
76
  description: "Источник входящего вебхука. Если у бота входящего вебхука не было, он включается.",
77
77
  }),
78
78
  'unfurl-domains': Flags.string({
79
- description: "Домены, ссылки на которые бот разворачивает, не больше 5. Работают вместе с событием `message_link_shared`.",
79
+ description: "Домены, ссылки на которые бот разворачивает, не больше 5. Работают вместе с событием `message_link_shared`. Список заменяется целиком.",
80
80
  }),
81
81
  'oauth-client': Flags.string({
82
- description: "Настройки авторизации от имени сотрудника. Если авторизация выключена, объект её включает, а `null` выключает: выданные сотрудниками авторизации отзываются, страница в витрине удаляется.",
82
+ description: "Настройки авторизации от имени сотрудника. Если авторизация выключена, объект её включает, а `null` выключает: выданные сотрудниками авторизации отзываются, страница в витрине удаляется, собственные токены бота продолжают работать.",
83
83
  }),
84
84
  'promo': Flags.string({
85
85
  description: "Страница бота в витрине. Доступна, только когда у бота включена авторизация.",
@@ -17,7 +17,7 @@ export default class ChatsCreate extends BaseCommand {
17
17
  static flags = {
18
18
  ...BaseCommand.baseFlags,
19
19
  'name': Flags.string({
20
- description: "Название (макс. 255 символов)",
20
+ description: "Название. Пустое название заменяется именем и фамилией владельца токена (у бота — его именем), а если их нет — никнеймом. (макс. 255 символов)",
21
21
  }),
22
22
  'member-ids': Flags.string({
23
23
  description: "Массив идентификаторов пользователей, которые станут участниками",
@@ -38,7 +38,7 @@ export default class ChatsCreate extends BaseCommand {
38
38
  const { args, flags } = await this.parse(ChatsCreate);
39
39
  this.parsedFlags = flags;
40
40
  const missingRequired = [
41
- { flag: 'name', label: "Название", type: 'string' },
41
+ { flag: 'name', label: "Название. Пустое название заменяется именем и фамилией владельца токена (у бота — его именем), а если их нет — никнеймом.", type: 'string' },
42
42
  ].filter((f) => flags[f.flag] === undefined || flags[f.flag] === null);
43
43
  if (missingRequired.length > 0) {
44
44
  if (this.isInteractive()) {
@@ -91,5 +91,6 @@ export default class ChatsCreate extends BaseCommand {
91
91
  const responseBody = (data ?? {});
92
92
  const result = responseBody.data ?? responseBody;
93
93
  this.output(result);
94
+ this.warnMetaList(responseBody.meta, "not_found_member_ids", "Не удалось добавить в чат", "Таких сотрудников нет в пространстве, либо они приостановлены или удалены.");
94
95
  }
95
96
  }
@@ -15,7 +15,7 @@ export default class ChatsDownloadExport extends BaseCommand {
15
15
  static apiPath = "/chats/exports/{id}";
16
16
  static args = {
17
17
  id: Args.integer({
18
- description: "Идентификатор экспорта (pachca chats list)",
18
+ description: "Идентификатор экспорта: `export_id` из вебхука о готовом архиве или число из ссылки вида `/full_exports/{id}` в уведомлении в Пачке (pachca chats list)",
19
19
  required: true,
20
20
  }),
21
21
  };
@@ -9,7 +9,7 @@ export default class ChatsGet extends BaseCommand {
9
9
  static defaultColumns = ["id", "name", "created_at", "owner_id", "channel"];
10
10
  static args = {
11
11
  id: Args.integer({
12
- description: "Идентификатор чата (pachca chats list)",
12
+ description: "Идентификатор чата: в ссылке веб-приложения это число из пути `/chats/{id}` (pachca chats list)",
13
13
  required: true,
14
14
  }),
15
15
  };
@@ -53,7 +53,7 @@ export default class ChatsListCompany extends BaseCommand {
53
53
  const paginate = meta?.paginate;
54
54
  nextCursor = paginate?.next_page;
55
55
  pages++;
56
- // Условие конца: списочные методы — has_next === false; методы поиска и /users?query= (без has_next) — пустой data
56
+ // Условие конца: списочные методы и /users?query= — has_next === false; методы поиска (без has_next) — пустой data
57
57
  const hasNext = paginate?.has_next;
58
58
  if (typeof hasNext === 'boolean') {
59
59
  if (!hasNext)
@@ -86,7 +86,7 @@ export default class ChatsList extends BaseCommand {
86
86
  const paginate = meta?.paginate;
87
87
  nextCursor = paginate?.next_page;
88
88
  pages++;
89
- // Условие конца: списочные методы — has_next === false; методы поиска и /users?query= (без has_next) — пустой data
89
+ // Условие конца: списочные методы и /users?query= — has_next === false; методы поиска (без has_next) — пустой data
90
90
  const hasNext = paginate?.has_next;
91
91
  if (typeof hasNext === 'boolean') {
92
92
  if (!hasNext)
@@ -8,7 +8,7 @@ export default class ChatsMarkUnread extends BaseCommand {
8
8
  static apiPath = "/chats/{id}/unread";
9
9
  static args = {
10
10
  id: Args.integer({
11
- description: "Идентификатор чата или треда (pachca chats list)",
11
+ description: "Идентификатор чата (беседы, канала, личного чата или чата треда) (pachca chats list)",
12
12
  required: true,
13
13
  }),
14
14
  };
@@ -5,13 +5,14 @@ import * as clack from '@clack/prompts';
5
5
  export default class ChatsRequestExport extends BaseCommand {
6
6
  static description = "Экспорт сообщений";
7
7
  static examples = [
8
- "Экспорт истории чата — Запроси экспорт:\n $ pachca chats request-export"
8
+ "Экспорт истории чата — Запроси экспорт и возьми номер выгрузки из `data.id`:\n $ pachca chats request-export"
9
9
  ];
10
10
  static hiddenAliases = ["common:request-export"];
11
11
  static scope = "chat_exports:write";
12
12
  static plan = "corporation";
13
13
  static apiMethod = "POST";
14
14
  static apiPath = "/chats/exports";
15
+ static defaultColumns = ["id"];
15
16
  static requiredFlags = ["start-at", "end-at"];
16
17
  static args = {};
17
18
  static flags = {
@@ -23,7 +24,7 @@ export default class ChatsRequestExport extends BaseCommand {
23
24
  description: "Дата окончания для экспорта в формате YYYY-MM-DD, включительно. Если прислать дату со временем, время молча отбрасывается.",
24
25
  }),
25
26
  'webhook-url': Flags.string({
26
- description: "Адрес, на который придёт вебхук с номером готовой выгрузки. Без него узнать номер неоткуда: заказавший получит письмо и уведомление, а вызывающая программа — ничего.",
27
+ description: "Адрес, на который придёт вебхук с номером готовой выгрузки, когда архив будет собран. Номер приходит в поле `export_id`, а всё тело вебхука описано в разделе [Экспорт](https://dev.pachca.com/guides/export).",
27
28
  }),
28
29
  'chat-ids': Flags.string({
29
30
  description: "Массив идентификаторов чатов. Указывается, если нужно получить сообщения только некоторых чатов.",
@@ -79,6 +80,7 @@ export default class ChatsRequestExport extends BaseCommand {
79
80
  method: 'POST',
80
81
  path: '/chats/exports',
81
82
  body,
83
+ headers: { "Prefer": "return=representation" },
82
84
  });
83
85
  const responseBody = (data ?? {});
84
86
  const result = responseBody.data ?? responseBody;
@@ -59,7 +59,7 @@ export default class DraftsList extends BaseCommand {
59
59
  const paginate = meta?.paginate;
60
60
  nextCursor = paginate?.next_page;
61
61
  pages++;
62
- // Условие конца: списочные методы — has_next === false; методы поиска и /users?query= (без has_next) — пустой data
62
+ // Условие конца: списочные методы и /users?query= — has_next === false; методы поиска (без has_next) — пустой data
63
63
  const hasNext = paginate?.has_next;
64
64
  if (typeof hasNext === 'boolean') {
65
65
  if (!hasNext)
@@ -9,7 +9,7 @@ export default class FilesDirectUrl extends BaseCommand {
9
9
  static hiddenAliases = ["common:direct-url"];
10
10
  static apiMethod = "POST";
11
11
  static apiPath = "/direct_url";
12
- static requiredFlags = ["content-disposition", "acl", "policy", "x-amz-credential", "x-amz-algorithm", "x-amz-date", "x-amz-signature", "key"];
12
+ static requiredFlags = ["content-disposition", "policy", "x-amz-credential", "x-amz-algorithm", "x-amz-date", "x-amz-signature", "key"];
13
13
  static args = {};
14
14
  static flags = {
15
15
  ...BaseCommand.baseFlags,
@@ -21,7 +21,7 @@ export default class FilesDirectUrl extends BaseCommand {
21
21
  description: "Параметр Content-Disposition, полученный в ответе на запрос [Получение подписи, ключа и других параметров](POST /uploads)",
22
22
  }),
23
23
  'acl': Flags.string({
24
- description: "Параметр acl, полученный в ответе на запрос [Получение подписи, ключа и других параметров](POST /uploads)",
24
+ description: "Параметр acl, полученный в ответе на запрос [Получение подписи, ключа и других параметров](POST /uploads). Передаётся, если пришёл в ответе.",
25
25
  }),
26
26
  'policy': Flags.string({
27
27
  description: "Параметр policy, полученный в ответе на запрос [Получение подписи, ключа и других параметров](POST /uploads)",
@@ -41,6 +41,9 @@ export default class FilesDirectUrl extends BaseCommand {
41
41
  'key': Flags.string({
42
42
  description: "Параметр key, полученный в ответе на запрос [Получение подписи, ключа и других параметров](POST /uploads)",
43
43
  }),
44
+ 'bucket': Flags.string({
45
+ description: "Параметр bucket, полученный в ответе на запрос [Получение подписи, ключа и других параметров](POST /uploads). Передаётся, если пришёл в ответе.",
46
+ }),
44
47
  file: Flags.string({
45
48
  description: "Файл для загрузки",
46
49
  }),
@@ -50,7 +53,6 @@ export default class FilesDirectUrl extends BaseCommand {
50
53
  this.parsedFlags = flags;
51
54
  const missingRequired = [
52
55
  { flag: 'content-disposition', label: "Параметр Content-Disposition, полученный в ответе на запрос [Получение подписи, ключа и других параметров](POST /uploads)", type: 'string' },
53
- { flag: 'acl', label: "Параметр acl, полученный в ответе на запрос [Получение подписи, ключа и других параметров](POST /uploads)", type: 'string' },
54
56
  { flag: 'policy', label: "Параметр policy, полученный в ответе на запрос [Получение подписи, ключа и других параметров](POST /uploads)", type: 'string' },
55
57
  { flag: 'x-amz-credential', label: "Параметр x-amz-credential, полученный в ответе на запрос [Получение подписи, ключа и других параметров](POST /uploads)", type: 'string' },
56
58
  { flag: 'x-amz-algorithm', label: "Параметр x-amz-algorithm, полученный в ответе на запрос [Получение подписи, ключа и других параметров](POST /uploads)", type: 'string' },
@@ -78,7 +80,7 @@ export default class FilesDirectUrl extends BaseCommand {
78
80
  }
79
81
  }
80
82
  else {
81
- this.validationError(missingRequired.map((f) => ({ message: `Обязательный флаг --${f.flag} не передан`, flag: f.flag })), { hint: "Обязательные: --content-disposition <string>, --acl <string>, --policy <string>, --x-amz-credential <string>, --x-amz-algorithm <string>, --x-amz-date <string>, --x-amz-signature <string>, --key <string>. pachca introspect files direct-url" });
83
+ this.validationError(missingRequired.map((f) => ({ message: `Обязательный флаг --${f.flag} не передан`, flag: f.flag })), { hint: "Обязательные: --content-disposition <string>, --policy <string>, --x-amz-credential <string>, --x-amz-algorithm <string>, --x-amz-date <string>, --x-amz-signature <string>, --key <string>. pachca introspect files direct-url" });
82
84
  }
83
85
  }
84
86
  let formData;
@@ -100,6 +102,8 @@ export default class FilesDirectUrl extends BaseCommand {
100
102
  formData.append('x-amz-signature', String(flags['x-amz-signature']));
101
103
  if (flags['key'])
102
104
  formData.append('key', String(flags['key']));
105
+ if (flags['bucket'])
106
+ formData.append('bucket', String(flags['bucket']));
103
107
  if (flags.file === '-') {
104
108
  const chunks = [];
105
109
  for await (const chunk of process.stdin)
@@ -9,7 +9,7 @@ export default class GroupTagsGet extends BaseCommand {
9
9
  static defaultColumns = ["id", "name", "users_count"];
10
10
  static args = {
11
11
  id: Args.integer({
12
- description: "Идентификатор тега",
12
+ description: "Идентификатор тега: в ссылке веб-приложения это число из параметра `tag_id`",
13
13
  required: true,
14
14
  }),
15
15
  };
@@ -12,7 +12,7 @@ export default class GroupTagsListUsers extends BaseCommand {
12
12
  static defaultColumns = ["id", "title", "first_name", "last_name", "email"];
13
13
  static args = {
14
14
  id: Args.integer({
15
- description: "Идентификатор тега",
15
+ description: "Идентификатор тега: в ссылке веб-приложения это число из параметра `tag_id`",
16
16
  required: true,
17
17
  }),
18
18
  };
@@ -52,7 +52,7 @@ export default class GroupTagsListUsers extends BaseCommand {
52
52
  const paginate = meta?.paginate;
53
53
  nextCursor = paginate?.next_page;
54
54
  pages++;
55
- // Условие конца: списочные методы — has_next === false; методы поиска и /users?query= (без has_next) — пустой data
55
+ // Условие конца: списочные методы и /users?query= — has_next === false; методы поиска (без has_next) — пустой data
56
56
  const hasNext = paginate?.has_next;
57
57
  if (typeof hasNext === 'boolean') {
58
58
  if (!hasNext)
@@ -38,7 +38,7 @@ export default class GroupTagsList extends BaseCommand {
38
38
  const seenCursors = new Set();
39
39
  while (pages < 500) {
40
40
  const query = {
41
- names: flags['names']?.split(','),
41
+ 'names[]': flags['names']?.split(','),
42
42
  limit: flags.limit,
43
43
  cursor: nextCursor,
44
44
  };
@@ -51,7 +51,7 @@ export default class GroupTagsList extends BaseCommand {
51
51
  const paginate = meta?.paginate;
52
52
  nextCursor = paginate?.next_page;
53
53
  pages++;
54
- // Условие конца: списочные методы — has_next === false; методы поиска и /users?query= (без has_next) — пустой data
54
+ // Условие конца: списочные методы и /users?query= — has_next === false; методы поиска (без has_next) — пустой data
55
55
  const hasNext = paginate?.has_next;
56
56
  if (typeof hasNext === 'boolean') {
57
57
  if (!hasNext)
@@ -85,7 +85,7 @@ export default class GroupTagsList extends BaseCommand {
85
85
  method: 'GET',
86
86
  path: '/group_tags',
87
87
  query: {
88
- names: flags['names']?.split(','),
88
+ 'names[]': flags['names']?.split(','),
89
89
  limit: flags.limit,
90
90
  cursor: flags.cursor,
91
91
  },
@@ -3,7 +3,7 @@ import { Args, Flags } from '@oclif/core';
3
3
  import { BaseCommand } from '../../base-command.js';
4
4
  import * as clack from '@clack/prompts';
5
5
  export default class MembersAdd extends BaseCommand {
6
- static description = "Добавление пользователей";
6
+ static description = "Добавление участников";
7
7
  static examples = [
8
8
  "Подписаться на тред сообщения — Добавь бота в участники чата треда:\n $ pachca members add",
9
9
  "Создать канал и пригласить участников — Или добавь участников позже:\n $ pachca members add",
@@ -25,7 +25,7 @@ export default class MembersAdd extends BaseCommand {
25
25
  description: "Массив идентификаторов пользователей, которые станут участниками",
26
26
  }),
27
27
  'silent': Flags.boolean({
28
- description: "Не создавать в чате системное сообщение о добавлении участника",
28
+ description: "При `true` в чат не приходит системное сообщение о добавлении, а добавленные сотрудники не получают письмо с приглашением. Сообщение бывает только в закрытой беседе, письмо — в беседах и каналах у тех, кто не отключил такие письма. В треде параметр ничего не меняет.",
29
29
  allowNo: true,
30
30
  }),
31
31
  };
@@ -20,7 +20,7 @@ export default class MembersList extends BaseCommand {
20
20
  static flags = {
21
21
  ...BaseCommand.baseFlags,
22
22
  'role': Flags.string({
23
- description: "Роль в чате",
23
+ description: "Роль в чате. В канале пишут создатель, админы и редакторы, а участник там — подписчик.",
24
24
  options: ["all", "owner", "admin", "editor", "member"],
25
25
  default: "all",
26
26
  }),
@@ -59,7 +59,7 @@ export default class MembersList extends BaseCommand {
59
59
  const paginate = meta?.paginate;
60
60
  nextCursor = paginate?.next_page;
61
61
  pages++;
62
- // Условие конца: списочные методы — has_next === false; методы поиска и /users?query= (без has_next) — пустой data
62
+ // Условие конца: списочные методы и /users?query= — has_next === false; методы поиска (без has_next) — пустой data
63
63
  const hasNext = paginate?.has_next;
64
64
  if (typeof hasNext === 'boolean') {
65
65
  if (!hasNext)
@@ -3,7 +3,7 @@ import { Args, Flags } from '@oclif/core';
3
3
  import { BaseCommand } from '../../base-command.js';
4
4
  import * as clack from '@clack/prompts';
5
5
  export default class MembersRemoveGroupTag extends BaseCommand {
6
- static description = "Исключение тега";
6
+ static description = "Исключение тега из чата";
7
7
  static scope = "chat_members:write";
8
8
  static apiMethod = "DELETE";
9
9
  static apiPath = "/chats/{id}/group_tags/{tag_id}";
@@ -3,7 +3,7 @@ import { Args, Flags } from '@oclif/core';
3
3
  import { BaseCommand } from '../../base-command.js';
4
4
  import * as clack from '@clack/prompts';
5
5
  export default class MembersRemove extends BaseCommand {
6
- static description = "Исключение пользователя";
6
+ static description = "Исключение участника";
7
7
  static examples = [
8
8
  "Архивация и управление чатом — Удалить участника:\n $ pachca members remove"
9
9
  ];
@@ -3,7 +3,7 @@ import { Args, Flags } from '@oclif/core';
3
3
  import { BaseCommand } from '../../base-command.js';
4
4
  import * as clack from '@clack/prompts';
5
5
  export default class MembersUpdate extends BaseCommand {
6
- static description = "Редактирование роли";
6
+ static description = "Редактирование роли участника";
7
7
  static examples = [
8
8
  "Архивация и управление чатом — Изменить роль участника:\n $ pachca members update"
9
9
  ];