@pachca/cli 2026.10.3 → 2026.11.0

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 (56) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/README.md +5 -5
  3. package/README.template.md +5 -5
  4. package/dist/base-command.js +68 -36
  5. package/dist/client.js +2 -1
  6. package/dist/commands/api.js +3 -3
  7. package/dist/commands/auth/login.js +12 -9
  8. package/dist/commands/bots/create.js +13 -7
  9. package/dist/commands/bots/list-company.js +4 -2
  10. package/dist/commands/bots/list-events.js +4 -2
  11. package/dist/commands/bots/list-tokens.js +4 -2
  12. package/dist/commands/bots/list.js +5 -3
  13. package/dist/commands/bots/update-webhook.js +8 -1
  14. package/dist/commands/bots/update.js +14 -7
  15. package/dist/commands/chats/list-company.js +4 -2
  16. package/dist/commands/chats/list.js +4 -2
  17. package/dist/commands/chats/update.js +1 -1
  18. package/dist/commands/doctor.js +60 -35
  19. package/dist/commands/drafts/create.js +6 -3
  20. package/dist/commands/drafts/list.js +4 -2
  21. package/dist/commands/drafts/update.js +7 -4
  22. package/dist/commands/group-tags/list-users.js +4 -2
  23. package/dist/commands/group-tags/list.js +4 -2
  24. package/dist/commands/important-messages/list.js +4 -2
  25. package/dist/commands/members/add.js +1 -1
  26. package/dist/commands/members/list.js +4 -2
  27. package/dist/commands/messages/create.js +7 -5
  28. package/dist/commands/messages/list.js +4 -2
  29. package/dist/commands/messages/update.js +16 -4
  30. package/dist/commands/profile/update-status.js +5 -4
  31. package/dist/commands/reactions/add.js +9 -2
  32. package/dist/commands/reactions/list.js +4 -2
  33. package/dist/commands/reactions/remove.js +1 -28
  34. package/dist/commands/read-member/list-readers.js +4 -2
  35. package/dist/commands/search/list-chats.js +5 -3
  36. package/dist/commands/search/list-messages.js +5 -3
  37. package/dist/commands/search/list-users.js +5 -3
  38. package/dist/commands/security/list.js +5 -3
  39. package/dist/commands/tasks/create.js +3 -29
  40. package/dist/commands/tasks/list.js +4 -2
  41. package/dist/commands/tasks/update.js +4 -2
  42. package/dist/commands/threads/list.js +4 -2
  43. package/dist/commands/upload.js +27 -8
  44. package/dist/commands/users/create.js +5 -2
  45. package/dist/commands/users/list.js +5 -3
  46. package/dist/commands/users/update-status.js +5 -4
  47. package/dist/commands/users/update.js +8 -5
  48. package/dist/commands/views/open.js +1 -0
  49. package/dist/data/changelog.json +150 -0
  50. package/dist/data/endpoints.json +1 -1
  51. package/dist/hooks/init.js +8 -4
  52. package/dist/lib/flags.js +25 -0
  53. package/dist/oauth.js +2 -1
  54. package/dist/profiles.js +22 -4
  55. package/oclif.manifest.json +1 -1
  56. package/package.json +2 -2
@@ -4,7 +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 { getDefaults, resolveToken, TokenNotFoundError, ProfileNotFoundError, } from '../profiles.js';
7
+ import { getDefaults, profileFlag, resolveToken, TokenNotFoundError, ProfileNotFoundError, } from '../profiles.js';
8
8
  import { ensureFreshToken, isSessionExpired } from '../token-refresh.js';
9
9
  import { outputError } from '../output.js';
10
10
  import { defaultOutputFormat, isInteractive } from '../utils.js';
@@ -146,18 +146,22 @@ const hook = async function (opts) {
146
146
  // runs with the current token and reports the real API error itself.
147
147
  if (!isSessionExpired(error))
148
148
  return;
149
+ // The server no longer renews this login: it was revoked (in the «Токены CLI»
150
+ // list, by an admin) or ran out. Name the profile, like the 401 hint does,
151
+ // so the command can be pasted as is.
152
+ const relogin = `pachca auth login${profileFlag(profileName)}`;
149
153
  const format = resolveOutputFromArgv();
150
154
  if (format === 'json' || !process.stderr.isTTY) {
151
155
  outputError({
152
156
  error: 'Session expired',
153
157
  type: 'PACHCA_AUTH_ERROR',
154
158
  code: null,
155
- hint: 'pachca auth login',
159
+ hint: relogin,
156
160
  }, format);
157
161
  }
158
162
  else {
159
- process.stderr.write(`✗ Срок входа истёк. Войдите заново:\n\n`);
160
- process.stderr.write(` pachca auth login\n`);
163
+ process.stderr.write(`✗ Вход завершён или отозван. Войдите заново:\n\n`);
164
+ process.stderr.write(` ${relogin}\n`);
161
165
  }
162
166
  process.exit(3);
163
167
  }
@@ -0,0 +1,25 @@
1
+ import { Errors, Flags } from '@oclif/core';
2
+ /**
3
+ * Flags for body fields the spec marks nullable.
4
+ *
5
+ * In such a field `null` carries meaning of its own: `--kind null` deletes a
6
+ * bot's incoming webhook, `--parent-message-id null` takes the reply off a
7
+ * draft. A plain string flag would send the text "null", which the API refuses,
8
+ * and an integer flag would not accept the word at all. These flags read the
9
+ * literal `null` as JSON null and pass every other value through as before.
10
+ */
11
+ export const nullableString = Flags.custom({
12
+ async parse(input) {
13
+ return input === 'null' ? null : input;
14
+ },
15
+ });
16
+ export const nullableInteger = Flags.custom({
17
+ async parse(input) {
18
+ if (input === 'null')
19
+ return null;
20
+ if (!/^-?\d+$/.test(input)) {
21
+ throw new Errors.CLIError(`Expected an integer or null but received: ${input}`);
22
+ }
23
+ return Number.parseInt(input, 10);
24
+ },
25
+ });
package/dist/oauth.js CHANGED
@@ -12,7 +12,8 @@ function delay(ms) {
12
12
  *
13
13
  * The CLI is a public client: it ships no secret and identifies itself with a
14
14
  * fixed `client_id`. Protection comes from the code never leaving the user's
15
- * own screen — see `printDeviceInstructions` in `commands/auth/login.ts`.
15
+ * own screen: the CLI prints the address and the code apart and never a link
16
+ * with the code in it.
16
17
  */
17
18
  export const CLI_CLIENT_ID = 'pachca_cli';
18
19
  const DEVICE_CODE_GRANT = 'urn:ietf:params:oauth:grant-type:device_code';
package/dist/profiles.js CHANGED
@@ -9,6 +9,10 @@ export function getSecretStorage(profile) {
9
9
  export function getAuthMethod(profile) {
10
10
  return profile.auth === 'oauth' ? 'oauth' : 'token';
11
11
  }
12
+ /** ` --profile <name>` to paste into a suggested command; empty for the default profile. */
13
+ export function profileFlag(profileName) {
14
+ return !profileName || profileName === 'default' ? '' : ` --profile ${profileName}`;
15
+ }
12
16
  /** True when the profile holds a refreshable OAuth session. */
13
17
  export function isRefreshable(profile) {
14
18
  return getAuthMethod(profile) === 'oauth' && !!profile.refresh_token;
@@ -262,19 +266,20 @@ export function setConfigValue(key, value) {
262
266
  * command silently wrote to the wrong workspace with the wrong token.
263
267
  */
264
268
  export function resolveToken(flags) {
269
+ const source = tokenSource(flags);
265
270
  // 1. --token flag (highest priority)
266
- if (flags.token) {
271
+ if (source.kind === 'flag') {
267
272
  return { token: flags.token };
268
273
  }
269
274
  // 2. PACHCA_TOKEN env — unless a profile was named explicitly
270
- if (!flags.profile && process.env.PACHCA_TOKEN) {
275
+ if (source.kind === 'env') {
271
276
  return { token: process.env.PACHCA_TOKEN };
272
277
  }
273
278
  // 3. --profile flag or PACHCA_PROFILE env
274
- const profileName = flags.profile || process.env.PACHCA_PROFILE || getActiveProfile();
275
- if (!profileName) {
279
+ if (source.kind === 'none') {
276
280
  throw new TokenNotFoundError();
277
281
  }
282
+ const { profileName } = source;
278
283
  const profile = getProfile(profileName);
279
284
  if (!profile) {
280
285
  throw new ProfileNotFoundError(profileName);
@@ -284,6 +289,19 @@ export function resolveToken(flags) {
284
289
  }
285
290
  return { token: profile.token, profileName, profile };
286
291
  }
292
+ export function tokenSource(flags) {
293
+ if (flags.token)
294
+ return { kind: 'flag' };
295
+ if (!flags.profile && process.env.PACHCA_TOKEN)
296
+ return { kind: 'env' };
297
+ if (flags.profile)
298
+ return { kind: 'profile', profileName: flags.profile, via: '--profile' };
299
+ if (process.env.PACHCA_PROFILE) {
300
+ return { kind: 'profile', profileName: process.env.PACHCA_PROFILE, via: 'PACHCA_PROFILE' };
301
+ }
302
+ const active = getActiveProfile();
303
+ return active ? { kind: 'profile', profileName: active, via: 'active_profile' } : { kind: 'none' };
304
+ }
287
305
  /**
288
306
  * Refresh just the cached scope list from the server's answer.
289
307
  *