@stacksjs/buddy 0.58.48 → 0.58.49

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.
@@ -0,0 +1,268 @@
1
+ import process from 'node:process'
2
+ import { Action } from '@stacksjs/enums'
3
+ import {
4
+ runAction,
5
+ runApiDevServer,
6
+ runComponentsDevServer,
7
+ runDashboardDevServer,
8
+ runDesktopDevServer,
9
+ runDocsDevServer,
10
+ runFrontendDevServer,
11
+ runSystemTrayDevServer,
12
+ } from '@stacksjs/actions'
13
+ import { ExitCode } from '@stacksjs/types'
14
+ import type { CLI, DevOptions } from '@stacksjs/types'
15
+ import { intro, log, outro, prompt, runCommand } from '@stacksjs/cli'
16
+ import { libsPath } from '@stacksjs/path'
17
+
18
+ export function dev(buddy: CLI) {
19
+ const descriptions = {
20
+ dev: 'Starts development server',
21
+ frontend: 'Starts the frontend development server',
22
+ components: 'Start the Components development server',
23
+ desktop: 'Start the Desktop App development server',
24
+ dashboard: 'Start the Dashboard development server',
25
+ api: 'Start the local API development server',
26
+ email: 'Start the Email development server',
27
+ docs: 'Start the Documentation development server',
28
+ systemTray: 'Start the System Tray development server',
29
+ interactive: 'Get asked which development server to start',
30
+ select: 'Which development server are you trying to start?',
31
+ withLocalhost: 'Include the localhost URL in the output',
32
+ project: 'Target a specific project',
33
+ verbose: 'Enable verbose output',
34
+ }
35
+
36
+ buddy
37
+ .command('dev [server]', descriptions.dev) // server is optional because options can be used
38
+ .option('-f, --frontend', descriptions.frontend)
39
+ .option('-a, --api', descriptions.api)
40
+ .option('-e, --email', descriptions.email)
41
+ .option('-c, --components', descriptions.components)
42
+ .option('-d, --dashboard', descriptions.dashboard)
43
+ .option('-t, --desktop', descriptions.desktop)
44
+ .option('-d, --docs', descriptions.docs)
45
+ .option('-t, --system-tray', descriptions.systemTray)
46
+ .option('-i, --interactive', descriptions.interactive, { default: false })
47
+ .option('-l, --with-localhost', descriptions.withLocalhost, { default: false })
48
+ .option('-p, --project', descriptions.project, { default: false })
49
+ .option('--verbose', descriptions.verbose, { default: false })
50
+ .action(async (server: string | undefined, options: DevOptions) => {
51
+ const perf = await intro('buddy dev')
52
+
53
+ // log.info('Ensuring web server/s running...') // in other words, ensure caddy is running
54
+
55
+ // // check if port 443 is open
56
+ // const result = await runCommand('lsof -i :443', { silent: true })
57
+
58
+ // if (result.isErr())
59
+ // log.warn('While checking if port 443 is open, we noticed it may be in use')
60
+
61
+ // runAction(Action.StartCaddy, { ...options, silent: true })
62
+
63
+ switch (server) {
64
+ case 'frontend':
65
+ await runFrontendDevServer(options)
66
+ break
67
+ case 'api':
68
+ await runApiDevServer(options)
69
+ break
70
+ case 'components':
71
+ await runComponentsDevServer(options)
72
+ break
73
+ case 'dashboard':
74
+ await runDashboardDevServer(options)
75
+ break
76
+ case 'desktop':
77
+ await runDesktopDevServer(options)
78
+ break
79
+ case 'system-tray':
80
+ await runSystemTrayDevServer(options)
81
+ break
82
+ // case 'email':
83
+ // await runEmailDevServer(options)
84
+ // break
85
+ case 'docs':
86
+ await runDocsDevServer(options)
87
+ break
88
+ default:
89
+ }
90
+
91
+ if (wantsInteractive(options)) {
92
+ const answer = await prompt.require()
93
+ .select(descriptions.select, {
94
+ options: [
95
+ { value: 'all', label: 'All' },
96
+ { value: 'frontend', label: 'Frontend' },
97
+ { value: 'api', label: 'Backend' },
98
+ { value: 'dashboard', label: 'Dashboard' },
99
+ { value: 'desktop', label: 'Desktop' },
100
+ { value: 'email', label: 'Email' },
101
+ { value: 'components', label: 'Components' },
102
+ { value: 'docs', label: 'Documentation' },
103
+ ],
104
+ })
105
+
106
+ if (answer === 'components') {
107
+ await runComponentsDevServer(options)
108
+ }
109
+ else if (answer === 'api') {
110
+ await runApiDevServer(options)
111
+ }
112
+ else if (answer === 'dashboard') {
113
+ await runDashboardDevServer(options)
114
+ }
115
+ // else if (answer === 'email')
116
+ // await runEmailDevServer(options)
117
+ else if (answer === 'docs') {
118
+ await runDocsDevServer(options)
119
+ }
120
+
121
+ else {
122
+ log.error('Invalid option during interactive mode')
123
+ process.exit(ExitCode.InvalidArgument)
124
+ }
125
+ }
126
+
127
+ else {
128
+ if (options.components)
129
+ await runComponentsDevServer(options)
130
+ if (options.docs)
131
+ await runDocsDevServer(options)
132
+ else if (options.api)
133
+ await runApiDevServer(options)
134
+ // else if (options.email)
135
+ // await runEmailDevServer(options)
136
+ }
137
+
138
+ await startDevelopmentServer(options)
139
+
140
+ outro('Exited', { startTime: perf, useSeconds: true })
141
+ process.exit(ExitCode.Success)
142
+ })
143
+
144
+ buddy
145
+ .command('dev:components', descriptions.components)
146
+ .option('-p, --project', descriptions.project, { default: false })
147
+ .option('--verbose', descriptions.verbose, { default: false })
148
+ .action(async (options: DevOptions) => {
149
+ const perf = await intro('buddy dev:components')
150
+ const result = await runCommand('bun run dev', {
151
+ cwd: libsPath('components/vue'),
152
+ // silent: !options.verbose,
153
+ })
154
+
155
+ if (options.verbose)
156
+ log.info('buddy dev:components result', result)
157
+
158
+ if (result.isErr()) {
159
+ await outro('While running the dev:components command, there was an issue', { startTime: perf, useSeconds: true }, result.error)
160
+ process.exit()
161
+ }
162
+
163
+ // eslint-disable-next-line no-console
164
+ console.log('')
165
+ await outro('Exited', { startTime: perf, useSeconds: true })
166
+ process.exit(ExitCode.Success)
167
+ })
168
+
169
+ buddy
170
+ .command('dev:docs', descriptions.docs)
171
+ .option('-p, --project', descriptions.project, { default: false })
172
+ .option('--verbose', descriptions.verbose, { default: false })
173
+ .action(async (options: DevOptions) => {
174
+ const perf = await intro('buddy dev:docs')
175
+ const result = await runAction(Action.DevDocs, options)
176
+
177
+ if (result.isErr()) {
178
+ await outro('While running the dev:docs command, there was an issue', { startTime: perf, useSeconds: true }, result.error)
179
+ process.exit()
180
+ }
181
+
182
+ // eslint-disable-next-line no-console
183
+ console.log('')
184
+ await outro('Exited', { startTime: perf, useSeconds: true })
185
+ process.exit(ExitCode.Success)
186
+ })
187
+
188
+ buddy
189
+ .command('dev:desktop', descriptions.desktop)
190
+ .option('-p, --project', descriptions.project, { default: false })
191
+ .option('--verbose', descriptions.verbose, { default: false })
192
+ .action(async (options: DevOptions) => {
193
+ const perf = await intro('buddy dev:desktop')
194
+ const result = await runAction(Action.DevDesktop, options)
195
+
196
+ if (result.isErr()) {
197
+ await outro('While running the dev:desktop command, there was an issue', { startTime: perf, useSeconds: true }, result.error)
198
+ process.exit()
199
+ }
200
+
201
+ // eslint-disable-next-line no-console
202
+ console.log('')
203
+ await outro('Exited', { startTime: perf, useSeconds: true })
204
+ process.exit(ExitCode.Success)
205
+ })
206
+
207
+ buddy
208
+ .command('dev:api', descriptions.api)
209
+ .option('-p, --project', descriptions.project, { default: false })
210
+ .option('--verbose', descriptions.verbose, { default: false })
211
+ .action(async (options: DevOptions) => {
212
+ await runApiDevServer(options)
213
+ })
214
+
215
+ // buddy
216
+ // .command('dev:functions', descriptions.api)
217
+ .option('-p, --project', descriptions.project, { default: false })//
218
+ .option('--verbose', descriptions.verbose, { default: false })
219
+ // .action(async (options: DevOptions) => {
220
+ // await runFunctionsDevServer(options)
221
+ // })
222
+
223
+ buddy
224
+ .command('dev:frontend', descriptions.frontend)
225
+ .alias('dev:pages')
226
+ .alias('dev:views')
227
+ .option('-p, --project', descriptions.project, { default: false })
228
+ .option('--verbose', descriptions.verbose, { default: false })
229
+ .action(async (options: DevOptions) => {
230
+ await runFrontendDevServer(options)
231
+ })
232
+
233
+ buddy
234
+ .command('dev:dashboard', descriptions.dashboard)
235
+ .alias('dev:admin')
236
+ .option('-p, --project', descriptions.project, { default: false })
237
+ .option('--verbose', descriptions.verbose, { default: false })
238
+ .action(async (options: DevOptions) => {
239
+ await runDashboardDevServer(options)
240
+ })
241
+
242
+ buddy
243
+ .command('dev:system-tray', descriptions.systemTray)
244
+ .alias('dev:tray')
245
+ .option('-p, --project', descriptions.project, { default: false })
246
+ .option('--verbose', descriptions.verbose, { default: false })
247
+ .action(async (options: DevOptions) => {
248
+ await runSystemTrayDevServer(options)
249
+ })
250
+
251
+ buddy.on('dev:*', () => {
252
+ console.error('Invalid command: %s\nSee --help for a list of available commands.', buddy.args.join(' '))
253
+ process.exit(1)
254
+ })
255
+ }
256
+
257
+ export async function startDevelopmentServer(options: DevOptions) {
258
+ const result = await runAction(Action.Dev, options)
259
+
260
+ if (result.isErr()) {
261
+ log.error('While running the dev command, there was an issue', result.error)
262
+ process.exit(ExitCode.InvalidArgument)
263
+ }
264
+ }
265
+
266
+ function wantsInteractive(options: DevOptions) {
267
+ return options.interactive
268
+ }
@@ -0,0 +1,80 @@
1
+ import process from 'node:process'
2
+ import { ExitCode } from '@stacksjs/types'
3
+ import type { CLI } from '@stacksjs/types'
4
+ import { config } from '@stacksjs/config'
5
+ import { runCommand } from '@stacksjs/cli'
6
+
7
+ // import { Action } from '@stacksjs/enums'
8
+ // import { runAction } from '@stacksjs/actions'
9
+
10
+ interface DnsOptions {
11
+ query?: string
12
+ type?: string
13
+ nameserver?: string
14
+ class?: string
15
+ udp?: boolean
16
+ tcp?: boolean
17
+ tls?: boolean
18
+ https?: boolean
19
+ short?: boolean
20
+ json?: boolean
21
+ pretty?: boolean
22
+ p?: boolean // short for pretty
23
+ verbose?: boolean
24
+ }
25
+
26
+ export function dns(buddy: CLI) {
27
+ const descriptions = {
28
+ dns: 'Lists the DNS records for a domain',
29
+ query: 'Host name or IP address to query',
30
+ type: 'Type of the DNS record being queried (A, MX, NS…)',
31
+ nameserver: 'Address of the nameserver to send packets to',
32
+ class: 'Network class of the DNS record being queried (IN, CH, HS)',
33
+ udp: 'Use the DNS protocol over UDP',
34
+ tcp: 'Use the DNS protocol over TCP',
35
+ tls: 'Use the DNS-over-TLS protocol',
36
+ https: 'Use the DNS-over-HTTPS protocol',
37
+ short: 'Short mode: display nothing but the first result',
38
+ json: 'Display the output as JSON',
39
+ pretty: 'Display the output as JSON in a pretty format',
40
+ project: 'Target a specific project',
41
+ verbose: 'Enable verbose output',
42
+ }
43
+
44
+ buddy
45
+ .command('dns [domain]', descriptions.dns)
46
+ .option('-q, --query <query>', descriptions.query)
47
+ .option('-t, --type <type>', descriptions.type, { default: 'ANY' })
48
+ .option('-n, --nameserver <nameserver>', descriptions.nameserver)
49
+ .option('--class <class>', descriptions.nameserver)
50
+ // transport options
51
+ .option('-U, --udp', descriptions.udp)
52
+ .option('-T, --tcp', descriptions.tcp)
53
+ .option('-S, --tls', descriptions.tls)
54
+ .option('-H, --https', descriptions.https)
55
+ // output options
56
+ .option('-1, --short', descriptions.short, { default: false })
57
+ .option('-J, --json', descriptions.json, { default: false })
58
+ .option('-p, --pretty', descriptions.pretty, { default: true })
59
+ .option('-p, --project', descriptions.project, { default: false })
60
+ .option('--verbose', descriptions.verbose, { default: false })
61
+ .action(async (domain: string | undefined, options: DnsOptions) => {
62
+ // let prettyOutput = false
63
+
64
+ // if (options.json && options.pretty)
65
+ // prettyOutput = true
66
+
67
+ delete options.pretty
68
+ delete options.p
69
+
70
+ // Convert options object to command-line options string
71
+ const optionsString = Object.entries(options)
72
+ .filter(([key, value]) => key !== '--' && key.length > 1 && value !== false) // filter out '--' key and short options
73
+ .map(([key, value]) => `--${key} ${value}`)
74
+ .join(' ')
75
+
76
+ await runCommand(`dog ${domain || config.app.url} ${optionsString}`)
77
+
78
+ process.exit(ExitCode.Success)
79
+ })
80
+ }
@@ -0,0 +1,158 @@
1
+ import process from 'node:process'
2
+ import { runAction } from '@stacksjs/actions'
3
+ import { bgCyan, bold, intro, italic, outro, prompts } from '@stacksjs/cli'
4
+ import { config } from '@stacksjs/config'
5
+ import { addDomain } from '@stacksjs/dns'
6
+ import { ExitCode } from '@stacksjs/types'
7
+ import type { CLI, DomainsOptions } from '@stacksjs/types'
8
+ import { Action } from '@stacksjs/enums'
9
+
10
+ export function domains(buddy: CLI) {
11
+ const descriptions = {
12
+ purchase: 'Purchase a domain',
13
+ add: 'Add a domain to your cloud', // given you already own it with a different registrar
14
+ remove: 'Remove a domain from your cloud',
15
+ skip: 'Skip the confirmation prompt',
16
+ project: 'Target a specific project',
17
+ verbose: 'Enable verbose output',
18
+ }
19
+
20
+ const c = config.dns.contactInfo
21
+
22
+ buddy
23
+ .command('domains:purchase <domain>', descriptions.purchase)
24
+ .option('--years <years>', 'Number of years to purchase the domain for', { default: 1 })
25
+ .option('--privacy', 'Enable privacy protection', { default: true })
26
+ .option('--auto-renew', 'Enable auto-renew', { default: true })
27
+ .option('--first-name <firstName>', 'Registrant first name', { default: c?.firstName })
28
+ .option('--last-name <lastName>', 'Registrant last name', { default: c?.lastName })
29
+ .option('--organization <organization>', 'Registrant organization name', { default: c?.organizationName })
30
+ .option('--address-line1 <address>', 'Registrant address line 1', { default: c?.addressLine1 })
31
+ .option('--address-line2 <address>', 'Registrant address line 2', { default: c?.addressLine2 })
32
+ .option('--city <city>', 'Registrant city', { default: c?.city })
33
+ .option('--state <state>', 'Registrant state', { default: c?.state })
34
+ .option('--country <country>', 'Registrant country code', { default: c?.countryCode })
35
+ .option('--zip <zip>', 'Registrant zip', { default: c?.zip })
36
+ .option('--phone <phone>', 'Registrant phone', { default: c?.phoneNumber })
37
+ .option('--email <email>', 'Registrant email', { default: c?.email })
38
+ .option('--admin-first-name <firstName>', 'Admin first name', { default: c?.admin?.firstName || c?.firstName })
39
+ .option('--admin-last-name <lastName>', 'Admin last name', { default: c?.admin?.lastName || c?.lastName })
40
+ .option('--admin-organization <organization>', 'Admin organization', { default: c?.admin?.organizationName || c?.organizationName })
41
+ .option('--admin-address-line1 <address>', 'Admin address line 1', { default: c?.admin?.addressLine1 || c?.addressLine1 })
42
+ .option('--admin-address-line2 <address>', 'Admin address line 2', { default: c?.admin?.addressLine2 || c?.addressLine2 })
43
+ .option('--admin-city <city>', 'Admin city', { default: c?.admin?.city || c?.city })
44
+ .option('--admin-state <state>', 'Admin state', { default: c?.admin?.state || c?.state })
45
+ .option('--admin-country <country>', 'Admin country code', { default: c?.admin?.countryCode || c?.countryCode })
46
+ .option('--admin-zip <zip>', 'Admin zip', { default: c?.admin?.zip || c?.zip })
47
+ .option('--admin-phone <phone>', 'Admin phone number', { default: c?.admin?.phoneNumber || c?.phoneNumber })
48
+ .option('--admin-email <email>', 'Admin email', { default: c?.admin?.email || c?.email })
49
+ .option('--tech-first-name <firstName>', 'Tech first name', { default: c?.tech?.firstName || c?.firstName })
50
+ .option('--tech-last-name <lastName>', 'Tech last name', { default: c?.tech?.lastName || c?.lastName })
51
+ .option('--tech-organization <organization>', 'Tech organization name', { default: c?.tech?.organizationName || c?.organizationName })
52
+ .option('--tech-address-line1 <address>', 'Tech address line 1', { default: c?.tech?.addressLine1 || c?.addressLine1 })
53
+ .option('--tech-address-line2 <address>', 'Tech address line 2', { default: c?.tech?.addressLine2 || c?.addressLine2 })
54
+ .option('--tech-city <city>', 'Tech city', { default: c?.tech?.city || c?.city })
55
+ .option('--tech-state <state>', 'Tech state', { default: c?.tech?.state || c?.state })
56
+ .option('--tech-country <country>', 'Tech country', { default: c?.tech?.countryCode || c?.countryCode })
57
+ .option('--tech-zip <zip>', 'Tech zip', { default: c?.tech?.zip || c?.zip })
58
+ .option('--tech-phone <phone>', 'Tech phone', { default: c?.tech?.phoneNumber || c?.phoneNumber })
59
+ .option('--tech-email <email>', 'Tech email', { default: c?.tech?.email || c?.email })
60
+ .option('--privacy-admin', 'Enable privacy protection for admin', { default: c?.privacyAdmin || c?.privacy || true })
61
+ .option('--privacy-tech', 'Enable privacy protection for tech', { default: c?.privacyTech || c?.privacy || true })
62
+ .option('--privacy-registrant', 'Enable privacy protection for registrant', { default: c?.privacyRegistrant || c?.privacy || true })
63
+ .option('--contact-type <type>', 'Contact type', { default: 'person' })
64
+ .option('-p, --project', descriptions.project, { default: false })
65
+ .option('--verbose', descriptions.verbose, { default: false })
66
+ .action(async (domain: string, options: DomainsOptions) => {
67
+ options.domain = domain
68
+ const startTime = await intro('buddy domains:purchase')
69
+ const result = await runAction(Action.DomainsPurchase, options)
70
+
71
+ if (result.isErr()) {
72
+ await outro('While running the domains:purchase command, there was an issue', { startTime, useSeconds: true }, result.error)
73
+ process.exit(ExitCode.FatalError)
74
+ }
75
+
76
+ const { confirm } = await prompts({
77
+ name: 'confirm',
78
+ type: 'confirm',
79
+ message: `Would you like to set ${domain} as your APP_URL?`,
80
+ })
81
+
82
+ if (!confirm) {
83
+ await outro(`Alrighty! ${italic(domain)} was added to your account.`, { startTime, useSeconds: true, type: 'success' })
84
+ log.info(`Please note, you may need to validate your email address. Check your ${italic(options.registrantEmail as string)} inbox.`)
85
+ process.exit(ExitCode.Success)
86
+ }
87
+
88
+ // set .env APP_URL to domain
89
+ const { writeEnv } = await import('@stacksjs/env')
90
+ writeEnv('APP_URL', domain)
91
+
92
+ let message = `Great! ${italic(domain)} was added to your account.`
93
+ message += `\n\nAnd your APP_URL has been set to ${italic(domain)}.
94
+ \nPlease note, this change has not been deployed yet.
95
+ \nThe next time you run ${bgCyan(italic(bold(' buddy deploy ')))}, your app will deploy to ${italic(domain)}.
96
+ \n${italic('You may need to deploy 2-3 times for the changes to take effect. Issue tracked here: https://github.com/stacksjs/stacks/issues/685')}`
97
+
98
+ await outro(message, { startTime, useSeconds: true, type: 'info' })
99
+ process.exit(ExitCode.Success)
100
+ })
101
+
102
+ buddy
103
+ .command('domains:add <domain>', descriptions.add)
104
+ .option('--verbose', descriptions.verbose, { default: false })
105
+ .action(async (options: DomainsOptions) => {
106
+ const startTime = await intro('buddy domains:add')
107
+ const result = await addDomain({
108
+ ...options,
109
+ startTime,
110
+ })
111
+
112
+ if (result.isErr()) {
113
+ await outro('While running the `buddy deploy`, there was an issue', { startTime, useSeconds: true }, result.error)
114
+ process.exit(ExitCode.FatalError)
115
+ }
116
+
117
+ await outro('Added your domain.', { startTime, useSeconds: true })
118
+ process.exit(ExitCode.Success)
119
+ })
120
+
121
+ buddy
122
+ .command('domains:remove <domain>', descriptions.remove)
123
+ .option('--yes', descriptions.skip, { default: false })
124
+ .option('--verbose', descriptions.verbose, { default: false })
125
+ .action(async (options: DomainsOptions) => {
126
+ const domain = options.domain || config.app.url
127
+ const opts = { ...options, domain }
128
+ const startTime = await intro('buddy domains:remove')
129
+
130
+ if (!opts.yes) {
131
+ const { confirm } = await prompts({
132
+ name: 'confirm',
133
+ type: 'confirm',
134
+ message: `Are you sure you want to remove ${domain}?`,
135
+ })
136
+
137
+ if (!confirm) {
138
+ await outro('Cancelled the domains:remove command', { startTime, useSeconds: true, type: 'info' })
139
+ process.exit(ExitCode.Success)
140
+ }
141
+ }
142
+
143
+ const result = await runAction(Action.DomainsRemove, opts)
144
+
145
+ if (result.isErr()) {
146
+ await outro('While running the domains:remove command, there was an issue', { startTime, useSeconds: true }, result.error)
147
+ process.exit(ExitCode.FatalError)
148
+ }
149
+
150
+ await outro('Removed your domain DNS records.', { startTime, useSeconds: true })
151
+ process.exit(ExitCode.Success)
152
+ })
153
+
154
+ buddy.on('domains:*', () => {
155
+ console.error('Invalid command: %s\nSee --help for a list of available commands.', buddy.args.join(' '))
156
+ process.exit(1)
157
+ })
158
+ }
@@ -0,0 +1,66 @@
1
+ import process from 'node:process'
2
+ import { ExitCode } from '@stacksjs/types'
3
+ import type { CLI, ExamplesOptions } from '@stacksjs/types'
4
+ import { runExample } from '@stacksjs/actions'
5
+
6
+ export function example(buddy: CLI) {
7
+ const descriptions = {
8
+ example: 'Which example do you want to see?',
9
+ components: 'Test your libraries against your built bundle',
10
+ vue: 'Test your Vue component library',
11
+ webComponents: 'Test your web component library',
12
+ select: 'Which example are you trying to view?',
13
+ project: 'Target a specific project',
14
+ verbose: 'Enable verbose output',
15
+ }
16
+
17
+ buddy
18
+ .command('example', descriptions.example)
19
+ .option('-c, --components', descriptions.components)
20
+ .option('-v, --vue', descriptions.vue)
21
+ .option('-w, --web-components', descriptions.webComponents)
22
+ .option('-p, --project', descriptions.project, { default: false })
23
+ .option('--verbose', descriptions.verbose, { default: false })
24
+ .action(async (options: ExamplesOptions) => {
25
+ // const answer = await prompt.require()
26
+ // .select(descriptions.select, {
27
+ // options: [
28
+ // { value: 'components', label: 'Vue Components' },
29
+ // { value: 'web-components', label: 'Web Components' },
30
+ // ],
31
+ // })
32
+
33
+ // if (answer === 'components')
34
+ // await componentExample(options)
35
+ // else if (answer === 'web-components')
36
+ // await webComponentExample(options)
37
+ // else process.exit(ExitCode.InvalidArgument)
38
+
39
+ await runExample(options)
40
+ process.exit(ExitCode.Success)
41
+ })
42
+
43
+ buddy
44
+ .command('example:vue', descriptions.vue)
45
+ .option('-v, --vue', descriptions.verbose, { default: true })
46
+ .option('-p, --project', descriptions.project, { default: false })
47
+ .option('--verbose', descriptions.verbose, { default: false })
48
+ .alias('example:components')
49
+ .action(async (options: ExamplesOptions) => {
50
+ await runExample(options)
51
+ })
52
+
53
+ buddy
54
+ .command('example:web-components', 'Test your Web Component library.')
55
+ .option('-w, --web-components', descriptions.verbose, { default: true })
56
+ .option('-p, --project', descriptions.project, { default: false })
57
+ .option('--verbose', descriptions.verbose, { default: false })
58
+ .action(async (options: ExamplesOptions) => {
59
+ await runExample(options)
60
+ })
61
+
62
+ buddy.on('example:*', () => {
63
+ console.error('Invalid command: %s\nSee --help for a list of available commands.', buddy.args.join(' '))
64
+ process.exit(1)
65
+ })
66
+ }
@@ -0,0 +1,36 @@
1
+ import process from 'node:process'
2
+ import { ExitCode } from '@stacksjs/types'
3
+ import type { CLI, FreshOptions } from '@stacksjs/types'
4
+ import { runAction } from '@stacksjs/actions'
5
+ import { intro, outro } from '@stacksjs/cli'
6
+ import { Action } from '@stacksjs/enums'
7
+
8
+ export function fresh(buddy: CLI) {
9
+ const descriptions = {
10
+ fresh: 'Reinstalls your npm dependencies',
11
+ project: 'Target a specific project',
12
+ verbose: 'Enable verbose output',
13
+ }
14
+
15
+ buddy
16
+ .command('fresh', descriptions.fresh)
17
+ .option('-p, --project', descriptions.project, { default: false })
18
+ .option('--verbose', descriptions.verbose, { default: false })
19
+ .action(async (options: FreshOptions) => {
20
+ const perf = await intro('buddy fresh')
21
+ const result = await runAction(Action.Fresh, { ...options, stdout: 'inherit' })
22
+
23
+ if (result.isErr()) {
24
+ await outro('While running `buddy fresh`, there was an issue', { startTime: perf, useSeconds: true }, result.error)
25
+ process.exit(ExitCode.FatalError)
26
+ }
27
+
28
+ await outro('Freshly reinstalled your dependencies', { startTime: perf, useSeconds: true })
29
+ process.exit(ExitCode.Success)
30
+ })
31
+
32
+ buddy.on('fresh:*', () => {
33
+ console.error('Invalid command: %s\nSee --help for a list of available commands.', buddy.args.join(' '))
34
+ process.exit(1)
35
+ })
36
+ }