@invarn/cibuild 1.4.1 → 1.4.3

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 (33) hide show
  1. package/dist/cli.cjs +1 -1
  2. package/dist/src/cli.d.ts.map +1 -1
  3. package/dist/src/cli.js +56 -678
  4. package/dist/src/commands/detect-platform.d.ts +13 -0
  5. package/dist/src/commands/detect-platform.d.ts.map +1 -0
  6. package/dist/src/commands/detect-platform.js +51 -0
  7. package/dist/src/commands/detect-project.d.ts +7 -0
  8. package/dist/src/commands/detect-project.d.ts.map +1 -0
  9. package/dist/src/commands/detect-project.js +12 -0
  10. package/dist/src/commands/index.d.ts +26 -0
  11. package/dist/src/commands/index.d.ts.map +1 -0
  12. package/dist/src/commands/index.js +22 -0
  13. package/dist/src/commands/init.d.ts +13 -0
  14. package/dist/src/commands/init.d.ts.map +1 -0
  15. package/dist/src/commands/init.js +262 -0
  16. package/dist/src/commands/run.d.ts +22 -0
  17. package/dist/src/commands/run.d.ts.map +1 -0
  18. package/dist/src/commands/run.js +131 -0
  19. package/dist/src/commands/validate.d.ts +10 -0
  20. package/dist/src/commands/validate.d.ts.map +1 -0
  21. package/dist/src/commands/validate.js +46 -0
  22. package/dist/src/shared/detect-project.d.ts +11 -0
  23. package/dist/src/shared/detect-project.d.ts.map +1 -0
  24. package/dist/src/shared/detect-project.js +53 -0
  25. package/dist/src/shared/gitignore.d.ts +6 -0
  26. package/dist/src/shared/gitignore.d.ts.map +1 -0
  27. package/dist/src/shared/gitignore.js +26 -0
  28. package/dist/src/shared/prompts.d.ts +18 -0
  29. package/dist/src/shared/prompts.d.ts.map +1 -0
  30. package/dist/src/shared/prompts.js +96 -0
  31. package/dist/src/yaml/steps/cache.d.ts.map +1 -1
  32. package/dist/src/yaml/steps/cache.js +24 -10
  33. package/package.json +7 -3
@@ -0,0 +1,53 @@
1
+ import { existsSync, readdirSync, statSync } from "node:fs";
2
+ import { resolve } from "node:path";
3
+ /**
4
+ * Detects whether the given directory is the root of an Android, iOS, or
5
+ * KMM project. Returns the detected project type, or null if none match.
6
+ *
7
+ * KMM is checked before Android because both have Gradle files; KMM is
8
+ * distinguished by the presence of an `iosApp/`, `shared/`, or
9
+ * `composeApp/` directory alongside the Gradle files.
10
+ */
11
+ export function detectMobileProjectRoot(dir) {
12
+ const androidIndicators = [
13
+ "build.gradle",
14
+ "build.gradle.kts",
15
+ "settings.gradle",
16
+ "settings.gradle.kts",
17
+ "gradlew",
18
+ ];
19
+ const hasAndroidIndicator = androidIndicators.some((f) => existsSync(resolve(dir, f)));
20
+ if (hasAndroidIndicator) {
21
+ const kmmIndicators = ["iosApp", "shared", "composeApp"];
22
+ const hasKmmIndicator = kmmIndicators.some((d) => {
23
+ const fullPath = resolve(dir, d);
24
+ try {
25
+ return existsSync(fullPath) && statSync(fullPath).isDirectory();
26
+ }
27
+ catch {
28
+ return false;
29
+ }
30
+ });
31
+ if (hasKmmIndicator)
32
+ return "kmm";
33
+ return "android";
34
+ }
35
+ const iosFileIndicators = ["Podfile"];
36
+ const hasIosFile = iosFileIndicators.some((f) => existsSync(resolve(dir, f)));
37
+ if (!hasIosFile) {
38
+ try {
39
+ const entries = readdirSync(dir);
40
+ const hasXcodeDir = entries.some((e) => e.endsWith(".xcodeproj") || e.endsWith(".xcworkspace"));
41
+ if (hasXcodeDir)
42
+ return "ios";
43
+ }
44
+ catch {
45
+ // Unreadable directory — fall through.
46
+ }
47
+ }
48
+ else {
49
+ return "ios";
50
+ }
51
+ return null;
52
+ }
53
+ //# sourceMappingURL=detect-project.js.map
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Ensures CI Build runtime files are listed in .gitignore. Safe to call
3
+ * repeatedly — only appends entries that are missing.
4
+ */
5
+ export declare function ensureCiBuildGitignoreEntries(cwd: string): void;
6
+ //# sourceMappingURL=gitignore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gitignore.d.ts","sourceRoot":"","sources":["../../../src/shared/gitignore.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,wBAAgB,6BAA6B,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAiB/D"}
@@ -0,0 +1,26 @@
1
+ import { appendFileSync, existsSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { resolve } from "node:path";
3
+ /**
4
+ * Ensures CI Build runtime files are listed in .gitignore. Safe to call
5
+ * repeatedly — only appends entries that are missing.
6
+ */
7
+ export function ensureCiBuildGitignoreEntries(cwd) {
8
+ const gitignorePath = resolve(cwd, ".gitignore");
9
+ const gitignoreEntries = [".cibuild-secrets.json", ".ci/.envstore.json", ".ci/keys/", "build/"];
10
+ if (existsSync(gitignorePath)) {
11
+ const contents = readFileSync(gitignorePath, "utf-8");
12
+ const lines = contents.split("\n").map((l) => l.trim());
13
+ const toAdd = gitignoreEntries.filter((e) => !lines.includes(e));
14
+ if (toAdd.length > 0) {
15
+ appendFileSync(gitignorePath, `\n${toAdd.join("\n")}\n`);
16
+ for (const entry of toAdd) {
17
+ console.log(`✅ Added ${entry} to .gitignore`);
18
+ }
19
+ }
20
+ }
21
+ else {
22
+ writeFileSync(gitignorePath, `${gitignoreEntries.join("\n")}\n`);
23
+ console.log(`✅ Created .gitignore with CI Build entries`);
24
+ }
25
+ }
26
+ //# sourceMappingURL=gitignore.js.map
@@ -0,0 +1,18 @@
1
+ import type { YAMLPipeline } from "../yaml/types.js";
2
+ import type { CIConfig } from "../types.js";
3
+ /**
4
+ * Shows an interactive workflow picker. If exactly one workflow exists,
5
+ * returns it without prompting. Returns `undefined` when the user cancels
6
+ * or no workflows are defined.
7
+ */
8
+ export declare function promptForWorkflow(workflows: string[]): Promise<string | undefined>;
9
+ /**
10
+ * Runs pre-execution validation, separates issues into user-fillable
11
+ * (missing env vars) vs hard-blocking, and collects all missing values
12
+ * upfront in a single form-like pass before execution begins.
13
+ *
14
+ * @returns true if it's safe to proceed, false if the user cancelled or
15
+ * hard errors exist.
16
+ */
17
+ export declare function promptForMissingVariables(yamlPipeline: YAMLPipeline, workflowName: string, config: CIConfig, yamlFilePath: string): Promise<boolean>;
18
+ //# sourceMappingURL=prompts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../../src/shared/prompts.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C;;;;GAIG;AACH,wBAAsB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CA0BxF;AAED;;;;;;;GAOG;AACH,wBAAsB,yBAAyB,CAC7C,YAAY,EAAE,YAAY,EAC1B,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,QAAQ,EAChB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,OAAO,CAAC,CAgFlB"}
@@ -0,0 +1,96 @@
1
+ import prompts from "prompts";
2
+ import { StepValidator, formatValidationResult } from "../yaml/step-validator.js";
3
+ import { MissingEnvHandler } from "../yaml/missing-env-handler.js";
4
+ import { MissingEnvironmentVariableError } from "../yaml/env-resolver.js";
5
+ /**
6
+ * Shows an interactive workflow picker. If exactly one workflow exists,
7
+ * returns it without prompting. Returns `undefined` when the user cancels
8
+ * or no workflows are defined.
9
+ */
10
+ export async function promptForWorkflow(workflows) {
11
+ if (workflows.length === 0) {
12
+ console.error("Error: No workflows found in pipeline file");
13
+ return undefined;
14
+ }
15
+ if (workflows.length === 1) {
16
+ console.log(`Using workflow: ${workflows[0]}\n`);
17
+ return workflows[0];
18
+ }
19
+ const response = await prompts({
20
+ type: "select",
21
+ name: "workflow",
22
+ message: "Select a workflow to run:",
23
+ choices: workflows.map((name) => ({ title: name, value: name })),
24
+ initial: 0,
25
+ });
26
+ if (!response.workflow) {
27
+ console.log("\nWorkflow selection cancelled");
28
+ return undefined;
29
+ }
30
+ console.log();
31
+ return response.workflow;
32
+ }
33
+ /**
34
+ * Runs pre-execution validation, separates issues into user-fillable
35
+ * (missing env vars) vs hard-blocking, and collects all missing values
36
+ * upfront in a single form-like pass before execution begins.
37
+ *
38
+ * @returns true if it's safe to proceed, false if the user cancelled or
39
+ * hard errors exist.
40
+ */
41
+ export async function promptForMissingVariables(yamlPipeline, workflowName, config, yamlFilePath) {
42
+ console.log(`\n🔍 Running pre-execution validation...`);
43
+ const validator = new StepValidator(yamlPipeline, workflowName, config, yamlFilePath);
44
+ const result = await validator.validateWorkflow();
45
+ const errorIssues = result.issues.filter((i) => i.requirement.severity === "error" && i.result && !i.result.passed);
46
+ const fillable = errorIssues.filter((i) => i.requirement.timing === "pre-execution" &&
47
+ (i.requirement.category === "environment" || i.requirement.category === "input"));
48
+ const blocking = errorIssues.filter((i) => !(i.requirement.timing === "pre-execution" &&
49
+ (i.requirement.category === "environment" || i.requirement.category === "input")));
50
+ if (blocking.length > 0) {
51
+ console.log(formatValidationResult(result));
52
+ return false;
53
+ }
54
+ if (fillable.length === 0) {
55
+ if (result.counts.warnings > 0 || result.counts.info > 0) {
56
+ console.log(formatValidationResult(result));
57
+ }
58
+ else {
59
+ console.log("✅ Pre-execution validation passed\n");
60
+ }
61
+ return true;
62
+ }
63
+ console.log(`\n${fillable.length} required value(s) missing — provide them to continue:\n`);
64
+ for (const issue of fillable) {
65
+ const stepInfo = issue.stepName ? ` needed by: ${issue.stepName}` : "";
66
+ console.log(` • ${issue.requirement.name.padEnd(30)}${stepInfo}`);
67
+ }
68
+ console.log();
69
+ const handler = new MissingEnvHandler({
70
+ interactive: true,
71
+ workflow: workflowName,
72
+ });
73
+ for (let i = 0; i < fillable.length; i++) {
74
+ const issue = fillable[i];
75
+ const error = new MissingEnvironmentVariableError(issue.requirement.name, issue.stepName, issue.requirement.hint);
76
+ const original = console.log;
77
+ const label = `(${i + 1} of ${fillable.length})`;
78
+ let patched = false;
79
+ console.log = (...args) => {
80
+ if (!patched && typeof args[0] === "string" && args[0].includes("MISSING REQUIRED")) {
81
+ original(`║ MISSING REQUIRED ENVIRONMENT VARIABLE ${label.padEnd(28)}║`);
82
+ patched = true;
83
+ return;
84
+ }
85
+ original(...args);
86
+ };
87
+ const handleResult = await handler.handleMissingVariable(error);
88
+ console.log = original;
89
+ if (handleResult.cancelled) {
90
+ return false;
91
+ }
92
+ }
93
+ handler.close();
94
+ return true;
95
+ }
96
+ //# sourceMappingURL=prompts.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../../../src/yaml/steps/cache.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAExD;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,yGAAyG;IACzG,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAUrD,CAAC;AAoBF;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,qBAAqB,CAAC,EAAE,OAAO,CAAC;CACjC;AAED;;;GAGG;AACH,qBAAa,qBAAsB,SAAQ,gBAAgB;IACnD,OAAO,CAAC,MAAM,EAAE,eAAe,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;YAoGzF,iBAAiB;CA2FhC;AAED;;;GAGG;AACH,qBAAa,qBAAsB,SAAQ,gBAAgB;IACnD,OAAO,CAAC,MAAM,EAAE,eAAe,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;YAwJzF,iBAAiB;CA6FhC"}
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../../../src/yaml/steps/cache.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAExD;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,yGAAyG;IACzG,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAUrD,CAAC;AAoBF;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,qBAAqB,CAAC,EAAE,OAAO,CAAC;CACjC;AAED;;;GAGG;AACH,qBAAa,qBAAsB,SAAQ,gBAAgB;IACnD,OAAO,CAAC,MAAM,EAAE,eAAe,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;YAoGzF,iBAAiB;CAoGhC;AAED;;;GAGG;AACH,qBAAa,qBAAsB,SAAQ,gBAAgB;IACnD,OAAO,CAAC,MAAM,EAAE,eAAe,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;YAwJzF,iBAAiB;CAoGhC"}
@@ -131,14 +131,21 @@ export class CachePullStepExecutor extends BaseStepExecutor {
131
131
  commands.push(`CACHE_DIR="${this.escapeBash(config.paths.cacheDir)}"`);
132
132
  commands.push('mkdir -p "$CACHE_DIR"');
133
133
  commands.push('');
134
+ // Helper: resolve lockfile path — checks exact path first, then searches
135
+ // recursively (handles SPM Package.resolved inside .xcodeproj/.xcworkspace)
136
+ commands.push('__ci_find_lockfile() {');
137
+ commands.push(' if [ -f "$1" ]; then echo "$1"; return; fi');
138
+ commands.push(' find . -name "$(basename "$1")" -not -path "*/DerivedData/*" -not -path "*/.build/*" 2>/dev/null | head -1');
139
+ commands.push('}');
140
+ commands.push('');
134
141
  if (chain.length === 1) {
135
142
  const preset = chain[0];
136
- commands.push(`LOCKFILE="${this.escapeBash(preset.lockfile)}"`);
137
- commands.push('if [ -f "$LOCKFILE" ]; then');
143
+ commands.push(`LOCKFILE=$(__ci_find_lockfile "${this.escapeBash(preset.lockfile)}")`);
144
+ commands.push('if [ -n "$LOCKFILE" ] && [ -f "$LOCKFILE" ]; then');
138
145
  commands.push(` CHECKSUM=$(shasum -a 256 "$LOCKFILE" | cut -d ' ' -f1 | head -c 16)`);
139
146
  commands.push(` CACHE_KEY="${this.escapeBash(preset.keyPrefix)}-\${CHECKSUM}"`);
140
147
  commands.push('else');
141
- commands.push(` echo "Warning: $LOCKFILE not found, using fallback cache key"`);
148
+ commands.push(` echo "Warning: ${this.escapeBash(preset.lockfile)} not found, using fallback cache key"`);
142
149
  commands.push(` CACHE_KEY="${this.escapeBash(preset.keyPrefix)}-no-lockfile"`);
143
150
  commands.push('fi');
144
151
  }
@@ -147,8 +154,9 @@ export class CachePullStepExecutor extends BaseStepExecutor {
147
154
  for (let i = 0; i < chain.length; i++) {
148
155
  const preset = chain[i];
149
156
  const cond = i === 0 ? 'if' : 'elif';
150
- commands.push(`${cond} [ -f "${this.escapeBash(preset.lockfile)}" ]; then`);
151
- commands.push(` LOCKFILE="${this.escapeBash(preset.lockfile)}"`);
157
+ commands.push(`__ci_lockfile_candidate=$(__ci_find_lockfile "${this.escapeBash(preset.lockfile)}")`);
158
+ commands.push(`${cond} [ -n "$__ci_lockfile_candidate" ] && [ -f "$__ci_lockfile_candidate" ]; then`);
159
+ commands.push(' LOCKFILE="$__ci_lockfile_candidate"');
152
160
  commands.push(` CHECKSUM=$(shasum -a 256 "$LOCKFILE" | cut -d ' ' -f1 | head -c 16)`);
153
161
  commands.push(` CACHE_KEY="${this.escapeBash(preset.keyPrefix)}-\${CHECKSUM}"`);
154
162
  if (isDebugMode) {
@@ -341,14 +349,19 @@ export class CachePushStepExecutor extends BaseStepExecutor {
341
349
  commands.push(`CACHE_DIR="${this.escapeBash(config.paths.cacheDir)}"`);
342
350
  commands.push('mkdir -p "$CACHE_DIR"');
343
351
  commands.push('');
352
+ commands.push('__ci_find_lockfile() {');
353
+ commands.push(' if [ -f "$1" ]; then echo "$1"; return; fi');
354
+ commands.push(' find . -name "$(basename "$1")" -not -path "*/DerivedData/*" -not -path "*/.build/*" 2>/dev/null | head -1');
355
+ commands.push('}');
356
+ commands.push('');
344
357
  if (chain.length === 1) {
345
358
  const preset = chain[0];
346
- commands.push(`LOCKFILE="${this.escapeBash(preset.lockfile)}"`);
347
- commands.push('if [ -f "$LOCKFILE" ]; then');
359
+ commands.push(`LOCKFILE=$(__ci_find_lockfile "${this.escapeBash(preset.lockfile)}")`);
360
+ commands.push('if [ -n "$LOCKFILE" ] && [ -f "$LOCKFILE" ]; then');
348
361
  commands.push(` CHECKSUM=$(shasum -a 256 "$LOCKFILE" | cut -d ' ' -f1 | head -c 16)`);
349
362
  commands.push(` CACHE_KEY="${this.escapeBash(preset.keyPrefix)}-\${CHECKSUM}"`);
350
363
  commands.push('else');
351
- commands.push(` echo "Warning: $LOCKFILE not found, using fallback cache key"`);
364
+ commands.push(` echo "Warning: ${this.escapeBash(preset.lockfile)} not found, using fallback cache key"`);
352
365
  commands.push(` CACHE_KEY="${this.escapeBash(preset.keyPrefix)}-no-lockfile"`);
353
366
  commands.push('fi');
354
367
  }
@@ -356,8 +369,9 @@ export class CachePushStepExecutor extends BaseStepExecutor {
356
369
  for (let i = 0; i < chain.length; i++) {
357
370
  const preset = chain[i];
358
371
  const cond = i === 0 ? 'if' : 'elif';
359
- commands.push(`${cond} [ -f "${this.escapeBash(preset.lockfile)}" ]; then`);
360
- commands.push(` LOCKFILE="${this.escapeBash(preset.lockfile)}"`);
372
+ commands.push(`__ci_lockfile_candidate=$(__ci_find_lockfile "${this.escapeBash(preset.lockfile)}")`);
373
+ commands.push(`${cond} [ -n "$__ci_lockfile_candidate" ] && [ -f "$__ci_lockfile_candidate" ]; then`);
374
+ commands.push(' LOCKFILE="$__ci_lockfile_candidate"');
361
375
  commands.push(` CHECKSUM=$(shasum -a 256 "$LOCKFILE" | cut -d ' ' -f1 | head -c 16)`);
362
376
  commands.push(` CACHE_KEY="${this.escapeBash(preset.keyPrefix)}-\${CHECKSUM}"`);
363
377
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@invarn/cibuild",
3
- "version": "1.4.1",
3
+ "version": "1.4.3",
4
4
  "description": "CI Build CLI — local pipeline orchestration and validation",
5
5
  "type": "module",
6
6
  "main": "dist/cli.cjs",
@@ -9,6 +9,10 @@
9
9
  "./lib": {
10
10
  "import": "./dist/src/lib.js",
11
11
  "types": "./dist/src/lib.d.ts"
12
+ },
13
+ "./commands": {
14
+ "import": "./dist/src/commands/index.js",
15
+ "types": "./dist/src/commands/index.d.ts"
12
16
  }
13
17
  },
14
18
  "bin": {
@@ -48,7 +52,8 @@
48
52
  },
49
53
  "homepage": "https://github.com/invarnhq/cibuild",
50
54
  "dependencies": {
51
- "js-yaml": "^4.1.0"
55
+ "js-yaml": "^4.1.0",
56
+ "prompts": "^2.4.2"
52
57
  },
53
58
  "devDependencies": {
54
59
  "@types/jest": "^29.5.14",
@@ -59,7 +64,6 @@
59
64
  "esbuild": "^0.27.3",
60
65
  "javascript-obfuscator": "^5.3.0",
61
66
  "jest": "^29.7.0",
62
- "prompts": "^2.4.2",
63
67
  "ts-jest": "^29.4.6",
64
68
  "typescript": "^5.7.2"
65
69
  }