@pachca/cli 2026.3.8 → 2026.3.10

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 (75) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/base-command.js +1 -43
  3. package/dist/commands/auth/list.js +0 -1
  4. package/dist/commands/auth/login.js +0 -9
  5. package/dist/commands/auth/status.js +0 -10
  6. package/dist/commands/bots/list-events.js +0 -1
  7. package/dist/commands/bots/remove-event.js +0 -1
  8. package/dist/commands/bots/update.js +0 -1
  9. package/dist/commands/chats/archive.js +0 -1
  10. package/dist/commands/chats/create.js +0 -1
  11. package/dist/commands/chats/get.js +0 -1
  12. package/dist/commands/chats/list.js +8 -9
  13. package/dist/commands/chats/unarchive.js +0 -1
  14. package/dist/commands/chats/update.js +0 -1
  15. package/dist/commands/commands.js +5 -12
  16. package/dist/commands/common/custom-properties.js +0 -1
  17. package/dist/commands/common/get-exports.js +0 -1
  18. package/dist/commands/common/request-export.js +0 -1
  19. package/dist/commands/common/uploads.js +0 -1
  20. package/dist/commands/group-tags/create.js +0 -1
  21. package/dist/commands/group-tags/delete.js +0 -1
  22. package/dist/commands/group-tags/get.js +0 -1
  23. package/dist/commands/group-tags/list-users.js +0 -1
  24. package/dist/commands/group-tags/list.js +0 -1
  25. package/dist/commands/group-tags/update.js +0 -1
  26. package/dist/commands/link-previews/add.js +0 -1
  27. package/dist/commands/members/add-group-tags.js +0 -1
  28. package/dist/commands/members/add.js +0 -1
  29. package/dist/commands/members/leave.js +0 -1
  30. package/dist/commands/members/list.js +0 -1
  31. package/dist/commands/members/remove-group-tag.js +0 -1
  32. package/dist/commands/members/remove.js +0 -1
  33. package/dist/commands/members/update.js +0 -1
  34. package/dist/commands/messages/create.js +9 -4
  35. package/dist/commands/messages/delete.js +0 -1
  36. package/dist/commands/messages/get.js +0 -1
  37. package/dist/commands/messages/list.js +9 -5
  38. package/dist/commands/messages/pin.js +0 -1
  39. package/dist/commands/messages/unpin.js +0 -1
  40. package/dist/commands/messages/update.js +0 -1
  41. package/dist/commands/profile/delete-status.js +0 -1
  42. package/dist/commands/profile/get-status.js +0 -1
  43. package/dist/commands/profile/get.js +0 -1
  44. package/dist/commands/profile/update-status.js +0 -1
  45. package/dist/commands/reactions/add.js +0 -1
  46. package/dist/commands/reactions/list.js +0 -1
  47. package/dist/commands/reactions/remove.js +0 -1
  48. package/dist/commands/read-member/list-readers.js +0 -1
  49. package/dist/commands/search/list-chats.js +0 -1
  50. package/dist/commands/search/list-messages.js +0 -1
  51. package/dist/commands/search/list-users.js +0 -1
  52. package/dist/commands/security/list.js +0 -30
  53. package/dist/commands/tasks/create.js +0 -1
  54. package/dist/commands/tasks/delete.js +0 -1
  55. package/dist/commands/tasks/get.js +0 -1
  56. package/dist/commands/tasks/list.js +0 -1
  57. package/dist/commands/tasks/update.js +0 -1
  58. package/dist/commands/threads/add.js +0 -1
  59. package/dist/commands/threads/get.js +0 -1
  60. package/dist/commands/upload.js +0 -1
  61. package/dist/commands/users/create.js +0 -1
  62. package/dist/commands/users/delete.js +0 -1
  63. package/dist/commands/users/get-status.js +0 -1
  64. package/dist/commands/users/get.js +0 -1
  65. package/dist/commands/users/list.js +0 -1
  66. package/dist/commands/users/remove-status.js +0 -1
  67. package/dist/commands/users/update-status.js +0 -1
  68. package/dist/commands/users/update.js +0 -1
  69. package/dist/commands/views/open.js +0 -1
  70. package/dist/data/changelog.json +42 -0
  71. package/dist/hooks/init.js +1 -20
  72. package/dist/profiles.js +0 -8
  73. package/oclif.manifest.json +1 -12709
  74. package/package.json +1 -1
  75. package/dist/commands/auth/refresh.js +0 -67
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## 2026.3.10 (21 марта 2026)
4
+
5
+ - **Изменено** (messages create): Поле link_preview перемещено на верхний уровень тела запроса (раньше было внутри message)
6
+ - **Изменено** (security list): Параметры start-time и end-time стали необязательными
7
+ - **Изменено** (chats list, messages list): Сортировка через --sort и --order вместо --sort-id и --sort-last-message-at
8
+
9
+ ## 2026.3.9 (19 марта 2026)
10
+
11
+ - **Изменено** (all): Убрана клиентская валидация скоупов — проверка разрешений теперь только на стороне API (403)
12
+ - **Изменено** (auth login): Профиль больше не сохраняет список скоупов — только тип, имя и email
13
+ - **Удалено** (auth refresh): Команда удалена — кеширование скоупов больше не используется
14
+
3
15
  ## 2026.3.8 (17 марта 2026)
4
16
 
5
17
  - **Добавлено** (upgrade): Команда pachca upgrade — обновление CLI до последней версии
@@ -1,5 +1,5 @@
1
1
  import { Command, Flags } from '@oclif/core';
2
- import { resolveToken, TokenNotFoundError, ProfileNotFoundError, getDefaults, getActiveProfile, invalidateScopes, } from './profiles.js';
2
+ import { resolveToken, TokenNotFoundError, ProfileNotFoundError, getDefaults, } from './profiles.js';
3
3
  import { ApiError, getExitCode, formatDryRun, request } from './client.js';
4
4
  import { outputData, outputError, outputSuccess } from './output.js';
5
5
  import { defaultOutputFormat, isInteractive } from './utils.js';
@@ -170,38 +170,6 @@ export class BaseCommand extends Command {
170
170
  profile: this.parsedFlags.profile,
171
171
  });
172
172
  }
173
- /**
174
- * Check if the current profile has the required scope.
175
- * Exits with error if scope is missing.
176
- */
177
- checkScope(requiredScope) {
178
- const { profileName, profile } = this.resolveAuth();
179
- if (!profile || !profile.scopes || profile.scopes.length === 0)
180
- return;
181
- if (!profile.scopes.includes(requiredScope)) {
182
- const format = this.getOutputFormat();
183
- if (format === 'json' || !process.stderr.isTTY) {
184
- outputError({
185
- error: 'Insufficient scope',
186
- code: null,
187
- type: 'PACHCA_SCOPE_ERROR',
188
- profile: profileName,
189
- required_scope: requiredScope,
190
- current_scopes: profile.scopes,
191
- }, format);
192
- }
193
- else {
194
- process.stderr.write(`✗ Токен профиля ${profileName} не имеет скоупа ${requiredScope}\n\n`);
195
- process.stderr.write(` Текущие скоупы: ${profile.scopes.join(', ')}\n`);
196
- process.stderr.write(` Требуется: ${requiredScope}\n\n`);
197
- process.stderr.write(` Используйте другой профиль:\n`);
198
- process.stderr.write(` pachca auth switch <profile>\n`);
199
- process.stderr.write(` Или проверьте актуальные скоупы:\n`);
200
- process.stderr.write(` pachca auth refresh ${profileName}\n`);
201
- }
202
- this.exit(3);
203
- }
204
- }
205
173
  /**
206
174
  * Make an authenticated API request.
207
175
  */
@@ -249,16 +217,6 @@ export class BaseCommand extends Command {
249
217
  */
250
218
  async catch(err) {
251
219
  if (err instanceof ApiError) {
252
- // Invalidate cached scopes on 403 insufficient_scope
253
- if (err.details.code === 403 && err.details.type === 'PACHCA_AUTH_ERROR' && err.details.message === 'insufficient_scope') {
254
- const profileName = this.parsedFlags?.profile || process.env.PACHCA_PROFILE || getActiveProfile();
255
- if (profileName) {
256
- invalidateScopes(profileName);
257
- }
258
- err.details.hint = profileName
259
- ? `pachca auth refresh ${profileName}`
260
- : 'pachca auth refresh';
261
- }
262
220
  outputError(err.details, this.getOutputFormat());
263
221
  this.exit(getExitCode(err));
264
222
  }
@@ -20,7 +20,6 @@ export default class AuthList extends BaseCommand {
20
20
  type: profile.type,
21
21
  user: profile.user,
22
22
  email: profile.email || null,
23
- scopes_count: profile.scopes?.length ?? 0,
24
23
  active: name === activeProfile,
25
24
  }));
26
25
  if (entries.length === 0) {
@@ -99,8 +99,6 @@ export default class AuthLogin extends BaseCommand {
99
99
  catch {
100
100
  // profile:read scope not available — use user_id from token info
101
101
  }
102
- // Determine scopes
103
- const scopes = tokenInfo.scopes || [];
104
102
  const profileType = isBot ? 'bot' : 'user';
105
103
  // Save profile
106
104
  const profile = {
@@ -108,8 +106,6 @@ export default class AuthLogin extends BaseCommand {
108
106
  token,
109
107
  user: isBot ? `${userName} (бот)` : userName,
110
108
  email: userEmail,
111
- scopes,
112
- ...(isBot ? { scopes_refreshed_at: new Date().toISOString() } : {}),
113
109
  };
114
110
  setProfile(profileName, profile);
115
111
  // Set as active if no active profile
@@ -123,18 +119,13 @@ export default class AuthLogin extends BaseCommand {
123
119
  type: profileType,
124
120
  user: profile.user,
125
121
  email: userEmail,
126
- scopes,
127
122
  });
128
123
  }
129
124
  else if (!flags.quiet) {
130
125
  const typeLabel = profileType === 'bot' ? 'bot' : 'user';
131
126
  const emailStr = userEmail ? ` (${userEmail})` : '';
132
127
  process.stderr.write(`✔ Подключён как: ${profile.user}${emailStr} [${typeLabel}]\n`);
133
- process.stderr.write(` Скоупы (${scopes.length}): ${scopes.join(' ')}\n`);
134
128
  process.stderr.write(` Профиль сохранён [${profileName}]\n`);
135
- if (isBot) {
136
- process.stderr.write(` ℹ Скоупы бота обновляются автоматически раз в сутки (синхронно при запуске команды)\n`);
137
- }
138
129
  }
139
130
  }
140
131
  }
@@ -30,21 +30,11 @@ export default class AuthStatus extends BaseCommand {
30
30
  type: profile.type,
31
31
  user: profile.user,
32
32
  email: profile.email || null,
33
- scopes: profile.scopes || [],
34
33
  });
35
34
  }
36
35
  else {
37
36
  const emailStr = profile.email ? ` (${profile.email})` : '';
38
37
  process.stderr.write(` Подключён как: ${profile.user}${emailStr} [${profile.type}, profile: ${profileName}]\n`);
39
- if (profile.scopes?.length) {
40
- process.stderr.write(` Скоупы:\n`);
41
- // Print scopes in rows of 3
42
- const scopes = profile.scopes;
43
- for (let i = 0; i < scopes.length; i += 3) {
44
- const row = scopes.slice(i, i + 3).map((s) => s.padEnd(20)).join(' ');
45
- process.stderr.write(` ${row}\n`);
46
- }
47
- }
48
38
  }
49
39
  }
50
40
  }
@@ -27,7 +27,6 @@ export default class BotsListEvents extends BaseCommand {
27
27
  async run() {
28
28
  const { args, flags } = await this.parse(BotsListEvents);
29
29
  this.parsedFlags = flags;
30
- this.checkScope("webhooks:events:read");
31
30
  if (flags.all) {
32
31
  // Auto-pagination
33
32
  const allData = [];
@@ -36,7 +36,6 @@ export default class BotsRemoveEvent extends BaseCommand {
36
36
  this.exit(0);
37
37
  }
38
38
  }
39
- this.checkScope("webhooks:events:delete");
40
39
  const { data } = await this.apiRequest({
41
40
  method: 'DELETE',
42
41
  path: `/webhooks/events/${args.id}`,
@@ -53,7 +53,6 @@ export default class BotsUpdate extends BaseCommand {
53
53
  this.validationError(missingRequired.map((f) => ({ message: `Обязательный флаг --${f.flag} не передан`, flag: f.flag })), { hint: "Обязательные: --webhook <string>. pachca introspect bots update" });
54
54
  }
55
55
  }
56
- this.checkScope("bots:write");
57
56
  const body = { bot: {
58
57
  webhook: flags['webhook'] ? this.parseJSON(flags['webhook'], 'webhook') : undefined,
59
58
  } };
@@ -22,7 +22,6 @@ export default class ChatsArchive extends BaseCommand {
22
22
  async run() {
23
23
  const { args, flags } = await this.parse(ChatsArchive);
24
24
  this.parsedFlags = flags;
25
- this.checkScope("chats:archive");
26
25
  const { data } = await this.apiRequest({
27
26
  method: 'PUT',
28
27
  path: `/chats/${args.id}/archive`,
@@ -64,7 +64,6 @@ export default class ChatsCreate extends BaseCommand {
64
64
  this.validationError(missingRequired.map((f) => ({ message: `Обязательный флаг --${f.flag} не передан`, flag: f.flag })), { hint: "Обязательные: --name <string>. pachca introspect chats create" });
65
65
  }
66
66
  }
67
- this.checkScope("chats:create");
68
67
  const body = { chat: {
69
68
  name: flags['name'],
70
69
  member_ids: flags['member-ids'] ? this.parseJSON(flags['member-ids'], 'member-ids') : undefined,
@@ -22,7 +22,6 @@ export default class ChatsGet extends BaseCommand {
22
22
  async run() {
23
23
  const { args, flags } = await this.parse(ChatsGet);
24
24
  this.parsedFlags = flags;
25
- this.checkScope("chats:read");
26
25
  const { data } = await this.apiRequest({
27
26
  method: 'GET',
28
27
  path: `/chats/${args.id}`,
@@ -15,11 +15,13 @@ export default class ChatsList extends BaseCommand {
15
15
  static args = {};
16
16
  static flags = {
17
17
  ...BaseCommand.baseFlags,
18
- 'sort-id': Flags.string({
19
- description: "Идентификатор чата",
18
+ sort: Flags.string({
19
+ description: "Поле сортировки (id — идентификатор чата, last-message-at — дата и время создания последнего сообщения)",
20
+ options: ["id", "last-message-at"],
20
21
  }),
21
- 'sort-last-message-at': Flags.string({
22
- description: "Дата и время создания последнего сообщения",
22
+ order: Flags.string({
23
+ description: "Порядок сортировки",
24
+ options: ["asc", "desc"],
23
25
  }),
24
26
  'availability': Flags.string({
25
27
  description: "Параметр, который отвечает за доступность и выборку чатов для пользователя",
@@ -48,7 +50,6 @@ export default class ChatsList extends BaseCommand {
48
50
  async run() {
49
51
  const { args, flags } = await this.parse(ChatsList);
50
52
  this.parsedFlags = flags;
51
- this.checkScope("chats:read");
52
53
  if (flags.all) {
53
54
  // Auto-pagination
54
55
  const allData = [];
@@ -57,8 +58,7 @@ export default class ChatsList extends BaseCommand {
57
58
  const seenCursors = new Set();
58
59
  while (pages < 500) {
59
60
  const query = {
60
- 'sort[id]': flags['sort-id'],
61
- 'sort[last_message_at]': flags['sort-last-message-at'],
61
+ ...(flags.sort ? { [`sort[${flags.sort.replace(/-/g, '_')}]`]: flags.order || 'desc' } : {}),
62
62
  availability: flags['availability'],
63
63
  'last_message_at_after': flags['last-message-at-after'],
64
64
  'last_message_at_before': flags['last-message-at-before'],
@@ -100,8 +100,7 @@ export default class ChatsList extends BaseCommand {
100
100
  method: 'GET',
101
101
  path: '/chats',
102
102
  query: {
103
- 'sort[id]': flags['sort-id'],
104
- 'sort[last_message_at]': flags['sort-last-message-at'],
103
+ ...(flags.sort ? { [`sort[${flags.sort.replace(/-/g, '_')}]`]: flags.order || 'desc' } : {}),
105
104
  availability: flags['availability'],
106
105
  'last_message_at_after': flags['last-message-at-after'],
107
106
  'last_message_at_before': flags['last-message-at-before'],
@@ -21,7 +21,6 @@ export default class ChatsUnarchive extends BaseCommand {
21
21
  async run() {
22
22
  const { args, flags } = await this.parse(ChatsUnarchive);
23
23
  this.parsedFlags = flags;
24
- this.checkScope("chats:archive");
25
24
  const { data } = await this.apiRequest({
26
25
  method: 'PUT',
27
26
  path: `/chats/${args.id}/unarchive`,
@@ -29,7 +29,6 @@ export default class ChatsUpdate extends BaseCommand {
29
29
  async run() {
30
30
  const { args, flags } = await this.parse(ChatsUpdate);
31
31
  this.parsedFlags = flags;
32
- this.checkScope("chats:update");
33
32
  const body = { chat: {
34
33
  name: flags['name'],
35
34
  public: flags['public'],
@@ -39,20 +39,13 @@ export default class Commands extends BaseCommand {
39
39
  this.output(commandList.map(({ command, summary }) => ({ command, summary })));
40
40
  return;
41
41
  }
42
- // --available: check token scopes
42
+ // --available: check token scopes via API
43
43
  let tokenScopes = [];
44
44
  try {
45
- const { token, profile } = resolveToken({ token: flags.token, profile: flags.profile });
46
- // Use cached scopes if available
47
- if (profile?.scopes) {
48
- tokenScopes = profile.scopes;
49
- }
50
- else {
51
- // Fetch from API
52
- const response = await request({ method: 'GET', path: '/oauth/token/info', token }, { quiet: true });
53
- const wrapper = response.data;
54
- tokenScopes = wrapper.data.scopes || [];
55
- }
45
+ const { token } = resolveToken({ token: flags.token, profile: flags.profile });
46
+ const response = await request({ method: 'GET', path: '/oauth/token/info', token }, { quiet: true });
47
+ const wrapper = response.data;
48
+ tokenScopes = wrapper.data.scopes || [];
56
49
  }
57
50
  catch (error) {
58
51
  if (error instanceof TokenNotFoundError) {
@@ -49,7 +49,6 @@ export default class CommonCustomProperties extends BaseCommand {
49
49
  this.validationError(missingRequired.map((f) => ({ message: `Обязательный флаг --${f.flag} не передан`, flag: f.flag })), { hint: "Обязательные: --entity-type <string>. pachca introspect common custom-properties" });
50
50
  }
51
51
  }
52
- this.checkScope("custom_properties:read");
53
52
  const { data } = await this.apiRequest({
54
53
  method: 'GET',
55
54
  path: '/custom_properties',
@@ -27,7 +27,6 @@ export default class CommonGetExports extends BaseCommand {
27
27
  async run() {
28
28
  const { args, flags } = await this.parse(CommonGetExports);
29
29
  this.parsedFlags = flags;
30
- this.checkScope("chat_exports:read");
31
30
  const { data } = await this.apiRequest({
32
31
  method: 'GET',
33
32
  path: `/chats/exports/${args.id}`,
@@ -63,7 +63,6 @@ export default class CommonRequestExport extends BaseCommand {
63
63
  this.validationError(missingRequired.map((f) => ({ message: `Обязательный флаг --${f.flag} не передан`, flag: f.flag })), { hint: "Обязательные: --start-at <string>, --end-at <string>, --webhook-url <string>. pachca introspect common request-export" });
64
64
  }
65
65
  }
66
- this.checkScope("chat_exports:write");
67
66
  const body = {
68
67
  start_at: flags['start-at'],
69
68
  end_at: flags['end-at'],
@@ -15,7 +15,6 @@ export default class CommonUploads extends BaseCommand {
15
15
  async run() {
16
16
  const { args, flags } = await this.parse(CommonUploads);
17
17
  this.parsedFlags = flags;
18
- this.checkScope("uploads:write");
19
18
  const { data } = await this.apiRequest({
20
19
  method: 'POST',
21
20
  path: '/uploads',
@@ -49,7 +49,6 @@ export default class GroupTagsCreate extends BaseCommand {
49
49
  this.validationError(missingRequired.map((f) => ({ message: `Обязательный флаг --${f.flag} не передан`, flag: f.flag })), { hint: "Обязательные: --name <string>. pachca introspect group-tags create" });
50
50
  }
51
51
  }
52
- this.checkScope("group_tags:write");
53
52
  const body = { group_tag: {
54
53
  name: flags['name'],
55
54
  } };
@@ -33,7 +33,6 @@ export default class GroupTagsDelete extends BaseCommand {
33
33
  this.exit(0);
34
34
  }
35
35
  }
36
- this.checkScope("group_tags:write");
37
36
  const { data } = await this.apiRequest({
38
37
  method: 'DELETE',
39
38
  path: `/group_tags/${args.id}`,
@@ -19,7 +19,6 @@ export default class GroupTagsGet extends BaseCommand {
19
19
  async run() {
20
20
  const { args, flags } = await this.parse(GroupTagsGet);
21
21
  this.parsedFlags = flags;
22
- this.checkScope("group_tags:read");
23
22
  const { data } = await this.apiRequest({
24
23
  method: 'GET',
25
24
  path: `/group_tags/${args.id}`,
@@ -32,7 +32,6 @@ export default class GroupTagsListUsers extends BaseCommand {
32
32
  async run() {
33
33
  const { args, flags } = await this.parse(GroupTagsListUsers);
34
34
  this.parsedFlags = flags;
35
- this.checkScope("group_tags:read");
36
35
  if (flags.all) {
37
36
  // Auto-pagination
38
37
  const allData = [];
@@ -31,7 +31,6 @@ export default class GroupTagsList extends BaseCommand {
31
31
  async run() {
32
32
  const { args, flags } = await this.parse(GroupTagsList);
33
33
  this.parsedFlags = flags;
34
- this.checkScope("group_tags:read");
35
34
  if (flags.all) {
36
35
  // Auto-pagination
37
36
  const allData = [];
@@ -50,7 +50,6 @@ export default class GroupTagsUpdate extends BaseCommand {
50
50
  this.validationError(missingRequired.map((f) => ({ message: `Обязательный флаг --${f.flag} не передан`, flag: f.flag })), { hint: "Обязательные: --name <string>. pachca introspect group-tags update" });
51
51
  }
52
52
  }
53
- this.checkScope("group_tags:write");
54
53
  const body = { group_tag: {
55
54
  name: flags['name'],
56
55
  } };
@@ -52,7 +52,6 @@ export default class LinkPreviewsAdd extends BaseCommand {
52
52
  this.validationError(missingRequired.map((f) => ({ message: `Обязательный флаг --${f.flag} не передан`, flag: f.flag })), { hint: "Обязательные: --link-previews <string>. pachca introspect link-previews add" });
53
53
  }
54
54
  }
55
- this.checkScope("link_previews:write");
56
55
  const body = {
57
56
  link_previews: flags['link-previews'] ? this.parseJSON(flags['link-previews'], 'link-previews') : undefined,
58
57
  };
@@ -49,7 +49,6 @@ export default class MembersAddGroupTags extends BaseCommand {
49
49
  this.validationError(missingRequired.map((f) => ({ message: `Обязательный флаг --${f.flag} не передан`, flag: f.flag })), { hint: "Обязательные: --group-tag-ids <string>. pachca introspect members add-group-tags" });
50
50
  }
51
51
  }
52
- this.checkScope("chat_members:write");
53
52
  const body = {
54
53
  group_tag_ids: flags['group-tag-ids'] ? this.parseJSON(flags['group-tag-ids'], 'group-tag-ids') : undefined,
55
54
  };
@@ -58,7 +58,6 @@ export default class MembersAdd extends BaseCommand {
58
58
  this.validationError(missingRequired.map((f) => ({ message: `Обязательный флаг --${f.flag} не передан`, flag: f.flag })), { hint: "Обязательные: --member-ids <string>. pachca introspect members add" });
59
59
  }
60
60
  }
61
- this.checkScope("chat_members:write");
62
61
  const body = {
63
62
  member_ids: flags['member-ids'] ? this.parseJSON(flags['member-ids'], 'member-ids') : undefined,
64
63
  silent: flags['silent'],
@@ -36,7 +36,6 @@ export default class MembersLeave extends BaseCommand {
36
36
  this.exit(0);
37
37
  }
38
38
  }
39
- this.checkScope("chats:leave");
40
39
  const { data } = await this.apiRequest({
41
40
  method: 'DELETE',
42
41
  path: `/chats/${args.id}/leave`,
@@ -37,7 +37,6 @@ export default class MembersList extends BaseCommand {
37
37
  async run() {
38
38
  const { args, flags } = await this.parse(MembersList);
39
39
  this.parsedFlags = flags;
40
- this.checkScope("chat_members:read");
41
40
  if (flags.all) {
42
41
  // Auto-pagination
43
42
  const allData = [];
@@ -37,7 +37,6 @@ export default class MembersRemoveGroupTag extends BaseCommand {
37
37
  this.exit(0);
38
38
  }
39
39
  }
40
- this.checkScope("chat_members:write");
41
40
  const { data } = await this.apiRequest({
42
41
  method: 'DELETE',
43
42
  path: `/chats/${args.id}/group_tags/${args.tag_id}`,
@@ -41,7 +41,6 @@ export default class MembersRemove extends BaseCommand {
41
41
  this.exit(0);
42
42
  }
43
43
  }
44
- this.checkScope("chat_members:write");
45
44
  const { data } = await this.apiRequest({
46
45
  method: 'DELETE',
47
46
  path: `/chats/${args.id}/members/${args.user_id}`,
@@ -57,7 +57,6 @@ export default class MembersUpdate extends BaseCommand {
57
57
  this.validationError(missingRequired.map((f) => ({ message: `Обязательный флаг --${f.flag} не передан`, flag: f.flag })), { hint: "Обязательные: --role <string>. pachca introspect members update" });
58
58
  }
59
59
  }
60
- this.checkScope("chat_members:write");
61
60
  const body = {
62
61
  role: flags['role'],
63
62
  };
@@ -98,8 +98,8 @@ export default class MessagesCreate extends BaseCommand {
98
98
  if (validationErrors.length > 0) {
99
99
  this.validationError(validationErrors);
100
100
  }
101
- this.checkScope("messages:create");
102
- const body = { message: {
101
+ const body = {
102
+ message: {
103
103
  entity_type: flags['entity-type'],
104
104
  entity_id: flags['entity-id'],
105
105
  content: flags['content'],
@@ -109,14 +109,19 @@ export default class MessagesCreate extends BaseCommand {
109
109
  display_avatar_url: flags['display-avatar-url'],
110
110
  display_name: flags['display-name'],
111
111
  skip_invite_mentions: flags['skip-invite-mentions'],
112
- link_preview: flags['link-preview'],
113
- } };
112
+ },
113
+ link_preview: flags['link-preview'],
114
+ };
114
115
  // Clean undefined fields
115
116
  const inner = body['message'];
116
117
  for (const [k, v] of Object.entries(inner)) {
117
118
  if (v === undefined)
118
119
  delete inner[k];
119
120
  }
121
+ for (const [k, v] of Object.entries(body)) {
122
+ if (k !== 'message' && v === undefined)
123
+ delete body[k];
124
+ }
120
125
  const { data } = await this.apiRequest({
121
126
  method: 'POST',
122
127
  path: '/messages',
@@ -38,7 +38,6 @@ export default class MessagesDelete extends BaseCommand {
38
38
  this.exit(0);
39
39
  }
40
40
  }
41
- this.checkScope("messages:delete");
42
41
  const { data } = await this.apiRequest({
43
42
  method: 'DELETE',
44
43
  path: `/messages/${args.id}`,
@@ -24,7 +24,6 @@ export default class MessagesGet extends BaseCommand {
24
24
  async run() {
25
25
  const { args, flags } = await this.parse(MessagesGet);
26
26
  this.parsedFlags = flags;
27
- this.checkScope("messages:read");
28
27
  const { data } = await this.apiRequest({
29
28
  method: 'GET',
30
29
  path: `/messages/${args.id}`,
@@ -20,8 +20,13 @@ export default class MessagesList extends BaseCommand {
20
20
  'chat-id': Flags.integer({
21
21
  description: "Идентификатор чата (беседа, канал, диалог или чат треда)",
22
22
  }),
23
- 'sort-id': Flags.string({
24
- description: "Идентификатор сообщения",
23
+ sort: Flags.string({
24
+ description: "Поле сортировки (id — идентификатор сообщения)",
25
+ options: ["id"],
26
+ }),
27
+ order: Flags.string({
28
+ description: "Порядок сортировки",
29
+ options: ["asc", "desc"],
25
30
  }),
26
31
  limit: Flags.integer({
27
32
  description: 'Количество результатов на страницу',
@@ -63,7 +68,6 @@ export default class MessagesList extends BaseCommand {
63
68
  this.validationError(missingRequired.map((f) => ({ message: `Обязательный флаг --${f.flag} не передан`, flag: f.flag })), { hint: "Обязательные: --chat-id <integer>. pachca introspect messages list" });
64
69
  }
65
70
  }
66
- this.checkScope("messages:read");
67
71
  if (flags.all) {
68
72
  // Auto-pagination
69
73
  const allData = [];
@@ -73,7 +77,7 @@ export default class MessagesList extends BaseCommand {
73
77
  while (pages < 500) {
74
78
  const query = {
75
79
  'chat_id': flags['chat-id'],
76
- 'sort[id]': flags['sort-id'],
80
+ ...(flags.sort ? { [`sort[${flags.sort.replace(/-/g, '_')}]`]: flags.order || 'desc' } : {}),
77
81
  limit: flags.limit,
78
82
  cursor: nextCursor,
79
83
  };
@@ -112,7 +116,7 @@ export default class MessagesList extends BaseCommand {
112
116
  path: '/messages',
113
117
  query: {
114
118
  'chat_id': flags['chat-id'],
115
- 'sort[id]': flags['sort-id'],
119
+ ...(flags.sort ? { [`sort[${flags.sort.replace(/-/g, '_')}]`]: flags.order || 'desc' } : {}),
116
120
  limit: flags.limit,
117
121
  cursor: flags.cursor,
118
122
  },
@@ -22,7 +22,6 @@ export default class MessagesPin extends BaseCommand {
22
22
  async run() {
23
23
  const { args, flags } = await this.parse(MessagesPin);
24
24
  this.parsedFlags = flags;
25
- this.checkScope("pins:write");
26
25
  const { data } = await this.apiRequest({
27
26
  method: 'POST',
28
27
  path: `/messages/${args.id}/pin`,
@@ -37,7 +37,6 @@ export default class MessagesUnpin extends BaseCommand {
37
37
  this.exit(0);
38
38
  }
39
39
  }
40
- this.checkScope("pins:write");
41
40
  const { data } = await this.apiRequest({
42
41
  method: 'DELETE',
43
42
  path: `/messages/${args.id}/pin`,
@@ -47,7 +47,6 @@ export default class MessagesUpdate extends BaseCommand {
47
47
  }
48
48
  flags['content'] = Buffer.concat(chunks).toString('utf-8').trimEnd();
49
49
  }
50
- this.checkScope("messages:update");
51
50
  const body = { message: {
52
51
  content: flags['content'],
53
52
  files: flags['files'] ? this.parseJSON(flags['files'], 'files') : undefined,
@@ -32,7 +32,6 @@ export default class ProfileDeleteStatus extends BaseCommand {
32
32
  this.exit(0);
33
33
  }
34
34
  }
35
- this.checkScope("profile_status:write");
36
35
  const { data } = await this.apiRequest({
37
36
  method: 'DELETE',
38
37
  path: '/profile/status',
@@ -16,7 +16,6 @@ export default class ProfileGetStatus extends BaseCommand {
16
16
  async run() {
17
17
  const { args, flags } = await this.parse(ProfileGetStatus);
18
18
  this.parsedFlags = flags;
19
- this.checkScope("profile_status:read");
20
19
  const { data } = await this.apiRequest({
21
20
  method: 'GET',
22
21
  path: '/profile/status',
@@ -16,7 +16,6 @@ export default class ProfileGet extends BaseCommand {
16
16
  async run() {
17
17
  const { args, flags } = await this.parse(ProfileGet);
18
18
  this.parsedFlags = flags;
19
- this.checkScope("profile:read");
20
19
  const { data } = await this.apiRequest({
21
20
  method: 'GET',
22
21
  path: '/profile',
@@ -70,7 +70,6 @@ export default class ProfileUpdateStatus extends BaseCommand {
70
70
  if (validationErrors.length > 0) {
71
71
  this.validationError(validationErrors);
72
72
  }
73
- this.checkScope("profile_status:write");
74
73
  const body = { status: {
75
74
  emoji: flags['emoji'],
76
75
  title: flags['title'],
@@ -57,7 +57,6 @@ export default class ReactionsAdd extends BaseCommand {
57
57
  this.validationError(missingRequired.map((f) => ({ message: `Обязательный флаг --${f.flag} не передан`, flag: f.flag })), { hint: "Обязательные: --code <string>. pachca introspect reactions add" });
58
58
  }
59
59
  }
60
- this.checkScope("reactions:write");
61
60
  const body = {
62
61
  code: flags['code'],
63
62
  name: flags['name'],