@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,37 @@
1
+ import { SecretsManager } from "../yaml/secrets-manager.js";
2
+ export interface WorkflowGroup {
3
+ label: string;
4
+ workflows: string[];
5
+ }
6
+ export interface FileSecretConfig {
7
+ /** Display name used in prompts, e.g. "keystore" */
8
+ displayName: string;
9
+ /** The secret variable name, e.g. "KEYSTORE_BASE64" */
10
+ secretName: string;
11
+ /** Returns true if a filename matches (e.g. name === "google-services.json") */
12
+ fileMatch: (name: string) => boolean;
13
+ /** How to read the file into a string value. Defaults to "text". */
14
+ readAs?: "text" | "base64";
15
+ /** Workflow groups to scope the secret to */
16
+ workflowGroups: WorkflowGroup[];
17
+ /**
18
+ * When true, prompt for the relative project path where this file should
19
+ * be placed at runtime whenever content is provided manually (not picked
20
+ * from disk candidates). The answer is stored in the returned paths map.
21
+ */
22
+ promptTargetPath?: boolean;
23
+ }
24
+ /**
25
+ * Maps each workflow name to the relative path of the file that was selected
26
+ * or auto-detected from disk. Empty when the value was pasted manually.
27
+ */
28
+ export type FileSecretPaths = Record<string, string>;
29
+ export declare function findProjectFiles(dir: string, match: (name: string) => boolean): string[];
30
+ /**
31
+ * Finds, prompts for, and stores a file-based secret.
32
+ * Only prompts for workflow groups that don't already have the secret.
33
+ * Returns a map of workflow → relative file path for every workflow
34
+ * that was resolved from disk (not from a manual paste).
35
+ */
36
+ export declare function collectFileSecret(config: FileSecretConfig, cwd: string, secretsManager: SecretsManager, nonInteractive?: boolean): Promise<FileSecretPaths>;
37
+ //# sourceMappingURL=file-secret-collector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-secret-collector.d.ts","sourceRoot":"","sources":["../../../src/commands/file-secret-collector.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAE5D,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,gBAAgB;IAC/B,oDAAoD;IACpD,WAAW,EAAE,MAAM,CAAC;IACpB,uDAAuD;IACvD,UAAU,EAAE,MAAM,CAAC;IACnB,gFAAgF;IAChF,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IACrC,oEAAoE;IACpE,MAAM,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;IAC3B,6CAA6C;IAC7C,cAAc,EAAE,aAAa,EAAE,CAAC;IAChC;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED;;;GAGG;AACH,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAMrD,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,GAAG,MAAM,EAAE,CAkBxF;AAiDD;;;;;GAKG;AACH,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,gBAAgB,EACxB,GAAG,EAAE,MAAM,EACX,cAAc,EAAE,cAAc,EAC9B,cAAc,UAAQ,GACrB,OAAO,CAAC,eAAe,CAAC,CAuH1B"}
@@ -0,0 +1,199 @@
1
+ import { resolve, relative } from "node:path";
2
+ import { readdirSync, readFileSync } from "node:fs";
3
+ import * as readline from "node:readline";
4
+ import prompts from "prompts";
5
+ const SKIP_DIRS = new Set([
6
+ ".git", ".ci", "build", "dist", "node_modules", ".gradle", ".idea",
7
+ ]);
8
+ export function findProjectFiles(dir, match) {
9
+ const results = [];
10
+ let entries;
11
+ try {
12
+ entries = readdirSync(dir, { withFileTypes: true });
13
+ }
14
+ catch {
15
+ return results;
16
+ }
17
+ for (const entry of entries) {
18
+ if (entry.isDirectory()) {
19
+ if (!SKIP_DIRS.has(entry.name)) {
20
+ results.push(...findProjectFiles(resolve(dir, entry.name), match));
21
+ }
22
+ }
23
+ else if (match(entry.name)) {
24
+ results.push(resolve(dir, entry.name));
25
+ }
26
+ }
27
+ return results;
28
+ }
29
+ /**
30
+ * Reads multiline content from stdin via readline.
31
+ * The user terminates input by typing .done on its own line.
32
+ */
33
+ function readMultilineContent(label) {
34
+ return new Promise((resolvePromise) => {
35
+ console.log(`\n ${label}`);
36
+ console.log(" Paste content, then type .done on its own line and press Enter:\n");
37
+ if (process.stdin.isTTY) {
38
+ try {
39
+ process.stdin.setRawMode(false);
40
+ }
41
+ catch { /* ignore */ }
42
+ }
43
+ process.stdin.resume();
44
+ const rl = readline.createInterface({ input: process.stdin, terminal: false });
45
+ const lines = [];
46
+ rl.on("line", (line) => {
47
+ if (line.trim() === ".done") {
48
+ rl.close();
49
+ return;
50
+ }
51
+ lines.push(line);
52
+ });
53
+ rl.once("close", () => {
54
+ process.stdin.pause();
55
+ resolvePromise(lines.length > 0 ? lines.join("\n") : undefined);
56
+ });
57
+ rl.on("SIGINT", () => { rl.close(); resolvePromise(undefined); });
58
+ });
59
+ }
60
+ /**
61
+ * Prompts the user for the relative path in the project where the file
62
+ * should be written at runtime (e.g. "app/release.jks").
63
+ */
64
+ async function promptTargetPathInProject(displayName) {
65
+ const { targetPath } = await prompts({
66
+ type: "text",
67
+ name: "targetPath",
68
+ message: `Where should the ${displayName} be placed in the project? (e.g. app/release.jks)`,
69
+ });
70
+ return targetPath?.trim() || undefined;
71
+ }
72
+ /**
73
+ * Finds, prompts for, and stores a file-based secret.
74
+ * Only prompts for workflow groups that don't already have the secret.
75
+ * Returns a map of workflow → relative file path for every workflow
76
+ * that was resolved from disk (not from a manual paste).
77
+ */
78
+ export async function collectFileSecret(config, cwd, secretsManager, nonInteractive = false) {
79
+ const paths = {};
80
+ // Only process groups where at least one workflow is missing the secret
81
+ const pendingGroups = config.workflowGroups.filter((g) => !g.workflows.every((wf) => secretsManager.hasSecret(config.secretName, wf)));
82
+ if (pendingGroups.length === 0) {
83
+ console.log(` ✅ ${config.secretName} already in .cibuild-secrets.json — will be used at runtime.`);
84
+ return paths;
85
+ }
86
+ const pendingWorkflows = pendingGroups.flatMap((g) => g.workflows);
87
+ const readContent = (p) => config.readAs === "base64"
88
+ ? readFileSync(p).toString("base64")
89
+ : readFileSync(p, "utf-8");
90
+ const candidates = findProjectFiles(cwd, config.fileMatch);
91
+ if (candidates.length === 1 && config.workflowGroups.length === 1) {
92
+ // Single file, single-group config — auto-apply without prompting
93
+ const content = readContent(candidates[0]);
94
+ const relPath = relative(cwd, candidates[0]);
95
+ for (const wf of pendingWorkflows) {
96
+ secretsManager.storeSecret(config.secretName, content, wf);
97
+ paths[wf] = relPath;
98
+ }
99
+ console.log(` ✅ Read ${relPath} and stored as ${config.secretName} (workflows: ${pendingWorkflows.join(", ")})`);
100
+ }
101
+ else if (candidates.length > 0 && nonInteractive) {
102
+ // Non-interactive: auto-pick first candidate for all pending groups
103
+ const content = readContent(candidates[0]);
104
+ const relPath = relative(cwd, candidates[0]);
105
+ for (const wf of pendingWorkflows) {
106
+ secretsManager.storeSecret(config.secretName, content, wf);
107
+ paths[wf] = relPath;
108
+ }
109
+ console.log(` ✅ Auto-selected ${relPath} for ${config.secretName} (workflows: ${pendingWorkflows.join(", ")})`);
110
+ }
111
+ else if (candidates.length > 0) {
112
+ // One or more files found — prompt per pending group
113
+ const ENTER_PATH = "__ENTER_PATH__";
114
+ for (const group of pendingGroups) {
115
+ const fileChoices = candidates.map((p) => ({
116
+ title: relative(cwd, p),
117
+ value: p,
118
+ }));
119
+ fileChoices.push({ title: "Enter file path", value: ENTER_PATH });
120
+ fileChoices.push({ title: "Skip (add manually later)", value: null });
121
+ const { chosen } = await prompts({
122
+ type: "select",
123
+ name: "chosen",
124
+ message: `Select ${config.displayName} for ${group.label}:`,
125
+ choices: fileChoices,
126
+ });
127
+ if (chosen === ENTER_PATH) {
128
+ const { filePath } = await prompts({
129
+ type: "text",
130
+ name: "filePath",
131
+ message: `Enter path to ${config.displayName} file:`,
132
+ });
133
+ if (filePath?.trim()) {
134
+ const expandedPath = filePath.trim().replace(/^~/, process.env.HOME ?? "~");
135
+ try {
136
+ const content = readContent(expandedPath);
137
+ const targetPath = config.promptTargetPath
138
+ ? await promptTargetPathInProject(config.displayName)
139
+ : undefined;
140
+ for (const wf of group.workflows) {
141
+ secretsManager.storeSecret(config.secretName, content, wf);
142
+ if (targetPath)
143
+ paths[wf] = targetPath;
144
+ }
145
+ console.log(` ✅ Stored ${config.secretName} for workflows: ${group.workflows.join(", ")}`);
146
+ }
147
+ catch {
148
+ console.log(` Could not read ${expandedPath} — check the path and try again.`);
149
+ console.log(` Add later: ci secrets add ${config.secretName} .ci/pipelines/cibuild.yml -w ${group.workflows[0]}`);
150
+ }
151
+ }
152
+ else {
153
+ console.log(` Add later: ci secrets add ${config.secretName} .ci/pipelines/cibuild.yml -w ${group.workflows[0]}`);
154
+ }
155
+ }
156
+ else if (chosen) {
157
+ const content = readContent(chosen);
158
+ const relPath = relative(cwd, chosen);
159
+ for (const wf of group.workflows) {
160
+ secretsManager.storeSecret(config.secretName, content, wf);
161
+ paths[wf] = relPath;
162
+ }
163
+ console.log(` ✅ Stored ${config.secretName} for workflows: ${group.workflows.join(", ")}`);
164
+ }
165
+ else if (chosen === null) {
166
+ console.log(` Add later: ci secrets add ${config.secretName} .ci/pipelines/cibuild.yml -w ${group.workflows[0]}`);
167
+ }
168
+ }
169
+ }
170
+ else if (nonInteractive) {
171
+ // Non-interactive: no files found — skip with hint
172
+ console.log(` ⚠ No ${config.displayName} files found — add later: ci secrets add ${config.secretName}`);
173
+ }
174
+ else {
175
+ // Nothing found on disk — prompt per pending group
176
+ for (const group of pendingGroups) {
177
+ const label = pendingGroups.length > 1
178
+ ? `Enter ${config.displayName} content for ${group.label} (or type .done immediately to add later):`
179
+ : `Enter ${config.displayName} content (or type .done immediately to add later):`;
180
+ const value = await readMultilineContent(label);
181
+ if (value) {
182
+ const targetPath = config.promptTargetPath
183
+ ? await promptTargetPathInProject(config.displayName)
184
+ : undefined;
185
+ for (const wf of group.workflows) {
186
+ secretsManager.storeSecret(config.secretName, value, wf);
187
+ if (targetPath)
188
+ paths[wf] = targetPath;
189
+ }
190
+ console.log(` ✅ ${config.secretName} stored (workflows: ${group.workflows.join(", ")})`);
191
+ }
192
+ else {
193
+ console.log(` Add later: ci secrets add ${config.secretName} .ci/pipelines/cibuild.yml -w ${group.workflows[0]}`);
194
+ }
195
+ }
196
+ }
197
+ return paths;
198
+ }
199
+ //# sourceMappingURL=file-secret-collector.js.map
@@ -0,0 +1,5 @@
1
+ export declare function generateGitHubActionsWorkflow(options: {
2
+ platform: "ios" | "android" | null;
3
+ cwd: string;
4
+ }): boolean;
5
+ //# sourceMappingURL=github-workflow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github-workflow.d.ts","sourceRoot":"","sources":["../../../src/commands/github-workflow.ts"],"names":[],"mappings":"AAGA,wBAAgB,6BAA6B,CAAC,OAAO,EAAE;IACrD,QAAQ,EAAE,KAAK,GAAG,SAAS,GAAG,IAAI,CAAC;IACnC,GAAG,EAAE,MAAM,CAAC;CACb,GAAG,OAAO,CA8CV"}
@@ -0,0 +1,45 @@
1
+ import { resolve } from "node:path";
2
+ import { existsSync, mkdirSync, writeFileSync } from "node:fs";
3
+ export function generateGitHubActionsWorkflow(options) {
4
+ const { platform, cwd } = options;
5
+ const workflowDir = resolve(cwd, ".github", "workflows");
6
+ const workflowPath = resolve(workflowDir, "ci.yml");
7
+ if (existsSync(workflowPath)) {
8
+ return false;
9
+ }
10
+ const runner = platform === "android" ? "ubuntu-latest" : "macos-latest";
11
+ const yaml = `name: CI
12
+
13
+ on:
14
+ push:
15
+ branches: [main]
16
+ tags: ['v*']
17
+ pull_request:
18
+
19
+ jobs:
20
+ build:
21
+ if: "!startsWith(github.ref, 'refs/tags/')"
22
+ runs-on: ${runner}
23
+ environment: cibuild
24
+ steps:
25
+ - uses: actions/checkout@v4
26
+ - uses: invarnhq/cibuild@v1
27
+ with:
28
+ workflow: \${{ github.event_name == 'pull_request' && 'pull-request' || 'primary' }}
29
+
30
+ release:
31
+ if: startsWith(github.ref, 'refs/tags/v')
32
+ runs-on: ${runner}
33
+ environment: cibuild
34
+ steps:
35
+ - uses: actions/checkout@v4
36
+ - uses: invarnhq/cibuild@v1
37
+ with:
38
+ workflow: release
39
+ `;
40
+ mkdirSync(workflowDir, { recursive: true });
41
+ writeFileSync(workflowPath, yaml, "utf-8");
42
+ console.log(`✅ Generated .github/workflows/ci.yml (${runner})`);
43
+ return true;
44
+ }
45
+ //# sourceMappingURL=github-workflow.js.map
@@ -0,0 +1,27 @@
1
+ export type IosWarningCategory = "missing-file" | "env-var" | "signing-config" | "cocoapods";
2
+ export type IosWarningSeverity = "warning" | "info";
3
+ export interface IosWarning {
4
+ category: IosWarningCategory;
5
+ severity: IosWarningSeverity;
6
+ message: string;
7
+ hint?: string;
8
+ location?: string;
9
+ }
10
+ export interface IosScanResult {
11
+ warnings: IosWarning[];
12
+ /** Schemes detected from .xcscheme files inside .xcodeproj. Falls back to project name. */
13
+ detectedSchemes: string[];
14
+ /** True if a Podfile exists in the project root. */
15
+ hasCocoaPods: boolean;
16
+ /** True if a Package.swift exists in the project root. */
17
+ hasSPM: boolean;
18
+ /** Relative path to .xcworkspace (preferred) or .xcodeproj. */
19
+ projectPath: string;
20
+ /** True if project.pbxproj indicates manual code signing. */
21
+ hasSigningConfig: boolean;
22
+ /** DEVELOPMENT_TEAM value from project.pbxproj, or empty string if not found. */
23
+ developmentTeam: string;
24
+ }
25
+ export declare function scanIosProject(projectRoot: string): Promise<IosScanResult>;
26
+ export declare function formatIosScanResult(result: IosScanResult): string;
27
+ //# sourceMappingURL=ios-scanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ios-scanner.d.ts","sourceRoot":"","sources":["../../../src/commands/ios-scanner.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,kBAAkB,GAAG,cAAc,GAAG,SAAS,GAAG,gBAAgB,GAAG,WAAW,CAAC;AAE7F,MAAM,MAAM,kBAAkB,GAAG,SAAS,GAAG,MAAM,CAAC;AAEpD,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,UAAU,EAAE,CAAC;IACvB,2FAA2F;IAC3F,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,oDAAoD;IACpD,YAAY,EAAE,OAAO,CAAC;IACtB,0DAA0D;IAC1D,MAAM,EAAE,OAAO,CAAC;IAChB,+DAA+D;IAC/D,WAAW,EAAE,MAAM,CAAC;IACpB,6DAA6D;IAC7D,gBAAgB,EAAE,OAAO,CAAC;IAC1B,iFAAiF;IACjF,eAAe,EAAE,MAAM,CAAC;CACzB;AAuND,wBAAsB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAqFhF;AAaD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,CAkDjE"}
@@ -0,0 +1,337 @@
1
+ import { resolve, relative } from "node:path";
2
+ import { existsSync, readFileSync, readdirSync } from "node:fs";
3
+ // ---------------------------------------------------------------------------
4
+ // File discovery
5
+ // ---------------------------------------------------------------------------
6
+ function safeRead(filePath) {
7
+ try {
8
+ return readFileSync(filePath, "utf-8");
9
+ }
10
+ catch {
11
+ return "";
12
+ }
13
+ }
14
+ function relPath(root, filePath) {
15
+ return relative(root, filePath);
16
+ }
17
+ /**
18
+ * Finds the primary Xcode project path.
19
+ * Prefers .xcworkspace over .xcodeproj (CocoaPods projects use workspace).
20
+ * Returns the relative path from root, or empty string if not found.
21
+ */
22
+ function findXcodeProjectPath(root) {
23
+ let entries;
24
+ try {
25
+ entries = readdirSync(root);
26
+ }
27
+ catch {
28
+ return "";
29
+ }
30
+ const workspaces = entries.filter((e) => e.endsWith(".xcworkspace"));
31
+ const projects = entries.filter((e) => e.endsWith(".xcodeproj"));
32
+ // Prefer workspace (CocoaPods / multi-package setups use these)
33
+ if (workspaces.length > 0)
34
+ return workspaces[0];
35
+ if (projects.length > 0)
36
+ return projects[0];
37
+ return "";
38
+ }
39
+ /**
40
+ * Detects Xcode schemes by reading *.xcscheme files from the
41
+ * xcshareddata/xcschemes/ directory inside a .xcodeproj bundle.
42
+ * Falls back to deriving the scheme name from the project file name.
43
+ */
44
+ function detectSchemes(root) {
45
+ const schemes = new Set();
46
+ let entries;
47
+ try {
48
+ entries = readdirSync(root);
49
+ }
50
+ catch {
51
+ return [];
52
+ }
53
+ for (const entry of entries) {
54
+ if (!entry.endsWith(".xcodeproj"))
55
+ continue;
56
+ const schemesDir = resolve(root, entry, "xcshareddata", "xcschemes");
57
+ let schemeFiles;
58
+ try {
59
+ schemeFiles = readdirSync(schemesDir);
60
+ }
61
+ catch {
62
+ // No shared schemes — fall back to project name
63
+ const projectName = entry.replace(/\.xcodeproj$/, "");
64
+ schemes.add(projectName);
65
+ continue;
66
+ }
67
+ for (const sf of schemeFiles) {
68
+ if (sf.endsWith(".xcscheme")) {
69
+ schemes.add(sf.replace(/\.xcscheme$/, ""));
70
+ }
71
+ }
72
+ }
73
+ return Array.from(schemes);
74
+ }
75
+ // ---------------------------------------------------------------------------
76
+ // xcconfig env var detection
77
+ // ---------------------------------------------------------------------------
78
+ /**
79
+ * Recursively finds all *.xcconfig files under root, skipping build/DerivedData/Pods.
80
+ */
81
+ const SKIP_XCCONFIG_DIRS = new Set(["build", "DerivedData", "Pods", ".git", ".ci", "node_modules"]);
82
+ function findXcconfigFiles(dir) {
83
+ const results = [];
84
+ let entries;
85
+ try {
86
+ entries = readdirSync(dir, { withFileTypes: true });
87
+ }
88
+ catch {
89
+ return results;
90
+ }
91
+ for (const entry of entries) {
92
+ if (entry.isDirectory()) {
93
+ if (!SKIP_XCCONFIG_DIRS.has(entry.name)) {
94
+ results.push(...findXcconfigFiles(resolve(dir, entry.name)));
95
+ }
96
+ }
97
+ else if (entry.name.endsWith(".xcconfig")) {
98
+ results.push(resolve(dir, entry.name));
99
+ }
100
+ }
101
+ return results;
102
+ }
103
+ /**
104
+ * Extract environment variable references from xcconfig content.
105
+ * xcconfig uses $(VAR_NAME) syntax.
106
+ */
107
+ function extractXcconfigEnvRefs(content) {
108
+ const results = [];
109
+ // Match $(VAR_NAME) — only uppercase + underscore patterns (likely env vars)
110
+ const re = /\$\(([A-Z][A-Z0-9_]+)\)/g;
111
+ const known = new Set(["SRCROOT", "PROJECT_DIR", "CONFIGURATION", "PRODUCT_NAME", "TARGET_NAME", "BUILT_PRODUCTS_DIR"]);
112
+ let m;
113
+ while ((m = re.exec(content)) !== null) {
114
+ const name = m[1];
115
+ if (!known.has(name)) {
116
+ results.push(name);
117
+ }
118
+ }
119
+ return [...new Set(results)];
120
+ }
121
+ // ---------------------------------------------------------------------------
122
+ // Signing config detection
123
+ // ---------------------------------------------------------------------------
124
+ /**
125
+ * Returns true if project.pbxproj indicates manual (non-automatic) code signing.
126
+ * Automatic signing sets PROVISIONING_PROFILE_SPECIFIER = "" and
127
+ * CODE_SIGN_STYLE = Automatic.
128
+ */
129
+ function detectManualSigning(root) {
130
+ let entries;
131
+ try {
132
+ entries = readdirSync(root);
133
+ }
134
+ catch {
135
+ return false;
136
+ }
137
+ for (const entry of entries) {
138
+ if (!entry.endsWith(".xcodeproj"))
139
+ continue;
140
+ const pbxprojPath = resolve(root, entry, "project.pbxproj");
141
+ const content = safeRead(pbxprojPath);
142
+ if (!content)
143
+ continue;
144
+ // Automatic signing sets CODE_SIGN_STYLE = Automatic
145
+ const isAutomatic = /CODE_SIGN_STYLE\s*=\s*Automatic/.test(content);
146
+ // Manual signing has a non-empty PROVISIONING_PROFILE_SPECIFIER or explicit identity
147
+ const hasProvisioningSpecifier = /PROVISIONING_PROFILE_SPECIFIER\s*=\s*"[^"]+"\s*;/.test(content);
148
+ const hasExplicitIdentity = /CODE_SIGN_IDENTITY\s*=\s*"iPhone (Developer|Distribution)"/.test(content);
149
+ if (!isAutomatic && (hasProvisioningSpecifier || hasExplicitIdentity)) {
150
+ return true;
151
+ }
152
+ }
153
+ return false;
154
+ }
155
+ /**
156
+ * Extracts the DEVELOPMENT_TEAM value from project.pbxproj.
157
+ * Returns the first non-empty team ID found, or empty string.
158
+ */
159
+ function detectDevelopmentTeam(root) {
160
+ let entries;
161
+ try {
162
+ entries = readdirSync(root);
163
+ }
164
+ catch {
165
+ return "";
166
+ }
167
+ for (const entry of entries) {
168
+ if (!entry.endsWith(".xcodeproj"))
169
+ continue;
170
+ const pbxprojPath = resolve(root, entry, "project.pbxproj");
171
+ const content = safeRead(pbxprojPath);
172
+ if (!content)
173
+ continue;
174
+ const match = content.match(/DEVELOPMENT_TEAM\s*=\s*([A-Z0-9]{10})\s*;/);
175
+ if (match)
176
+ return match[1];
177
+ }
178
+ return "";
179
+ }
180
+ // ---------------------------------------------------------------------------
181
+ // Gitignore check
182
+ // ---------------------------------------------------------------------------
183
+ const IOS_RELEVANT_GITIGNORE_PATTERNS = [
184
+ { pattern: /^Pods\/$|^\/Pods\//, label: "Pods/ (CocoaPods dependencies)" },
185
+ { pattern: /\*\.p12|\*\.cer/, label: "certificates (*.p12, *.cer)" },
186
+ { pattern: /\*\.mobileprovision/, label: "provisioning profiles (*.mobileprovision)" },
187
+ { pattern: /\.env$|\*\.env/, label: ".env files" },
188
+ ];
189
+ function checkGitignore(root) {
190
+ const gitignorePath = resolve(root, ".gitignore");
191
+ if (!existsSync(gitignorePath))
192
+ return [];
193
+ const content = safeRead(gitignorePath);
194
+ const lines = content.split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
195
+ const found = [];
196
+ for (const { pattern, label } of IOS_RELEVANT_GITIGNORE_PATTERNS) {
197
+ if (lines.some((l) => pattern.test(l))) {
198
+ found.push(label);
199
+ }
200
+ }
201
+ return found;
202
+ }
203
+ // ---------------------------------------------------------------------------
204
+ // Main scanner
205
+ // ---------------------------------------------------------------------------
206
+ export async function scanIosProject(projectRoot) {
207
+ const warnings = [];
208
+ // 1. Find project path
209
+ const projectPath = findXcodeProjectPath(projectRoot);
210
+ // 2. Detect schemes
211
+ const detectedSchemes = detectSchemes(projectRoot);
212
+ // 3. CocoaPods
213
+ const hasCocoaPods = existsSync(resolve(projectRoot, "Podfile"));
214
+ // 4. SPM
215
+ const hasSPM = existsSync(resolve(projectRoot, "Package.swift"));
216
+ // 5. Signing config + team ID
217
+ const hasSigningConfig = detectManualSigning(projectRoot);
218
+ const developmentTeam = detectDevelopmentTeam(projectRoot);
219
+ // 6. CocoaPods warnings
220
+ const gitignoreItems = checkGitignore(projectRoot);
221
+ const podsGitignored = gitignoreItems.some((i) => i.includes("Pods/"));
222
+ if (hasCocoaPods) {
223
+ if (podsGitignored) {
224
+ warnings.push({
225
+ category: "cocoapods",
226
+ severity: "info",
227
+ message: "Pods/ is gitignored — pod install will run on CI",
228
+ hint: "The generated pipeline includes a pod install step",
229
+ });
230
+ }
231
+ if (!existsSync(resolve(projectRoot, "Podfile.lock"))) {
232
+ warnings.push({
233
+ category: "cocoapods",
234
+ severity: "warning",
235
+ message: "Podfile.lock not found",
236
+ hint: "Run 'pod install' locally and commit Podfile.lock for reproducible builds",
237
+ });
238
+ }
239
+ }
240
+ // 7. Signing warnings
241
+ if (hasSigningConfig) {
242
+ warnings.push({
243
+ category: "signing-config",
244
+ severity: "warning",
245
+ message: "Manual code signing detected in project.pbxproj",
246
+ hint: "Provide CERTIFICATE_P12, CERTIFICATE_PASSWORD, and PROVISIONING_PROFILE as secrets",
247
+ });
248
+ }
249
+ // 8. xcconfig env var warnings
250
+ const seenEnvVars = new Set();
251
+ const xcconfigFiles = findXcconfigFiles(projectRoot);
252
+ for (const xcconfigPath of xcconfigFiles) {
253
+ const content = safeRead(xcconfigPath);
254
+ const rel = relPath(projectRoot, xcconfigPath);
255
+ for (const varName of extractXcconfigEnvRefs(content)) {
256
+ if (!seenEnvVars.has(varName)) {
257
+ seenEnvVars.add(varName);
258
+ warnings.push({
259
+ category: "env-var",
260
+ severity: "warning",
261
+ message: `Environment variable referenced: ${varName}`,
262
+ hint: `Add via: ci secrets add ${varName}`,
263
+ location: rel,
264
+ });
265
+ }
266
+ }
267
+ }
268
+ // 9. Gitignore cross-check for certs / profiles
269
+ for (const item of gitignoreItems) {
270
+ if (item.includes("certificate") || item.includes("provisioning")) {
271
+ warnings.push({
272
+ category: "missing-file",
273
+ severity: "info",
274
+ message: `${item} is in .gitignore — likely absent in CI`,
275
+ hint: "Provide as secrets (CERTIFICATE_P12, PROVISIONING_PROFILE)",
276
+ });
277
+ }
278
+ }
279
+ return { warnings, detectedSchemes, hasCocoaPods, hasSPM, projectPath, hasSigningConfig, developmentTeam };
280
+ }
281
+ // ---------------------------------------------------------------------------
282
+ // Formatter
283
+ // ---------------------------------------------------------------------------
284
+ const CATEGORY_LABELS = {
285
+ "missing-file": "Missing files",
286
+ "env-var": "Environment variables referenced in xcconfig files",
287
+ "signing-config": "Code signing configuration",
288
+ "cocoapods": "CocoaPods",
289
+ };
290
+ export function formatIosScanResult(result) {
291
+ const lines = [];
292
+ const sep = "─".repeat(50);
293
+ if (result.detectedSchemes.length > 0) {
294
+ lines.push(`ℹ Detected schemes: ${result.detectedSchemes.join(", ")}`);
295
+ lines.push("");
296
+ }
297
+ if (result.hasSPM) {
298
+ lines.push("ℹ Swift Package Manager detected — dependencies resolved automatically by Xcode");
299
+ lines.push("");
300
+ }
301
+ if (result.warnings.length === 0) {
302
+ lines.push("✅ No potential unknowns detected.");
303
+ return lines.join("\n") + "\n";
304
+ }
305
+ lines.push("⚠ iOS Project Scan — Potential Unknowns");
306
+ lines.push(sep);
307
+ lines.push("");
308
+ const byCategory = new Map();
309
+ for (const w of result.warnings) {
310
+ if (!byCategory.has(w.category))
311
+ byCategory.set(w.category, []);
312
+ byCategory.get(w.category).push(w);
313
+ }
314
+ for (const [cat, items] of byCategory) {
315
+ lines.push(`${CATEGORY_LABELS[cat]}:`);
316
+ for (const w of items) {
317
+ const icon = w.severity === "warning" ? "⚠ " : "ℹ ";
318
+ const loc = w.location ? ` (${w.location})` : "";
319
+ lines.push(` ${icon} ${w.message}${loc}`);
320
+ if (w.hint) {
321
+ lines.push(` Hint: ${w.hint}`);
322
+ }
323
+ }
324
+ lines.push("");
325
+ }
326
+ lines.push(sep);
327
+ const warnCount = result.warnings.filter((w) => w.severity === "warning").length;
328
+ const infoCount = result.warnings.filter((w) => w.severity === "info").length;
329
+ const parts = [];
330
+ if (warnCount > 0)
331
+ parts.push(`${warnCount} warning(s)`);
332
+ if (infoCount > 0)
333
+ parts.push(`${infoCount} info`);
334
+ lines.push(`${parts.join(", ")} found. Review before running on CI.`);
335
+ return lines.join("\n");
336
+ }
337
+ //# sourceMappingURL=ios-scanner.js.map
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Reset command — removes all files and folders created by cibuild.
3
+ */
4
+ export declare function handleResetCommand(options?: {
5
+ force?: boolean;
6
+ }): Promise<void>;
7
+ //# sourceMappingURL=reset.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reset.d.ts","sourceRoot":"","sources":["../../../src/commands/reset.ts"],"names":[],"mappings":"AAAA;;GAEG;AAsBH,wBAAsB,kBAAkB,CAAC,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAsDzF"}