@pachca/cli 2026.3.8 → 2026.3.9
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 +6 -0
- package/dist/base-command.js +1 -43
- package/dist/commands/auth/list.js +0 -1
- package/dist/commands/auth/login.js +0 -9
- package/dist/commands/auth/status.js +0 -10
- package/dist/commands/bots/list-events.js +0 -1
- package/dist/commands/bots/remove-event.js +0 -1
- package/dist/commands/bots/update.js +0 -1
- package/dist/commands/chats/archive.js +0 -1
- package/dist/commands/chats/create.js +0 -1
- package/dist/commands/chats/get.js +0 -1
- package/dist/commands/chats/list.js +0 -1
- package/dist/commands/chats/unarchive.js +0 -1
- package/dist/commands/chats/update.js +0 -1
- package/dist/commands/commands.js +5 -12
- package/dist/commands/common/custom-properties.js +0 -1
- package/dist/commands/common/get-exports.js +0 -1
- package/dist/commands/common/request-export.js +0 -1
- package/dist/commands/common/uploads.js +0 -1
- package/dist/commands/group-tags/create.js +0 -1
- package/dist/commands/group-tags/delete.js +0 -1
- package/dist/commands/group-tags/get.js +0 -1
- package/dist/commands/group-tags/list-users.js +0 -1
- package/dist/commands/group-tags/list.js +0 -1
- package/dist/commands/group-tags/update.js +0 -1
- package/dist/commands/link-previews/add.js +0 -1
- package/dist/commands/members/add-group-tags.js +0 -1
- package/dist/commands/members/add.js +0 -1
- package/dist/commands/members/leave.js +0 -1
- package/dist/commands/members/list.js +0 -1
- package/dist/commands/members/remove-group-tag.js +0 -1
- package/dist/commands/members/remove.js +0 -1
- package/dist/commands/members/update.js +0 -1
- package/dist/commands/messages/create.js +0 -1
- package/dist/commands/messages/delete.js +0 -1
- package/dist/commands/messages/get.js +0 -1
- package/dist/commands/messages/list.js +0 -1
- package/dist/commands/messages/pin.js +0 -1
- package/dist/commands/messages/unpin.js +0 -1
- package/dist/commands/messages/update.js +0 -1
- package/dist/commands/profile/delete-status.js +0 -1
- package/dist/commands/profile/get-status.js +0 -1
- package/dist/commands/profile/get.js +0 -1
- package/dist/commands/profile/update-status.js +0 -1
- package/dist/commands/reactions/add.js +0 -1
- package/dist/commands/reactions/list.js +0 -1
- package/dist/commands/reactions/remove.js +0 -1
- package/dist/commands/read-member/list-readers.js +0 -1
- package/dist/commands/search/list-chats.js +0 -1
- package/dist/commands/search/list-messages.js +0 -1
- package/dist/commands/search/list-users.js +0 -1
- package/dist/commands/security/list.js +0 -1
- package/dist/commands/tasks/create.js +0 -1
- package/dist/commands/tasks/delete.js +0 -1
- package/dist/commands/tasks/get.js +0 -1
- package/dist/commands/tasks/list.js +0 -1
- package/dist/commands/tasks/update.js +0 -1
- package/dist/commands/threads/add.js +0 -1
- package/dist/commands/threads/get.js +0 -1
- package/dist/commands/upload.js +0 -1
- package/dist/commands/users/create.js +0 -1
- package/dist/commands/users/delete.js +0 -1
- package/dist/commands/users/get-status.js +0 -1
- package/dist/commands/users/get.js +0 -1
- package/dist/commands/users/list.js +0 -1
- package/dist/commands/users/remove-status.js +0 -1
- package/dist/commands/users/update-status.js +0 -1
- package/dist/commands/users/update.js +0 -1
- package/dist/commands/views/open.js +0 -1
- package/dist/data/changelog.json +21 -0
- package/dist/hooks/init.js +1 -20
- package/dist/profiles.js +0 -8
- package/oclif.manifest.json +1 -134
- package/package.json +1 -1
- package/dist/commands/auth/refresh.js +0 -67
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2026.3.9 (19 марта 2026)
|
|
4
|
+
|
|
5
|
+
- **Изменено** (all): Убрана клиентская валидация скоупов — проверка разрешений теперь только на стороне API (403)
|
|
6
|
+
- **Изменено** (auth login): Профиль больше не сохраняет список скоупов — только тип, имя и email
|
|
7
|
+
- **Удалено** (auth refresh): Команда удалена — кеширование скоупов больше не используется
|
|
8
|
+
|
|
3
9
|
## 2026.3.8 (17 марта 2026)
|
|
4
10
|
|
|
5
11
|
- **Добавлено** (upgrade): Команда pachca upgrade — обновление CLI до последней версии
|
package/dist/base-command.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Command, Flags } from '@oclif/core';
|
|
2
|
-
import { resolveToken, TokenNotFoundError, ProfileNotFoundError, getDefaults,
|
|
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
|
}
|
|
@@ -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 = [];
|
|
@@ -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}`,
|
|
@@ -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
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
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
|
} };
|
|
@@ -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'],
|
|
@@ -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 = [];
|
|
@@ -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,7 +98,6 @@ 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
101
|
const body = { message: {
|
|
103
102
|
entity_type: flags['entity-type'],
|
|
104
103
|
entity_id: flags['entity-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}`,
|
|
@@ -63,7 +63,6 @@ export default class MessagesList extends BaseCommand {
|
|
|
63
63
|
this.validationError(missingRequired.map((f) => ({ message: `Обязательный флаг --${f.flag} не передан`, flag: f.flag })), { hint: "Обязательные: --chat-id <integer>. pachca introspect messages list" });
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
|
-
this.checkScope("messages:read");
|
|
67
66
|
if (flags.all) {
|
|
68
67
|
// Auto-pagination
|
|
69
68
|
const allData = [];
|
|
@@ -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`,
|
|
@@ -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,
|
|
@@ -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'],
|
|
@@ -33,7 +33,6 @@ export default class ReactionsList extends BaseCommand {
|
|
|
33
33
|
async run() {
|
|
34
34
|
const { args, flags } = await this.parse(ReactionsList);
|
|
35
35
|
this.parsedFlags = flags;
|
|
36
|
-
this.checkScope("reactions:read");
|
|
37
36
|
if (flags.all) {
|
|
38
37
|
// Auto-pagination
|
|
39
38
|
const allData = [];
|
|
@@ -31,7 +31,6 @@ export default class ReadMemberListReaders extends BaseCommand {
|
|
|
31
31
|
async run() {
|
|
32
32
|
const { args, flags } = await this.parse(ReadMemberListReaders);
|
|
33
33
|
this.parsedFlags = flags;
|
|
34
|
-
this.checkScope("messages:read");
|
|
35
34
|
if (flags.all) {
|
|
36
35
|
// Auto-pagination
|
|
37
36
|
const allData = [];
|
|
@@ -53,7 +53,6 @@ export default class SearchListChats extends BaseCommand {
|
|
|
53
53
|
async run() {
|
|
54
54
|
const { args, flags } = await this.parse(SearchListChats);
|
|
55
55
|
this.parsedFlags = flags;
|
|
56
|
-
this.checkScope("search:chats");
|
|
57
56
|
if (flags.all) {
|
|
58
57
|
// Auto-pagination
|
|
59
58
|
const allData = [];
|
|
@@ -50,7 +50,6 @@ export default class SearchListMessages extends BaseCommand {
|
|
|
50
50
|
async run() {
|
|
51
51
|
const { args, flags } = await this.parse(SearchListMessages);
|
|
52
52
|
this.parsedFlags = flags;
|
|
53
|
-
this.checkScope("search:messages");
|
|
54
53
|
if (flags.all) {
|
|
55
54
|
// Auto-pagination
|
|
56
55
|
const allData = [];
|
|
@@ -49,7 +49,6 @@ export default class SearchListUsers extends BaseCommand {
|
|
|
49
49
|
async run() {
|
|
50
50
|
const { args, flags } = await this.parse(SearchListUsers);
|
|
51
51
|
this.parsedFlags = flags;
|
|
52
|
-
this.checkScope("search:users");
|
|
53
52
|
if (flags.all) {
|
|
54
53
|
// Auto-pagination
|
|
55
54
|
const allData = [];
|
|
@@ -81,7 +81,6 @@ export default class SecurityList extends BaseCommand {
|
|
|
81
81
|
this.validationError(missingRequired.map((f) => ({ message: `Обязательный флаг --${f.flag} не передан`, flag: f.flag })), { hint: "Обязательные: --start-time <string>, --end-time <string>. pachca introspect security list" });
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
|
-
this.checkScope("audit_events:read");
|
|
85
84
|
if (flags.all) {
|
|
86
85
|
// Auto-pagination
|
|
87
86
|
const allData = [];
|
|
@@ -80,7 +80,6 @@ export default class TasksCreate extends BaseCommand {
|
|
|
80
80
|
this.validationError(missingRequired.map((f) => ({ message: `Обязательный флаг --${f.flag} не передан`, flag: f.flag })), { hint: "Обязательные: --kind <string>. pachca introspect tasks create" });
|
|
81
81
|
}
|
|
82
82
|
}
|
|
83
|
-
this.checkScope("tasks:create");
|
|
84
83
|
const body = { task: {
|
|
85
84
|
kind: flags['kind'],
|
|
86
85
|
content: flags['content'],
|
|
@@ -24,7 +24,6 @@ export default class TasksGet extends BaseCommand {
|
|
|
24
24
|
async run() {
|
|
25
25
|
const { args, flags } = await this.parse(TasksGet);
|
|
26
26
|
this.parsedFlags = flags;
|
|
27
|
-
this.checkScope("tasks:read");
|
|
28
27
|
const { data } = await this.apiRequest({
|
|
29
28
|
method: 'GET',
|
|
30
29
|
path: `/tasks/${args.id}`,
|
|
@@ -23,7 +23,6 @@ export default class ThreadsAdd extends BaseCommand {
|
|
|
23
23
|
async run() {
|
|
24
24
|
const { args, flags } = await this.parse(ThreadsAdd);
|
|
25
25
|
this.parsedFlags = flags;
|
|
26
|
-
this.checkScope("threads:create");
|
|
27
26
|
const { data } = await this.apiRequest({
|
|
28
27
|
method: 'POST',
|
|
29
28
|
path: `/messages/${args.id}/thread`,
|
|
@@ -19,7 +19,6 @@ export default class ThreadsGet extends BaseCommand {
|
|
|
19
19
|
async run() {
|
|
20
20
|
const { args, flags } = await this.parse(ThreadsGet);
|
|
21
21
|
this.parsedFlags = flags;
|
|
22
|
-
this.checkScope("threads:read");
|
|
23
22
|
const { data } = await this.apiRequest({
|
|
24
23
|
method: 'GET',
|
|
25
24
|
path: `/threads/${args.id}`,
|
package/dist/commands/upload.js
CHANGED
|
@@ -21,7 +21,6 @@ export default class Upload extends BaseCommand {
|
|
|
21
21
|
async run() {
|
|
22
22
|
const { args, flags } = await this.parse(Upload);
|
|
23
23
|
this.parsedFlags = flags;
|
|
24
|
-
this.checkScope('uploads:write');
|
|
25
24
|
// Step 1: Get upload params
|
|
26
25
|
const { data: uploadData } = await this.apiRequest({
|
|
27
26
|
method: 'POST',
|
|
@@ -85,7 +85,6 @@ export default class UsersCreate extends BaseCommand {
|
|
|
85
85
|
this.validationError(missingRequired.map((f) => ({ message: `Обязательный флаг --${f.flag} не передан`, flag: f.flag })), { hint: "Обязательные: --email <string>. pachca introspect users create" });
|
|
86
86
|
}
|
|
87
87
|
}
|
|
88
|
-
this.checkScope("users:create");
|
|
89
88
|
const body = {
|
|
90
89
|
user: {
|
|
91
90
|
first_name: flags['first-name'],
|
|
@@ -24,7 +24,6 @@ export default class UsersGetStatus extends BaseCommand {
|
|
|
24
24
|
async run() {
|
|
25
25
|
const { args, flags } = await this.parse(UsersGetStatus);
|
|
26
26
|
this.parsedFlags = flags;
|
|
27
|
-
this.checkScope("user_status:read");
|
|
28
27
|
const { data } = await this.apiRequest({
|
|
29
28
|
method: 'GET',
|
|
30
29
|
path: `/users/${args.user_id}/status`,
|
|
@@ -24,7 +24,6 @@ export default class UsersGet extends BaseCommand {
|
|
|
24
24
|
async run() {
|
|
25
25
|
const { args, flags } = await this.parse(UsersGet);
|
|
26
26
|
this.parsedFlags = flags;
|
|
27
|
-
this.checkScope("users:read");
|
|
28
27
|
const { data } = await this.apiRequest({
|
|
29
28
|
method: 'GET',
|
|
30
29
|
path: `/users/${args.id}`,
|
|
@@ -76,7 +76,6 @@ export default class UsersUpdateStatus extends BaseCommand {
|
|
|
76
76
|
if (validationErrors.length > 0) {
|
|
77
77
|
this.validationError(validationErrors);
|
|
78
78
|
}
|
|
79
|
-
this.checkScope("user_status:write");
|
|
80
79
|
const body = { status: {
|
|
81
80
|
emoji: flags['emoji'],
|
|
82
81
|
title: flags['title'],
|
|
@@ -58,7 +58,6 @@ export default class UsersUpdate extends BaseCommand {
|
|
|
58
58
|
async run() {
|
|
59
59
|
const { args, flags } = await this.parse(UsersUpdate);
|
|
60
60
|
this.parsedFlags = flags;
|
|
61
|
-
this.checkScope("users:update");
|
|
62
61
|
const body = { user: {
|
|
63
62
|
first_name: flags['first-name'],
|
|
64
63
|
last_name: flags['last-name'],
|
package/dist/data/changelog.json
CHANGED
|
@@ -1,4 +1,25 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"version": "2026.3.9",
|
|
4
|
+
"date": "19 марта 2026",
|
|
5
|
+
"changes": [
|
|
6
|
+
{
|
|
7
|
+
"type": "~",
|
|
8
|
+
"command": "all",
|
|
9
|
+
"description": "Убрана клиентская валидация скоупов — проверка разрешений теперь только на стороне API (403)"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"type": "~",
|
|
13
|
+
"command": "auth login",
|
|
14
|
+
"description": "Профиль больше не сохраняет список скоупов — только тип, имя и email"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"type": "-",
|
|
18
|
+
"command": "auth refresh",
|
|
19
|
+
"description": "Команда удалена — кеширование скоупов больше не используется"
|
|
20
|
+
}
|
|
21
|
+
]
|
|
22
|
+
},
|
|
2
23
|
{
|
|
3
24
|
"version": "2026.3.8",
|
|
4
25
|
"date": "17 марта 2026",
|
package/dist/hooks/init.js
CHANGED
|
@@ -4,8 +4,7 @@ import { fileURLToPath } from 'node:url';
|
|
|
4
4
|
import { spawn } from 'node:child_process';
|
|
5
5
|
import semver from 'semver';
|
|
6
6
|
import ansis from 'ansis';
|
|
7
|
-
import {
|
|
8
|
-
import { request } from '../client.js';
|
|
7
|
+
import { getDefaults, resolveToken, TokenNotFoundError, ProfileNotFoundError, } from '../profiles.js';
|
|
9
8
|
import { outputError } from '../output.js';
|
|
10
9
|
import { defaultOutputFormat, isInteractive } from '../utils.js';
|
|
11
10
|
/**
|
|
@@ -131,24 +130,6 @@ const hook = async function (opts) {
|
|
|
131
130
|
// Verify auth exists
|
|
132
131
|
try {
|
|
133
132
|
const { profileName, profile } = resolveToken({ token: argvToken, profile: argvProfile });
|
|
134
|
-
// Refresh bot scopes if stale (>24h)
|
|
135
|
-
if (profileName && profile?.type === 'bot' && profile.scopes_refreshed_at) {
|
|
136
|
-
const refreshedAt = new Date(profile.scopes_refreshed_at).getTime();
|
|
137
|
-
const now = Date.now();
|
|
138
|
-
const twentyFourHours = 24 * 60 * 60 * 1000;
|
|
139
|
-
if (now - refreshedAt > twentyFourHours) {
|
|
140
|
-
try {
|
|
141
|
-
const response = await request({ method: 'GET', path: '/oauth/token/info', token: profile.token }, { quiet: true });
|
|
142
|
-
const wrapper = response.data;
|
|
143
|
-
profile.scopes = wrapper.data.scopes || [];
|
|
144
|
-
profile.scopes_refreshed_at = new Date().toISOString();
|
|
145
|
-
setProfile(profileName, profile);
|
|
146
|
-
}
|
|
147
|
-
catch {
|
|
148
|
-
// Silently ignore refresh errors — use cached scopes
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
133
|
}
|
|
153
134
|
catch (error) {
|
|
154
135
|
if (error instanceof TokenNotFoundError) {
|
package/dist/profiles.js
CHANGED
|
@@ -171,14 +171,6 @@ export function getConfigFilePermissions() {
|
|
|
171
171
|
const stat = fs.statSync(configPath);
|
|
172
172
|
return (stat.mode & 0o777).toString(8);
|
|
173
173
|
}
|
|
174
|
-
export function invalidateScopes(profileName) {
|
|
175
|
-
const config = readConfig();
|
|
176
|
-
if (config.profiles?.[profileName]) {
|
|
177
|
-
config.profiles[profileName].scopes = [];
|
|
178
|
-
config.profiles[profileName].scopes_refreshed_at = undefined;
|
|
179
|
-
writeConfig(config);
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
174
|
export class TokenNotFoundError extends Error {
|
|
183
175
|
constructor() {
|
|
184
176
|
super('Token not found');
|
package/oclif.manifest.json
CHANGED
|
@@ -1598,139 +1598,6 @@
|
|
|
1598
1598
|
"logout.js"
|
|
1599
1599
|
]
|
|
1600
1600
|
},
|
|
1601
|
-
"auth:refresh": {
|
|
1602
|
-
"aliases": [],
|
|
1603
|
-
"args": {
|
|
1604
|
-
"profile": {
|
|
1605
|
-
"description": "Profile name to refresh",
|
|
1606
|
-
"name": "profile",
|
|
1607
|
-
"required": false
|
|
1608
|
-
}
|
|
1609
|
-
},
|
|
1610
|
-
"description": "Обновление кешированных разрешений профиля",
|
|
1611
|
-
"examples": [
|
|
1612
|
-
"<%= config.bin %> auth refresh bot-support",
|
|
1613
|
-
"<%= config.bin %> auth refresh"
|
|
1614
|
-
],
|
|
1615
|
-
"flags": {
|
|
1616
|
-
"output": {
|
|
1617
|
-
"char": "o",
|
|
1618
|
-
"description": "Output format: table, json, yaml, csv",
|
|
1619
|
-
"name": "output",
|
|
1620
|
-
"hasDynamicHelp": false,
|
|
1621
|
-
"multiple": false,
|
|
1622
|
-
"options": [
|
|
1623
|
-
"table",
|
|
1624
|
-
"json",
|
|
1625
|
-
"yaml",
|
|
1626
|
-
"csv"
|
|
1627
|
-
],
|
|
1628
|
-
"type": "option"
|
|
1629
|
-
},
|
|
1630
|
-
"columns": {
|
|
1631
|
-
"char": "c",
|
|
1632
|
-
"description": "Columns to display (comma-separated)",
|
|
1633
|
-
"name": "columns",
|
|
1634
|
-
"hasDynamicHelp": false,
|
|
1635
|
-
"multiple": false,
|
|
1636
|
-
"type": "option"
|
|
1637
|
-
},
|
|
1638
|
-
"no-header": {
|
|
1639
|
-
"description": "Hide table header",
|
|
1640
|
-
"name": "no-header",
|
|
1641
|
-
"allowNo": false,
|
|
1642
|
-
"type": "boolean"
|
|
1643
|
-
},
|
|
1644
|
-
"no-truncate": {
|
|
1645
|
-
"description": "Do not truncate values in table",
|
|
1646
|
-
"name": "no-truncate",
|
|
1647
|
-
"allowNo": false,
|
|
1648
|
-
"type": "boolean"
|
|
1649
|
-
},
|
|
1650
|
-
"profile": {
|
|
1651
|
-
"char": "p",
|
|
1652
|
-
"description": "Profile to use for this command",
|
|
1653
|
-
"name": "profile",
|
|
1654
|
-
"hasDynamicHelp": false,
|
|
1655
|
-
"multiple": false,
|
|
1656
|
-
"type": "option"
|
|
1657
|
-
},
|
|
1658
|
-
"token": {
|
|
1659
|
-
"description": "Bearer token for this call (not saved)",
|
|
1660
|
-
"name": "token",
|
|
1661
|
-
"hasDynamicHelp": false,
|
|
1662
|
-
"multiple": false,
|
|
1663
|
-
"type": "option"
|
|
1664
|
-
},
|
|
1665
|
-
"quiet": {
|
|
1666
|
-
"char": "q",
|
|
1667
|
-
"description": "Suppress output except errors",
|
|
1668
|
-
"name": "quiet",
|
|
1669
|
-
"allowNo": false,
|
|
1670
|
-
"type": "boolean"
|
|
1671
|
-
},
|
|
1672
|
-
"no-color": {
|
|
1673
|
-
"description": "Disable color output",
|
|
1674
|
-
"name": "no-color",
|
|
1675
|
-
"allowNo": false,
|
|
1676
|
-
"type": "boolean"
|
|
1677
|
-
},
|
|
1678
|
-
"verbose": {
|
|
1679
|
-
"char": "v",
|
|
1680
|
-
"description": "Show HTTP request/response details",
|
|
1681
|
-
"name": "verbose",
|
|
1682
|
-
"allowNo": false,
|
|
1683
|
-
"type": "boolean"
|
|
1684
|
-
},
|
|
1685
|
-
"no-input": {
|
|
1686
|
-
"description": "Disable interactive prompts",
|
|
1687
|
-
"name": "no-input",
|
|
1688
|
-
"allowNo": false,
|
|
1689
|
-
"type": "boolean"
|
|
1690
|
-
},
|
|
1691
|
-
"dry-run": {
|
|
1692
|
-
"description": "Show HTTP request without sending",
|
|
1693
|
-
"name": "dry-run",
|
|
1694
|
-
"allowNo": false,
|
|
1695
|
-
"type": "boolean"
|
|
1696
|
-
},
|
|
1697
|
-
"timeout": {
|
|
1698
|
-
"description": "Request timeout in seconds",
|
|
1699
|
-
"name": "timeout",
|
|
1700
|
-
"hasDynamicHelp": false,
|
|
1701
|
-
"multiple": false,
|
|
1702
|
-
"type": "option"
|
|
1703
|
-
},
|
|
1704
|
-
"no-retry": {
|
|
1705
|
-
"description": "Disable auto-retry on 429/503",
|
|
1706
|
-
"name": "no-retry",
|
|
1707
|
-
"allowNo": false,
|
|
1708
|
-
"type": "boolean"
|
|
1709
|
-
},
|
|
1710
|
-
"json": {
|
|
1711
|
-
"description": "Output as JSON (alias for --output json)",
|
|
1712
|
-
"hidden": true,
|
|
1713
|
-
"name": "json",
|
|
1714
|
-
"allowNo": false,
|
|
1715
|
-
"type": "boolean"
|
|
1716
|
-
}
|
|
1717
|
-
},
|
|
1718
|
-
"hasDynamicHelp": false,
|
|
1719
|
-
"hiddenAliases": [],
|
|
1720
|
-
"id": "auth:refresh",
|
|
1721
|
-
"pluginAlias": "@pachca/cli",
|
|
1722
|
-
"pluginName": "@pachca/cli",
|
|
1723
|
-
"pluginType": "core",
|
|
1724
|
-
"strict": true,
|
|
1725
|
-
"enableJsonFlag": false,
|
|
1726
|
-
"isESM": true,
|
|
1727
|
-
"relativePath": [
|
|
1728
|
-
"dist",
|
|
1729
|
-
"commands",
|
|
1730
|
-
"auth",
|
|
1731
|
-
"refresh.js"
|
|
1732
|
-
]
|
|
1733
|
-
},
|
|
1734
1601
|
"auth:status": {
|
|
1735
1602
|
"aliases": [],
|
|
1736
1603
|
"args": {},
|
|
@@ -12705,5 +12572,5 @@
|
|
|
12705
12572
|
]
|
|
12706
12573
|
}
|
|
12707
12574
|
},
|
|
12708
|
-
"version": "2026.3.
|
|
12575
|
+
"version": "2026.3.9"
|
|
12709
12576
|
}
|
package/package.json
CHANGED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import { Args } from '@oclif/core';
|
|
2
|
-
import { BaseCommand } from '../../base-command.js';
|
|
3
|
-
import { getActiveProfile, getProfile, setProfile } from '../../profiles.js';
|
|
4
|
-
import { request } from '../../client.js';
|
|
5
|
-
import { outputError } from '../../output.js';
|
|
6
|
-
export default class AuthRefresh extends BaseCommand {
|
|
7
|
-
static description = 'Обновление кешированных разрешений профиля';
|
|
8
|
-
static examples = [
|
|
9
|
-
'<%= config.bin %> auth refresh bot-support',
|
|
10
|
-
'<%= config.bin %> auth refresh',
|
|
11
|
-
];
|
|
12
|
-
static args = {
|
|
13
|
-
profile: Args.string({
|
|
14
|
-
description: 'Profile name to refresh',
|
|
15
|
-
required: false,
|
|
16
|
-
}),
|
|
17
|
-
};
|
|
18
|
-
static flags = {
|
|
19
|
-
...BaseCommand.baseFlags,
|
|
20
|
-
};
|
|
21
|
-
async run() {
|
|
22
|
-
const { args, flags } = await this.parse(AuthRefresh);
|
|
23
|
-
this.parsedFlags = flags;
|
|
24
|
-
const profileName = args.profile || flags.profile || process.env.PACHCA_PROFILE || getActiveProfile();
|
|
25
|
-
const format = this.getOutputFormat();
|
|
26
|
-
if (!profileName) {
|
|
27
|
-
outputError({ error: 'No profile specified. Run: pachca auth refresh <profile>', type: 'PACHCA_USAGE_ERROR', code: null }, format);
|
|
28
|
-
this.exit(2);
|
|
29
|
-
}
|
|
30
|
-
const profile = getProfile(profileName);
|
|
31
|
-
if (!profile) {
|
|
32
|
-
outputError({ error: `Profile "${profileName}" not found`, type: 'PACHCA_USAGE_ERROR', code: null }, format);
|
|
33
|
-
this.exit(2);
|
|
34
|
-
}
|
|
35
|
-
// Fetch fresh scopes
|
|
36
|
-
const response = await request({ method: 'GET', path: '/oauth/token/info', token: profile.token }, { quiet: flags.quiet });
|
|
37
|
-
const wrapper = response.data;
|
|
38
|
-
const newScopes = wrapper.data.scopes || [];
|
|
39
|
-
const oldScopes = profile.scopes || [];
|
|
40
|
-
// Update profile
|
|
41
|
-
profile.scopes = newScopes;
|
|
42
|
-
profile.scopes_refreshed_at = new Date().toISOString();
|
|
43
|
-
setProfile(profileName, profile);
|
|
44
|
-
// Calculate diff
|
|
45
|
-
const added = newScopes.filter((s) => !oldScopes.includes(s));
|
|
46
|
-
const removed = oldScopes.filter((s) => !newScopes.includes(s));
|
|
47
|
-
if (format === 'json') {
|
|
48
|
-
this.output({
|
|
49
|
-
profile: profileName,
|
|
50
|
-
scopes_before: oldScopes,
|
|
51
|
-
scopes_after: newScopes,
|
|
52
|
-
added,
|
|
53
|
-
removed,
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
else if (!flags.quiet) {
|
|
57
|
-
this.success(`Скоупы обновлены [${profileName}]`);
|
|
58
|
-
if (added.length || removed.length) {
|
|
59
|
-
process.stderr.write(` Было: ${oldScopes.join(', ')}\n`);
|
|
60
|
-
process.stderr.write(` Стало: ${newScopes.join(', ')}`);
|
|
61
|
-
if (added.length)
|
|
62
|
-
process.stderr.write(` (+${added.length} новых)`);
|
|
63
|
-
process.stderr.write('\n');
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|