@invarn/cibuild 1.3.16 → 1.3.17

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 (242) hide show
  1. package/dist/cli.cjs +1 -1
  2. package/dist/src/cli.d.ts +3 -0
  3. package/dist/src/cli.d.ts.map +1 -0
  4. package/dist/src/cli.js +987 -0
  5. package/dist/src/commands/android-scanner.d.ts +32 -0
  6. package/dist/src/commands/android-scanner.d.ts.map +1 -0
  7. package/dist/src/commands/android-scanner.js +667 -0
  8. package/dist/src/commands/build.d.ts +5 -0
  9. package/dist/src/commands/build.d.ts.map +1 -0
  10. package/dist/src/commands/build.js +1096 -0
  11. package/dist/src/commands/edit.d.ts +3 -0
  12. package/dist/src/commands/edit.d.ts.map +1 -0
  13. package/dist/src/commands/edit.js +651 -0
  14. package/dist/src/commands/file-secret-collector.d.ts +37 -0
  15. package/dist/src/commands/file-secret-collector.d.ts.map +1 -0
  16. package/dist/src/commands/file-secret-collector.js +199 -0
  17. package/dist/src/commands/github-workflow.d.ts +5 -0
  18. package/dist/src/commands/github-workflow.d.ts.map +1 -0
  19. package/dist/src/commands/github-workflow.js +45 -0
  20. package/dist/src/commands/ios-scanner.d.ts +27 -0
  21. package/dist/src/commands/ios-scanner.d.ts.map +1 -0
  22. package/dist/src/commands/ios-scanner.js +337 -0
  23. package/dist/src/commands/reset.d.ts +7 -0
  24. package/dist/src/commands/reset.d.ts.map +1 -0
  25. package/dist/src/commands/reset.js +81 -0
  26. package/dist/src/commands/secrets-sync-workflow.d.ts +15 -0
  27. package/dist/src/commands/secrets-sync-workflow.d.ts.map +1 -0
  28. package/dist/src/commands/secrets-sync-workflow.js +255 -0
  29. package/dist/src/commands/secrets-upload.d.ts +21 -0
  30. package/dist/src/commands/secrets-upload.d.ts.map +1 -0
  31. package/dist/src/commands/secrets-upload.js +177 -0
  32. package/dist/src/commands/secrets-upload.test.d.ts +5 -0
  33. package/dist/src/commands/secrets-upload.test.d.ts.map +1 -0
  34. package/dist/src/commands/secrets-upload.test.js +60 -0
  35. package/dist/src/config.d.ts +3 -0
  36. package/dist/src/config.d.ts.map +1 -0
  37. package/dist/src/config.js +46 -0
  38. package/dist/src/envman/cli.d.ts +21 -0
  39. package/dist/src/envman/cli.d.ts.map +1 -0
  40. package/dist/src/envman/cli.js +240 -0
  41. package/dist/src/envman/envman.d.ts +83 -0
  42. package/dist/src/envman/envman.d.ts.map +1 -0
  43. package/dist/src/envman/envman.js +361 -0
  44. package/dist/src/envman/envman.test.d.ts +5 -0
  45. package/dist/src/envman/envman.test.d.ts.map +1 -0
  46. package/dist/src/envman/envman.test.js +236 -0
  47. package/dist/src/envman/index.d.ts +23 -0
  48. package/dist/src/envman/index.d.ts.map +1 -0
  49. package/dist/src/envman/index.js +23 -0
  50. package/dist/src/envman/types.d.ts +55 -0
  51. package/dist/src/envman/types.d.ts.map +1 -0
  52. package/dist/src/envman/types.js +12 -0
  53. package/dist/src/lib.d.ts +27 -0
  54. package/dist/src/lib.d.ts.map +1 -0
  55. package/dist/src/lib.js +32 -0
  56. package/dist/src/pipeline.d.ts +3 -0
  57. package/dist/src/pipeline.d.ts.map +1 -0
  58. package/dist/src/pipeline.js +57 -0
  59. package/dist/src/runner.d.ts +17 -0
  60. package/dist/src/runner.d.ts.map +1 -0
  61. package/dist/src/runner.js +234 -0
  62. package/dist/src/types.d.ts +57 -0
  63. package/dist/src/types.d.ts.map +1 -0
  64. package/dist/src/types.js +2 -0
  65. package/dist/src/yaml/bitrise-compat.d.ts +65 -0
  66. package/dist/src/yaml/bitrise-compat.d.ts.map +1 -0
  67. package/dist/src/yaml/bitrise-compat.js +206 -0
  68. package/dist/src/yaml/bitrise-compat.test.d.ts +5 -0
  69. package/dist/src/yaml/bitrise-compat.test.d.ts.map +1 -0
  70. package/dist/src/yaml/bitrise-compat.test.js +347 -0
  71. package/dist/src/yaml/converter.d.ts +33 -0
  72. package/dist/src/yaml/converter.d.ts.map +1 -0
  73. package/dist/src/yaml/converter.js +222 -0
  74. package/dist/src/yaml/converter.test.d.ts +5 -0
  75. package/dist/src/yaml/converter.test.d.ts.map +1 -0
  76. package/dist/src/yaml/converter.test.js +348 -0
  77. package/dist/src/yaml/e2e.test.d.ts +6 -0
  78. package/dist/src/yaml/e2e.test.d.ts.map +1 -0
  79. package/dist/src/yaml/e2e.test.js +446 -0
  80. package/dist/src/yaml/env-resolver.d.ts +120 -0
  81. package/dist/src/yaml/env-resolver.d.ts.map +1 -0
  82. package/dist/src/yaml/env-resolver.js +405 -0
  83. package/dist/src/yaml/env-resolver.test.d.ts +5 -0
  84. package/dist/src/yaml/env-resolver.test.d.ts.map +1 -0
  85. package/dist/src/yaml/env-resolver.test.js +502 -0
  86. package/dist/src/yaml/interactive-prompts.d.ts +71 -0
  87. package/dist/src/yaml/interactive-prompts.d.ts.map +1 -0
  88. package/dist/src/yaml/interactive-prompts.js +258 -0
  89. package/dist/src/yaml/missing-env-handler.d.ts +45 -0
  90. package/dist/src/yaml/missing-env-handler.d.ts.map +1 -0
  91. package/dist/src/yaml/missing-env-handler.js +64 -0
  92. package/dist/src/yaml/parser.d.ts +33 -0
  93. package/dist/src/yaml/parser.d.ts.map +1 -0
  94. package/dist/src/yaml/parser.js +145 -0
  95. package/dist/src/yaml/pipeline-with-secrets.d.ts +25 -0
  96. package/dist/src/yaml/pipeline-with-secrets.d.ts.map +1 -0
  97. package/dist/src/yaml/pipeline-with-secrets.js +76 -0
  98. package/dist/src/yaml/platform-detector.d.ts +83 -0
  99. package/dist/src/yaml/platform-detector.d.ts.map +1 -0
  100. package/dist/src/yaml/platform-detector.js +188 -0
  101. package/dist/src/yaml/platform-detector.test.d.ts +5 -0
  102. package/dist/src/yaml/platform-detector.test.d.ts.map +1 -0
  103. package/dist/src/yaml/platform-detector.test.js +414 -0
  104. package/dist/src/yaml/preflight-validation.d.ts +40 -0
  105. package/dist/src/yaml/preflight-validation.d.ts.map +1 -0
  106. package/dist/src/yaml/preflight-validation.js +152 -0
  107. package/dist/src/yaml/secrets-manager.d.ts +77 -0
  108. package/dist/src/yaml/secrets-manager.d.ts.map +1 -0
  109. package/dist/src/yaml/secrets-manager.js +219 -0
  110. package/dist/src/yaml/step-validator.d.ts +54 -0
  111. package/dist/src/yaml/step-validator.d.ts.map +1 -0
  112. package/dist/src/yaml/step-validator.js +403 -0
  113. package/dist/src/yaml/steps/android-sign.d.ts +35 -0
  114. package/dist/src/yaml/steps/android-sign.d.ts.map +1 -0
  115. package/dist/src/yaml/steps/android-sign.js +147 -0
  116. package/dist/src/yaml/steps/android-version.d.ts +26 -0
  117. package/dist/src/yaml/steps/android-version.d.ts.map +1 -0
  118. package/dist/src/yaml/steps/android-version.js +128 -0
  119. package/dist/src/yaml/steps/android-version.test.d.ts +5 -0
  120. package/dist/src/yaml/steps/android-version.test.d.ts.map +1 -0
  121. package/dist/src/yaml/steps/android-version.test.js +196 -0
  122. package/dist/src/yaml/steps/android.d.ts +95 -0
  123. package/dist/src/yaml/steps/android.d.ts.map +1 -0
  124. package/dist/src/yaml/steps/android.js +916 -0
  125. package/dist/src/yaml/steps/app-store-deploy.d.ts +48 -0
  126. package/dist/src/yaml/steps/app-store-deploy.d.ts.map +1 -0
  127. package/dist/src/yaml/steps/app-store-deploy.js +162 -0
  128. package/dist/src/yaml/steps/base.d.ts +238 -0
  129. package/dist/src/yaml/steps/base.d.ts.map +1 -0
  130. package/dist/src/yaml/steps/base.js +345 -0
  131. package/dist/src/yaml/steps/bitrise-android-tools.d.ts +26 -0
  132. package/dist/src/yaml/steps/bitrise-android-tools.d.ts.map +1 -0
  133. package/dist/src/yaml/steps/bitrise-android-tools.js +198 -0
  134. package/dist/src/yaml/steps/bitrise-android-tools.test.d.ts +5 -0
  135. package/dist/src/yaml/steps/bitrise-android-tools.test.d.ts.map +1 -0
  136. package/dist/src/yaml/steps/bitrise-android-tools.test.js +280 -0
  137. package/dist/src/yaml/steps/bitrise-apk-info.d.ts +22 -0
  138. package/dist/src/yaml/steps/bitrise-apk-info.d.ts.map +1 -0
  139. package/dist/src/yaml/steps/bitrise-apk-info.js +144 -0
  140. package/dist/src/yaml/steps/bitrise-apk-info.test.d.ts +5 -0
  141. package/dist/src/yaml/steps/bitrise-apk-info.test.d.ts.map +1 -0
  142. package/dist/src/yaml/steps/bitrise-apk-info.test.js +331 -0
  143. package/dist/src/yaml/steps/bitrise-slack.d.ts +49 -0
  144. package/dist/src/yaml/steps/bitrise-slack.d.ts.map +1 -0
  145. package/dist/src/yaml/steps/bitrise-slack.js +280 -0
  146. package/dist/src/yaml/steps/bitrise-slack.test.d.ts +5 -0
  147. package/dist/src/yaml/steps/bitrise-slack.test.d.ts.map +1 -0
  148. package/dist/src/yaml/steps/bitrise-slack.test.js +484 -0
  149. package/dist/src/yaml/steps/bitrise-ssh.d.ts +27 -0
  150. package/dist/src/yaml/steps/bitrise-ssh.d.ts.map +1 -0
  151. package/dist/src/yaml/steps/bitrise-ssh.js +134 -0
  152. package/dist/src/yaml/steps/bitrise-ssh.test.d.ts +5 -0
  153. package/dist/src/yaml/steps/bitrise-ssh.test.d.ts.map +1 -0
  154. package/dist/src/yaml/steps/bitrise-ssh.test.js +205 -0
  155. package/dist/src/yaml/steps/cache.d.ts +52 -0
  156. package/dist/src/yaml/steps/cache.d.ts.map +1 -0
  157. package/dist/src/yaml/steps/cache.js +351 -0
  158. package/dist/src/yaml/steps/fastlane.d.ts +27 -0
  159. package/dist/src/yaml/steps/fastlane.d.ts.map +1 -0
  160. package/dist/src/yaml/steps/fastlane.js +79 -0
  161. package/dist/src/yaml/steps/file.d.ts +27 -0
  162. package/dist/src/yaml/steps/file.d.ts.map +1 -0
  163. package/dist/src/yaml/steps/file.js +35 -0
  164. package/dist/src/yaml/steps/flutter.d.ts +63 -0
  165. package/dist/src/yaml/steps/flutter.d.ts.map +1 -0
  166. package/dist/src/yaml/steps/flutter.js +215 -0
  167. package/dist/src/yaml/steps/git-clone.d.ts +26 -0
  168. package/dist/src/yaml/steps/git-clone.d.ts.map +1 -0
  169. package/dist/src/yaml/steps/git-clone.js +111 -0
  170. package/dist/src/yaml/steps/google-play-deploy.d.ts +37 -0
  171. package/dist/src/yaml/steps/google-play-deploy.d.ts.map +1 -0
  172. package/dist/src/yaml/steps/google-play-deploy.js +193 -0
  173. package/dist/src/yaml/steps/google-play-deploy.test.d.ts +5 -0
  174. package/dist/src/yaml/steps/google-play-deploy.test.d.ts.map +1 -0
  175. package/dist/src/yaml/steps/google-play-deploy.test.js +310 -0
  176. package/dist/src/yaml/steps/index.d.ts +10 -0
  177. package/dist/src/yaml/steps/index.d.ts.map +1 -0
  178. package/dist/src/yaml/steps/index.js +1361 -0
  179. package/dist/src/yaml/steps/ios-deps.d.ts +43 -0
  180. package/dist/src/yaml/steps/ios-deps.d.ts.map +1 -0
  181. package/dist/src/yaml/steps/ios-deps.js +141 -0
  182. package/dist/src/yaml/steps/ios-deps.test.d.ts +5 -0
  183. package/dist/src/yaml/steps/ios-deps.test.d.ts.map +1 -0
  184. package/dist/src/yaml/steps/ios-deps.test.js +90 -0
  185. package/dist/src/yaml/steps/ios-signing.d.ts +31 -0
  186. package/dist/src/yaml/steps/ios-signing.d.ts.map +1 -0
  187. package/dist/src/yaml/steps/ios-signing.js +144 -0
  188. package/dist/src/yaml/steps/ios-version.d.ts +47 -0
  189. package/dist/src/yaml/steps/ios-version.d.ts.map +1 -0
  190. package/dist/src/yaml/steps/ios-version.js +151 -0
  191. package/dist/src/yaml/steps/linting.d.ts +47 -0
  192. package/dist/src/yaml/steps/linting.d.ts.map +1 -0
  193. package/dist/src/yaml/steps/linting.js +148 -0
  194. package/dist/src/yaml/steps/phase2.test.d.ts +6 -0
  195. package/dist/src/yaml/steps/phase2.test.d.ts.map +1 -0
  196. package/dist/src/yaml/steps/phase2.test.js +197 -0
  197. package/dist/src/yaml/steps/phase3.test.d.ts +5 -0
  198. package/dist/src/yaml/steps/phase3.test.d.ts.map +1 -0
  199. package/dist/src/yaml/steps/phase3.test.js +144 -0
  200. package/dist/src/yaml/steps/phase4.test.d.ts +5 -0
  201. package/dist/src/yaml/steps/phase4.test.d.ts.map +1 -0
  202. package/dist/src/yaml/steps/phase4.test.js +166 -0
  203. package/dist/src/yaml/steps/phase5.test.d.ts +6 -0
  204. package/dist/src/yaml/steps/phase5.test.d.ts.map +1 -0
  205. package/dist/src/yaml/steps/phase5.test.js +263 -0
  206. package/dist/src/yaml/steps/registry.d.ts +88 -0
  207. package/dist/src/yaml/steps/registry.d.ts.map +1 -0
  208. package/dist/src/yaml/steps/registry.js +125 -0
  209. package/dist/src/yaml/steps/registry.test.d.ts +5 -0
  210. package/dist/src/yaml/steps/registry.test.d.ts.map +1 -0
  211. package/dist/src/yaml/steps/registry.test.js +235 -0
  212. package/dist/src/yaml/steps/release.d.ts +50 -0
  213. package/dist/src/yaml/steps/release.d.ts.map +1 -0
  214. package/dist/src/yaml/steps/release.js +154 -0
  215. package/dist/src/yaml/steps/script.d.ts +23 -0
  216. package/dist/src/yaml/steps/script.d.ts.map +1 -0
  217. package/dist/src/yaml/steps/script.js +63 -0
  218. package/dist/src/yaml/steps/spec-validation.test.d.ts +6 -0
  219. package/dist/src/yaml/steps/spec-validation.test.d.ts.map +1 -0
  220. package/dist/src/yaml/steps/spec-validation.test.js +130 -0
  221. package/dist/src/yaml/steps/steps.test.d.ts +6 -0
  222. package/dist/src/yaml/steps/steps.test.d.ts.map +1 -0
  223. package/dist/src/yaml/steps/steps.test.js +474 -0
  224. package/dist/src/yaml/steps/test-config.d.ts +3 -0
  225. package/dist/src/yaml/steps/test-config.d.ts.map +1 -0
  226. package/dist/src/yaml/steps/test-config.js +16 -0
  227. package/dist/src/yaml/steps/xcode-new.test.d.ts +5 -0
  228. package/dist/src/yaml/steps/xcode-new.test.d.ts.map +1 -0
  229. package/dist/src/yaml/steps/xcode-new.test.js +211 -0
  230. package/dist/src/yaml/steps/xcode.d.ts +222 -0
  231. package/dist/src/yaml/steps/xcode.d.ts.map +1 -0
  232. package/dist/src/yaml/steps/xcode.js +999 -0
  233. package/dist/src/yaml/types.d.ts +68 -0
  234. package/dist/src/yaml/types.d.ts.map +1 -0
  235. package/dist/src/yaml/types.js +5 -0
  236. package/dist/src/yaml/validation-types.d.ts +96 -0
  237. package/dist/src/yaml/validation-types.d.ts.map +1 -0
  238. package/dist/src/yaml/validation-types.js +8 -0
  239. package/dist/src/yaml/yaml-updater.d.ts +24 -0
  240. package/dist/src/yaml/yaml-updater.d.ts.map +1 -0
  241. package/dist/src/yaml/yaml-updater.js +128 -0
  242. package/package.json +16 -4
@@ -0,0 +1,258 @@
1
+ /**
2
+ * Interactive prompts for missing environment variables
3
+ * Allows users to fill in missing values or cancel the build
4
+ */
5
+ import prompts from 'prompts';
6
+ /**
7
+ * Interactive prompt manager for collecting missing environment variables
8
+ */
9
+ export class InteractivePrompts {
10
+ secretsManager;
11
+ workflow;
12
+ constructor(secretsManager, workflow) {
13
+ this.secretsManager = secretsManager;
14
+ this.workflow = workflow;
15
+ }
16
+ /**
17
+ * Prompt user for a missing environment variable
18
+ * @param varName Variable name
19
+ * @param stepName Optional step name that requires this variable
20
+ * @param hint Optional hint describing what the variable is for and expected format
21
+ * @returns Promise with the entered value or cancellation
22
+ */
23
+ async promptForVariable(varName, stepName, hint) {
24
+ console.log('\n╔═══════════════════════════════════════════════════════════════════╗');
25
+ console.log('ā•‘ MISSING REQUIRED ENVIRONMENT VARIABLE ā•‘');
26
+ console.log('ā•šā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•\n');
27
+ console.log(`Variable: ${varName}`);
28
+ if (stepName) {
29
+ console.log(`Required by: ${stepName} step`);
30
+ }
31
+ // Display hint if provided
32
+ if (hint) {
33
+ console.log('');
34
+ console.log('šŸ’” Hint:');
35
+ // Process hint lines - preserve formatting, only wrap plain text
36
+ const hintLines = this.processHintText(hint, 67);
37
+ hintLines.forEach(line => console.log(line));
38
+ }
39
+ console.log('');
40
+ // Check if this variable is already in secrets (workflow-scoped first, then global)
41
+ const existingSecretId = this.secretsManager.getSecretIdByName(varName, this.workflow);
42
+ if (existingSecretId) {
43
+ const secretName = this.secretsManager.getSecretName(existingSecretId);
44
+ const workflowInfo = this.workflow ? ` (workflow: ${this.workflow})` : ' (global)';
45
+ console.log(`\nā„¹ļø This variable already exists in your secrets file${workflowInfo}.`);
46
+ const useExisting = await this.promptYesNo('Use existing value?');
47
+ if (useExisting) {
48
+ const value = this.secretsManager.getSecret(existingSecretId);
49
+ if (value) {
50
+ return { value, cancelled: false };
51
+ }
52
+ }
53
+ }
54
+ console.log('');
55
+ // Show interactive menu
56
+ const menuResponse = await prompts({
57
+ type: 'select',
58
+ name: 'action',
59
+ message: 'What would you like to do?',
60
+ choices: [
61
+ { title: 'Enter value now (will be saved to secrets file)', value: 'enter' },
62
+ { title: 'Copy prompt for AI (get guidance from AI assistant)', value: 'ai' },
63
+ { title: 'Cancel build', value: 'cancel' }
64
+ ],
65
+ initial: 0,
66
+ });
67
+ if (!menuResponse.action || menuResponse.action === 'cancel') {
68
+ return { value: '', cancelled: true };
69
+ }
70
+ if (menuResponse.action === 'ai') {
71
+ // Copy AI prompt to clipboard
72
+ if (hint) {
73
+ const aiPrompt = this.generateAIPrompt(hint);
74
+ await this.copyToClipboard(aiPrompt);
75
+ console.log('\nāœ… AI prompt copied to clipboard!');
76
+ console.log('šŸ“‹ Paste it into your AI assistant to get guidance.\n');
77
+ }
78
+ else {
79
+ console.log('\nāš ļø No hint available for this variable.\n');
80
+ }
81
+ return { value: '', cancelled: true, copiedToAI: true };
82
+ }
83
+ // Prompt for value
84
+ const isSensitive = this.isSensitiveVariable(varName);
85
+ console.log('');
86
+ if (isSensitive) {
87
+ console.log('āš ļø This appears to be a sensitive value (input will be hidden)\n');
88
+ }
89
+ const valueResponse = await prompts({
90
+ type: isSensitive ? 'password' : 'text',
91
+ name: 'value',
92
+ message: `Enter value for ${varName}:`,
93
+ validate: value => value.trim() === '' ? 'Value cannot be empty' : true
94
+ });
95
+ if (!valueResponse.value || valueResponse.value.trim() === '') {
96
+ console.log('āŒ Error: Value cannot be empty');
97
+ return { value: '', cancelled: true };
98
+ }
99
+ return { value: valueResponse.value, cancelled: false };
100
+ }
101
+ /**
102
+ * Determine if a variable name suggests it's sensitive
103
+ * @param varName Variable name
104
+ * @returns True if variable appears to be sensitive
105
+ */
106
+ isSensitiveVariable(varName) {
107
+ const sensitivePatterns = [
108
+ /KEY/i,
109
+ /SECRET/i,
110
+ /PASSWORD/i,
111
+ /TOKEN/i,
112
+ /API/i,
113
+ /WEBHOOK/i,
114
+ /PRIVATE/i,
115
+ /CREDENTIAL/i,
116
+ ];
117
+ return sensitivePatterns.some((pattern) => pattern.test(varName));
118
+ }
119
+ /**
120
+ * Prompt for yes/no confirmation
121
+ * @param message Prompt message
122
+ * @returns Promise with true for yes, false for no
123
+ */
124
+ async promptYesNo(message) {
125
+ const response = await prompts({
126
+ type: 'confirm',
127
+ name: 'value',
128
+ message,
129
+ initial: true,
130
+ });
131
+ return response.value ?? false;
132
+ }
133
+ /**
134
+ * Process hint text to preserve formatting while wrapping plain text
135
+ * @param hint Hint text (may contain newlines and formatted sections)
136
+ * @param maxWidth Maximum width for wrapping plain text lines
137
+ * @returns Array of processed lines ready for display
138
+ */
139
+ processHintText(hint, maxWidth) {
140
+ const lines = hint.split('\n');
141
+ const result = [];
142
+ for (const line of lines) {
143
+ // Check if this line is formatted (contains box chars, bullets, or is indented)
144
+ const isFormatted = line.includes('ā”Œ') || line.includes('┐') ||
145
+ line.includes('ā””') || line.includes('ā”˜') ||
146
+ line.includes('│') || line.includes('─') ||
147
+ line.trimStart().startsWith('•') ||
148
+ (line.startsWith(' ') && line.trim().length > 0);
149
+ if (isFormatted || line.trim() === '') {
150
+ // Preserve formatted lines and empty lines as-is with indent
151
+ result.push(` ${line}`);
152
+ }
153
+ else {
154
+ // Wrap plain text lines
155
+ const wrapped = this.wrapText(line, maxWidth);
156
+ wrapped.forEach(wrappedLine => result.push(` ${wrappedLine}`));
157
+ }
158
+ }
159
+ return result;
160
+ }
161
+ /**
162
+ * Wrap text to fit within a specified width
163
+ * @param text Text to wrap
164
+ * @param maxWidth Maximum width per line
165
+ * @returns Array of wrapped lines
166
+ */
167
+ wrapText(text, maxWidth) {
168
+ const words = text.split(' ');
169
+ const lines = [];
170
+ let currentLine = '';
171
+ for (const word of words) {
172
+ const testLine = currentLine ? `${currentLine} ${word}` : word;
173
+ if (testLine.length <= maxWidth) {
174
+ currentLine = testLine;
175
+ }
176
+ else {
177
+ if (currentLine) {
178
+ lines.push(currentLine);
179
+ }
180
+ currentLine = word;
181
+ }
182
+ }
183
+ if (currentLine) {
184
+ lines.push(currentLine);
185
+ }
186
+ return lines.length > 0 ? lines : [''];
187
+ }
188
+ /**
189
+ * Generate AI prompt with hint for getting guidance
190
+ * @param hint Hint text from the step
191
+ * @returns Formatted AI prompt
192
+ */
193
+ generateAIPrompt(hint) {
194
+ return `This is a mobile CI/CD build step. Provide a brief, senior-level explanation of its purpose and when it is used. Do not execute anything.
195
+
196
+ ${hint}
197
+
198
+ Instructions for the assistant:
199
+ - Give a short purpose summary (what it enables in CI/CD).
200
+ - List only the required setup/usage steps.
201
+ - Include example commands if relevant (e.g., how to generate, retrieve, or configure the value).
202
+ - Include key security handling notes (storage, scope, rotation).
203
+ - Skip beginner explanations and background theory.
204
+ - Do not request or expose real secret values.
205
+ - Do not simulate execution.
206
+ - Ask only the minimum clarification questions required to avoid provider-specific mistakes. If setup differs by CI system, Git provider, signing provider, artifact host, or mobile platform — ask first; otherwise answer directly.
207
+
208
+ Finish with a short "Follow-up questions" numbered list only if clarification would change the setup guidance.`;
209
+ }
210
+ /**
211
+ * Copy text to system clipboard
212
+ * @param text Text to copy
213
+ */
214
+ async copyToClipboard(text) {
215
+ const { spawn } = await import('child_process');
216
+ return new Promise((resolve, reject) => {
217
+ // Detect platform and use appropriate clipboard command
218
+ const platform = process.platform;
219
+ let clipboardProcess;
220
+ if (platform === 'darwin') {
221
+ // macOS
222
+ clipboardProcess = spawn('pbcopy');
223
+ }
224
+ else if (platform === 'linux') {
225
+ // Linux - try xclip first, then xsel
226
+ clipboardProcess = spawn('xclip', ['-selection', 'clipboard']);
227
+ }
228
+ else if (platform === 'win32') {
229
+ // Windows
230
+ clipboardProcess = spawn('clip');
231
+ }
232
+ else {
233
+ reject(new Error(`Clipboard not supported on platform: ${platform}`));
234
+ return;
235
+ }
236
+ clipboardProcess.stdin.write(text);
237
+ clipboardProcess.stdin.end();
238
+ clipboardProcess.on('close', (code) => {
239
+ if (code === 0) {
240
+ resolve();
241
+ }
242
+ else {
243
+ reject(new Error(`Clipboard command failed with code ${code}`));
244
+ }
245
+ });
246
+ clipboardProcess.on('error', (error) => {
247
+ reject(error);
248
+ });
249
+ });
250
+ }
251
+ /**
252
+ * Close the prompts interface (no-op with prompts library)
253
+ */
254
+ close() {
255
+ // No cleanup needed with prompts library
256
+ }
257
+ }
258
+ //# sourceMappingURL=interactive-prompts.js.map
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Handler for missing environment variables with interactive prompts
3
+ */
4
+ import { SecretsManager } from './secrets-manager.js';
5
+ import { MissingEnvironmentVariableError } from './env-resolver.js';
6
+ /**
7
+ * Options for MissingEnvHandler
8
+ */
9
+ export interface MissingEnvHandlerOptions {
10
+ interactive: boolean;
11
+ workflow?: string;
12
+ secretsManager?: SecretsManager;
13
+ }
14
+ /**
15
+ * Result of handling a missing environment variable
16
+ */
17
+ export interface HandleResult {
18
+ value?: string;
19
+ cancelled: boolean;
20
+ }
21
+ /**
22
+ * Handler for missing environment variables
23
+ * Stores values in the universal secrets file — no YAML modification
24
+ */
25
+ export declare class MissingEnvHandler {
26
+ private secretsManager;
27
+ private prompts;
28
+ private interactive;
29
+ private workflow?;
30
+ constructor(options: MissingEnvHandlerOptions);
31
+ /**
32
+ * Handle a missing environment variable error
33
+ * Prompts user for value and saves to the universal secrets file
34
+ */
35
+ handleMissingVariable(error: MissingEnvironmentVariableError): Promise<HandleResult>;
36
+ /**
37
+ * Close the prompts interface
38
+ */
39
+ close(): void;
40
+ /**
41
+ * Get the secrets manager instance
42
+ */
43
+ getSecretsManager(): SecretsManager;
44
+ }
45
+ //# sourceMappingURL=missing-env-handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"missing-env-handler.d.ts","sourceRoot":"","sources":["../../../src/yaml/missing-env-handler.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,OAAO,EAAE,+BAA+B,EAAE,MAAM,mBAAmB,CAAC;AAEpE;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,WAAW,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,cAAc,CAAC;CACjC;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,OAAO,CAAC;CACpB;AAED;;;GAGG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,OAAO,CAAqB;IACpC,OAAO,CAAC,WAAW,CAAU;IAC7B,OAAO,CAAC,QAAQ,CAAC,CAAS;gBAEd,OAAO,EAAE,wBAAwB;IAO7C;;;OAGG;IACG,qBAAqB,CAAC,KAAK,EAAE,+BAA+B,GAAG,OAAO,CAAC,YAAY,CAAC;IAgC1F;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;OAEG;IACH,iBAAiB,IAAI,cAAc;CAGpC"}
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Handler for missing environment variables with interactive prompts
3
+ */
4
+ import { SecretsManager } from './secrets-manager.js';
5
+ import { InteractivePrompts } from './interactive-prompts.js';
6
+ /**
7
+ * Handler for missing environment variables
8
+ * Stores values in the universal secrets file — no YAML modification
9
+ */
10
+ export class MissingEnvHandler {
11
+ secretsManager;
12
+ prompts;
13
+ interactive;
14
+ workflow;
15
+ constructor(options) {
16
+ this.secretsManager = options.secretsManager || new SecretsManager();
17
+ this.workflow = options.workflow;
18
+ this.prompts = new InteractivePrompts(this.secretsManager, this.workflow);
19
+ this.interactive = options.interactive;
20
+ }
21
+ /**
22
+ * Handle a missing environment variable error
23
+ * Prompts user for value and saves to the universal secrets file
24
+ */
25
+ async handleMissingVariable(error) {
26
+ const { variableName, stepName, hint } = error;
27
+ if (!this.interactive) {
28
+ return { cancelled: true };
29
+ }
30
+ const promptResult = await this.prompts.promptForVariable(variableName, stepName, hint);
31
+ if (promptResult.cancelled) {
32
+ if (promptResult.copiedToAI) {
33
+ console.log('šŸ’” After getting guidance from AI, run the pipeline again to enter the value.');
34
+ }
35
+ else {
36
+ console.log('\nāŒ Build cancelled by user');
37
+ }
38
+ return { cancelled: true };
39
+ }
40
+ // Store in secrets file (workflow-scoped if workflow is set) and inject into current process env
41
+ this.secretsManager.storeSecret(variableName, promptResult.value, this.workflow);
42
+ process.env[variableName] = promptResult.value;
43
+ console.log(`\nāœ… Secret stored: ${variableName}`);
44
+ if (this.workflow) {
45
+ console.log(` Workflow: ${this.workflow}`);
46
+ }
47
+ console.log(` Location: ${this.secretsManager.getSecretsFilePath()}`);
48
+ console.log(`\nšŸ’” Next time you run this pipeline, the value will be loaded automatically.\n`);
49
+ return { value: promptResult.value, cancelled: false };
50
+ }
51
+ /**
52
+ * Close the prompts interface
53
+ */
54
+ close() {
55
+ this.prompts.close();
56
+ }
57
+ /**
58
+ * Get the secrets manager instance
59
+ */
60
+ getSecretsManager() {
61
+ return this.secretsManager;
62
+ }
63
+ }
64
+ //# sourceMappingURL=missing-env-handler.js.map
@@ -0,0 +1,33 @@
1
+ /**
2
+ * YAML pipeline parser - loads and validates YAML pipeline files
3
+ */
4
+ import type { YAMLPipeline } from './types.js';
5
+ export declare class YAMLParseError extends Error {
6
+ readonly filePath?: string | undefined;
7
+ constructor(message: string, filePath?: string | undefined);
8
+ }
9
+ export declare class YAMLValidationError extends Error {
10
+ constructor(message: string);
11
+ }
12
+ /**
13
+ * Loads and parses a YAML pipeline file
14
+ * @param filePath Path to the YAML file
15
+ * @returns Parsed YAML pipeline object
16
+ * @throws YAMLParseError if file doesn't exist or YAML syntax is invalid
17
+ * @throws YAMLValidationError if YAML structure is invalid
18
+ */
19
+ export declare function loadYAMLPipeline(filePath: string): YAMLPipeline;
20
+ /**
21
+ * Gets the list of workflow names from a YAML pipeline
22
+ * @param pipeline Parsed YAML pipeline
23
+ * @returns Array of workflow names
24
+ */
25
+ export declare function getWorkflowNames(pipeline: YAMLPipeline): string[];
26
+ /**
27
+ * Checks if a specific workflow exists in the pipeline
28
+ * @param pipeline Parsed YAML pipeline
29
+ * @param workflowName Name of the workflow to check
30
+ * @returns True if workflow exists
31
+ */
32
+ export declare function hasWorkflow(pipeline: YAMLPipeline, workflowName: string): boolean;
33
+ //# sourceMappingURL=parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../../src/yaml/parser.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAG/C,qBAAa,cAAe,SAAQ,KAAK;aACM,QAAQ,CAAC,EAAE,MAAM;gBAAlD,OAAO,EAAE,MAAM,EAAkB,QAAQ,CAAC,EAAE,MAAM,YAAA;CAI/D;AAED,qBAAa,mBAAoB,SAAQ,KAAK;gBAChC,OAAO,EAAE,MAAM;CAI5B;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,YAAY,CA0C/D;AA8GD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,YAAY,GAAG,MAAM,EAAE,CAEjE;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAEjF"}
@@ -0,0 +1,145 @@
1
+ /**
2
+ * YAML pipeline parser - loads and validates YAML pipeline files
3
+ */
4
+ import * as yaml from 'js-yaml';
5
+ import { readFileSync, existsSync } from 'fs';
6
+ import { resolve } from 'path';
7
+ import { convertBitriseMetadata } from './bitrise-compat.js';
8
+ export class YAMLParseError extends Error {
9
+ filePath;
10
+ constructor(message, filePath) {
11
+ super(message);
12
+ this.filePath = filePath;
13
+ this.name = 'YAMLParseError';
14
+ }
15
+ }
16
+ export class YAMLValidationError extends Error {
17
+ constructor(message) {
18
+ super(message);
19
+ this.name = 'YAMLValidationError';
20
+ }
21
+ }
22
+ /**
23
+ * Loads and parses a YAML pipeline file
24
+ * @param filePath Path to the YAML file
25
+ * @returns Parsed YAML pipeline object
26
+ * @throws YAMLParseError if file doesn't exist or YAML syntax is invalid
27
+ * @throws YAMLValidationError if YAML structure is invalid
28
+ */
29
+ export function loadYAMLPipeline(filePath) {
30
+ const absolutePath = resolve(filePath);
31
+ // Check if file exists
32
+ if (!existsSync(absolutePath)) {
33
+ throw new YAMLParseError(`YAML pipeline file not found: ${filePath}`, absolutePath);
34
+ }
35
+ let fileContent;
36
+ try {
37
+ fileContent = readFileSync(absolutePath, 'utf-8');
38
+ }
39
+ catch (err) {
40
+ throw new YAMLParseError(`Failed to read YAML file: ${filePath}\n${err.message}`, absolutePath);
41
+ }
42
+ // Parse YAML
43
+ let parsed;
44
+ try {
45
+ parsed = yaml.load(fileContent);
46
+ }
47
+ catch (err) {
48
+ const yamlError = err;
49
+ throw new YAMLParseError(`Failed to parse YAML file: ${filePath}\n${yamlError.name}: ${yamlError.message}`, absolutePath);
50
+ }
51
+ // Validate structure
52
+ validateYAMLPipeline(parsed, filePath);
53
+ const pipeline = parsed;
54
+ // Convert Bitrise metadata to CI Build format (FR-1.1, FR-1.2)
55
+ convertBitriseMetadata(pipeline);
56
+ return pipeline;
57
+ }
58
+ /**
59
+ * Validates the basic structure of a parsed YAML pipeline
60
+ * @param parsed Parsed YAML object
61
+ * @param filePath File path for error messages
62
+ * @throws YAMLValidationError if validation fails
63
+ */
64
+ function validateYAMLPipeline(parsed, filePath) {
65
+ if (!parsed || typeof parsed !== 'object') {
66
+ throw new YAMLValidationError(`Invalid YAML structure in ${filePath}: Expected an object at root level`);
67
+ }
68
+ // Check required fields
69
+ if (!parsed.format_version) {
70
+ throw new YAMLValidationError(`Missing required field 'format_version' in ${filePath}`);
71
+ }
72
+ if (!parsed.workflows || typeof parsed.workflows !== 'object') {
73
+ throw new YAMLValidationError(`Missing or invalid 'workflows' section in ${filePath}`);
74
+ }
75
+ // Check that workflows is not empty
76
+ const workflowNames = Object.keys(parsed.workflows);
77
+ if (workflowNames.length === 0) {
78
+ throw new YAMLValidationError(`No workflows defined in ${filePath}. At least one workflow is required.`);
79
+ }
80
+ // Validate each workflow has required fields
81
+ for (const workflowName of workflowNames) {
82
+ const workflow = parsed.workflows[workflowName];
83
+ if (!workflow || typeof workflow !== 'object') {
84
+ throw new YAMLValidationError(`Invalid workflow '${workflowName}' in ${filePath}: Expected an object`);
85
+ }
86
+ if (!Array.isArray(workflow.steps)) {
87
+ throw new YAMLValidationError(`Missing or invalid 'steps' array in workflow '${workflowName}' in ${filePath}`);
88
+ }
89
+ if (workflow.steps.length === 0) {
90
+ throw new YAMLValidationError(`Workflow '${workflowName}' in ${filePath} has no steps defined`);
91
+ }
92
+ }
93
+ // Validate meta section if present
94
+ if (parsed.meta) {
95
+ if (typeof parsed.meta !== 'object') {
96
+ throw new YAMLValidationError(`Invalid 'meta' section in ${filePath}: Expected an object`);
97
+ }
98
+ // Validate platform if specified
99
+ if (parsed.meta.platform) {
100
+ const validPlatforms = ['macos', 'linux', 'windows'];
101
+ if (!validPlatforms.includes(parsed.meta.platform)) {
102
+ throw new YAMLValidationError(`Invalid platform '${parsed.meta.platform}' in ${filePath}. Must be one of: ${validPlatforms.join(', ')}`);
103
+ }
104
+ }
105
+ // Validate cibuild.io section if present
106
+ if (parsed.meta['cibuild.io']) {
107
+ const cibuildMeta = parsed.meta['cibuild.io'];
108
+ if (typeof cibuildMeta !== 'object') {
109
+ throw new YAMLValidationError(`Invalid 'meta.cibuild.io' section in ${filePath}: Expected an object`);
110
+ }
111
+ // Validate stack pattern if specified
112
+ if (cibuildMeta.stack && typeof cibuildMeta.stack === 'string') {
113
+ const stackPattern = /^(macos|linux|windows)-/;
114
+ if (cibuildMeta.stack !== 'local' && !stackPattern.test(cibuildMeta.stack)) {
115
+ throw new YAMLValidationError(`Invalid stack '${cibuildMeta.stack}' in ${filePath}. Stack must be 'local' or start with 'macos-', 'linux-', or 'windows-'`);
116
+ }
117
+ }
118
+ // Validate machine_type if specified
119
+ if (cibuildMeta.machine_type) {
120
+ const validMachineTypes = ['standard', 'performance'];
121
+ if (!validMachineTypes.includes(cibuildMeta.machine_type)) {
122
+ throw new YAMLValidationError(`Invalid machine_type '${cibuildMeta.machine_type}' in ${filePath}. Must be one of: ${validMachineTypes.join(', ')}`);
123
+ }
124
+ }
125
+ }
126
+ }
127
+ }
128
+ /**
129
+ * Gets the list of workflow names from a YAML pipeline
130
+ * @param pipeline Parsed YAML pipeline
131
+ * @returns Array of workflow names
132
+ */
133
+ export function getWorkflowNames(pipeline) {
134
+ return Object.keys(pipeline.workflows);
135
+ }
136
+ /**
137
+ * Checks if a specific workflow exists in the pipeline
138
+ * @param pipeline Parsed YAML pipeline
139
+ * @param workflowName Name of the workflow to check
140
+ * @returns True if workflow exists
141
+ */
142
+ export function hasWorkflow(pipeline, workflowName) {
143
+ return workflowName in pipeline.workflows;
144
+ }
145
+ //# sourceMappingURL=parser.js.map
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Pipeline execution with secrets management integration
3
+ * Wraps converter and runner with interactive prompts for missing environment variables
4
+ */
5
+ import { type ConversionResult } from './converter.js';
6
+ import type { YAMLPipeline } from './types.js';
7
+ import type { CIConfig } from '../types.js';
8
+ /**
9
+ * Options for pipeline conversion with secrets
10
+ */
11
+ export interface ConvertYAMLWithSecretsOptions {
12
+ yamlFilePath: string;
13
+ interactive: boolean;
14
+ config: CIConfig;
15
+ workflowName?: string;
16
+ }
17
+ /**
18
+ * Converts YAML pipeline with automatic secrets management
19
+ * Prompts user for missing environment variables and updates YAML file
20
+ * @param pipeline Parsed YAML pipeline
21
+ * @param options Execution options
22
+ * @returns ConversionResult with pipeline and warnings
23
+ */
24
+ export declare function convertYAMLWithSecrets(pipeline: YAMLPipeline, options: ConvertYAMLWithSecretsOptions): Promise<ConversionResult>;
25
+ //# sourceMappingURL=pipeline-with-secrets.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pipeline-with-secrets.d.ts","sourceRoot":"","sources":["../../../src/yaml/pipeline-with-secrets.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAA4B,KAAK,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAKjF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C;;GAEG;AACH,MAAM,WAAW,6BAA6B;IAC5C,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;IACrB,MAAM,EAAE,QAAQ,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;GAMG;AACH,wBAAsB,sBAAsB,CAC1C,QAAQ,EAAE,YAAY,EACtB,OAAO,EAAE,6BAA6B,GACrC,OAAO,CAAC,gBAAgB,CAAC,CAiF3B"}
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Pipeline execution with secrets management integration
3
+ * Wraps converter and runner with interactive prompts for missing environment variables
4
+ */
5
+ import { convertYAMLToPipelineDef } from './converter.js';
6
+ import { MissingEnvironmentVariableError } from './env-resolver.js';
7
+ import { MissingEnvHandler } from './missing-env-handler.js';
8
+ import { SecretsManager } from './secrets-manager.js';
9
+ import { PreFlightValidator } from './preflight-validation.js';
10
+ /**
11
+ * Converts YAML pipeline with automatic secrets management
12
+ * Prompts user for missing environment variables and updates YAML file
13
+ * @param pipeline Parsed YAML pipeline
14
+ * @param options Execution options
15
+ * @returns ConversionResult with pipeline and warnings
16
+ */
17
+ export async function convertYAMLWithSecrets(pipeline, options) {
18
+ const secretsManager = new SecretsManager();
19
+ const missingEnvHandler = new MissingEnvHandler({
20
+ interactive: options.interactive,
21
+ workflow: options.workflowName,
22
+ secretsManager,
23
+ });
24
+ // Pre-flight validation: Check repository access before workflow execution
25
+ // Get the selected workflow for validation
26
+ const selectedWorkflowName = options.workflowName || Object.keys(pipeline.workflows)[0];
27
+ const selectedWorkflow = pipeline.workflows[selectedWorkflowName];
28
+ const preFlightValidator = new PreFlightValidator();
29
+ const preFlightResult = await preFlightValidator.validate(process.env, secretsManager, selectedWorkflow);
30
+ if (!preFlightResult.success && preFlightResult.error) {
31
+ console.log('\n'); // Add spacing before prompt
32
+ // Handle the missing or invalid repository URL
33
+ const handleResult = await missingEnvHandler.handleMissingVariable(preFlightResult.error);
34
+ missingEnvHandler.close();
35
+ if (handleResult.cancelled) {
36
+ throw new Error('Build cancelled: Repository validation failed');
37
+ }
38
+ // Retry validation after secret is stored
39
+ console.log('\nšŸ”„ Retrying pre-flight validation with stored secret...\n');
40
+ // Import the parser to reload the YAML
41
+ const { loadYAMLPipeline } = await import('./parser.js');
42
+ const reloadedPipeline = loadYAMLPipeline(options.yamlFilePath);
43
+ // Retry conversion (which will re-run pre-flight)
44
+ return await convertYAMLWithSecrets(reloadedPipeline, options);
45
+ }
46
+ try {
47
+ // Attempt conversion
48
+ const result = await convertYAMLToPipelineDef(pipeline, options.config, options.workflowName);
49
+ missingEnvHandler.close();
50
+ return result;
51
+ }
52
+ catch (error) {
53
+ // Check if it's a missing environment variable error
54
+ if (error instanceof MissingEnvironmentVariableError) {
55
+ console.log('\n'); // Add spacing before prompt
56
+ // Handle the missing variable
57
+ const handleResult = await missingEnvHandler.handleMissingVariable(error);
58
+ missingEnvHandler.close();
59
+ if (handleResult.cancelled) {
60
+ throw new Error('Build cancelled: Missing required environment variable');
61
+ }
62
+ // Retry conversion after secret is stored
63
+ // The YAML file has been updated with the secret reference
64
+ // We need to reload and convert again
65
+ console.log('\nšŸ”„ Retrying pipeline conversion with stored secret...\n');
66
+ // Import the parser to reload the YAML
67
+ const { loadYAMLPipeline } = await import('./parser.js');
68
+ const reloadedPipeline = loadYAMLPipeline(options.yamlFilePath);
69
+ // Retry conversion with the new secrets manager that has the value
70
+ return await convertYAMLWithSecrets(reloadedPipeline, options);
71
+ }
72
+ // Re-throw other errors
73
+ throw error;
74
+ }
75
+ }
76
+ //# sourceMappingURL=pipeline-with-secrets.js.map