@orchid-labs/pluxx 0.1.1 → 0.1.4

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 (103) hide show
  1. package/README.md +25 -8
  2. package/bin/pluxx.js +19 -28
  3. package/dist/agents.d.ts +16 -0
  4. package/dist/agents.d.ts.map +1 -0
  5. package/dist/cli/agent.d.ts +62 -0
  6. package/dist/cli/agent.d.ts.map +1 -1
  7. package/dist/cli/doctor.d.ts +2 -0
  8. package/dist/cli/doctor.d.ts.map +1 -1
  9. package/dist/cli/entry.d.ts +2 -0
  10. package/dist/cli/entry.d.ts.map +1 -0
  11. package/dist/cli/index.d.ts +7 -1
  12. package/dist/cli/index.d.ts.map +1 -1
  13. package/dist/cli/index.js +21810 -0
  14. package/dist/cli/init-from-mcp.d.ts +17 -1
  15. package/dist/cli/init-from-mcp.d.ts.map +1 -1
  16. package/dist/cli/install.d.ts +1 -0
  17. package/dist/cli/install.d.ts.map +1 -1
  18. package/dist/cli/lint.d.ts +3 -1
  19. package/dist/cli/lint.d.ts.map +1 -1
  20. package/dist/cli/mcp-proxy.d.ts.map +1 -1
  21. package/dist/cli/migrate.d.ts.map +1 -1
  22. package/dist/cli/primitive-summary.d.ts +14 -0
  23. package/dist/cli/primitive-summary.d.ts.map +1 -0
  24. package/dist/cli/prompt.d.ts +1 -1
  25. package/dist/cli/publish.d.ts +6 -1
  26. package/dist/cli/publish.d.ts.map +1 -1
  27. package/dist/cli/sync-from-mcp.d.ts.map +1 -1
  28. package/dist/cli/verify-install.d.ts +25 -0
  29. package/dist/cli/verify-install.d.ts.map +1 -0
  30. package/dist/commands.d.ts +10 -0
  31. package/dist/commands.d.ts.map +1 -0
  32. package/dist/compiler-intent.d.ts +165 -0
  33. package/dist/compiler-intent.d.ts.map +1 -0
  34. package/dist/config/load.d.ts.map +1 -1
  35. package/dist/delegation.d.ts +11 -0
  36. package/dist/delegation.d.ts.map +1 -0
  37. package/dist/generators/amp/index.d.ts.map +1 -1
  38. package/dist/generators/base.d.ts +5 -0
  39. package/dist/generators/base.d.ts.map +1 -1
  40. package/dist/generators/claude-code/index.d.ts.map +1 -1
  41. package/dist/generators/cline/index.d.ts.map +1 -1
  42. package/dist/generators/codex/index.d.ts +4 -0
  43. package/dist/generators/codex/index.d.ts.map +1 -1
  44. package/dist/generators/cursor/index.d.ts +1 -0
  45. package/dist/generators/cursor/index.d.ts.map +1 -1
  46. package/dist/generators/gemini-cli/index.d.ts.map +1 -1
  47. package/dist/generators/github-copilot/index.d.ts.map +1 -1
  48. package/dist/generators/opencode/index.d.ts +1 -0
  49. package/dist/generators/opencode/index.d.ts.map +1 -1
  50. package/dist/generators/openhands/index.d.ts.map +1 -1
  51. package/dist/generators/roo-code/index.d.ts.map +1 -1
  52. package/dist/generators/shared/claude-family.d.ts.map +1 -1
  53. package/dist/generators/warp/index.d.ts.map +1 -1
  54. package/dist/index.d.ts +4 -1
  55. package/dist/index.d.ts.map +1 -1
  56. package/dist/index.js +5371 -553
  57. package/dist/schema.d.ts +91 -42
  58. package/dist/schema.d.ts.map +1 -1
  59. package/dist/text-files.d.ts +5 -0
  60. package/dist/text-files.d.ts.map +1 -0
  61. package/dist/validation/platform-rules.d.ts +15 -1
  62. package/dist/validation/platform-rules.d.ts.map +1 -1
  63. package/package.json +15 -13
  64. package/src/cli/agent.ts +0 -1455
  65. package/src/cli/dev.ts +0 -112
  66. package/src/cli/doctor.ts +0 -987
  67. package/src/cli/eval.ts +0 -470
  68. package/src/cli/index.ts +0 -2933
  69. package/src/cli/init-from-mcp.ts +0 -2115
  70. package/src/cli/install.ts +0 -860
  71. package/src/cli/lint.ts +0 -1249
  72. package/src/cli/mcp-proxy.ts +0 -322
  73. package/src/cli/migrate.ts +0 -867
  74. package/src/cli/prompt.ts +0 -82
  75. package/src/cli/publish.ts +0 -401
  76. package/src/cli/runtime.ts +0 -86
  77. package/src/cli/sync-from-mcp.ts +0 -586
  78. package/src/cli/test.ts +0 -142
  79. package/src/compatibility/matrix.ts +0 -149
  80. package/src/config/define.ts +0 -20
  81. package/src/config/load.ts +0 -74
  82. package/src/generators/amp/index.ts +0 -63
  83. package/src/generators/base.ts +0 -188
  84. package/src/generators/claude-code/index.ts +0 -172
  85. package/src/generators/cline/index.ts +0 -35
  86. package/src/generators/codex/index.ts +0 -143
  87. package/src/generators/cursor/index.ts +0 -158
  88. package/src/generators/gemini-cli/index.ts +0 -83
  89. package/src/generators/github-copilot/index.ts +0 -32
  90. package/src/generators/hooks-warning.ts +0 -51
  91. package/src/generators/index.ts +0 -71
  92. package/src/generators/opencode/index.ts +0 -526
  93. package/src/generators/openhands/index.ts +0 -32
  94. package/src/generators/roo-code/index.ts +0 -35
  95. package/src/generators/shared/claude-family.ts +0 -215
  96. package/src/generators/warp/index.ts +0 -32
  97. package/src/hook-events.ts +0 -33
  98. package/src/index.ts +0 -34
  99. package/src/mcp/introspect.ts +0 -1107
  100. package/src/permissions.ts +0 -260
  101. package/src/schema.ts +0 -312
  102. package/src/user-config.ts +0 -177
  103. package/src/validation/platform-rules.ts +0 -686
package/src/cli/prompt.ts DELETED
@@ -1,82 +0,0 @@
1
- /**
2
- * Simple interactive prompt utilities using Bun's built-in readline.
3
- * Zero external dependencies.
4
- */
5
-
6
- import * as readline from 'readline'
7
-
8
- export class PromptCancelledError extends Error {
9
- constructor() {
10
- super('Init cancelled')
11
- this.name = 'PromptCancelledError'
12
- }
13
- }
14
-
15
- function ask(question: string): Promise<string> {
16
- return new Promise((resolve, reject) => {
17
- const rl = readline.createInterface({
18
- input: process.stdin,
19
- output: process.stdout,
20
- })
21
-
22
- let settled = false
23
-
24
- const settle = (fn: () => void) => {
25
- if (settled) return
26
- settled = true
27
- rl.removeListener('SIGINT', onCancel)
28
- rl.removeListener('close', onClose)
29
- fn()
30
- }
31
-
32
- const onCancel = () => {
33
- settle(() => {
34
- rl.close()
35
- reject(new PromptCancelledError())
36
- })
37
- }
38
-
39
- const onClose = () => {
40
- settle(() => {
41
- reject(new PromptCancelledError())
42
- })
43
- }
44
-
45
- rl.once('SIGINT', onCancel)
46
- rl.once('close', onClose)
47
-
48
- rl.question(question, (answer) => {
49
- settle(() => {
50
- resolve(answer)
51
- rl.close()
52
- })
53
- })
54
- })
55
- }
56
-
57
- /**
58
- * Prompt for text input with an optional default value.
59
- */
60
- export async function promptText(label: string, defaultValue?: string): Promise<string> {
61
- const suffix = defaultValue ? ` (${defaultValue})` : ''
62
- const answer = await ask(` ${label}${suffix}: `)
63
- return answer.trim() || defaultValue || ''
64
- }
65
-
66
- /**
67
- * Prompt for a yes/no answer. Returns true for yes.
68
- */
69
- export async function promptYesNo(label: string, defaultYes = false): Promise<boolean> {
70
- const hint = defaultYes ? '(Y/n)' : '(y/N)'
71
- const answer = await ask(` ${label} ${hint}: `)
72
- const normalized = answer.trim().toLowerCase()
73
- if (normalized === '') return defaultYes
74
- return normalized === 'y' || normalized === 'yes'
75
- }
76
-
77
- /**
78
- * Close the readline interface. Must be called when done prompting.
79
- */
80
- export function closePrompts(): void {
81
- // Prompts are created per-question, so there is nothing to close here.
82
- }
@@ -1,401 +0,0 @@
1
- import { existsSync, mkdirSync, readFileSync, rmSync } from 'fs'
2
- import { mkdtempSync } from 'fs'
3
- import { resolve } from 'path'
4
- import { spawnSync } from 'child_process'
5
- import { tmpdir } from 'os'
6
- import type { PluginConfig, TargetPlatform } from '../schema'
7
-
8
- type PublishChannel = 'npm' | 'github-release'
9
-
10
- interface CommandResult {
11
- status: number | null
12
- stdout: string
13
- stderr: string
14
- }
15
-
16
- type CommandRunner = (
17
- command: string,
18
- args: string[],
19
- options?: { cwd?: string },
20
- ) => CommandResult
21
-
22
- export interface PublishPlanOptions {
23
- requestedChannels?: PublishChannel[]
24
- version?: string
25
- tag?: string
26
- dryRun?: boolean
27
- rootDir?: string
28
- runCommand?: CommandRunner
29
- }
30
-
31
- export interface PublishAssetPlan {
32
- platform: TargetPlatform
33
- name: string
34
- path: string
35
- }
36
-
37
- export interface PublishCheck {
38
- name: string
39
- ok: boolean
40
- code: string
41
- detail?: string
42
- }
43
-
44
- export interface PublishPlan {
45
- command: 'publish'
46
- dryRun: boolean
47
- version: string
48
- tag: string
49
- channels: {
50
- npm: {
51
- enabled: boolean
52
- explicit: boolean
53
- packageName?: string
54
- packageDir?: string
55
- wouldPublish: boolean
56
- }
57
- githubRelease: {
58
- enabled: boolean
59
- explicit: boolean
60
- releaseTag?: string
61
- wouldCreateRelease: boolean
62
- assets: PublishAssetPlan[]
63
- }
64
- }
65
- checks: PublishCheck[]
66
- }
67
-
68
- export interface PublishRunResult extends PublishPlan {
69
- ok: boolean
70
- execution?: {
71
- npm?: { ok: boolean; detail?: string }
72
- githubRelease?: { ok: boolean; detail?: string }
73
- }
74
- }
75
-
76
- function runCommandDefault(command: string, args: string[], options?: { cwd?: string }): CommandResult {
77
- const result = spawnSync(command, args, {
78
- cwd: options?.cwd,
79
- encoding: 'utf-8',
80
- })
81
-
82
- return {
83
- status: result.status,
84
- stdout: result.stdout ?? '',
85
- stderr: result.stderr ?? '',
86
- }
87
- }
88
-
89
- function isTargetNpmBacked(platform: TargetPlatform): boolean {
90
- return platform === 'opencode'
91
- }
92
-
93
- function resolveRequestedChannels(options: PublishPlanOptions): {
94
- requested: Set<PublishChannel>
95
- explicit: { npm: boolean; githubRelease: boolean }
96
- } {
97
- const requested = new Set<PublishChannel>(options.requestedChannels ?? [])
98
- return {
99
- requested,
100
- explicit: {
101
- npm: requested.has('npm'),
102
- githubRelease: requested.has('github-release'),
103
- },
104
- }
105
- }
106
-
107
- function getBuiltTargets(rootDir: string, config: PluginConfig): TargetPlatform[] {
108
- return config.targets.filter((platform) =>
109
- existsSync(resolve(rootDir, config.outDir, platform)),
110
- )
111
- }
112
-
113
- function buildReleaseAssets(rootDir: string, config: PluginConfig, version: string, targets: TargetPlatform[]): PublishAssetPlan[] {
114
- return targets.map((platform) => ({
115
- platform,
116
- name: `${platform}-v${version}.tgz`,
117
- path: resolve(rootDir, config.outDir, platform),
118
- }))
119
- }
120
-
121
- function readNpmPackageName(rootDir: string, config: PluginConfig): { packageName?: string; packageDir?: string } {
122
- const packageDir = resolve(rootDir, config.outDir, 'opencode')
123
- const packageJsonPath = resolve(packageDir, 'package.json')
124
- if (!existsSync(packageJsonPath)) {
125
- return {}
126
- }
127
-
128
- try {
129
- const pkg = JSON.parse(readFileSync(packageJsonPath, 'utf-8')) as { name?: string }
130
- return {
131
- packageName: pkg.name,
132
- packageDir,
133
- }
134
- } catch {
135
- return {
136
- packageDir,
137
- }
138
- }
139
- }
140
-
141
- function collectChecks(args: {
142
- rootDir: string
143
- config: PluginConfig
144
- npmEnabled: boolean
145
- githubReleaseEnabled: boolean
146
- packageDir?: string
147
- packageName?: string
148
- runCommand: CommandRunner
149
- }): PublishCheck[] {
150
- const builtTargets = getBuiltTargets(args.rootDir, args.config)
151
- const checks: PublishCheck[] = [
152
- {
153
- name: 'artifacts-exist',
154
- ok: builtTargets.length > 0,
155
- code: 'artifacts-exist',
156
- detail: builtTargets.length > 0
157
- ? `Built targets: ${builtTargets.join(', ')}`
158
- : `No built platform outputs found in ${args.config.outDir}/`,
159
- },
160
- ]
161
-
162
- const gitStatus = args.runCommand('git', ['status', '--porcelain'], { cwd: args.rootDir })
163
- checks.push({
164
- name: 'git-clean',
165
- ok: gitStatus.status === 0 && gitStatus.stdout.trim() === '',
166
- code: 'git-clean',
167
- detail: gitStatus.status !== 0
168
- ? (gitStatus.stderr || gitStatus.stdout || 'Unable to read git status')
169
- : gitStatus.stdout.trim() === ''
170
- ? 'Working tree is clean.'
171
- : 'Working tree has uncommitted changes.',
172
- })
173
-
174
- if (args.npmEnabled) {
175
- checks.push({
176
- name: 'npm-package-ready',
177
- ok: Boolean(args.packageDir && existsSync(resolve(args.packageDir, 'package.json')) && args.packageName),
178
- code: 'npm-package-ready',
179
- detail: args.packageDir
180
- ? `OpenCode package dir: ${args.packageDir}`
181
- : 'No npm-backed target package found.',
182
- })
183
-
184
- const npmAuth = args.runCommand('npm', ['whoami'], { cwd: args.rootDir })
185
- checks.push({
186
- name: 'npm-auth',
187
- ok: npmAuth.status === 0,
188
- code: 'npm-auth',
189
- detail: npmAuth.status === 0
190
- ? (npmAuth.stdout.trim() || 'npm auth OK')
191
- : (npmAuth.stderr || npmAuth.stdout || 'npm auth unavailable'),
192
- })
193
- }
194
-
195
- if (args.githubReleaseEnabled) {
196
- const ghAuth = args.runCommand('gh', ['auth', 'status'], { cwd: args.rootDir })
197
- checks.push({
198
- name: 'github-release-auth',
199
- ok: ghAuth.status === 0,
200
- code: 'github-release-auth',
201
- detail: ghAuth.status === 0
202
- ? 'gh auth OK'
203
- : (ghAuth.stderr || ghAuth.stdout || 'gh auth unavailable'),
204
- })
205
- }
206
-
207
- return checks
208
- }
209
-
210
- export function planPublish(config: PluginConfig, options: PublishPlanOptions = {}): PublishPlan {
211
- const rootDir = options.rootDir ?? process.cwd()
212
- const runCommand = options.runCommand ?? runCommandDefault
213
- const builtTargets = getBuiltTargets(rootDir, config)
214
- const { requested, explicit } = resolveRequestedChannels(options)
215
- const defaultNpm = builtTargets.some(isTargetNpmBacked)
216
- const defaultGithubRelease = builtTargets.length > 0
217
- const npmEnabled = explicit.npm ? true : (requested.size === 0 ? defaultNpm : false)
218
- const githubReleaseEnabled = explicit.githubRelease ? true : (requested.size === 0 ? defaultGithubRelease : false)
219
- const version = options.version ?? config.version
220
- const tag = options.tag ?? 'latest'
221
- const { packageDir, packageName } = readNpmPackageName(rootDir, config)
222
- const checks = collectChecks({
223
- rootDir,
224
- config,
225
- npmEnabled,
226
- githubReleaseEnabled,
227
- packageDir,
228
- packageName,
229
- runCommand,
230
- })
231
-
232
- return {
233
- command: 'publish',
234
- dryRun: options.dryRun ?? false,
235
- version,
236
- tag,
237
- channels: {
238
- npm: {
239
- enabled: npmEnabled,
240
- explicit: explicit.npm,
241
- packageName,
242
- packageDir,
243
- wouldPublish: npmEnabled,
244
- },
245
- githubRelease: {
246
- enabled: githubReleaseEnabled,
247
- explicit: explicit.githubRelease,
248
- releaseTag: githubReleaseEnabled ? `v${version}` : undefined,
249
- wouldCreateRelease: githubReleaseEnabled,
250
- assets: githubReleaseEnabled ? buildReleaseAssets(rootDir, config, version, builtTargets) : [],
251
- },
252
- },
253
- checks,
254
- }
255
- }
256
-
257
- function createReleaseArchives(
258
- rootDir: string,
259
- config: PluginConfig,
260
- assets: PublishAssetPlan[],
261
- runCommand: CommandRunner,
262
- ): { tempRoot: string; archives: string[] } {
263
- const tempRoot = mkdtempSync(resolve(tmpdir(), 'pluxx-publish-'))
264
- const created: string[] = []
265
-
266
- try {
267
- for (const asset of assets) {
268
- const archivePath = resolve(tempRoot, asset.name)
269
- const result = runCommand(
270
- 'tar',
271
- ['-czf', archivePath, '-C', resolve(rootDir, config.outDir), asset.platform],
272
- { cwd: rootDir },
273
- )
274
- if (result.status !== 0) {
275
- throw new Error(result.stderr || result.stdout || `Failed to create archive for ${asset.platform}`)
276
- }
277
- created.push(archivePath)
278
- }
279
- return { tempRoot, archives: created }
280
- } catch (error) {
281
- rmSync(tempRoot, { recursive: true, force: true })
282
- throw error
283
- }
284
- }
285
-
286
- export function formatPublishPlan(plan: PublishPlan): string[] {
287
- const lines: string[] = [
288
- `Resolved version: ${plan.version}`,
289
- `Resolved tag: ${plan.tag}`,
290
- `Channels: ${[
291
- plan.channels.npm.enabled ? `npm${plan.channels.npm.explicit ? ' (explicit)' : ' (auto)'}` : null,
292
- plan.channels.githubRelease.enabled ? `github-release${plan.channels.githubRelease.explicit ? ' (explicit)' : ' (auto)'}` : null,
293
- ].filter(Boolean).join(', ') || 'none'}`,
294
- '',
295
- 'Checks:',
296
- ]
297
-
298
- for (const check of plan.checks) {
299
- lines.push(` - ${check.name}: ${check.ok ? 'ok' : 'fail'}${check.detail ? ` — ${check.detail}` : ''}`)
300
- }
301
-
302
- lines.push('')
303
- if (plan.channels.npm.enabled) {
304
- lines.push(`npm package: ${plan.channels.npm.packageName ?? 'unknown'} (${plan.channels.npm.packageDir ?? 'missing'})`)
305
- }
306
-
307
- if (plan.channels.githubRelease.enabled) {
308
- lines.push(`GitHub release tag: ${plan.channels.githubRelease.releaseTag}`)
309
- lines.push('Assets:')
310
- for (const asset of plan.channels.githubRelease.assets) {
311
- lines.push(` - ${asset.name} <- ${asset.path}`)
312
- }
313
- }
314
-
315
- if (plan.dryRun) {
316
- lines.push('')
317
- lines.push('No remote changes were made.')
318
- }
319
-
320
- return lines
321
- }
322
-
323
- export function runPublish(config: PluginConfig, options: PublishPlanOptions = {}): PublishRunResult {
324
- const rootDir = options.rootDir ?? process.cwd()
325
- const runCommand = options.runCommand ?? runCommandDefault
326
- const plan = planPublish(config, options)
327
-
328
- const failedChecks = plan.checks.filter((check) => !check.ok)
329
- if (failedChecks.length > 0) {
330
- return {
331
- ...plan,
332
- ok: false,
333
- }
334
- }
335
-
336
- if (options.dryRun) {
337
- return {
338
- ...plan,
339
- ok: true,
340
- }
341
- }
342
-
343
- const execution: NonNullable<PublishRunResult['execution']> = {}
344
-
345
- if (plan.channels.npm.enabled) {
346
- const npmChannel = plan.channels.npm
347
- const result = runCommand(
348
- 'npm',
349
- ['publish', '--tag', plan.tag, '--access', 'public'],
350
- { cwd: npmChannel.packageDir },
351
- )
352
- execution.npm = {
353
- ok: result.status === 0,
354
- detail: result.status === 0
355
- ? (result.stdout.trim() || 'npm publish complete')
356
- : (result.stderr || result.stdout || 'npm publish failed'),
357
- }
358
- }
359
-
360
- if (plan.channels.githubRelease.enabled) {
361
- const releaseTag = plan.channels.githubRelease.releaseTag!
362
- const { tempRoot, archives } = createReleaseArchives(rootDir, config, plan.channels.githubRelease.assets, runCommand)
363
-
364
- try {
365
- const existing = runCommand('gh', ['release', 'view', releaseTag], { cwd: rootDir })
366
-
367
- const result = existing.status === 0
368
- ? runCommand('gh', ['release', 'upload', releaseTag, '--clobber', ...archives], { cwd: rootDir })
369
- : runCommand(
370
- 'gh',
371
- [
372
- 'release',
373
- 'create',
374
- releaseTag,
375
- ...archives,
376
- '--title',
377
- `${config.name} ${plan.version}`,
378
- '--notes',
379
- `Release generated by pluxx publish for ${config.name}@${plan.version}.`,
380
- ],
381
- { cwd: rootDir },
382
- )
383
-
384
- execution.githubRelease = {
385
- ok: result.status === 0,
386
- detail: result.status === 0
387
- ? (result.stdout.trim() || `GitHub release ${releaseTag} updated`)
388
- : (result.stderr || result.stdout || 'GitHub release publish failed'),
389
- }
390
- } finally {
391
- rmSync(tempRoot, { recursive: true, force: true })
392
- }
393
- }
394
-
395
- const ok = Object.values(execution).every((channel) => channel.ok)
396
- return {
397
- ...plan,
398
- ok,
399
- execution,
400
- }
401
- }
@@ -1,86 +0,0 @@
1
- import * as clack from '@clack/prompts'
2
-
3
- export interface CliRuntime {
4
- dryRun: boolean
5
- jsonOutput: boolean
6
- quiet: boolean
7
- isCI: boolean
8
- isTTY: boolean
9
- isInteractive: boolean
10
- }
11
-
12
- export function createCliRuntime(rawArgs: string[]): CliRuntime {
13
- const isCI = process.env.CI === '1' || process.env.CI === 'true'
14
- const isTTY = process.stdin.isTTY === true && process.stdout.isTTY === true
15
-
16
- return {
17
- dryRun: rawArgs.includes('--dry-run'),
18
- jsonOutput: rawArgs.includes('--json'),
19
- quiet: rawArgs.includes('--quiet'),
20
- isCI,
21
- isTTY,
22
- isInteractive: isTTY && !isCI,
23
- }
24
- }
25
-
26
- export function readFlag(rawArgs: string[], flag: string): boolean {
27
- return rawArgs.includes(flag)
28
- }
29
-
30
- export function readOption(rawArgs: string[], flag: string): string | undefined {
31
- const index = rawArgs.indexOf(flag)
32
- if (index === -1) return undefined
33
-
34
- const value = rawArgs[index + 1]
35
- if (!value || value.startsWith('-')) {
36
- return undefined
37
- }
38
-
39
- return value
40
- }
41
-
42
- export function readMultiValueOption(rawArgs: string[], flag: string): string[] | undefined {
43
- const index = rawArgs.indexOf(flag)
44
- if (index === -1) return undefined
45
-
46
- const values: string[] = []
47
- for (let i = index + 1; i < rawArgs.length; i += 1) {
48
- const value = rawArgs[i]
49
- if (value.startsWith('-')) break
50
- values.push(value)
51
- }
52
-
53
- return values.length > 0 ? values : undefined
54
- }
55
-
56
- export function createSpinner(runtime: CliRuntime): ReturnType<typeof clack.spinner> | undefined {
57
- if (runtime.jsonOutput || runtime.quiet || !runtime.isInteractive) {
58
- return undefined
59
- }
60
-
61
- return clack.spinner()
62
- }
63
-
64
- export function printJson(value: unknown): void {
65
- console.log(JSON.stringify(value, null, 2))
66
- }
67
-
68
- export function logInfo(runtime: CliRuntime, message: string): void {
69
- if (!runtime.jsonOutput && !runtime.quiet) {
70
- console.log(message)
71
- }
72
- }
73
-
74
- export function logWarn(runtime: CliRuntime, message: string): void {
75
- if (!runtime.jsonOutput && !runtime.quiet) {
76
- console.warn(message)
77
- }
78
- }
79
-
80
- export function logError(message: string): void {
81
- console.error(message)
82
- }
83
-
84
- export function formatPathList(paths: string[]): string {
85
- return paths.length > 0 ? paths.join(', ') : 'none'
86
- }