@pachca/cli 2026.3.6 → 2026.3.8

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 CHANGED
@@ -1,5 +1,16 @@
1
1
  # Changelog
2
2
 
3
+ ## 2026.3.8 (17 марта 2026)
4
+
5
+ - **Добавлено** (upgrade): Команда pachca upgrade — обновление CLI до последней версии
6
+ - **Удалено** (init hook): Ошибки авторизации теперь выводятся в JSON при -o json (раньше формат игнорировался)
7
+ - **Удалено** (update banner): Баннер обновления теперь показывается даже при ошибках команд
8
+
9
+ ## 2026.3.7 (16 марта 2026)
10
+
11
+ - **Добавлено** (upload): Загрузка файла одной командой (получает подпись + загружает автоматически)
12
+ - **Изменено** (common direct-url): Обязательный флаг --direct-url вместо хардкод URL, запрос идёт без Authorization
13
+
3
14
  ## 2026.3.6 (15 марта 2026)
4
15
 
5
16
  - **Изменено** (threads): Топик thread переименован в threads (pachca threads add, pachca threads get)
package/README.md CHANGED
@@ -233,6 +233,18 @@ pachca guide # список всех сценариев
233
233
 
234
234
  <!-- AUTO:FLAGS:END -->
235
235
 
236
+ ## Загрузка файлов
237
+
238
+ ```
239
+ # Загрузить файл (получает подпись и загружает автоматически)
240
+ pachca upload photo.jpg
241
+
242
+ # Из stdin
243
+ cat data.csv | pachca upload -
244
+ ```
245
+
246
+ Команда `upload` автоматически получает подпись (`POST /uploads`) и загружает файл на S3. Возвращает `key` — используйте его в `--files` при создании сообщений.
247
+
236
248
  ## Пагинация
237
249
 
238
250
  ```
@@ -71,6 +71,18 @@ pachca guide # список всех сценариев
71
71
  <!-- AUTO:FLAGS -->
72
72
  <!-- AUTO:FLAGS:END -->
73
73
 
74
+ ## Загрузка файлов
75
+
76
+ ```
77
+ # Загрузить файл (получает подпись и загружает автоматически)
78
+ pachca upload photo.jpg
79
+
80
+ # Из stdin
81
+ cat data.csv | pachca upload -
82
+ ```
83
+
84
+ Команда `upload` автоматически получает подпись (`POST /uploads`) и загружает файл на S3. Возвращает `key` — используйте его в `--files` при создании сообщений.
85
+
74
86
  ## Пагинация
75
87
 
76
88
  ```
package/dist/client.js CHANGED
@@ -25,7 +25,10 @@ function getBaseUrl() {
25
25
  const MAX_RETRIES = 3;
26
26
  const DEFAULT_TIMEOUT = 30;
27
27
  function buildUrl(apiPath, query) {
28
- const url = new URL(apiPath.startsWith('/') ? `${getBaseUrl()}${apiPath}` : `${getBaseUrl()}/${apiPath}`);
28
+ const base = apiPath.startsWith('http://') || apiPath.startsWith('https://')
29
+ ? apiPath
30
+ : apiPath.startsWith('/') ? `${getBaseUrl()}${apiPath}` : `${getBaseUrl()}/${apiPath}`;
31
+ const url = new URL(base);
29
32
  if (query) {
30
33
  for (const [key, value] of Object.entries(query)) {
31
34
  if (value !== undefined) {
@@ -71,7 +74,7 @@ export async function request(opts, clientFlags) {
71
74
  const timeoutSeconds = opts.timeout ?? clientFlags?.timeout ?? envTimeout ?? DEFAULT_TIMEOUT;
72
75
  const noRetry = opts.noRetry ?? clientFlags?.['no-retry'] ?? false;
73
76
  const fetchHeaders = {
74
- Authorization: `Bearer ${opts.token}`,
77
+ ...(opts.noAuth ? {} : { Authorization: `Bearer ${opts.token}` }),
75
78
  Accept: 'application/json',
76
79
  ...opts.headers,
77
80
  };
@@ -12,6 +12,10 @@ export default class CommonDirectUrl extends BaseCommand {
12
12
  static args = {};
13
13
  static flags = {
14
14
  ...BaseCommand.baseFlags,
15
+ 'direct-url': Flags.string({
16
+ description: 'URL для отправки запроса (получается из ответа POST /uploads)',
17
+ required: true,
18
+ }),
15
19
  'content-disposition': Flags.string({
16
20
  description: "Параметр Content-Disposition, полученный в ответе на запрос [Получение подписи, ключа и других параметров](POST /uploads)",
17
21
  }),
@@ -109,8 +113,9 @@ export default class CommonDirectUrl extends BaseCommand {
109
113
  }
110
114
  const { data } = await this.apiRequest({
111
115
  method: 'POST',
112
- path: '/direct_url',
116
+ path: flags['direct-url'],
113
117
  formData,
118
+ noAuth: true,
114
119
  });
115
120
  const responseBody = data;
116
121
  const result = responseBody.data ?? responseBody;
@@ -2,7 +2,6 @@ import { BaseCommand } from '../../base-command.js';
2
2
  export default class CommonUploads extends BaseCommand {
3
3
  static description = "Получение подписи, ключа и других параметров";
4
4
  static examples = [
5
- "Отправить сообщение с файлами:\n $ pachca common uploads",
6
5
  "Изменить вложения сообщения:\n $ pachca common uploads"
7
6
  ];
8
7
  static scope = "uploads:write";
@@ -127,7 +127,7 @@ export default class Doctor extends BaseCommand {
127
127
  if (latest && semver.valid(latest) && semver.valid(currentVersion)) {
128
128
  if (semver.gt(latest, currentVersion)) {
129
129
  checks.push({ name: 'cli_version', status: 'warning', current: currentVersion, latest });
130
- this.printCheck('warning', `CLI v${currentVersion} → доступна v${latest} (npm install -g @pachca/cli)`, format);
130
+ this.printCheck('warning', `CLI v${currentVersion} → доступна v${latest} (pachca upgrade)`, format);
131
131
  }
132
132
  else {
133
133
  checks.push({ name: 'cli_version', status: 'ok', current: currentVersion, latest });
@@ -0,0 +1,111 @@
1
+ import { execFileSync } from 'node:child_process';
2
+ import * as fs from 'node:fs';
3
+ import * as path from 'node:path';
4
+ import semver from 'semver';
5
+ import { BaseCommand } from '../base-command.js';
6
+ /**
7
+ * Detect how CLI was installed by examining the executable path.
8
+ */
9
+ function detectPackageManager(binPath) {
10
+ const resolved = fs.realpathSync(binPath);
11
+ // Homebrew: /opt/homebrew/... or /usr/local/Cellar/...
12
+ if (resolved.includes('/homebrew/') || resolved.includes('/Cellar/')) {
13
+ return { name: 'homebrew', cmd: 'brew', args: ['upgrade', '@pachca/cli'] };
14
+ }
15
+ // Bun global: ~/.bun/install/global/ or contains /bun/
16
+ if (resolved.includes('/bun/') || resolved.includes('.bun/')) {
17
+ return { name: 'bun', cmd: 'bun', args: ['install', '-g', '@pachca/cli@latest'] };
18
+ }
19
+ // pnpm global: contains /pnpm/
20
+ if (resolved.includes('/pnpm/')) {
21
+ return { name: 'pnpm', cmd: 'pnpm', args: ['install', '-g', '@pachca/cli@latest'] };
22
+ }
23
+ // yarn global: contains /yarn/
24
+ if (resolved.includes('/yarn/')) {
25
+ return { name: 'yarn', cmd: 'yarn', args: ['global', 'add', '@pachca/cli@latest'] };
26
+ }
27
+ // Default: npm
28
+ return { name: 'npm', cmd: 'npm', args: ['install', '-g', '@pachca/cli@latest'] };
29
+ }
30
+ export default class Upgrade extends BaseCommand {
31
+ static description = 'Обновить CLI до последней версии';
32
+ static examples = [
33
+ '<%= config.bin %> upgrade',
34
+ ];
35
+ static flags = {
36
+ ...BaseCommand.baseFlags,
37
+ };
38
+ async run() {
39
+ const { flags } = await this.parse(Upgrade);
40
+ this.parsedFlags = flags;
41
+ const currentVersion = this.config.version;
42
+ const format = this.getOutputFormat();
43
+ // Fetch latest version from npm registry
44
+ let latest;
45
+ try {
46
+ const response = await fetch('https://registry.npmjs.org/@pachca/cli');
47
+ if (response.ok) {
48
+ const data = (await response.json());
49
+ latest = data['dist-tags']?.latest;
50
+ }
51
+ }
52
+ catch {
53
+ // Fallback: try cached version
54
+ }
55
+ if (!latest) {
56
+ try {
57
+ const versionFile = path.join(this.config.cacheDir, 'version');
58
+ if (fs.existsSync(versionFile)) {
59
+ const cached = JSON.parse(fs.readFileSync(versionFile, 'utf-8'));
60
+ latest = cached.latest;
61
+ }
62
+ }
63
+ catch {
64
+ // ignore
65
+ }
66
+ }
67
+ if (!latest) {
68
+ if (format === 'json') {
69
+ this.output({ upgraded: false, current: currentVersion, error: 'Cannot determine latest version' });
70
+ }
71
+ else {
72
+ process.stderr.write('✗ Не удалось определить последнюю версию\n');
73
+ }
74
+ this.exit(1);
75
+ }
76
+ if (semver.valid(currentVersion) && semver.valid(latest) && !semver.gt(latest, currentVersion)) {
77
+ if (format === 'json') {
78
+ this.output({ upgraded: false, current: currentVersion, latest });
79
+ }
80
+ else {
81
+ process.stderr.write(`✔ CLI уже обновлён (${currentVersion})\n`);
82
+ }
83
+ return;
84
+ }
85
+ const pm = detectPackageManager(process.argv[1] || this.config.binPath || '');
86
+ if (format !== 'json' && process.stderr.isTTY) {
87
+ process.stderr.write(`Обновление ${currentVersion} → ${latest} (${pm.name})...\n`);
88
+ }
89
+ try {
90
+ execFileSync(pm.cmd, pm.args, {
91
+ stdio: format === 'json' ? 'ignore' : 'inherit',
92
+ });
93
+ if (format === 'json') {
94
+ this.output({ upgraded: true, from: currentVersion, to: latest, package_manager: pm.name });
95
+ }
96
+ else {
97
+ process.stderr.write(`\n✔ Обновлено до ${latest}\n`);
98
+ }
99
+ }
100
+ catch {
101
+ if (format === 'json') {
102
+ this.output({ upgraded: false, current: currentVersion, latest, package_manager: pm.name, error: `${pm.cmd} failed` });
103
+ }
104
+ else {
105
+ process.stderr.write(`\n✗ Не удалось обновить через ${pm.name}. Попробуйте вручную:\n`);
106
+ process.stderr.write(` ${pm.cmd} ${pm.args.join(' ')}\n`);
107
+ }
108
+ this.exit(1);
109
+ }
110
+ }
111
+ }
@@ -0,0 +1,71 @@
1
+ import { Args } from '@oclif/core';
2
+ import * as fs from 'node:fs';
3
+ import * as path from 'node:path';
4
+ import { BaseCommand } from '../base-command.js';
5
+ export default class Upload extends BaseCommand {
6
+ static description = 'Загрузить файл (получает подпись и загружает автоматически)';
7
+ static examples = [
8
+ '<%= config.bin %> upload photo.jpg',
9
+ 'cat data.csv | <%= config.bin %> upload -',
10
+ ];
11
+ static scope = 'uploads:write';
12
+ static args = {
13
+ file: Args.string({
14
+ description: 'Путь к файлу или - для stdin',
15
+ required: true,
16
+ }),
17
+ };
18
+ static flags = {
19
+ ...BaseCommand.baseFlags,
20
+ };
21
+ async run() {
22
+ const { args, flags } = await this.parse(Upload);
23
+ this.parsedFlags = flags;
24
+ this.checkScope('uploads:write');
25
+ // Step 1: Get upload params
26
+ const { data: uploadData } = await this.apiRequest({
27
+ method: 'POST',
28
+ path: '/uploads',
29
+ });
30
+ const params = uploadData;
31
+ // Step 2: Read file
32
+ let fileBlob;
33
+ let fileName;
34
+ if (args.file === '-') {
35
+ const chunks = [];
36
+ for await (const chunk of process.stdin)
37
+ chunks.push(chunk);
38
+ fileBlob = new Blob([Buffer.concat(chunks)]);
39
+ fileName = 'stdin';
40
+ }
41
+ else {
42
+ if (!fs.existsSync(args.file)) {
43
+ this.validationError([{ message: `Файл не найден: ${args.file}` }], { type: 'PACHCA_USAGE_ERROR' });
44
+ }
45
+ fileBlob = new Blob([fs.readFileSync(args.file)]);
46
+ fileName = path.basename(args.file);
47
+ }
48
+ // Step 3: Replace ${filename} in key
49
+ const key = params.key.replace('${filename}', fileName);
50
+ // Step 4: Build FormData
51
+ const formData = new FormData();
52
+ formData.append('Content-Disposition', params['Content-Disposition']);
53
+ formData.append('acl', params.acl);
54
+ formData.append('policy', params.policy);
55
+ formData.append('x-amz-credential', params['x-amz-credential']);
56
+ formData.append('x-amz-algorithm', params['x-amz-algorithm']);
57
+ formData.append('x-amz-date', params['x-amz-date']);
58
+ formData.append('x-amz-signature', params['x-amz-signature']);
59
+ formData.append('key', key);
60
+ formData.append('file', fileBlob, fileName);
61
+ // Step 5: Upload to external URL (no auth)
62
+ await this.apiRequest({
63
+ method: 'POST',
64
+ path: params.direct_url,
65
+ formData,
66
+ noAuth: true,
67
+ });
68
+ // Output the key for use in messages
69
+ this.output({ key });
70
+ }
71
+ }
@@ -1,4 +1,41 @@
1
1
  [
2
+ {
3
+ "version": "2026.3.8",
4
+ "date": "17 марта 2026",
5
+ "changes": [
6
+ {
7
+ "type": "+",
8
+ "command": "upgrade",
9
+ "description": "Команда pachca upgrade — обновление CLI до последней версии"
10
+ },
11
+ {
12
+ "type": "-",
13
+ "command": "init hook",
14
+ "description": "Ошибки авторизации теперь выводятся в JSON при -o json (раньше формат игнорировался)"
15
+ },
16
+ {
17
+ "type": "-",
18
+ "command": "update banner",
19
+ "description": "Баннер обновления теперь показывается даже при ошибках команд"
20
+ }
21
+ ]
22
+ },
23
+ {
24
+ "version": "2026.3.7",
25
+ "date": "16 марта 2026",
26
+ "changes": [
27
+ {
28
+ "type": "+",
29
+ "command": "upload",
30
+ "description": "Загрузка файла одной командой (получает подпись + загружает автоматически)"
31
+ },
32
+ {
33
+ "type": "~",
34
+ "command": "common direct-url",
35
+ "description": "Обязательный флаг --direct-url вместо хардкод URL, запрос идёт без Authorization"
36
+ }
37
+ ]
38
+ },
2
39
  {
3
40
  "version": "2026.3.6",
4
41
  "date": "15 марта 2026",
@@ -79,13 +79,13 @@
79
79
  "skill": "pachca-messages",
80
80
  "steps": [
81
81
  {
82
- "description": "Для каждого файла: получи параметры загрузки",
83
- "command": "pachca common uploads",
84
- "notes": "Получишь `key` (с `${filename}`), `direct_url`, `policy`, подпись"
82
+ "description": "Загрузи каждый файл — команда вернёт `key`",
83
+ "command": "pachca upload report.pdf",
84
+ "notes": "Команда автоматически получает подпись и загружает файл на S3"
85
85
  },
86
86
  {
87
87
  "description": "Отправь сообщение со всеми файлами",
88
- "command": "pachca messages create --entity-id=<chat_id> --content=\"Смотри файл\" --files='[{\"key\":\"...\",\"name\":\"report.pdf\",\"file_type\":\"file\",\"size\":12345}]'"
88
+ "command": "pachca messages create --entity-id=<chat_id> --content=\"Смотри файл\" --files='[{\"key\":\"attaches/files/.../report.pdf\",\"name\":\"report.pdf\",\"file_type\":\"file\",\"size\":12345}]'"
89
89
  }
90
90
  ]
91
91
  },
@@ -1,7 +1,30 @@
1
- import { setProfile, resolveToken, TokenNotFoundError, ProfileNotFoundError, } from '../profiles.js';
1
+ import * as fs from 'node:fs';
2
+ import * as path from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { spawn } from 'node:child_process';
5
+ import semver from 'semver';
6
+ import ansis from 'ansis';
7
+ import { setProfile, getDefaults, resolveToken, TokenNotFoundError, ProfileNotFoundError, } from '../profiles.js';
2
8
  import { request } from '../client.js';
3
9
  import { outputError } from '../output.js';
4
- import { defaultOutputFormat } from '../utils.js';
10
+ import { defaultOutputFormat, isInteractive } from '../utils.js';
11
+ /**
12
+ * Resolve output format from argv before flags are parsed by oclif.
13
+ */
14
+ function resolveOutputFromArgv() {
15
+ if (process.argv.includes('--json'))
16
+ return 'json';
17
+ const outputIdx = Math.max(process.argv.indexOf('-o'), process.argv.indexOf('--output'));
18
+ if (outputIdx !== -1) {
19
+ const val = process.argv[outputIdx + 1];
20
+ if (val && ['json', 'yaml', 'csv', 'table'].includes(val))
21
+ return val;
22
+ }
23
+ const defaults = getDefaults();
24
+ if (defaults.output)
25
+ return defaults.output;
26
+ return defaultOutputFormat();
27
+ }
5
28
  // Commands that don't require auth
6
29
  const SKIP_AUTH = new Set([
7
30
  'auth:login',
@@ -20,12 +43,62 @@ const SKIP_AUTH = new Set([
20
43
  'guide',
21
44
  'introspect',
22
45
  'changelog',
46
+ 'upgrade',
23
47
  'help',
24
48
  ]);
25
49
  const hook = async function (opts) {
26
50
  const commandId = opts.id;
27
51
  if (!commandId)
28
52
  return;
53
+ // Register update banner on process exit (fires even when command fails)
54
+ if (isInteractive() && !process.env.PACHCA_SKIP_NEW_VERSION_CHECK) {
55
+ const cacheDir = opts.config.cacheDir;
56
+ const versionFile = path.join(cacheDir, 'version');
57
+ const currentVersion = opts.config.version;
58
+ process.on('exit', () => {
59
+ try {
60
+ if (fs.existsSync(versionFile)) {
61
+ const cached = JSON.parse(fs.readFileSync(versionFile, 'utf-8'));
62
+ const latest = cached.latest;
63
+ if (latest && semver.valid(latest) && semver.valid(currentVersion) && semver.gt(latest, currentVersion)) {
64
+ const box = [
65
+ '',
66
+ ansis.yellow(`╭${'─'.repeat(37)}╮`),
67
+ ansis.yellow(`│ Доступна новая версия: ${latest.padEnd(12)}│`),
68
+ ansis.yellow(`│ pachca upgrade${' '.repeat(21)}│`),
69
+ ansis.yellow(`╰${'─'.repeat(37)}╯`),
70
+ '',
71
+ ].join('\n');
72
+ process.stderr.write(box);
73
+ }
74
+ }
75
+ }
76
+ catch {
77
+ // ignore
78
+ }
79
+ });
80
+ // Background refresh if cache is stale (>1h)
81
+ try {
82
+ let shouldRefresh = true;
83
+ if (fs.existsSync(versionFile)) {
84
+ const stat = fs.statSync(versionFile);
85
+ shouldRefresh = Date.now() - stat.mtimeMs > 60 * 60 * 1000;
86
+ }
87
+ if (shouldRefresh) {
88
+ if (!fs.existsSync(cacheDir)) {
89
+ fs.mkdirSync(cacheDir, { recursive: true });
90
+ }
91
+ const scriptPath = path.join(path.dirname(fileURLToPath(import.meta.url)), '..', 'get-version.js');
92
+ if (fs.existsSync(scriptPath)) {
93
+ const child = spawn(process.execPath, [scriptPath, versionFile], { detached: true, stdio: 'ignore' });
94
+ child.unref();
95
+ }
96
+ }
97
+ }
98
+ catch {
99
+ // ignore
100
+ }
101
+ }
29
102
  // Skip auth for exempt commands
30
103
  if (SKIP_AUTH.has(commandId))
31
104
  return;
@@ -79,7 +152,7 @@ const hook = async function (opts) {
79
152
  }
80
153
  catch (error) {
81
154
  if (error instanceof TokenNotFoundError) {
82
- const format = defaultOutputFormat();
155
+ const format = resolveOutputFromArgv();
83
156
  if (format === 'json' || !process.stderr.isTTY) {
84
157
  outputError({ error: 'Token not found', type: 'PACHCA_AUTH_ERROR', code: null, hint: 'pachca auth login --token <your-token>' }, format);
85
158
  }
@@ -94,7 +167,7 @@ const hook = async function (opts) {
94
167
  process.exit(3);
95
168
  }
96
169
  if (error instanceof ProfileNotFoundError) {
97
- const format = defaultOutputFormat();
170
+ const format = resolveOutputFromArgv();
98
171
  outputError({ error: `Profile "${error.profileName}" not found`, type: 'PACHCA_USAGE_ERROR', code: null, hint: 'pachca auth list' }, format);
99
172
  process.exit(2);
100
173
  }
@@ -1,67 +1,4 @@
1
- import * as fs from 'node:fs';
2
- import * as path from 'node:path';
3
- import { fileURLToPath } from 'node:url';
4
- import { spawn } from 'node:child_process';
5
- import semver from 'semver';
6
- import ansis from 'ansis';
7
- import { isInteractive } from '../utils.js';
8
- const hook = async function (opts) {
9
- // Don't show update banner in non-interactive mode
10
- if (!isInteractive())
11
- return;
12
- if (process.env.PACHCA_SKIP_NEW_VERSION_CHECK)
13
- return;
14
- const cacheDir = opts.config.cacheDir;
15
- const versionFile = path.join(cacheDir, 'version');
16
- // Check if version file exists and show banner
17
- try {
18
- if (fs.existsSync(versionFile)) {
19
- const cached = JSON.parse(fs.readFileSync(versionFile, 'utf-8'));
20
- const latest = cached.latest;
21
- const currentVersion = opts.config.version;
22
- if (latest && semver.valid(latest) && semver.valid(currentVersion)) {
23
- if (semver.gt(latest, currentVersion)) {
24
- const box = [
25
- '',
26
- ansis.yellow(`╭${'─'.repeat(37)}╮`),
27
- ansis.yellow(`│ Доступна новая версия: ${latest.padEnd(12)}│`),
28
- ansis.yellow(`│ npm install -g @pachca/cli${' '.repeat(9)}│`),
29
- ansis.yellow(`╰${'─'.repeat(37)}╯`),
30
- '',
31
- ].join('\n');
32
- process.stderr.write(box);
33
- }
34
- }
35
- }
36
- }
37
- catch {
38
- // Ignore cache read errors
39
- }
40
- // Check if we should refresh version cache (mtime > 24h)
41
- try {
42
- let shouldRefresh = true;
43
- if (fs.existsSync(versionFile)) {
44
- const stat = fs.statSync(versionFile);
45
- const ageMs = Date.now() - stat.mtimeMs;
46
- shouldRefresh = ageMs > 60 * 60 * 1000;
47
- }
48
- if (shouldRefresh) {
49
- if (!fs.existsSync(cacheDir)) {
50
- fs.mkdirSync(cacheDir, { recursive: true });
51
- }
52
- // Spawn detached background process to fetch latest version
53
- const scriptPath = path.join(path.dirname(fileURLToPath(import.meta.url)), '..', 'get-version.js');
54
- if (fs.existsSync(scriptPath)) {
55
- const child = spawn(process.execPath, [scriptPath, versionFile], {
56
- detached: true,
57
- stdio: 'ignore',
58
- });
59
- child.unref();
60
- }
61
- }
62
- }
63
- catch {
64
- // Ignore errors in update check
65
- }
66
- };
1
+ // Banner and version refresh moved to init hook (process.on('exit'))
2
+ // so they fire even when commands fail.
3
+ const hook = async function () { };
67
4
  export default hook;
@@ -826,6 +826,264 @@
826
826
  "introspect.js"
827
827
  ]
828
828
  },
829
+ "upgrade": {
830
+ "aliases": [],
831
+ "args": {},
832
+ "description": "Обновить CLI до последней версии",
833
+ "examples": [
834
+ "<%= config.bin %> upgrade"
835
+ ],
836
+ "flags": {
837
+ "output": {
838
+ "char": "o",
839
+ "description": "Output format: table, json, yaml, csv",
840
+ "name": "output",
841
+ "hasDynamicHelp": false,
842
+ "multiple": false,
843
+ "options": [
844
+ "table",
845
+ "json",
846
+ "yaml",
847
+ "csv"
848
+ ],
849
+ "type": "option"
850
+ },
851
+ "columns": {
852
+ "char": "c",
853
+ "description": "Columns to display (comma-separated)",
854
+ "name": "columns",
855
+ "hasDynamicHelp": false,
856
+ "multiple": false,
857
+ "type": "option"
858
+ },
859
+ "no-header": {
860
+ "description": "Hide table header",
861
+ "name": "no-header",
862
+ "allowNo": false,
863
+ "type": "boolean"
864
+ },
865
+ "no-truncate": {
866
+ "description": "Do not truncate values in table",
867
+ "name": "no-truncate",
868
+ "allowNo": false,
869
+ "type": "boolean"
870
+ },
871
+ "profile": {
872
+ "char": "p",
873
+ "description": "Profile to use for this command",
874
+ "name": "profile",
875
+ "hasDynamicHelp": false,
876
+ "multiple": false,
877
+ "type": "option"
878
+ },
879
+ "token": {
880
+ "description": "Bearer token for this call (not saved)",
881
+ "name": "token",
882
+ "hasDynamicHelp": false,
883
+ "multiple": false,
884
+ "type": "option"
885
+ },
886
+ "quiet": {
887
+ "char": "q",
888
+ "description": "Suppress output except errors",
889
+ "name": "quiet",
890
+ "allowNo": false,
891
+ "type": "boolean"
892
+ },
893
+ "no-color": {
894
+ "description": "Disable color output",
895
+ "name": "no-color",
896
+ "allowNo": false,
897
+ "type": "boolean"
898
+ },
899
+ "verbose": {
900
+ "char": "v",
901
+ "description": "Show HTTP request/response details",
902
+ "name": "verbose",
903
+ "allowNo": false,
904
+ "type": "boolean"
905
+ },
906
+ "no-input": {
907
+ "description": "Disable interactive prompts",
908
+ "name": "no-input",
909
+ "allowNo": false,
910
+ "type": "boolean"
911
+ },
912
+ "dry-run": {
913
+ "description": "Show HTTP request without sending",
914
+ "name": "dry-run",
915
+ "allowNo": false,
916
+ "type": "boolean"
917
+ },
918
+ "timeout": {
919
+ "description": "Request timeout in seconds",
920
+ "name": "timeout",
921
+ "hasDynamicHelp": false,
922
+ "multiple": false,
923
+ "type": "option"
924
+ },
925
+ "no-retry": {
926
+ "description": "Disable auto-retry on 429/503",
927
+ "name": "no-retry",
928
+ "allowNo": false,
929
+ "type": "boolean"
930
+ },
931
+ "json": {
932
+ "description": "Output as JSON (alias for --output json)",
933
+ "hidden": true,
934
+ "name": "json",
935
+ "allowNo": false,
936
+ "type": "boolean"
937
+ }
938
+ },
939
+ "hasDynamicHelp": false,
940
+ "hiddenAliases": [],
941
+ "id": "upgrade",
942
+ "pluginAlias": "@pachca/cli",
943
+ "pluginName": "@pachca/cli",
944
+ "pluginType": "core",
945
+ "strict": true,
946
+ "enableJsonFlag": false,
947
+ "isESM": true,
948
+ "relativePath": [
949
+ "dist",
950
+ "commands",
951
+ "upgrade.js"
952
+ ]
953
+ },
954
+ "upload": {
955
+ "aliases": [],
956
+ "args": {
957
+ "file": {
958
+ "description": "Путь к файлу или - для stdin",
959
+ "name": "file",
960
+ "required": true
961
+ }
962
+ },
963
+ "description": "Загрузить файл (получает подпись и загружает автоматически)",
964
+ "examples": [
965
+ "<%= config.bin %> upload photo.jpg",
966
+ "cat data.csv | <%= config.bin %> upload -"
967
+ ],
968
+ "flags": {
969
+ "output": {
970
+ "char": "o",
971
+ "description": "Output format: table, json, yaml, csv",
972
+ "name": "output",
973
+ "hasDynamicHelp": false,
974
+ "multiple": false,
975
+ "options": [
976
+ "table",
977
+ "json",
978
+ "yaml",
979
+ "csv"
980
+ ],
981
+ "type": "option"
982
+ },
983
+ "columns": {
984
+ "char": "c",
985
+ "description": "Columns to display (comma-separated)",
986
+ "name": "columns",
987
+ "hasDynamicHelp": false,
988
+ "multiple": false,
989
+ "type": "option"
990
+ },
991
+ "no-header": {
992
+ "description": "Hide table header",
993
+ "name": "no-header",
994
+ "allowNo": false,
995
+ "type": "boolean"
996
+ },
997
+ "no-truncate": {
998
+ "description": "Do not truncate values in table",
999
+ "name": "no-truncate",
1000
+ "allowNo": false,
1001
+ "type": "boolean"
1002
+ },
1003
+ "profile": {
1004
+ "char": "p",
1005
+ "description": "Profile to use for this command",
1006
+ "name": "profile",
1007
+ "hasDynamicHelp": false,
1008
+ "multiple": false,
1009
+ "type": "option"
1010
+ },
1011
+ "token": {
1012
+ "description": "Bearer token for this call (not saved)",
1013
+ "name": "token",
1014
+ "hasDynamicHelp": false,
1015
+ "multiple": false,
1016
+ "type": "option"
1017
+ },
1018
+ "quiet": {
1019
+ "char": "q",
1020
+ "description": "Suppress output except errors",
1021
+ "name": "quiet",
1022
+ "allowNo": false,
1023
+ "type": "boolean"
1024
+ },
1025
+ "no-color": {
1026
+ "description": "Disable color output",
1027
+ "name": "no-color",
1028
+ "allowNo": false,
1029
+ "type": "boolean"
1030
+ },
1031
+ "verbose": {
1032
+ "char": "v",
1033
+ "description": "Show HTTP request/response details",
1034
+ "name": "verbose",
1035
+ "allowNo": false,
1036
+ "type": "boolean"
1037
+ },
1038
+ "no-input": {
1039
+ "description": "Disable interactive prompts",
1040
+ "name": "no-input",
1041
+ "allowNo": false,
1042
+ "type": "boolean"
1043
+ },
1044
+ "dry-run": {
1045
+ "description": "Show HTTP request without sending",
1046
+ "name": "dry-run",
1047
+ "allowNo": false,
1048
+ "type": "boolean"
1049
+ },
1050
+ "timeout": {
1051
+ "description": "Request timeout in seconds",
1052
+ "name": "timeout",
1053
+ "hasDynamicHelp": false,
1054
+ "multiple": false,
1055
+ "type": "option"
1056
+ },
1057
+ "no-retry": {
1058
+ "description": "Disable auto-retry on 429/503",
1059
+ "name": "no-retry",
1060
+ "allowNo": false,
1061
+ "type": "boolean"
1062
+ },
1063
+ "json": {
1064
+ "description": "Output as JSON (alias for --output json)",
1065
+ "hidden": true,
1066
+ "name": "json",
1067
+ "allowNo": false,
1068
+ "type": "boolean"
1069
+ }
1070
+ },
1071
+ "hasDynamicHelp": false,
1072
+ "hiddenAliases": [],
1073
+ "id": "upload",
1074
+ "pluginAlias": "@pachca/cli",
1075
+ "pluginName": "@pachca/cli",
1076
+ "pluginType": "core",
1077
+ "strict": true,
1078
+ "enableJsonFlag": false,
1079
+ "scope": "uploads:write",
1080
+ "isESM": true,
1081
+ "relativePath": [
1082
+ "dist",
1083
+ "commands",
1084
+ "upload.js"
1085
+ ]
1086
+ },
829
1087
  "version": {
830
1088
  "aliases": [],
831
1089
  "args": {},
@@ -3371,6 +3629,14 @@
3371
3629
  "allowNo": false,
3372
3630
  "type": "boolean"
3373
3631
  },
3632
+ "direct-url": {
3633
+ "description": "URL для отправки запроса (получается из ответа POST /uploads)",
3634
+ "name": "direct-url",
3635
+ "required": true,
3636
+ "hasDynamicHelp": false,
3637
+ "multiple": false,
3638
+ "type": "option"
3639
+ },
3374
3640
  "content-disposition": {
3375
3641
  "description": "Параметр Content-Disposition, полученный в ответе на запрос [Получение подписи, ключа и других параметров](POST /uploads)",
3376
3642
  "name": "content-disposition",
@@ -3780,7 +4046,6 @@
3780
4046
  "args": {},
3781
4047
  "description": "Получение подписи, ключа и других параметров",
3782
4048
  "examples": [
3783
- "Отправить сообщение с файлами:\n $ pachca common uploads",
3784
4049
  "Изменить вложения сообщения:\n $ pachca common uploads"
3785
4050
  ],
3786
4051
  "flags": {
@@ -12440,5 +12705,5 @@
12440
12705
  ]
12441
12706
  }
12442
12707
  },
12443
- "version": "2026.3.6"
12708
+ "version": "2026.3.8"
12444
12709
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pachca/cli",
3
- "version": "2026.3.6",
3
+ "version": "2026.3.8",
4
4
  "description": "CLI для Pachca API",
5
5
  "type": "module",
6
6
  "bin": {