pipecraft 0.29.3 → 0.36.14

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 (142) hide show
  1. package/README.md +128 -54
  2. package/dist/cli/index.d.ts +3 -3
  3. package/dist/cli/index.js +68 -25
  4. package/dist/cli/index.js.map +1 -1
  5. package/dist/generators/init.tpl.d.ts +4 -4
  6. package/dist/generators/init.tpl.d.ts.map +1 -1
  7. package/dist/generators/init.tpl.js +214 -108
  8. package/dist/generators/init.tpl.js.map +1 -1
  9. package/dist/generators/workflows.tpl.d.ts +9 -9
  10. package/dist/generators/workflows.tpl.d.ts.map +1 -1
  11. package/dist/generators/workflows.tpl.js +33 -36
  12. package/dist/generators/workflows.tpl.js.map +1 -1
  13. package/dist/templates/actions/calculate-version.yml.tpl.d.ts +7 -4
  14. package/dist/templates/actions/calculate-version.yml.tpl.d.ts.map +1 -1
  15. package/dist/templates/actions/calculate-version.yml.tpl.js +49 -23
  16. package/dist/templates/actions/calculate-version.yml.tpl.js.map +1 -1
  17. package/dist/templates/actions/create-pr.yml.tpl.d.ts +5 -2
  18. package/dist/templates/actions/create-pr.yml.tpl.d.ts.map +1 -1
  19. package/dist/templates/actions/create-pr.yml.tpl.js +14 -8
  20. package/dist/templates/actions/create-pr.yml.tpl.js.map +1 -1
  21. package/dist/templates/actions/create-release.yml.tpl.d.ts +5 -2
  22. package/dist/templates/actions/create-release.yml.tpl.d.ts.map +1 -1
  23. package/dist/templates/actions/create-release.yml.tpl.js +16 -11
  24. package/dist/templates/actions/create-release.yml.tpl.js.map +1 -1
  25. package/dist/templates/actions/create-tag.yml.tpl.d.ts +5 -2
  26. package/dist/templates/actions/create-tag.yml.tpl.d.ts.map +1 -1
  27. package/dist/templates/actions/create-tag.yml.tpl.js +13 -9
  28. package/dist/templates/actions/create-tag.yml.tpl.js.map +1 -1
  29. package/dist/templates/actions/detect-changes.yml.tpl.d.ts +17 -51
  30. package/dist/templates/actions/detect-changes.yml.tpl.d.ts.map +1 -1
  31. package/dist/templates/actions/detect-changes.yml.tpl.js +130 -110
  32. package/dist/templates/actions/detect-changes.yml.tpl.js.map +1 -1
  33. package/dist/templates/actions/manage-branch.yml.tpl.d.ts +5 -2
  34. package/dist/templates/actions/manage-branch.yml.tpl.d.ts.map +1 -1
  35. package/dist/templates/actions/manage-branch.yml.tpl.js +13 -9
  36. package/dist/templates/actions/manage-branch.yml.tpl.js.map +1 -1
  37. package/dist/templates/actions/promote-branch.yml.tpl.d.ts +5 -2
  38. package/dist/templates/actions/promote-branch.yml.tpl.d.ts.map +1 -1
  39. package/dist/templates/actions/promote-branch.yml.tpl.js +39 -92
  40. package/dist/templates/actions/promote-branch.yml.tpl.js.map +1 -1
  41. package/dist/templates/release-it.cjs.tpl.d.ts +1 -1
  42. package/dist/templates/release-it.cjs.tpl.d.ts.map +1 -1
  43. package/dist/templates/release-it.cjs.tpl.js +38 -29
  44. package/dist/templates/release-it.cjs.tpl.js.map +1 -1
  45. package/dist/templates/workflows/enforce-pr-target.yml.tpl.d.ts +1 -1
  46. package/dist/templates/workflows/enforce-pr-target.yml.tpl.d.ts.map +1 -1
  47. package/dist/templates/workflows/enforce-pr-target.yml.tpl.js +2 -3
  48. package/dist/templates/workflows/enforce-pr-target.yml.tpl.js.map +1 -1
  49. package/dist/templates/workflows/pipeline.yml.tpl.d.ts +2 -2
  50. package/dist/templates/workflows/pipeline.yml.tpl.d.ts.map +1 -1
  51. package/dist/templates/workflows/pipeline.yml.tpl.js +337 -84
  52. package/dist/templates/workflows/pipeline.yml.tpl.js.map +1 -1
  53. package/dist/templates/workflows/pr-title-check.yml.tpl.d.ts +1 -1
  54. package/dist/templates/workflows/pr-title-check.yml.tpl.d.ts.map +1 -1
  55. package/dist/templates/workflows/pr-title-check.yml.tpl.js +101 -22
  56. package/dist/templates/workflows/pr-title-check.yml.tpl.js.map +1 -1
  57. package/dist/templates/workflows/shared/index.d.ts +4 -2
  58. package/dist/templates/workflows/shared/index.d.ts.map +1 -1
  59. package/dist/templates/workflows/shared/index.js +4 -2
  60. package/dist/templates/workflows/shared/index.js.map +1 -1
  61. package/dist/templates/workflows/shared/managed-workflow.d.ts +32 -0
  62. package/dist/templates/workflows/shared/managed-workflow.d.ts.map +1 -0
  63. package/dist/templates/workflows/shared/managed-workflow.js +51 -0
  64. package/dist/templates/workflows/shared/managed-workflow.js.map +1 -0
  65. package/dist/templates/workflows/shared/operations-changes.d.ts +13 -3
  66. package/dist/templates/workflows/shared/operations-changes.d.ts.map +1 -1
  67. package/dist/templates/workflows/shared/operations-changes.js +42 -16
  68. package/dist/templates/workflows/shared/operations-changes.js.map +1 -1
  69. package/dist/templates/workflows/shared/operations-domain-jobs.d.ts +18 -1
  70. package/dist/templates/workflows/shared/operations-domain-jobs.d.ts.map +1 -1
  71. package/dist/templates/workflows/shared/operations-domain-jobs.js +142 -17
  72. package/dist/templates/workflows/shared/operations-domain-jobs.js.map +1 -1
  73. package/dist/templates/workflows/shared/operations-gate.d.ts +6 -0
  74. package/dist/templates/workflows/shared/operations-gate.d.ts.map +1 -0
  75. package/dist/templates/workflows/shared/operations-gate.js +116 -0
  76. package/dist/templates/workflows/shared/operations-gate.js.map +1 -0
  77. package/dist/templates/workflows/shared/operations-header.d.ts +11 -1
  78. package/dist/templates/workflows/shared/operations-header.d.ts.map +1 -1
  79. package/dist/templates/workflows/shared/operations-header.js +66 -7
  80. package/dist/templates/workflows/shared/operations-header.js.map +1 -1
  81. package/dist/templates/workflows/shared/operations-tag-promote.d.ts +4 -3
  82. package/dist/templates/workflows/shared/operations-tag-promote.d.ts.map +1 -1
  83. package/dist/templates/workflows/shared/operations-tag-promote.js +144 -33
  84. package/dist/templates/workflows/shared/operations-tag-promote.js.map +1 -1
  85. package/dist/templates/workflows/shared/operations-version.d.ts +3 -2
  86. package/dist/templates/workflows/shared/operations-version.d.ts.map +1 -1
  87. package/dist/templates/workflows/shared/operations-version.js +17 -16
  88. package/dist/templates/workflows/shared/operations-version.js.map +1 -1
  89. package/dist/templates/yaml-format-utils.d.ts.map +1 -1
  90. package/dist/templates/yaml-format-utils.js +1 -5
  91. package/dist/templates/yaml-format-utils.js.map +1 -1
  92. package/dist/types/index.d.ts +65 -53
  93. package/dist/types/index.d.ts.map +1 -1
  94. package/dist/utils/action-reference.d.ts +73 -0
  95. package/dist/utils/action-reference.d.ts.map +1 -0
  96. package/dist/utils/action-reference.js +120 -0
  97. package/dist/utils/action-reference.js.map +1 -0
  98. package/dist/utils/ast-path-operations.d.ts +3 -3
  99. package/dist/utils/ast-path-operations.d.ts.map +1 -1
  100. package/dist/utils/ast-path-operations.js +58 -17
  101. package/dist/utils/ast-path-operations.js.map +1 -1
  102. package/dist/utils/config.d.ts +16 -5
  103. package/dist/utils/config.d.ts.map +1 -1
  104. package/dist/utils/config.js +69 -12
  105. package/dist/utils/config.js.map +1 -1
  106. package/dist/utils/github-setup.d.ts +7 -7
  107. package/dist/utils/github-setup.d.ts.map +1 -1
  108. package/dist/utils/github-setup.js +84 -63
  109. package/dist/utils/github-setup.js.map +1 -1
  110. package/dist/utils/logger.d.ts.map +1 -1
  111. package/dist/utils/logger.js.map +1 -1
  112. package/dist/utils/messaging.d.ts +2 -2
  113. package/dist/utils/messaging.d.ts.map +1 -1
  114. package/dist/utils/messaging.js +12 -8
  115. package/dist/utils/messaging.js.map +1 -1
  116. package/dist/utils/preflight.d.ts +2 -2
  117. package/dist/utils/preflight.d.ts.map +1 -1
  118. package/dist/utils/preflight.js +43 -41
  119. package/dist/utils/preflight.js.map +1 -1
  120. package/dist/utils/versioning.d.ts +1 -1
  121. package/dist/utils/versioning.d.ts.map +1 -1
  122. package/dist/utils/versioning.js +10 -10
  123. package/dist/utils/versioning.js.map +1 -1
  124. package/dist/utils/workflow-semantics.d.ts +61 -0
  125. package/dist/utils/workflow-semantics.d.ts.map +1 -0
  126. package/dist/utils/workflow-semantics.js +230 -0
  127. package/dist/utils/workflow-semantics.js.map +1 -0
  128. package/package.json +12 -4
  129. package/src/generators/init.tpl.ts +275 -128
  130. package/src/generators/workflows.tpl.ts +54 -57
  131. package/dist/templates/actions/detect-changes-nx.yml.tpl.d.ts +0 -32
  132. package/dist/templates/actions/detect-changes-nx.yml.tpl.d.ts.map +0 -1
  133. package/dist/templates/actions/detect-changes-nx.yml.tpl.js +0 -227
  134. package/dist/templates/actions/detect-changes-nx.yml.tpl.js.map +0 -1
  135. package/dist/templates/workflows/pipeline-nx.yml.tpl.d.ts +0 -22
  136. package/dist/templates/workflows/pipeline-nx.yml.tpl.d.ts.map +0 -1
  137. package/dist/templates/workflows/pipeline-nx.yml.tpl.js +0 -196
  138. package/dist/templates/workflows/pipeline-nx.yml.tpl.js.map +0 -1
  139. package/dist/utils/idempotency.d.ts +0 -187
  140. package/dist/utils/idempotency.d.ts.map +0 -1
  141. package/dist/utils/idempotency.js +0 -304
  142. package/dist/utils/idempotency.js.map +0 -1
@@ -1,43 +1,40 @@
1
1
  /**
2
2
  * Init Template Generator
3
- *
4
- * Generates the initial PipeCraft configuration file (.pipecraftrc.json) with default settings.
3
+ *
4
+ * Generates the initial PipeCraft configuration file (.pipecraftrc) with default settings.
5
5
  * This generator is invoked by the `pipecraft init` command and prompts the user for
6
6
  * basic project configuration preferences.
7
- *
7
+ *
8
8
  * @module generators/init.tpl
9
- *
9
+ *
10
10
  * @example
11
11
  * ```typescript
12
12
  * import { generate } from './generators/init.tpl.js'
13
- *
13
+ *
14
14
  * // Called by CLI with Pinion context
15
15
  * await generate(pinionContext)
16
- *
17
- * // Creates .pipecraftrc.json with:
16
+ *
17
+ * // Creates .pipecraftrc with:
18
18
  * // - CI provider (GitHub/GitLab)
19
19
  * // - Merge strategy (fast-forward/merge)
20
20
  * // - Branch flow configuration
21
21
  * // - Domain-based change detection
22
22
  * // - Semantic versioning rules
23
23
  * ```
24
- *
24
+ *
25
25
  * @note Current Implementation: The generator currently uses hardcoded defaults
26
26
  * from `defaultConfig` regardless of user prompt responses. This is intentional
27
27
  * for the initial release to ensure consistent behavior. Future versions will
28
28
  * respect user input and allow customization.
29
29
  */
30
30
 
31
- import { PinionContext, toFile, renderTemplate, writeJSON } from '@featherscloud/pinion'
32
- import { existsSync, readFileSync } from 'fs'
31
+ import type { PinionContext } from '@featherscloud/pinion'
32
+ import { existsSync, writeFileSync } from 'fs'
33
33
  import inquirer from 'inquirer'
34
- import { IdempotencyManager } from '../utils/idempotency.js'
35
- import { VersionManager } from '../utils/versioning.js'
36
- import { PipecraftConfig } from '../types/index.js'
37
34
 
38
35
  /**
39
36
  * Default PipeCraft configuration for new projects.
40
- *
37
+ *
41
38
  * Provides a complete, working trunk-based development workflow with:
42
39
  * - GitHub Actions CI/CD
43
40
  * - Fast-forward merge strategy
@@ -45,7 +42,7 @@ import { PipecraftConfig } from '../types/index.js'
45
42
  * - Conventional commits enforcement
46
43
  * - Semantic versioning with standard bump rules
47
44
  * - Domain-based change detection for monorepos
48
- *
45
+ *
49
46
  * @const
50
47
  */
51
48
  const defaultConfig = {
@@ -55,14 +52,28 @@ const defaultConfig = {
55
52
  initialBranch: 'develop',
56
53
  finalBranch: 'main',
57
54
  branchFlow: ['develop', 'staging', 'main'],
58
- autoMerge: {
55
+ autoPromote: {
59
56
  staging: true,
60
57
  main: true
61
58
  },
62
59
  semver: {
63
60
  bumpRules: {
64
- feat: 'minor',
61
+ test: 'ignore',
62
+ build: 'ignore',
63
+
64
+ ci: 'patch',
65
+ docs: 'patch',
66
+ style: 'patch',
65
67
  fix: 'patch',
68
+ perf: 'patch',
69
+ refactor: 'patch',
70
+ chore: 'patch',
71
+ patch: 'patch',
72
+
73
+ feat: 'minor',
74
+ minor: 'minor',
75
+
76
+ major: 'major',
66
77
  breaking: 'major'
67
78
  }
68
79
  },
@@ -87,54 +98,216 @@ const defaultConfig = {
87
98
  }
88
99
 
89
100
  /**
90
- * Generates a JSON string representation of the PipeCraft configuration.
91
- *
92
- * Serializes the configuration object with proper formatting (2-space indentation)
93
- * for writing to .pipecraftrc.json file.
94
- *
95
- * @param {PipecraftConfig} ctx - The configuration context to serialize
96
- * @returns {string} JSON string representation of the configuration
97
- *
98
- * @note The function extracts specific fields from the context to ensure
99
- * only valid configuration properties are included in the output file.
101
+ * Generates a YAML configuration file with comprehensive comments.
102
+ *
103
+ * Creates a .pipecraftrc file with:
104
+ * - Descriptive section headers
105
+ * - Inline comments for each configuration option
106
+ * - Examples and valid values
107
+ * - Proper YAML formatting
108
+ *
109
+ * @param {any} config - The configuration object to serialize
110
+ * @returns {string} YAML string with comments
100
111
  */
101
- const configTemplate = (ctx: PipecraftConfig) => {
102
- const config: any = {
103
- ciProvider: ctx.ciProvider,
104
- mergeStrategy: ctx.mergeStrategy,
105
- requireConventionalCommits: ctx.requireConventionalCommits,
106
- initialBranch: ctx.initialBranch,
107
- finalBranch: ctx.finalBranch,
108
- branchFlow: ctx.branchFlow,
109
- autoMerge: ctx.autoMerge,
110
- semver: {
111
- bumpRules: ctx.semver.bumpRules
112
+ const generateYamlConfig = (config: any): string => {
113
+ const lines: string[] = []
114
+
115
+ // Header
116
+ lines.push('# PipeCraft Configuration')
117
+ lines.push('# Trunk-based development workflow automation')
118
+ lines.push('# https://pipecraft.thecraftlab.dev')
119
+ lines.push('')
120
+
121
+ // CI Provider
122
+ lines.push('# CI/CD Platform')
123
+ lines.push(`ciProvider: ${config.ciProvider}`)
124
+ lines.push('')
125
+
126
+ // Merge Strategy
127
+ lines.push('# Merge strategy for automatic promotions')
128
+ lines.push(
129
+ "# Options: 'fast-forward' (clean linear history, recommended) | 'merge' (creates merge commits)"
130
+ )
131
+ lines.push(`mergeStrategy: ${config.mergeStrategy}`)
132
+ lines.push('')
133
+
134
+ // Conventional Commits
135
+ lines.push('# Enforce conventional commit messages (feat:, fix:, etc.)')
136
+ lines.push(`requireConventionalCommits: ${config.requireConventionalCommits}`)
137
+ lines.push('')
138
+
139
+ // Branch Configuration
140
+ lines.push('# Branch flow configuration')
141
+ lines.push(`initialBranch: ${config.initialBranch} # Where features land`)
142
+ lines.push(`finalBranch: ${config.finalBranch} # Production branch`)
143
+ lines.push('')
144
+
145
+ // Branch Flow
146
+ lines.push(`# Promotion flow: ${config.branchFlow.join(' → ')}`)
147
+ lines.push('branchFlow:')
148
+ config.branchFlow.forEach((branch: string, index: number) => {
149
+ const comments = [
150
+ '# Feature integration and initial testing',
151
+ '# Pre-production validation',
152
+ '# Production releases'
153
+ ]
154
+ lines.push(` - ${branch} ${comments[index] || ''}`)
155
+ })
156
+ lines.push('')
157
+
158
+ // Auto Merge
159
+ lines.push('# Automatic promotion after successful tests')
160
+ lines.push('autoPromote:')
161
+ const autoPromoteEntries = Object.entries(config.autoPromote)
162
+ autoPromoteEntries.forEach(([key, value]) => {
163
+ const flowIndex = config.branchFlow.indexOf(key)
164
+ const fromBranch = flowIndex > 0 ? config.branchFlow[flowIndex - 1] : ''
165
+ const comment = fromBranch ? ` # Auto-promote ${fromBranch} → ${key}` : ''
166
+ lines.push(` ${key}: ${value}${comment}`)
167
+ })
168
+ lines.push('')
169
+
170
+ // Package Manager (if present)
171
+ if (config.packageManager) {
172
+ lines.push('# Package manager')
173
+ lines.push(`packageManager: ${config.packageManager}`)
174
+ lines.push('')
175
+ }
176
+
177
+ // Semantic Versioning
178
+ lines.push('# Semantic versioning rules')
179
+ lines.push('# Prefixes are used to determine the type of change and the version bump level')
180
+ lines.push('semver:')
181
+ lines.push(' bumpRules:')
182
+
183
+ const bumpRules = config.semver.bumpRules
184
+ const ruleGroups = [
185
+ { title: '# Ignored types (no version bump)', keys: ['test', 'build'] },
186
+ {
187
+ title: '# Patch-level changes (0.0.x)',
188
+ keys: ['ci', 'docs', 'style', 'fix', 'perf', 'refactor', 'chore', 'patch']
112
189
  },
113
- domains: ctx.domains
190
+ { title: '# Minor-level changes (0.x.0)', keys: ['feat', 'minor'] },
191
+ { title: '# Major-level changes (x.0.0)', keys: ['major', 'breaking'] }
192
+ ]
193
+
194
+ ruleGroups.forEach((group, groupIndex) => {
195
+ if (groupIndex > 0) lines.push('')
196
+ lines.push(` ${group.title}`)
197
+ group.keys.forEach(key => {
198
+ if (bumpRules[key]) {
199
+ lines.push(` ${key}: '${bumpRules[key]}'`)
200
+ }
201
+ })
202
+ })
203
+ lines.push('')
204
+
205
+ // Domains
206
+ lines.push('# Domain definitions - what parts of your codebase trigger which jobs')
207
+ lines.push(
208
+ '# Will create placeholder jobs for each domain if no jobs are defined in the pipeline.yml'
209
+ )
210
+ lines.push('domains:')
211
+
212
+ Object.entries(config.domains).forEach(([domainName, domainConfig]: [string, any]) => {
213
+ lines.push(` ${domainName}:`)
214
+
215
+ // Description (always write as field)
216
+ if (domainConfig.description) {
217
+ lines.push(` description: '${domainConfig.description}'`)
218
+ }
219
+
220
+ // Paths
221
+ if (domainConfig.paths) {
222
+ lines.push(' paths:')
223
+ domainConfig.paths.forEach((path: string) => {
224
+ lines.push(` - ${path}`)
225
+ })
226
+ }
227
+
228
+ // Prefixes (if present)
229
+ if (domainConfig.prefixes) {
230
+ lines.push(` prefixes: [${domainConfig.prefixes.map((p: string) => `'${p}'`).join(', ')}]`)
231
+ }
232
+
233
+ lines.push('')
234
+ })
235
+
236
+ // Versioning (if present)
237
+ if (config.versioning) {
238
+ lines.push('# Version calculation and release automation')
239
+ lines.push('versioning:')
240
+ lines.push(` enabled: ${config.versioning.enabled}`)
241
+ if (config.versioning.releaseItConfig) {
242
+ lines.push(` releaseItConfig: ${config.versioning.releaseItConfig}`)
243
+ }
244
+ if (config.versioning.conventionalCommits !== undefined) {
245
+ lines.push(
246
+ ` conventionalCommits: ${config.versioning.conventionalCommits} # Use conventional commits for version bumps`
247
+ )
248
+ }
249
+ if (config.versioning.autoTag !== undefined) {
250
+ lines.push(
251
+ ` autoTag: ${config.versioning.autoTag} # Automatically create git tags`
252
+ )
253
+ }
254
+ if (config.versioning.autoPush !== undefined) {
255
+ lines.push(
256
+ ` autoPush: ${config.versioning.autoPush} # Manual control over git push`
257
+ )
258
+ }
259
+ if (config.versioning.changelog !== undefined) {
260
+ lines.push(` changelog: ${config.versioning.changelog} # Generate CHANGELOG.md`)
261
+ }
262
+ // Note: bumpRules are defined in the semver section, not here
263
+ lines.push('')
114
264
  }
115
265
 
116
- // Include Nx configuration if detected
117
- if (ctx.nx) {
118
- config.nx = ctx.nx
266
+ // Rebuild configuration (if present)
267
+ if (config.rebuild) {
268
+ lines.push('# Workflow rebuild optimization')
269
+ lines.push('rebuild:')
270
+ lines.push(` enabled: ${config.rebuild.enabled} # Enable smart rebuild detection`)
271
+ if (config.rebuild.skipIfUnchanged !== undefined) {
272
+ lines.push(
273
+ ` skipIfUnchanged: ${config.rebuild.skipIfUnchanged} # Skip regeneration if config hasn't changed`
274
+ )
275
+ }
276
+ if (config.rebuild.forceRegenerate !== undefined) {
277
+ lines.push(
278
+ ` forceRegenerate: ${config.rebuild.forceRegenerate} # Force regenerate even if unchanged`
279
+ )
280
+ }
281
+ if (config.rebuild.cacheFile) {
282
+ lines.push(` cacheFile: ${config.rebuild.cacheFile}`)
283
+ }
284
+ lines.push('')
285
+ }
286
+
287
+ // Remove trailing empty line
288
+ while (lines[lines.length - 1] === '') {
289
+ lines.pop()
119
290
  }
120
291
 
121
- return JSON.stringify(config, null, 2)
292
+ lines.push('') // Single trailing newline
293
+
294
+ return lines.join('\n')
122
295
  }
123
296
 
124
297
  /**
125
298
  * Init generator main entry point.
126
- *
299
+ *
127
300
  * Orchestrates the initialization process by:
128
301
  * 1. Prompting user for project preferences (currently unused - see note)
129
302
  * 2. Merging user input with default configuration
130
303
  * 3. Generating and writing .pipecraftrc.json file
131
- *
304
+ *
132
305
  * @param {PinionContext} ctx - Pinion generator context from CLI
133
306
  * @returns {Promise<PinionContext>} Updated context after file generation
134
- *
307
+ *
135
308
  * @throws {Error} If configuration file cannot be written
136
309
  * @throws {Error} If user input validation fails
137
- *
310
+ *
138
311
  * @example
139
312
  * ```typescript
140
313
  * // Called by Pinion framework when user runs `pipecraft init`
@@ -143,16 +316,16 @@ const configTemplate = (ctx: PipecraftConfig) => {
143
316
  * argv: ['init'],
144
317
  * pinion: { ... }
145
318
  * })
146
- *
319
+ *
147
320
  * // Results in: /path/to/project/.pipecraftrc.json
148
321
  * ```
149
- *
322
+ *
150
323
  * @note Current Behavior: Despite prompting for user input, the generator
151
324
  * currently overwrites all responses with `defaultConfig` values (line 167).
152
325
  * This ensures consistency for the initial release. Future versions will
153
326
  * respect user choices and allow customization of branch names, merge strategies,
154
327
  * and domain configurations.
155
- *
328
+ *
156
329
  * Prompts Presented (currently unused):
157
330
  * - Project name
158
331
  * - CI provider (GitHub/GitLab)
@@ -165,24 +338,36 @@ const configTemplate = (ctx: PipecraftConfig) => {
165
338
  export const generate = async (ctx: PinionContext) => {
166
339
  const cwd = ctx.cwd || process.cwd()
167
340
 
168
- // Detect package manager before prompting
169
- let detectedPackageManager: 'npm' | 'yarn' | 'pnpm' = 'npm'
170
- if (existsSync(`${cwd}/pnpm-lock.yaml`)) {
171
- detectedPackageManager = 'pnpm'
172
- } else if (existsSync(`${cwd}/yarn.lock`)) {
173
- detectedPackageManager = 'yarn'
174
- } else if (existsSync(`${cwd}/package-lock.json`)) {
175
- detectedPackageManager = 'npm'
341
+ // Check if .pipecraftrc already exists (YAML format)
342
+ const configPath = `${cwd}/.pipecraftrc`
343
+ const legacyConfigPath = `${cwd}/.pipecraftrc.json`
344
+
345
+ if (existsSync(configPath) || existsSync(legacyConfigPath)) {
346
+ const existingPath = existsSync(configPath) ? '.pipecraftrc' : '.pipecraftrc.json'
347
+ const overwriteAnswer = await inquirer.prompt([
348
+ {
349
+ type: 'confirm',
350
+ name: 'overwrite',
351
+ message: `⚠️ ${existingPath} already exists. Overwrite it?`,
352
+ default: false
353
+ }
354
+ ])
355
+
356
+ if (!overwriteAnswer.overwrite) {
357
+ console.log('\n❌ Init cancelled. Existing configuration preserved.\n')
358
+ return
359
+ }
360
+
361
+ console.log('\n✅ Proceeding with overwrite...\n')
362
+
363
+ // Set force flag to true so Pinion will overwrite the file
364
+ if (ctx.pinion) {
365
+ ctx.pinion.force = true
366
+ }
176
367
  }
177
368
 
178
369
  // Run inquirer prompts
179
370
  const answers = await inquirer.prompt([
180
- {
181
- type: 'input',
182
- name: 'projectName',
183
- message: 'What is your project name?',
184
- default: 'my-project'
185
- },
186
371
  {
187
372
  type: 'list',
188
373
  name: 'ciProvider',
@@ -228,13 +413,6 @@ export const generate = async (ctx: PinionContext) => {
228
413
  default: 'develop,staging,main',
229
414
  filter: (input: string) => input.split(',').map(b => b.trim())
230
415
  },
231
- {
232
- type: 'list',
233
- name: 'packageManager',
234
- message: `Which package manager do you use? (detected: ${detectedPackageManager})`,
235
- choices: ['npm', 'yarn', 'pnpm'],
236
- default: detectedPackageManager
237
- },
238
416
  {
239
417
  type: 'list',
240
418
  name: 'domainSelection',
@@ -261,13 +439,20 @@ export const generate = async (ctx: PinionContext) => {
261
439
  if (!input.trim()) {
262
440
  return 'Please enter at least one domain'
263
441
  }
264
- const domains = input.split(',').map(d => d.trim()).filter(d => d)
442
+ const domains = input
443
+ .split(',')
444
+ .map(d => d.trim())
445
+ .filter(d => d)
265
446
  if (domains.length === 0) {
266
447
  return 'Please enter valid domain names'
267
448
  }
268
449
  return true
269
450
  },
270
- filter: (input: string) => input.split(',').map(d => d.trim()).filter(d => d)
451
+ filter: (input: string) =>
452
+ input
453
+ .split(',')
454
+ .map(d => d.trim())
455
+ .filter(d => d)
271
456
  }
272
457
  ])
273
458
  selectedDomains = customDomainsAnswer.customDomains
@@ -278,7 +463,10 @@ export const generate = async (ctx: PinionContext) => {
278
463
  'frontend-backend': ['frontend', 'backend'],
279
464
  'apps-libs': ['apps', 'libs']
280
465
  }
281
- selectedDomains = domainMappings[answers.domainSelection as keyof typeof domainMappings] || ['api', 'web']
466
+ selectedDomains = domainMappings[answers.domainSelection as keyof typeof domainMappings] || [
467
+ 'api',
468
+ 'web'
469
+ ]
282
470
  }
283
471
 
284
472
  // Generate domain configuration
@@ -292,64 +480,20 @@ export const generate = async (ctx: PinionContext) => {
292
480
 
293
481
  // Add cicd domain for CI/CD changes
294
482
  domainConfig.cicd = {
295
- paths: ['.github/workflows/**'],
483
+ paths: ['.github/**'],
296
484
  description: 'CI/CD configuration changes'
297
485
  }
298
486
 
299
487
  // Show warning for custom domains about path editing
300
488
  if (answers.domainSelection === 'custom') {
301
489
  console.log('\n⚠️ Custom domains selected!')
302
- console.log(' You will need to edit the paths in .pipecraftrc.json after generation')
490
+ console.log(' You will need to edit the paths in .pipecraftrc after generation')
303
491
  console.log(' to match your actual project structure.\n')
304
492
  }
305
493
 
306
494
  // Merge answers with context and defaults
307
495
  const mergedCtx = { ...ctx, ...defaultConfig, ...answers } as any
308
496
 
309
- // Detect Nx workspace
310
- const nxJsonPath = `${cwd}/nx.json`
311
- let nxConfig = undefined
312
-
313
- if (existsSync(nxJsonPath)) {
314
- try {
315
- const nxJsonContent = readFileSync(nxJsonPath, 'utf8')
316
- const nxJson = JSON.parse(nxJsonContent)
317
-
318
- // Extract tasks from targetDefaults
319
- const tasks = nxJson.targetDefaults ? Object.keys(nxJson.targetDefaults) : []
320
-
321
- // Sort tasks in a logical order (quality → test → build → e2e)
322
- const taskOrder = ['lint', 'typecheck', 'test', 'unit-test', 'build', 'integration-test', 'e2e', 'e2e-ci']
323
- const sortedTasks = tasks.sort((a, b) => {
324
- const aIdx = taskOrder.indexOf(a)
325
- const bIdx = taskOrder.indexOf(b)
326
- if (aIdx === -1 && bIdx === -1) return 0
327
- if (aIdx === -1) return 1
328
- if (bIdx === -1) return -1
329
- return aIdx - bIdx
330
- })
331
-
332
- console.log('✅ Nx workspace detected - enabling Nx integration')
333
- console.log(` Detected tasks: ${sortedTasks.join(', ')}`)
334
-
335
- nxConfig = {
336
- enabled: true,
337
- tasks: sortedTasks,
338
- baseRef: 'origin/main',
339
- enableCache: true
340
- }
341
- } catch (error) {
342
- console.warn('⚠️ Found nx.json but could not parse it:', error)
343
- console.log(' Using default Nx configuration')
344
- nxConfig = {
345
- enabled: true,
346
- tasks: ['lint', 'test', 'build', 'integration-test'],
347
- baseRef: 'origin/main',
348
- enableCache: true
349
- }
350
- }
351
- }
352
-
353
497
  const configData: any = {
354
498
  ciProvider: mergedCtx.ciProvider,
355
499
  mergeStrategy: mergedCtx.mergeStrategy,
@@ -357,18 +501,21 @@ export const generate = async (ctx: PinionContext) => {
357
501
  initialBranch: mergedCtx.initialBranch,
358
502
  finalBranch: mergedCtx.finalBranch,
359
503
  branchFlow: mergedCtx.branchFlow,
360
- autoMerge: mergedCtx.autoMerge,
361
- packageManager: mergedCtx.packageManager,
504
+ autoPromote: mergedCtx.autoPromote,
362
505
  semver: {
363
506
  bumpRules: mergedCtx.semver.bumpRules
364
507
  },
365
508
  domains: domainConfig // Use user-selected domains instead of defaults
366
509
  }
367
510
 
368
- // Add Nx config if detected
369
- if (nxConfig) {
370
- configData.nx = nxConfig
371
- }
511
+ // Generate YAML content with comments
512
+ const yamlContent = generateYamlConfig(configData)
513
+
514
+ // Write the .pipecraftrc file
515
+ const outputPath = `${cwd}/.pipecraftrc`
516
+ writeFileSync(outputPath, yamlContent, 'utf-8')
372
517
 
373
- return writeJSON(() => configData, toFile('.pipecraftrc.json'))(mergedCtx)
374
- }
518
+ console.log(`\n✅ Created ${outputPath}\n`)
519
+
520
+ return mergedCtx
521
+ }