@wyxos/zephyr 0.9.5 → 0.9.6

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wyxos/zephyr",
3
- "version": "0.9.5",
3
+ "version": "0.9.6",
4
4
  "description": "A streamlined deployment tool for web applications with intelligent Laravel project detection",
5
5
  "type": "module",
6
6
  "main": "./src/index.mjs",
@@ -3,6 +3,7 @@ import {tmpdir} from 'node:os'
3
3
  import path from 'node:path'
4
4
  import process from 'node:process'
5
5
 
6
+ import {describeCodexAdvisorFailure, logCapturedCodexDiagnostics} from '../runtime/codex-diagnostics.mjs'
6
7
  import {commandExists} from '../utils/command.mjs'
7
8
 
8
9
  const CONVENTIONAL_COMMIT_PATTERN = /^(build|chore|ci|docs|feat|fix|perf|refactor|revert|style|test): .+/i
@@ -237,7 +238,7 @@ export async function suggestCommitMessage(rootDir = process.cwd(), {
237
238
 
238
239
  logStep?.('Generating a suggested commit message with Codex...')
239
240
 
240
- await runCommand('codex', [
241
+ const codexResult = await runCommand('codex', [
241
242
  'exec',
242
243
  '--ephemeral',
243
244
  '--model',
@@ -258,6 +259,7 @@ export async function suggestCommitMessage(rootDir = process.cwd(), {
258
259
  capture: true,
259
260
  cwd: rootDir
260
261
  })
262
+ logCapturedCodexDiagnostics(codexResult, {label: 'commit-message advisor', logWarning})
261
263
 
262
264
  const rawMessage = await readFile(outputPath, 'utf8')
263
265
  const message = sanitizeSuggestedCommitMessage(rawMessage)
@@ -269,7 +271,7 @@ export async function suggestCommitMessage(rootDir = process.cwd(), {
269
271
  logWarning?.('Codex suggested an unusable commit message.')
270
272
  return fallbackMessage()
271
273
  } catch (error) {
272
- logWarning?.(`Codex could not suggest a commit message: ${error.message}`)
274
+ logWarning?.(`${describeCodexAdvisorFailure(error, {label: 'commit-message advisor'})} Using path-based fallback.`)
273
275
  return fallbackMessage()
274
276
  } finally {
275
277
  if (tempDir) {
@@ -4,6 +4,7 @@ import path from 'node:path'
4
4
  import process from 'node:process'
5
5
  import semver from 'semver'
6
6
 
7
+ import {describeCodexAdvisorFailure, logCapturedCodexDiagnostics} from '../runtime/codex-diagnostics.mjs'
7
8
  import {commandExists} from '../utils/command.mjs'
8
9
 
9
10
  export const RELEASE_TYPES = [
@@ -240,7 +241,7 @@ async function suggestReleaseType(rootDir = process.cwd(), {
240
241
 
241
242
  logStep?.('Evaluating the recommended version bump with Codex...')
242
243
 
243
- await runCommand('codex', [
244
+ const codexResult = await runCommand('codex', [
244
245
  'exec',
245
246
  '--ephemeral',
246
247
  '--model',
@@ -267,6 +268,7 @@ async function suggestReleaseType(rootDir = process.cwd(), {
267
268
  capture: true,
268
269
  cwd: rootDir
269
270
  })
271
+ logCapturedCodexDiagnostics(codexResult, {label: 'release advisor', logWarning})
270
272
 
271
273
  const rawSuggestion = await readFile(outputPath, 'utf8')
272
274
  const releaseType = sanitizeSuggestedReleaseType(rawSuggestion, allowedSuggestedReleaseTypes)
@@ -287,7 +289,7 @@ async function suggestReleaseType(rootDir = process.cwd(), {
287
289
  source: flooredReleaseType === releaseType ? 'codex' : 'codex+heuristic-floor'
288
290
  }
289
291
  } catch (error) {
290
- logWarning?.(`Codex could not suggest a release type: ${error.message}`)
292
+ logWarning?.(`${describeCodexAdvisorFailure(error, {label: 'release advisor'})} Using heuristic release type.`)
291
293
 
292
294
  return {
293
295
  ...context,
@@ -0,0 +1,62 @@
1
+ function splitLines(text = '') {
2
+ return String(text)
3
+ .split(/\r?\n/)
4
+ .map((line) => line.trim())
5
+ .filter(Boolean)
6
+ }
7
+
8
+ function normalizeCapturedOutput(commandOutput = {}) {
9
+ if (typeof commandOutput === 'string') {
10
+ return {stdout: commandOutput, stderr: ''}
11
+ }
12
+
13
+ return {
14
+ stdout: commandOutput?.stdout ?? '',
15
+ stderr: commandOutput?.stderr ?? ''
16
+ }
17
+ }
18
+
19
+ export function collectCodexDiagnosticLines(commandOutput = {}) {
20
+ const {stdout, stderr} = normalizeCapturedOutput(commandOutput)
21
+ const stderrLines = splitLines(stderr)
22
+ const stdoutDiagnosticLines = splitLines(stdout)
23
+ .filter((line) => /\b(error|warn|warning|failed|failure|rejected|declined)\b/i.test(line))
24
+
25
+ return [...stderrLines, ...stdoutDiagnosticLines]
26
+ }
27
+
28
+ export function logCapturedCodexDiagnostics(commandOutput = {}, {
29
+ label = 'advisor',
30
+ logWarning
31
+ } = {}) {
32
+ const diagnosticCount = collectCodexDiagnosticLines(commandOutput).length
33
+
34
+ if (diagnosticCount === 0) {
35
+ return
36
+ }
37
+
38
+ const noun = diagnosticCount === 1 ? 'line' : 'lines'
39
+ logWarning?.(
40
+ `Codex ${label} emitted ${diagnosticCount} diagnostic ${noun}; ` +
41
+ 'captured and hidden because the advisor returned a usable result.'
42
+ )
43
+ }
44
+
45
+ export function describeCodexAdvisorFailure(error, {
46
+ label = 'advisor'
47
+ } = {}) {
48
+ const diagnosticCount = collectCodexDiagnosticLines(error).length
49
+ const exitCode = error?.exitCode
50
+ const exitText = exitCode == null ? 'failed' : `exited with code ${exitCode}`
51
+
52
+ if (diagnosticCount > 0) {
53
+ const noun = diagnosticCount === 1 ? 'line' : 'lines'
54
+ return `Codex ${label} ${exitText}; captured ${diagnosticCount} diagnostic ${noun}.`
55
+ }
56
+
57
+ if (error?.code === 'ENOENT') {
58
+ return `Codex ${label} failed because the codex command was not found.`
59
+ }
60
+
61
+ return `Codex ${label} ${exitText}.`
62
+ }
@@ -6,10 +6,24 @@ export function createLocalCommandRunners({ runCommandBase, runCommandCaptureBas
6
6
  }
7
7
 
8
8
  const runCommand = async (command, args, {
9
+ capture = false,
9
10
  silent = false,
10
11
  cwd,
11
12
  forwardStdoutToStderr = false
12
13
  } = {}) => {
14
+ if (capture) {
15
+ const captured = await runCommandCaptureBase(command, args, {cwd})
16
+
17
+ if (typeof captured === 'string') {
18
+ return {stdout: captured.trim(), stderr: ''}
19
+ }
20
+
21
+ return {
22
+ stdout: (captured?.stdout ?? '').trim(),
23
+ stderr: (captured?.stderr ?? '').trim()
24
+ }
25
+ }
26
+
13
27
  const stdio = silent
14
28
  ? 'ignore'
15
29
  : forwardStdoutToStderr