@wyxos/zephyr 0.3.3 → 0.4.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.
@@ -0,0 +1,46 @@
1
+ export class ZephyrError extends Error {
2
+ constructor(message, {
3
+ code = 'ZEPHYR_FAILURE',
4
+ data = {},
5
+ cause
6
+ } = {}) {
7
+ super(message, cause ? {cause} : undefined)
8
+ this.name = this.constructor.name
9
+ this.code = code
10
+ this.data = data
11
+ }
12
+ }
13
+
14
+ export class PromptRequiredError extends ZephyrError {
15
+ constructor(message, {
16
+ data = {},
17
+ cause
18
+ } = {}) {
19
+ super(message, {
20
+ code: 'ZEPHYR_PROMPT_REQUIRED',
21
+ data,
22
+ cause
23
+ })
24
+ }
25
+ }
26
+
27
+ export class InvalidCliOptionsError extends ZephyrError {
28
+ constructor(message, {
29
+ data = {},
30
+ cause
31
+ } = {}) {
32
+ super(message, {
33
+ code: 'ZEPHYR_INVALID_OPTIONS',
34
+ data,
35
+ cause
36
+ })
37
+ }
38
+ }
39
+
40
+ export function getErrorCode(error) {
41
+ if (error && typeof error === 'object' && typeof error.code === 'string' && error.code.length > 0) {
42
+ return error.code
43
+ }
44
+
45
+ return 'ZEPHYR_FAILURE'
46
+ }
@@ -1,10 +1,20 @@
1
+ import process from 'node:process'
2
+
1
3
  export function createLocalCommandRunners({ runCommandBase, runCommandCaptureBase }) {
2
4
  if (!runCommandBase || !runCommandCaptureBase) {
3
5
  throw new Error('createLocalCommandRunners requires runCommandBase and runCommandCaptureBase')
4
6
  }
5
7
 
6
- const runCommand = async (command, args, { silent = false, cwd } = {}) => {
7
- const stdio = silent ? 'ignore' : 'inherit'
8
+ const runCommand = async (command, args, {
9
+ silent = false,
10
+ cwd,
11
+ forwardStdoutToStderr = false
12
+ } = {}) => {
13
+ const stdio = silent
14
+ ? 'ignore'
15
+ : forwardStdoutToStderr
16
+ ? ['ignore', process.stderr, process.stderr]
17
+ : 'inherit'
8
18
  return runCommandBase(command, args, { cwd, stdio })
9
19
  }
10
20
 
@@ -15,4 +25,3 @@ export function createLocalCommandRunners({ runCommandBase, runCommandCaptureBas
15
25
 
16
26
  return { runCommand, runCommandCapture }
17
27
  }
18
-
@@ -1,9 +1,48 @@
1
- export function createRunPrompt({ inquirer }) {
1
+ import {PromptRequiredError} from './errors.mjs'
2
+
3
+ function buildPromptMessage(questions = []) {
4
+ const messages = questions
5
+ .map((question) => question?.message)
6
+ .filter((message) => typeof message === 'string' && message.trim().length > 0)
7
+
8
+ return messages[0] ?? 'Zephyr requires interactive input to continue.'
9
+ }
10
+
11
+ export function createRunPrompt({
12
+ inquirer,
13
+ interactive = true,
14
+ emitEvent,
15
+ workflow = 'deploy'
16
+ }) {
2
17
  if (!inquirer) {
3
18
  throw new Error('createRunPrompt requires inquirer')
4
19
  }
5
20
 
6
21
  return async function runPrompt(questions) {
22
+ if (!interactive) {
23
+ const message = buildPromptMessage(questions)
24
+ const error = new PromptRequiredError(message, {
25
+ data: {
26
+ workflow,
27
+ questions: Array.isArray(questions)
28
+ ? questions.map((question) => ({
29
+ name: question?.name ?? null,
30
+ type: question?.type ?? null,
31
+ message: question?.message ?? null
32
+ }))
33
+ : []
34
+ }
35
+ })
36
+
37
+ emitEvent?.('prompt_required', {
38
+ message,
39
+ code: error.code,
40
+ data: error.data
41
+ })
42
+
43
+ throw error
44
+ }
45
+
7
46
  if (typeof globalThis !== 'undefined' && globalThis.__zephyrPrompt) {
8
47
  return globalThis.__zephyrPrompt(questions)
9
48
  }
@@ -11,4 +50,3 @@ export function createRunPrompt({ inquirer }) {
11
50
  return inquirer.prompt(questions)
12
51
  }
13
52
  }
14
-
@@ -25,6 +25,36 @@ export function writeStderr(message = '') {
25
25
  }
26
26
  }
27
27
 
28
+ export function createJsonEventEmitter({
29
+ workflow,
30
+ writeEvent = writeStdoutLine
31
+ } = {}) {
32
+ return function emitEvent(event, {
33
+ level,
34
+ message = '',
35
+ data = {},
36
+ code
37
+ } = {}) {
38
+ const payload = {
39
+ event,
40
+ timestamp: new Date().toISOString(),
41
+ workflow,
42
+ message
43
+ }
44
+
45
+ if (level) {
46
+ payload.level = level
47
+ }
48
+
49
+ if (code) {
50
+ payload.code = code
51
+ }
52
+
53
+ payload.data = data ?? {}
54
+ writeEvent(JSON.stringify(payload))
55
+ }
56
+ }
57
+
28
58
  export function formatLogMessage(message = '', prefix = '') {
29
59
  const text = message == null ? '' : String(message)
30
60
 
@@ -52,3 +82,18 @@ export function createChalkLogger(chalk, {
52
82
  logError: (message = '') => writeStderrLine(chalk.red(formatLogMessage(message, prefixes.error)))
53
83
  }
54
84
  }
85
+
86
+ export function createJsonLogger({
87
+ emitEvent
88
+ } = {}) {
89
+ if (typeof emitEvent !== 'function') {
90
+ throw new Error('createJsonLogger requires emitEvent')
91
+ }
92
+
93
+ return {
94
+ logProcessing: (message = '', data = {}) => emitEvent('log', {level: 'processing', message: String(message ?? ''), data}),
95
+ logSuccess: (message = '', data = {}) => emitEvent('log', {level: 'success', message: String(message ?? ''), data}),
96
+ logWarning: (message = '', data = {}) => emitEvent('log', {level: 'warning', message: String(message ?? ''), data}),
97
+ logError: (message = '', data = {}) => emitEvent('log', {level: 'error', message: String(message ?? ''), data})
98
+ }
99
+ }