@capawesome/cli 3.10.1 → 3.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 (44) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/dist/commands/apps/builds/cancel.js +3 -3
  3. package/dist/commands/apps/builds/create.js +6 -6
  4. package/dist/commands/apps/builds/download.js +4 -4
  5. package/dist/commands/apps/builds/logs.js +3 -3
  6. package/dist/commands/apps/bundles/create.js +6 -6
  7. package/dist/commands/apps/bundles/delete.js +4 -4
  8. package/dist/commands/apps/bundles/delete.test.js +2 -2
  9. package/dist/commands/apps/bundles/update.js +3 -3
  10. package/dist/commands/apps/bundles/update.test.js +2 -2
  11. package/dist/commands/apps/channels/create.js +3 -3
  12. package/dist/commands/apps/channels/create.test.js +2 -2
  13. package/dist/commands/apps/channels/delete.js +14 -6
  14. package/dist/commands/apps/channels/delete.test.js +24 -9
  15. package/dist/commands/apps/channels/list.js +34 -2
  16. package/dist/commands/apps/channels/list.test.js +1 -1
  17. package/dist/commands/apps/channels/update.js +3 -3
  18. package/dist/commands/apps/channels/update.test.js +2 -2
  19. package/dist/commands/apps/create.js +3 -3
  20. package/dist/commands/apps/create.test.js +2 -2
  21. package/dist/commands/apps/delete.js +3 -3
  22. package/dist/commands/apps/delete.test.js +2 -2
  23. package/dist/commands/apps/deployments/cancel.js +3 -3
  24. package/dist/commands/apps/deployments/create.js +4 -4
  25. package/dist/commands/apps/deployments/logs.js +3 -3
  26. package/dist/commands/apps/devices/delete.js +4 -4
  27. package/dist/commands/apps/devices/delete.test.js +2 -2
  28. package/dist/commands/apps/environments/create.js +68 -0
  29. package/dist/commands/apps/environments/delete.js +87 -0
  30. package/dist/commands/apps/environments/list.js +69 -0
  31. package/dist/commands/apps/environments/set.js +126 -0
  32. package/dist/commands/apps/environments/unset.js +98 -0
  33. package/dist/commands/login.js +2 -2
  34. package/dist/commands/login.test.js +4 -4
  35. package/dist/commands/manifests/generate.js +2 -2
  36. package/dist/commands/manifests/generate.test.js +2 -2
  37. package/dist/commands/organizations/create.js +2 -2
  38. package/dist/commands/organizations/create.test.js +2 -2
  39. package/dist/index.js +5 -0
  40. package/dist/services/app-environments.js +67 -2
  41. package/dist/utils/app-environments.js +34 -0
  42. package/dist/utils/app-environments.ts.test.js +76 -0
  43. package/dist/utils/environment.js +20 -0
  44. package/package.json +2 -3
package/CHANGELOG.md CHANGED
@@ -2,6 +2,15 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [commit-and-tag-version](https://github.com/absolute-version/commit-and-tag-version) for commit guidelines.
4
4
 
5
+ ## [3.11.0](https://github.com/capawesome-team/cli/compare/v3.10.2...v3.11.0) (2026-01-08)
6
+
7
+
8
+ ### Features
9
+
10
+ * **apps:** add commands for managing environments ([#109](https://github.com/capawesome-team/cli/issues/109)) ([2d548f3](https://github.com/capawesome-team/cli/commit/2d548f380e536e94a38b6908dadb31566eac449e))
11
+
12
+ ## [3.10.2](https://github.com/capawesome-team/cli/compare/v3.10.1...v3.10.2) (2025-12-30)
13
+
5
14
  ## [3.10.1](https://github.com/capawesome-team/cli/compare/v3.10.0...v3.10.1) (2025-12-29)
6
15
 
7
16
 
@@ -6,7 +6,7 @@ import organizationsService from '../../../services/organizations.js';
6
6
  import { prompt } from '../../../utils/prompt.js';
7
7
  import { defineCommand, defineOptions } from '@robingenz/zli';
8
8
  import consola from 'consola';
9
- import { hasTTY } from 'std-env';
9
+ import { isInteractive } from '../../../utils/environment.js';
10
10
  import { z } from 'zod';
11
11
  export default defineCommand({
12
12
  description: 'Cancel an app build.',
@@ -33,7 +33,7 @@ export default defineCommand({
33
33
  }
34
34
  // Prompt for app ID if not provided
35
35
  if (!appId) {
36
- if (!hasTTY) {
36
+ if (!isInteractive()) {
37
37
  consola.error('You must provide an app ID when running in non-interactive environment.');
38
38
  process.exit(1);
39
39
  }
@@ -70,7 +70,7 @@ export default defineCommand({
70
70
  }
71
71
  // Prompt for build ID if not provided
72
72
  if (!buildId) {
73
- if (!hasTTY) {
73
+ if (!isInteractive()) {
74
74
  consola.error('You must provide a build ID when running in non-interactive environment.');
75
75
  process.exit(1);
76
76
  }
@@ -12,7 +12,7 @@ import { defineCommand, defineOptions } from '@robingenz/zli';
12
12
  import consola from 'consola';
13
13
  import fs from 'fs/promises';
14
14
  import path from 'path';
15
- import { hasTTY } from 'std-env';
15
+ import { isInteractive } from '../../../utils/environment.js';
16
16
  import { z } from 'zod';
17
17
  const IOS_BUILD_TYPES = ['simulator', 'development', 'ad-hoc', 'app-store', 'enterprise'];
18
18
  const ANDROID_BUILD_TYPES = ['debug', 'release'];
@@ -76,7 +76,7 @@ export default defineCommand({
76
76
  }
77
77
  // Prompt for app ID if not provided
78
78
  if (!appId) {
79
- if (!hasTTY) {
79
+ if (!isInteractive()) {
80
80
  consola.error('You must provide an app ID when running in non-interactive environment.');
81
81
  process.exit(1);
82
82
  }
@@ -113,7 +113,7 @@ export default defineCommand({
113
113
  }
114
114
  // Prompt for platform if not provided
115
115
  if (!platform) {
116
- if (!hasTTY) {
116
+ if (!isInteractive()) {
117
117
  consola.error('You must provide a platform when running in non-interactive environment.');
118
118
  process.exit(1);
119
119
  }
@@ -132,7 +132,7 @@ export default defineCommand({
132
132
  }
133
133
  // Prompt for git ref if not provided
134
134
  if (!gitRef) {
135
- if (!hasTTY) {
135
+ if (!isInteractive()) {
136
136
  consola.error('You must provide a git ref when running in non-interactive environment.');
137
137
  process.exit(1);
138
138
  }
@@ -158,7 +158,7 @@ export default defineCommand({
158
158
  process.exit(1);
159
159
  }
160
160
  // Prompt for environment if not provided
161
- if (!environment && hasTTY) {
161
+ if (!environment && isInteractive()) {
162
162
  // @ts-ignore wait till https://github.com/unjs/consola/pull/280 is merged
163
163
  const selectEnvironment = await prompt('Do you want to select an environment?', {
164
164
  type: 'confirm',
@@ -179,7 +179,7 @@ export default defineCommand({
179
179
  }
180
180
  }
181
181
  // Prompt for certificate if not provided
182
- if (!certificate && hasTTY) {
182
+ if (!certificate && isInteractive()) {
183
183
  // @ts-ignore wait till https://github.com/unjs/consola/pull/280 is merged
184
184
  const selectCertificate = await prompt('Do you want to select a certificate?', {
185
185
  type: 'confirm',
@@ -7,7 +7,7 @@ import { defineCommand, defineOptions } from '@robingenz/zli';
7
7
  import consola from 'consola';
8
8
  import fs from 'fs/promises';
9
9
  import path from 'path';
10
- import { hasTTY } from 'std-env';
10
+ import { isInteractive } from '../../../utils/environment.js';
11
11
  import { z } from 'zod';
12
12
  export default defineCommand({
13
13
  description: 'Download an app build.',
@@ -46,7 +46,7 @@ export default defineCommand({
46
46
  }
47
47
  // Prompt for app ID if not provided
48
48
  if (!appId) {
49
- if (!hasTTY) {
49
+ if (!isInteractive()) {
50
50
  consola.error('You must provide an app ID when running in non-interactive environment.');
51
51
  process.exit(1);
52
52
  }
@@ -83,7 +83,7 @@ export default defineCommand({
83
83
  }
84
84
  // Prompt for build ID if not provided
85
85
  if (!buildId) {
86
- if (!hasTTY) {
86
+ if (!isInteractive()) {
87
87
  consola.error('You must provide a build ID when running in non-interactive environment.');
88
88
  process.exit(1);
89
89
  }
@@ -126,7 +126,7 @@ export default defineCommand({
126
126
  let downloadIpa = options.ipa;
127
127
  // Prompt for artifact types if none were provided
128
128
  if (!downloadApk && !downloadAab && !downloadIpa) {
129
- if (!hasTTY) {
129
+ if (!isInteractive()) {
130
130
  consola.error('You must specify at least one artifact type (--apk, --aab, or --ipa) when running in non-interactive environment.');
131
131
  process.exit(1);
132
132
  }
@@ -7,7 +7,7 @@ import { prompt } from '../../../utils/prompt.js';
7
7
  import { wait } from '../../../utils/wait.js';
8
8
  import { defineCommand, defineOptions } from '@robingenz/zli';
9
9
  import consola from 'consola';
10
- import { hasTTY } from 'std-env';
10
+ import { isInteractive } from '../../../utils/environment.js';
11
11
  import { z } from 'zod';
12
12
  export default defineCommand({
13
13
  description: 'Show logs of an app build.',
@@ -34,7 +34,7 @@ export default defineCommand({
34
34
  }
35
35
  // Prompt for app ID if not provided
36
36
  if (!appId) {
37
- if (!hasTTY) {
37
+ if (!isInteractive()) {
38
38
  consola.error('You must provide an app ID when running in non-interactive environment.');
39
39
  process.exit(1);
40
40
  }
@@ -71,7 +71,7 @@ export default defineCommand({
71
71
  }
72
72
  // Prompt for platform if not provided
73
73
  if (!buildId) {
74
- if (!hasTTY) {
74
+ if (!isInteractive()) {
75
75
  consola.error('You must provide a platform when running in non-interactive environment.');
76
76
  process.exit(1);
77
77
  }
@@ -19,9 +19,9 @@ import { exec } from 'child_process';
19
19
  import consola from 'consola';
20
20
  import { createReadStream } from 'fs';
21
21
  import pathModule from 'path';
22
- import { hasTTY } from 'std-env';
23
22
  import { promisify } from 'util';
24
23
  import { z } from 'zod';
24
+ import { isInteractive } from '../../../utils/environment.js';
25
25
  // Promisified exec for running build scripts
26
26
  const execAsync = promisify(exec);
27
27
  export default defineCommand({
@@ -138,7 +138,7 @@ export default defineCommand({
138
138
  }
139
139
  // If still no path, prompt the user
140
140
  if (!path) {
141
- if (!hasTTY) {
141
+ if (!isInteractive()) {
142
142
  consola.error('You must provide either a path or a url when running in non-interactive environment.');
143
143
  process.exit(1);
144
144
  }
@@ -164,7 +164,7 @@ export default defineCommand({
164
164
  if (!buildScript) {
165
165
  consola.warn('No build script (`capawesome:build` or `build`) found in package.json.');
166
166
  }
167
- else if (hasTTY) {
167
+ else if (isInteractive()) {
168
168
  const shouldBuild = await prompt('Do you want to run the build script before creating the bundle to ensure the latest assets are included?', {
169
169
  type: 'confirm',
170
170
  initial: true,
@@ -249,7 +249,7 @@ export default defineCommand({
249
249
  }
250
250
  // If still no appId, prompt the user
251
251
  if (!appId) {
252
- if (!hasTTY) {
252
+ if (!isInteractive()) {
253
253
  consola.error('You must provide an app ID when running in non-interactive environment.');
254
254
  process.exit(1);
255
255
  }
@@ -285,7 +285,7 @@ export default defineCommand({
285
285
  }
286
286
  }
287
287
  }
288
- if (!channel && hasTTY) {
288
+ if (!channel && isInteractive()) {
289
289
  const shouldDeployToChannel = await prompt('Do you want to deploy to a specific channel?', {
290
290
  type: 'confirm',
291
291
  initial: false,
@@ -338,7 +338,7 @@ export default defineCommand({
338
338
  const app = await appsService.findOne({ appId });
339
339
  const appName = app.name;
340
340
  // Final confirmation before creating bundle
341
- if (path && hasTTY) {
341
+ if (path && isInteractive()) {
342
342
  const relativePath = pathModule.relative(process.cwd(), path);
343
343
  const confirmed = await prompt(`Are you sure you want to create a bundle from path "${relativePath}" for app "${appName}" (${appId})?`, {
344
344
  type: 'confirm',
@@ -5,7 +5,7 @@ import organizationsService from '../../../services/organizations.js';
5
5
  import { prompt } from '../../../utils/prompt.js';
6
6
  import { defineCommand, defineOptions } from '@robingenz/zli';
7
7
  import consola from 'consola';
8
- import { hasTTY } from 'std-env';
8
+ import { isInteractive } from '../../../utils/environment.js';
9
9
  import { z } from 'zod';
10
10
  export default defineCommand({
11
11
  description: 'Delete an app bundle.',
@@ -21,7 +21,7 @@ export default defineCommand({
21
21
  }
22
22
  // Prompt for missing arguments
23
23
  if (!appId) {
24
- if (!hasTTY) {
24
+ if (!isInteractive()) {
25
25
  consola.error('You must provide an app ID when running in non-interactive environment.');
26
26
  process.exit(1);
27
27
  }
@@ -53,7 +53,7 @@ export default defineCommand({
53
53
  });
54
54
  }
55
55
  if (!bundleId) {
56
- if (!hasTTY) {
56
+ if (!isInteractive()) {
57
57
  consola.error('You must provide the bundle ID when running in non-interactive environment.');
58
58
  process.exit(1);
59
59
  }
@@ -62,7 +62,7 @@ export default defineCommand({
62
62
  });
63
63
  }
64
64
  // Confirm deletion
65
- if (hasTTY) {
65
+ if (isInteractive()) {
66
66
  const confirmed = await prompt('Are you sure you want to delete this bundle?', {
67
67
  type: 'confirm',
68
68
  });
@@ -11,8 +11,8 @@ vi.mock('@/utils/user-config.js');
11
11
  vi.mock('@/utils/prompt.js');
12
12
  vi.mock('@/services/authorization-service.js');
13
13
  vi.mock('consola');
14
- vi.mock('std-env', () => ({
15
- hasTTY: true,
14
+ vi.mock('@/utils/environment.js', () => ({
15
+ isInteractive: () => true,
16
16
  }));
17
17
  describe('apps-bundles-delete', () => {
18
18
  const mockUserConfig = vi.mocked(userConfig);
@@ -5,7 +5,7 @@ import organizationsService from '../../../services/organizations.js';
5
5
  import { prompt } from '../../../utils/prompt.js';
6
6
  import { defineCommand, defineOptions } from '@robingenz/zli';
7
7
  import consola from 'consola';
8
- import { hasTTY } from 'std-env';
8
+ import { isInteractive } from '../../../utils/environment.js';
9
9
  import { z } from 'zod';
10
10
  export default defineCommand({
11
11
  description: 'Update an app bundle.',
@@ -53,7 +53,7 @@ export default defineCommand({
53
53
  }
54
54
  // Prompt for missing arguments
55
55
  if (!appId) {
56
- if (!hasTTY) {
56
+ if (!isInteractive()) {
57
57
  consola.error('You must provide an app ID when running in non-interactive environment.');
58
58
  process.exit(1);
59
59
  }
@@ -85,7 +85,7 @@ export default defineCommand({
85
85
  });
86
86
  }
87
87
  if (!bundleId) {
88
- if (!hasTTY) {
88
+ if (!isInteractive()) {
89
89
  consola.error('You must provide the bundle ID when running in non-interactive environment.');
90
90
  process.exit(1);
91
91
  }
@@ -11,8 +11,8 @@ vi.mock('@/utils/user-config.js');
11
11
  vi.mock('@/utils/prompt.js');
12
12
  vi.mock('@/services/authorization-service.js');
13
13
  vi.mock('consola');
14
- vi.mock('std-env', () => ({
15
- hasTTY: true,
14
+ vi.mock('@/utils/environment.js', () => ({
15
+ isInteractive: () => true,
16
16
  }));
17
17
  describe('apps-bundles-update', () => {
18
18
  const mockUserConfig = vi.mocked(userConfig);
@@ -6,7 +6,7 @@ import { getMessageFromUnknownError } from '../../../utils/error.js';
6
6
  import { prompt } from '../../../utils/prompt.js';
7
7
  import { defineCommand, defineOptions } from '@robingenz/zli';
8
8
  import consola from 'consola';
9
- import { hasTTY } from 'std-env';
9
+ import { isInteractive } from '../../../utils/environment.js';
10
10
  import { z } from 'zod';
11
11
  export default defineCommand({
12
12
  description: 'Create a new app channel.',
@@ -43,7 +43,7 @@ export default defineCommand({
43
43
  }
44
44
  // Validate the app ID
45
45
  if (!appId) {
46
- if (!hasTTY) {
46
+ if (!isInteractive()) {
47
47
  consola.error('You must provide an app ID when running in non-interactive environment.');
48
48
  process.exit(1);
49
49
  }
@@ -76,7 +76,7 @@ export default defineCommand({
76
76
  }
77
77
  // Validate the channel name
78
78
  if (!name) {
79
- if (!hasTTY) {
79
+ if (!isInteractive()) {
80
80
  consola.error('You must provide the channel name when running in non-interactive environment.');
81
81
  process.exit(1);
82
82
  }
@@ -11,8 +11,8 @@ vi.mock('@/utils/user-config.js');
11
11
  vi.mock('@/utils/prompt.js');
12
12
  vi.mock('@/services/authorization-service.js');
13
13
  vi.mock('consola');
14
- vi.mock('std-env', () => ({
15
- hasTTY: true,
14
+ vi.mock('@/utils/environment.js', () => ({
15
+ isInteractive: () => true,
16
16
  }));
17
17
  describe('apps-channels-create', () => {
18
18
  const mockUserConfig = vi.mocked(userConfig);
@@ -5,7 +5,7 @@ import organizationsService from '../../../services/organizations.js';
5
5
  import { prompt } from '../../../utils/prompt.js';
6
6
  import { defineCommand, defineOptions } from '@robingenz/zli';
7
7
  import consola from 'consola';
8
- import { hasTTY } from 'std-env';
8
+ import { isInteractive } from '../../../utils/environment.js';
9
9
  import { z } from 'zod';
10
10
  export default defineCommand({
11
11
  description: 'Delete an app channel.',
@@ -27,7 +27,7 @@ export default defineCommand({
27
27
  process.exit(1);
28
28
  }
29
29
  if (!appId) {
30
- if (!hasTTY) {
30
+ if (!isInteractive()) {
31
31
  consola.error('You must provide an app ID when running in non-interactive environment.');
32
32
  process.exit(1);
33
33
  }
@@ -60,16 +60,24 @@ export default defineCommand({
60
60
  }
61
61
  // Prompt for channel ID or name if neither is provided
62
62
  if (!channelId && !name) {
63
- if (!hasTTY) {
63
+ if (!isInteractive()) {
64
64
  consola.error('You must provide either the channel ID or name when running in non-interactive environment.');
65
65
  process.exit(1);
66
66
  }
67
- name = await prompt('Enter the channel name:', {
68
- type: 'text',
67
+ const channels = await appChannelsService.findAll({ appId });
68
+ if (!channels.length) {
69
+ consola.error('No channels found for this app. Create one first.');
70
+ process.exit(1);
71
+ }
72
+ // @ts-ignore wait till https://github.com/unjs/consola/pull/280 is merged
73
+ const selectedChannelId = await prompt('Select the channel to delete:', {
74
+ type: 'select',
75
+ options: channels.map((channel) => ({ label: channel.name, value: channel.id })),
69
76
  });
77
+ channelId = selectedChannelId;
70
78
  }
71
79
  // Confirm deletion
72
- if (hasTTY) {
80
+ if (isInteractive()) {
73
81
  const confirmed = await prompt('Are you sure you want to delete this channel?', {
74
82
  type: 'confirm',
75
83
  });
@@ -11,8 +11,8 @@ vi.mock('@/utils/user-config.js');
11
11
  vi.mock('@/utils/prompt.js');
12
12
  vi.mock('@/services/authorization-service.js');
13
13
  vi.mock('consola');
14
- vi.mock('std-env', () => ({
15
- hasTTY: true,
14
+ vi.mock('@/utils/environment.js', () => ({
15
+ isInteractive: () => true,
16
16
  }));
17
17
  describe('apps-channels-delete', () => {
18
18
  const mockUserConfig = vi.mocked(userConfig);
@@ -107,22 +107,37 @@ describe('apps-channels-delete', () => {
107
107
  expect(deleteScope.isDone()).toBe(true);
108
108
  expect(mockConsola.success).toHaveBeenCalledWith('Channel deleted successfully.');
109
109
  });
110
- it('should prompt for channel name when neither channelId nor name provided', async () => {
110
+ it('should prompt for channel selection when channelId and name not provided', async () => {
111
111
  const appId = 'app-123';
112
+ const channelId = 'channel-456';
112
113
  const channelName = 'development';
113
114
  const testToken = 'test-token';
114
115
  const options = { appId };
115
- const scope = nock(DEFAULT_API_BASE_URL)
116
- .delete(`/v1/apps/${appId}/channels`)
117
- .query({ name: channelName })
116
+ const channelsListScope = nock(DEFAULT_API_BASE_URL)
117
+ .get(`/v1/apps/${appId}/channels`)
118
+ .query(true)
119
+ .matchHeader('Authorization', `Bearer ${testToken}`)
120
+ .reply(200, [
121
+ {
122
+ id: channelId,
123
+ name: channelName,
124
+ appId,
125
+ },
126
+ ]);
127
+ const deleteScope = nock(DEFAULT_API_BASE_URL)
128
+ .delete(`/v1/apps/${appId}/channels/${channelId}`)
118
129
  .matchHeader('Authorization', `Bearer ${testToken}`)
119
130
  .reply(200);
120
131
  mockPrompt
121
- .mockResolvedValueOnce(channelName) // channel name input
132
+ .mockResolvedValueOnce(channelId) // channel selection
122
133
  .mockResolvedValueOnce(true); // confirmation
123
134
  await deleteChannelCommand.action(options, undefined);
124
- expect(scope.isDone()).toBe(true);
125
- expect(mockPrompt).toHaveBeenCalledWith('Enter the channel name:', { type: 'text' });
135
+ expect(channelsListScope.isDone()).toBe(true);
136
+ expect(deleteScope.isDone()).toBe(true);
137
+ expect(mockPrompt).toHaveBeenCalledWith('Select the channel to delete:', {
138
+ type: 'select',
139
+ options: [{ label: channelName, value: channelId }],
140
+ });
126
141
  expect(mockConsola.success).toHaveBeenCalledWith('Channel deleted successfully.');
127
142
  });
128
143
  it('should handle API error during deletion', async () => {
@@ -1,5 +1,9 @@
1
1
  import appChannelsService from '../../../services/app-channels.js';
2
+ import appsService from '../../../services/apps.js';
2
3
  import authorizationService from '../../../services/authorization-service.js';
4
+ import organizationsService from '../../../services/organizations.js';
5
+ import { isInteractive } from '../../../utils/environment.js';
6
+ import { prompt } from '../../../utils/prompt.js';
3
7
  import { defineCommand, defineOptions } from '@robingenz/zli';
4
8
  import consola from 'consola';
5
9
  import { z } from 'zod';
@@ -18,8 +22,36 @@ export default defineCommand({
18
22
  process.exit(1);
19
23
  }
20
24
  if (!appId) {
21
- consola.error('You must provide an app ID.');
22
- process.exit(1);
25
+ if (!isInteractive()) {
26
+ consola.error('You must provide an app ID when running in non-interactive environment.');
27
+ process.exit(1);
28
+ }
29
+ const organizations = await organizationsService.findAll();
30
+ if (organizations.length === 0) {
31
+ consola.error('You must create an organization before listing channels.');
32
+ process.exit(1);
33
+ }
34
+ // @ts-ignore wait till https://github.com/unjs/consola/pull/280 is merged
35
+ const organizationId = await prompt('Select the organization of the app for which you want to list channels.', {
36
+ type: 'select',
37
+ options: organizations.map((organization) => ({ label: organization.name, value: organization.id })),
38
+ });
39
+ if (!organizationId) {
40
+ consola.error('You must select the organization of an app for which you want to list channels.');
41
+ process.exit(1);
42
+ }
43
+ const apps = await appsService.findAll({
44
+ organizationId,
45
+ });
46
+ if (!apps.length) {
47
+ consola.error('You must create an app before listing channels.');
48
+ process.exit(1);
49
+ }
50
+ // @ts-ignore wait till https://github.com/unjs/consola/pull/280 is merged
51
+ appId = await prompt('Which app do you want to list the channels for?', {
52
+ type: 'select',
53
+ options: apps.map((app) => ({ label: app.name, value: app.id })),
54
+ });
23
55
  }
24
56
  const foundChannels = await appChannelsService.findAll({
25
57
  appId,
@@ -38,7 +38,7 @@ describe('apps-channels-list', () => {
38
38
  it('should require appId', async () => {
39
39
  const options = { appId: undefined };
40
40
  await expect(listChannelsCommand.action(options, undefined)).rejects.toThrow('Process exited with code 1');
41
- expect(mockConsola.error).toHaveBeenCalledWith('You must provide an app ID.');
41
+ expect(mockConsola.error).toHaveBeenCalledWith('You must provide an app ID when running in non-interactive environment.');
42
42
  });
43
43
  it('should list channels and display table format', async () => {
44
44
  const appId = 'app-123';
@@ -5,7 +5,7 @@ import organizationsService from '../../../services/organizations.js';
5
5
  import { prompt } from '../../../utils/prompt.js';
6
6
  import { defineCommand, defineOptions } from '@robingenz/zli';
7
7
  import consola from 'consola';
8
- import { hasTTY } from 'std-env';
8
+ import { isInteractive } from '../../../utils/environment.js';
9
9
  import { z } from 'zod';
10
10
  export default defineCommand({
11
11
  description: 'Update an existing app channel.',
@@ -26,7 +26,7 @@ export default defineCommand({
26
26
  }
27
27
  // Prompt app ID if not provided
28
28
  if (!appId) {
29
- if (!hasTTY) {
29
+ if (!isInteractive()) {
30
30
  consola.error('You must provide an app ID when running in non-interactive environment.');
31
31
  process.exit(1);
32
32
  }
@@ -59,7 +59,7 @@ export default defineCommand({
59
59
  }
60
60
  // Prompt for channel ID if not provided
61
61
  if (!channelId) {
62
- if (!hasTTY) {
62
+ if (!isInteractive()) {
63
63
  consola.error('You must provide the channel ID when running in non-interactive environment.');
64
64
  process.exit(1);
65
65
  }
@@ -11,8 +11,8 @@ vi.mock('@/utils/user-config.js');
11
11
  vi.mock('@/utils/prompt.js');
12
12
  vi.mock('@/services/authorization-service.js');
13
13
  vi.mock('consola');
14
- vi.mock('std-env', () => ({
15
- hasTTY: true,
14
+ vi.mock('@/utils/environment.js', () => ({
15
+ isInteractive: () => true,
16
16
  }));
17
17
  describe('apps-channels-update', () => {
18
18
  const mockUserConfig = vi.mocked(userConfig);
@@ -1,10 +1,10 @@
1
1
  import appsService from '../../services/apps.js';
2
2
  import authorizationService from '../../services/authorization-service.js';
3
3
  import organizationsService from '../../services/organizations.js';
4
+ import { isInteractive } from '../../utils/environment.js';
4
5
  import { prompt } from '../../utils/prompt.js';
5
6
  import { defineCommand, defineOptions } from '@robingenz/zli';
6
7
  import consola from 'consola';
7
- import { hasTTY } from 'std-env';
8
8
  import { z } from 'zod';
9
9
  export default defineCommand({
10
10
  description: 'Create a new app.',
@@ -19,7 +19,7 @@ export default defineCommand({
19
19
  process.exit(1);
20
20
  }
21
21
  if (!organizationId) {
22
- if (!hasTTY) {
22
+ if (!isInteractive()) {
23
23
  consola.error('You must provide the organization ID when running in non-interactive environment.');
24
24
  process.exit(1);
25
25
  }
@@ -39,7 +39,7 @@ export default defineCommand({
39
39
  }
40
40
  }
41
41
  if (!name) {
42
- if (!hasTTY) {
42
+ if (!isInteractive()) {
43
43
  consola.error('You must provide the app name when running in non-interactive environment.');
44
44
  process.exit(1);
45
45
  }
@@ -11,8 +11,8 @@ vi.mock('@/utils/user-config.js');
11
11
  vi.mock('@/utils/prompt.js');
12
12
  vi.mock('@/services/authorization-service.js');
13
13
  vi.mock('consola');
14
- vi.mock('std-env', () => ({
15
- hasTTY: true,
14
+ vi.mock('@/utils/environment.js', () => ({
15
+ isInteractive: () => true,
16
16
  }));
17
17
  describe('apps-create', () => {
18
18
  const mockUserConfig = vi.mocked(userConfig);
@@ -1,10 +1,10 @@
1
1
  import appsService from '../../services/apps.js';
2
2
  import authorizationService from '../../services/authorization-service.js';
3
3
  import organizationsService from '../../services/organizations.js';
4
+ import { isInteractive } from '../../utils/environment.js';
4
5
  import { prompt } from '../../utils/prompt.js';
5
6
  import { defineCommand, defineOptions } from '@robingenz/zli';
6
7
  import consola from 'consola';
7
- import { hasTTY } from 'std-env';
8
8
  import { z } from 'zod';
9
9
  export default defineCommand({
10
10
  description: 'Delete an app.',
@@ -18,7 +18,7 @@ export default defineCommand({
18
18
  process.exit(1);
19
19
  }
20
20
  if (!appId) {
21
- if (!hasTTY) {
21
+ if (!isInteractive()) {
22
22
  consola.error('You must provide the app ID when running in non-interactive environment.');
23
23
  process.exit(1);
24
24
  }
@@ -49,7 +49,7 @@ export default defineCommand({
49
49
  options: apps.map((app) => ({ label: app.name, value: app.id })),
50
50
  });
51
51
  }
52
- if (hasTTY) {
52
+ if (isInteractive()) {
53
53
  const confirmed = await prompt('Are you sure you want to delete this app?', {
54
54
  type: 'confirm',
55
55
  });
@@ -11,8 +11,8 @@ vi.mock('@/utils/user-config.js');
11
11
  vi.mock('@/utils/prompt.js');
12
12
  vi.mock('@/services/authorization-service.js');
13
13
  vi.mock('consola');
14
- vi.mock('std-env', () => ({
15
- hasTTY: true,
14
+ vi.mock('@/utils/environment.js', () => ({
15
+ isInteractive: () => true,
16
16
  }));
17
17
  describe('apps-delete', () => {
18
18
  const mockUserConfig = vi.mocked(userConfig);