@planu/cli 0.97.1 → 0.98.0

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 (139) hide show
  1. package/dist/cli/commands/install.d.ts.map +1 -1
  2. package/dist/cli/commands/install.js +1 -1
  3. package/dist/cli/commands/install.js.map +1 -1
  4. package/dist/config/license-plans.json +6 -2
  5. package/dist/config/mobile-ci-templates/android-github-actions.yml +149 -0
  6. package/dist/config/mobile-ci-templates/ios-github-actions.yml +120 -0
  7. package/dist/engine/api-validation/graphql-schema-validator.d.ts +3 -0
  8. package/dist/engine/api-validation/graphql-schema-validator.d.ts.map +1 -0
  9. package/dist/engine/api-validation/graphql-schema-validator.js +134 -0
  10. package/dist/engine/api-validation/graphql-schema-validator.js.map +1 -0
  11. package/dist/engine/api-validation/index.d.ts +3 -0
  12. package/dist/engine/api-validation/index.d.ts.map +1 -0
  13. package/dist/engine/api-validation/index.js +4 -0
  14. package/dist/engine/api-validation/index.js.map +1 -0
  15. package/dist/engine/api-validation/openapi-impl-validator.d.ts +3 -0
  16. package/dist/engine/api-validation/openapi-impl-validator.d.ts.map +1 -0
  17. package/dist/engine/api-validation/openapi-impl-validator.js +205 -0
  18. package/dist/engine/api-validation/openapi-impl-validator.js.map +1 -0
  19. package/dist/engine/ci-generator/android-jobs.d.ts +17 -0
  20. package/dist/engine/ci-generator/android-jobs.d.ts.map +1 -0
  21. package/dist/engine/ci-generator/android-jobs.js +168 -0
  22. package/dist/engine/ci-generator/android-jobs.js.map +1 -0
  23. package/dist/engine/ci-generator/ios-jobs.d.ts +17 -0
  24. package/dist/engine/ci-generator/ios-jobs.d.ts.map +1 -0
  25. package/dist/engine/ci-generator/ios-jobs.js +151 -0
  26. package/dist/engine/ci-generator/ios-jobs.js.map +1 -0
  27. package/dist/engine/ci-generator/yaml-builder.d.ts +10 -1
  28. package/dist/engine/ci-generator/yaml-builder.d.ts.map +1 -1
  29. package/dist/engine/ci-generator/yaml-builder.js +46 -1
  30. package/dist/engine/ci-generator/yaml-builder.js.map +1 -1
  31. package/dist/engine/compliance-checker.js +3 -0
  32. package/dist/engine/compliance-checker.js.map +1 -1
  33. package/dist/engine/coverage-gap-analyzer.d.ts +6 -0
  34. package/dist/engine/coverage-gap-analyzer.d.ts.map +1 -0
  35. package/dist/engine/coverage-gap-analyzer.js +177 -0
  36. package/dist/engine/coverage-gap-analyzer.js.map +1 -0
  37. package/dist/engine/dashboard/templates-kanban.d.ts.map +1 -1
  38. package/dist/engine/dashboard/templates-kanban.js +22 -0
  39. package/dist/engine/dashboard/templates-kanban.js.map +1 -1
  40. package/dist/engine/dashboard/templates-layout.d.ts.map +1 -1
  41. package/dist/engine/dashboard/templates-layout.js +59 -7
  42. package/dist/engine/dashboard/templates-layout.js.map +1 -1
  43. package/dist/engine/doc-generator/portal/portal-regenerator.d.ts.map +1 -1
  44. package/dist/engine/doc-generator/portal/portal-regenerator.js +7 -17
  45. package/dist/engine/doc-generator/portal/portal-regenerator.js.map +1 -1
  46. package/dist/engine/hooks/event-bus.d.ts +5 -0
  47. package/dist/engine/hooks/event-bus.d.ts.map +1 -1
  48. package/dist/engine/hooks/event-bus.js +14 -1
  49. package/dist/engine/hooks/event-bus.js.map +1 -1
  50. package/dist/engine/hooks/hook-engine.d.ts.map +1 -1
  51. package/dist/engine/hooks/hook-engine.js +1 -0
  52. package/dist/engine/hooks/hook-engine.js.map +1 -1
  53. package/dist/engine/hooks-reconciler.d.ts.map +1 -1
  54. package/dist/engine/hooks-reconciler.js +24 -35
  55. package/dist/engine/hooks-reconciler.js.map +1 -1
  56. package/dist/engine/jira-exporter.d.ts.map +1 -1
  57. package/dist/engine/jira-exporter.js +1 -0
  58. package/dist/engine/jira-exporter.js.map +1 -1
  59. package/dist/engine/mutation-config-generator.d.ts +6 -0
  60. package/dist/engine/mutation-config-generator.d.ts.map +1 -0
  61. package/dist/engine/mutation-config-generator.js +111 -0
  62. package/dist/engine/mutation-config-generator.js.map +1 -0
  63. package/dist/engine/skill-evaluator.d.ts.map +1 -1
  64. package/dist/engine/skill-evaluator.js +18 -0
  65. package/dist/engine/skill-evaluator.js.map +1 -1
  66. package/dist/engine/spec-quality-scorer.d.ts.map +1 -1
  67. package/dist/engine/spec-quality-scorer.js +10 -2
  68. package/dist/engine/spec-quality-scorer.js.map +1 -1
  69. package/dist/engine/tdd-scaffold-generator.d.ts +7 -0
  70. package/dist/engine/tdd-scaffold-generator.d.ts.map +1 -0
  71. package/dist/engine/tdd-scaffold-generator.js +252 -0
  72. package/dist/engine/tdd-scaffold-generator.js.map +1 -0
  73. package/dist/engine/token-optimizer/response-cache.d.ts.map +1 -1
  74. package/dist/engine/token-optimizer/response-cache.js +7 -2
  75. package/dist/engine/token-optimizer/response-cache.js.map +1 -1
  76. package/dist/engine/version-resolver.d.ts +10 -0
  77. package/dist/engine/version-resolver.d.ts.map +1 -0
  78. package/dist/engine/version-resolver.js +144 -0
  79. package/dist/engine/version-resolver.js.map +1 -0
  80. package/dist/engine/web-fetcher/stack-advisor.d.ts.map +1 -1
  81. package/dist/engine/web-fetcher/stack-advisor.js +32 -4
  82. package/dist/engine/web-fetcher/stack-advisor.js.map +1 -1
  83. package/dist/engine/webhook/server.d.ts.map +1 -1
  84. package/dist/engine/webhook/server.js +3 -0
  85. package/dist/engine/webhook/server.js.map +1 -1
  86. package/dist/index.js +7 -11
  87. package/dist/index.js.map +1 -1
  88. package/dist/storage/base-store.d.ts.map +1 -1
  89. package/dist/storage/base-store.js +2 -1
  90. package/dist/storage/base-store.js.map +1 -1
  91. package/dist/tools/checkpoint-handler.d.ts.map +1 -1
  92. package/dist/tools/checkpoint-handler.js +24 -1
  93. package/dist/tools/checkpoint-handler.js.map +1 -1
  94. package/dist/tools/dashboard.d.ts.map +1 -1
  95. package/dist/tools/dashboard.js +2 -0
  96. package/dist/tools/dashboard.js.map +1 -1
  97. package/dist/tools/register-spec-322-tools.d.ts +3 -0
  98. package/dist/tools/register-spec-322-tools.d.ts.map +1 -0
  99. package/dist/tools/register-spec-322-tools.js +41 -0
  100. package/dist/tools/register-spec-322-tools.js.map +1 -0
  101. package/dist/tools/register-spec-323-tools.d.ts +3 -0
  102. package/dist/tools/register-spec-323-tools.d.ts.map +1 -0
  103. package/dist/tools/register-spec-323-tools.js +57 -0
  104. package/dist/tools/register-spec-323-tools.js.map +1 -0
  105. package/dist/tools/resolve-project-id.d.ts.map +1 -1
  106. package/dist/tools/resolve-project-id.js +6 -1
  107. package/dist/tools/resolve-project-id.js.map +1 -1
  108. package/dist/tools/tdd-scaffold-handler.d.ts +5 -0
  109. package/dist/tools/tdd-scaffold-handler.d.ts.map +1 -0
  110. package/dist/tools/tdd-scaffold-handler.js +92 -0
  111. package/dist/tools/tdd-scaffold-handler.js.map +1 -0
  112. package/dist/tools/update-status/index.d.ts.map +1 -1
  113. package/dist/tools/update-status/index.js +8 -2
  114. package/dist/tools/update-status/index.js.map +1 -1
  115. package/dist/tools/validate-api-contract-handler.d.ts +3 -0
  116. package/dist/tools/validate-api-contract-handler.d.ts.map +1 -0
  117. package/dist/tools/validate-api-contract-handler.js +74 -0
  118. package/dist/tools/validate-api-contract-handler.js.map +1 -0
  119. package/dist/tools/validate.d.ts.map +1 -1
  120. package/dist/tools/validate.js +22 -2
  121. package/dist/tools/validate.js.map +1 -1
  122. package/dist/types/api-contract.d.ts +58 -0
  123. package/dist/types/api-contract.d.ts.map +1 -1
  124. package/dist/types/ci.d.ts +8 -0
  125. package/dist/types/ci.d.ts.map +1 -1
  126. package/dist/types/index.d.ts +1 -0
  127. package/dist/types/index.d.ts.map +1 -1
  128. package/dist/types/index.js +1 -0
  129. package/dist/types/index.js.map +1 -1
  130. package/dist/types/testing.d.ts +60 -0
  131. package/dist/types/testing.d.ts.map +1 -1
  132. package/dist/types/version-resolution.d.ts +23 -0
  133. package/dist/types/version-resolution.d.ts.map +1 -0
  134. package/dist/types/version-resolution.js +3 -0
  135. package/dist/types/version-resolution.js.map +1 -0
  136. package/package.json +1 -1
  137. package/src/config/license-plans.json +6 -2
  138. package/src/config/mobile-ci-templates/android-github-actions.yml +149 -0
  139. package/src/config/mobile-ci-templates/ios-github-actions.yml +120 -0
@@ -0,0 +1,205 @@
1
+ // engine/api-validation/openapi-impl-validator.ts — Validate OpenAPI contract vs implementation (SPEC-322)
2
+ import { readFile } from 'node:fs/promises';
3
+ import { glob } from 'glob';
4
+ // ---------------------------------------------------------------------------
5
+ // Route pattern detectors
6
+ // ---------------------------------------------------------------------------
7
+ const ROUTE_PATTERNS = [
8
+ // Express: app.get('/path', ...) or router.post('/path')
9
+ {
10
+ regex: /(?:app|router)\.(get|post|put|patch|delete|head|options)\s*\(\s*['"`]([^'"`]+)['"`]/g,
11
+ framework: 'express',
12
+ },
13
+ // Fastify: fastify.get('/path')
14
+ {
15
+ regex: /fastify\.(get|post|put|patch|delete|head|options)\s*\(\s*['"`]([^'"`]+)['"`]/g,
16
+ framework: 'fastify',
17
+ },
18
+ // Next.js API routes: export async function GET/POST/PUT/DELETE
19
+ {
20
+ regex: /export\s+(?:async\s+)?function\s+(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)\s*\(/g,
21
+ framework: 'nextjs',
22
+ },
23
+ // FastAPI: @router.get('/path') or @app.get('/path')
24
+ {
25
+ regex: /@(?:router|app)\.(get|post|put|patch|delete|head|options)\s*\(\s*['"`]([^'"`]+)['"`]/g,
26
+ framework: 'fastapi',
27
+ },
28
+ ];
29
+ // ---------------------------------------------------------------------------
30
+ // Helpers
31
+ // ---------------------------------------------------------------------------
32
+ function normalizeMethod(m) {
33
+ return m.toUpperCase();
34
+ }
35
+ function normalizePath(p) {
36
+ // Convert :param → {param} for comparison with OpenAPI style
37
+ return p.replace(/:([a-zA-Z_][a-zA-Z0-9_]*)/g, '{$1}');
38
+ }
39
+ function pathsMatch(contractPath, implPath) {
40
+ const norm = normalizePath(implPath);
41
+ if (contractPath === norm || contractPath === implPath) {
42
+ return true;
43
+ }
44
+ const contractParts = contractPath.split('/');
45
+ const implParts = norm.split('/');
46
+ if (contractParts.length !== implParts.length) {
47
+ return false;
48
+ }
49
+ return contractParts.every((part, i) => {
50
+ if (part.startsWith('{') && part.endsWith('}')) {
51
+ return true;
52
+ }
53
+ return part === implParts[i];
54
+ });
55
+ }
56
+ async function scanSourceFilesForRoutes(projectPath) {
57
+ const patterns = [
58
+ `${projectPath}/**/*.ts`,
59
+ `${projectPath}/**/*.tsx`,
60
+ `${projectPath}/**/*.js`,
61
+ `${projectPath}/**/*.jsx`,
62
+ `${projectPath}/**/*.py`,
63
+ ];
64
+ const ignores = ['**/node_modules/**', '**/dist/**', '**/.next/**', '**/build/**'];
65
+ const routes = [];
66
+ const files = await glob(patterns, { ignore: ignores });
67
+ for (const file of files) {
68
+ const content = await readFile(file, 'utf-8').catch(() => '');
69
+ if (!content) {
70
+ continue;
71
+ }
72
+ for (const { regex, framework } of ROUTE_PATTERNS) {
73
+ const re = new RegExp(regex.source, regex.flags);
74
+ let match;
75
+ while ((match = re.exec(content)) !== null) {
76
+ if (framework === 'nextjs') {
77
+ const relPath = file
78
+ .replace(projectPath, '')
79
+ .replace(/\\/g, '/')
80
+ .replace(/\/app\/|\/pages\/api\//, '/')
81
+ .replace(/\/route\.(ts|js|tsx|jsx)$/, '')
82
+ .replace(/\.(ts|js|tsx|jsx)$/, '');
83
+ routes.push({
84
+ method: normalizeMethod(match[1] ?? 'GET'),
85
+ path: relPath || '/',
86
+ framework,
87
+ file,
88
+ });
89
+ }
90
+ else {
91
+ const rawMethod = match[1] ?? '';
92
+ const rawPath = match[2] ?? '';
93
+ if (rawMethod && rawPath) {
94
+ routes.push({
95
+ method: normalizeMethod(rawMethod),
96
+ path: rawPath,
97
+ framework,
98
+ file,
99
+ });
100
+ }
101
+ }
102
+ }
103
+ }
104
+ }
105
+ // Deduplicate by method+path (multiple patterns may match the same route)
106
+ const seen = new Set();
107
+ return routes.filter((r) => {
108
+ const key = `${r.method}:${r.path}`;
109
+ if (seen.has(key)) {
110
+ return false;
111
+ }
112
+ seen.add(key);
113
+ return true;
114
+ });
115
+ }
116
+ // ---------------------------------------------------------------------------
117
+ // OpenAPI contract reader
118
+ // ---------------------------------------------------------------------------
119
+ async function readOpenApiDoc(contractPath) {
120
+ const content = await readFile(contractPath, 'utf-8');
121
+ if (contractPath.endsWith('.json')) {
122
+ return JSON.parse(content);
123
+ }
124
+ // Minimal YAML fallback: strip comments and attempt JSON parse
125
+ const stripped = content
126
+ .split('\n')
127
+ .filter((line) => !line.trim().startsWith('#'))
128
+ .join('\n');
129
+ try {
130
+ return JSON.parse(stripped);
131
+ }
132
+ catch {
133
+ return {};
134
+ }
135
+ }
136
+ // ---------------------------------------------------------------------------
137
+ // Main validator
138
+ // ---------------------------------------------------------------------------
139
+ const HTTP_METHODS_LIST = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options'];
140
+ export async function validateOpenApiContract(contractPath, projectPath) {
141
+ const doc = await readOpenApiDoc(contractPath);
142
+ const implRoutes = await scanSourceFilesForRoutes(projectPath);
143
+ const contractEndpoints = [];
144
+ const paths = doc.paths ?? {};
145
+ for (const [apiPath, pathItem] of Object.entries(paths)) {
146
+ for (const method of HTTP_METHODS_LIST) {
147
+ if (pathItem[method] !== undefined) {
148
+ contractEndpoints.push({ path: apiPath, method: method.toUpperCase() });
149
+ }
150
+ }
151
+ }
152
+ const missingEndpoints = [];
153
+ for (const endpoint of contractEndpoints) {
154
+ const found = implRoutes.some((r) => r.method === endpoint.method && pathsMatch(endpoint.path, r.path));
155
+ if (!found) {
156
+ missingEndpoints.push({
157
+ path: endpoint.path,
158
+ method: endpoint.method,
159
+ severity: 'critical',
160
+ message: `Endpoint ${endpoint.method} ${endpoint.path} is documented in the contract but no implementation was found in the project source files.`,
161
+ });
162
+ }
163
+ }
164
+ const undocumentedEndpoints = [];
165
+ for (const route of implRoutes) {
166
+ const found = contractEndpoints.some((e) => e.method === route.method && pathsMatch(e.path, route.path));
167
+ if (!found) {
168
+ undocumentedEndpoints.push({
169
+ path: route.path,
170
+ method: route.method,
171
+ severity: 'warning',
172
+ message: `Endpoint ${route.method} ${route.path} is implemented (found in ${route.file}) but is not documented in the API contract.`,
173
+ });
174
+ }
175
+ }
176
+ const findings = [...missingEndpoints, ...undocumentedEndpoints];
177
+ const contractInfo = doc.info ?? {};
178
+ return {
179
+ contractFormat: 'openapi',
180
+ contractVersion: contractInfo.version ?? 'unknown',
181
+ contractTitle: contractInfo.title ?? 'Unknown API',
182
+ totalContractEndpoints: contractEndpoints.length,
183
+ totalImplEndpoints: implRoutes.length,
184
+ missingEndpoints,
185
+ undocumentedEndpoints,
186
+ schemaDrift: [],
187
+ breakingChanges: [],
188
+ findings,
189
+ summary: buildSummary(missingEndpoints.length, undocumentedEndpoints.length),
190
+ };
191
+ }
192
+ function buildSummary(missing, undocumented) {
193
+ if (missing === 0 && undocumented === 0) {
194
+ return 'Contract and implementation are fully aligned. No issues found.';
195
+ }
196
+ const parts = [];
197
+ if (missing > 0) {
198
+ parts.push(`${missing} endpoint(s) documented in the contract but missing from implementation`);
199
+ }
200
+ if (undocumented > 0) {
201
+ parts.push(`${undocumented} endpoint(s) implemented but not documented in the contract`);
202
+ }
203
+ return parts.join('; ') + '.';
204
+ }
205
+ //# sourceMappingURL=openapi-impl-validator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openapi-impl-validator.js","sourceRoot":"","sources":["../../../src/engine/api-validation/openapi-impl-validator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import type { CIJob, MobileCiConfig } from '../../types/index.js';
2
+ /**
3
+ * Build a Gradle test job that runs unit tests on ubuntu-latest.
4
+ * Uses JDK 17 (Temurin) and caches Gradle dependencies.
5
+ */
6
+ export declare function buildGradleTestJob(config: MobileCiConfig): CIJob;
7
+ /**
8
+ * Build an APK/AAB signing job using the project keystore.
9
+ * Decodes the base64-encoded KEYSTORE_FILE secret and runs assembleRelease.
10
+ */
11
+ export declare function buildPlayStoreSigningJob(config: MobileCiConfig): CIJob;
12
+ /**
13
+ * Build a Play Console deploy job that uploads the signed AAB via Fastlane Supply.
14
+ * Depends on the signing job artifact. Requires PLAY_STORE_JSON_KEY secret.
15
+ */
16
+ export declare function buildPlayConsoleDeployJob(config: MobileCiConfig): CIJob;
17
+ //# sourceMappingURL=android-jobs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"android-jobs.d.ts","sourceRoot":"","sources":["../../../src/engine/ci-generator/android-jobs.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,KAAK,EAAU,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAmD1E;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,cAAc,GAAG,KAAK,CA2BhE;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,cAAc,GAAG,KAAK,CAuCtE;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,cAAc,GAAG,KAAK,CA+CvE"}
@@ -0,0 +1,168 @@
1
+ // ci-generator/android-jobs.ts — Android CI job builders for Gradle + Play Store (SPEC-325)
2
+ // -- Shared helpers -----------------------------------------------------------
3
+ function checkoutStep() {
4
+ return { name: 'Checkout code', uses: 'actions/checkout@v4' };
5
+ }
6
+ function javaSetupStep() {
7
+ return {
8
+ name: 'Setup JDK',
9
+ uses: 'actions/setup-java@v4',
10
+ with: { 'java-version': '17', distribution: 'temurin' },
11
+ };
12
+ }
13
+ function gradleCacheStep() {
14
+ return {
15
+ name: 'Cache Gradle packages',
16
+ uses: 'actions/cache@v4',
17
+ with: {
18
+ path: '~/.gradle/caches\n~/.gradle/wrapper',
19
+ key: "${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}",
20
+ 'restore-keys': '${{ runner.os }}-gradle-',
21
+ },
22
+ };
23
+ }
24
+ function gradlePermissionsStep() {
25
+ return {
26
+ name: 'Grant Gradle execute permission',
27
+ run: 'chmod +x gradlew',
28
+ };
29
+ }
30
+ /** Common env vars required for Play Store keystore signing. */
31
+ function keystoreEnv() {
32
+ return {
33
+ KEYSTORE_FILE: '${{ secrets.KEYSTORE_FILE }}',
34
+ KEYSTORE_PASSWORD: '${{ secrets.KEYSTORE_PASSWORD }}',
35
+ KEY_ALIAS: '${{ secrets.KEY_ALIAS }}',
36
+ KEY_PASSWORD: '${{ secrets.KEY_PASSWORD }}',
37
+ };
38
+ }
39
+ function resolveModule(config) {
40
+ return config.scheme ?? 'app';
41
+ }
42
+ // -- Job builders -------------------------------------------------------------
43
+ /**
44
+ * Build a Gradle test job that runs unit tests on ubuntu-latest.
45
+ * Uses JDK 17 (Temurin) and caches Gradle dependencies.
46
+ */
47
+ export function buildGradleTestJob(config) {
48
+ const module = resolveModule(config);
49
+ const steps = [
50
+ checkoutStep(),
51
+ javaSetupStep(),
52
+ gradleCacheStep(),
53
+ gradlePermissionsStep(),
54
+ {
55
+ name: 'Run unit tests',
56
+ run: `./gradlew :${module}:testDebugUnitTest`,
57
+ },
58
+ {
59
+ name: 'Upload test reports',
60
+ uses: 'actions/upload-artifact@v4',
61
+ with: {
62
+ name: 'test-results',
63
+ path: `${module}/build/reports/tests/`,
64
+ 'if-no-files-found': 'warn',
65
+ },
66
+ },
67
+ ];
68
+ return {
69
+ name: 'Android — Gradle Unit Tests',
70
+ runsOn: 'ubuntu-latest',
71
+ steps,
72
+ };
73
+ }
74
+ /**
75
+ * Build an APK/AAB signing job using the project keystore.
76
+ * Decodes the base64-encoded KEYSTORE_FILE secret and runs assembleRelease.
77
+ */
78
+ export function buildPlayStoreSigningJob(config) {
79
+ const module = resolveModule(config);
80
+ const steps = [
81
+ checkoutStep(),
82
+ javaSetupStep(),
83
+ gradleCacheStep(),
84
+ gradlePermissionsStep(),
85
+ {
86
+ name: 'Decode keystore',
87
+ run: 'echo "$KEYSTORE_FILE" | base64 --decode > keystore.jks',
88
+ env: keystoreEnv(),
89
+ },
90
+ {
91
+ name: 'Build signed release AAB',
92
+ run: [
93
+ `./gradlew :${module}:bundleRelease \\`,
94
+ ` -Pandroid.injected.signing.store.file=$(pwd)/keystore.jks \\`,
95
+ ` -Pandroid.injected.signing.store.password="$KEYSTORE_PASSWORD" \\`,
96
+ ` -Pandroid.injected.signing.key.alias="$KEY_ALIAS" \\`,
97
+ ` -Pandroid.injected.signing.key.password="$KEY_PASSWORD"`,
98
+ ].join('\n'),
99
+ env: keystoreEnv(),
100
+ },
101
+ {
102
+ name: 'Upload signed AAB',
103
+ uses: 'actions/upload-artifact@v4',
104
+ with: {
105
+ name: 'release-aab',
106
+ path: `${module}/build/outputs/bundle/release/*.aab`,
107
+ },
108
+ },
109
+ ];
110
+ return {
111
+ name: 'Android — Sign Release AAB',
112
+ runsOn: 'ubuntu-latest',
113
+ steps,
114
+ env: keystoreEnv(),
115
+ };
116
+ }
117
+ /**
118
+ * Build a Play Console deploy job that uploads the signed AAB via Fastlane Supply.
119
+ * Depends on the signing job artifact. Requires PLAY_STORE_JSON_KEY secret.
120
+ */
121
+ export function buildPlayConsoleDeployJob(config) {
122
+ const module = resolveModule(config);
123
+ const packageName = config.bundleId ?? 'com.example.app';
124
+ const steps = [
125
+ checkoutStep(),
126
+ {
127
+ name: 'Download signed AAB',
128
+ uses: 'actions/download-artifact@v4',
129
+ with: { name: 'release-aab', path: './release' },
130
+ },
131
+ {
132
+ name: 'Setup Ruby for Fastlane',
133
+ uses: 'ruby/setup-ruby@v1',
134
+ with: { 'ruby-version': 'bundler-cache: true' },
135
+ },
136
+ {
137
+ name: 'Install Fastlane',
138
+ run: 'gem install fastlane --no-document',
139
+ },
140
+ {
141
+ name: 'Decode Play Store JSON key',
142
+ run: 'echo "$PLAY_STORE_JSON_KEY" > play-store-key.json',
143
+ env: {
144
+ PLAY_STORE_JSON_KEY: '${{ secrets.PLAY_STORE_JSON_KEY }}',
145
+ },
146
+ },
147
+ {
148
+ name: 'Upload to Play Console (internal track)',
149
+ run: [
150
+ 'fastlane supply \\',
151
+ ` --aab ./release/${module}/build/outputs/bundle/release/*.aab \\`,
152
+ ` --package_name "${packageName}" \\`,
153
+ ' --track internal \\',
154
+ ' --json_key ./play-store-key.json',
155
+ ].join('\n'),
156
+ },
157
+ ];
158
+ return {
159
+ name: 'Android — Play Console Deploy',
160
+ runsOn: 'ubuntu-latest',
161
+ needs: ['android-sign'],
162
+ steps,
163
+ env: {
164
+ PLAY_STORE_JSON_KEY: '${{ secrets.PLAY_STORE_JSON_KEY }}',
165
+ },
166
+ };
167
+ }
168
+ //# sourceMappingURL=android-jobs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"android-jobs.js","sourceRoot":"","sources":["../../../src/engine/ci-generator/android-jobs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import type { CIJob, MobileCiConfig } from '../../types/index.js';
2
+ /**
3
+ * Build a basic Xcode Cloud setup job that compiles and runs unit tests.
4
+ * Uses macos-latest runner with Apple API key authentication.
5
+ */
6
+ export declare function buildXcodeCloudJob(config: MobileCiConfig): CIJob;
7
+ /**
8
+ * Build a Fastlane TestFlight job that compiles a signed IPA and uploads it.
9
+ * Requires MATCH_PASSWORD secret for code signing via Fastlane Match.
10
+ */
11
+ export declare function buildFastlaneTestFlightJob(config: MobileCiConfig): CIJob;
12
+ /**
13
+ * Build a production App Store submission job via Fastlane Deliver.
14
+ * Runs only on main branch. Requires Apple API credentials and signing secrets.
15
+ */
16
+ export declare function buildAppStoreDeployJob(config: MobileCiConfig): CIJob;
17
+ //# sourceMappingURL=ios-jobs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ios-jobs.d.ts","sourceRoot":"","sources":["../../../src/engine/ci-generator/ios-jobs.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,KAAK,EAAU,cAAc,EAAE,MAAM,sBAAsB,CAAC;AA6C1E;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,cAAc,GAAG,KAAK,CAwBhE;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,cAAc,GAAG,KAAK,CAqCxE;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,cAAc,GAAG,KAAK,CA2CpE"}
@@ -0,0 +1,151 @@
1
+ // ci-generator/ios-jobs.ts — iOS CI job builders for Xcode Cloud + TestFlight + App Store (SPEC-325)
2
+ // -- Shared helpers -----------------------------------------------------------
3
+ function checkoutStep() {
4
+ return { name: 'Checkout code', uses: 'actions/checkout@v4' };
5
+ }
6
+ function rubySetupStep() {
7
+ return {
8
+ name: 'Setup Ruby for Fastlane',
9
+ uses: 'ruby/setup-ruby@v1',
10
+ with: { 'ruby-version': 'bundler-cache: true' },
11
+ };
12
+ }
13
+ function selectXcodeStep() {
14
+ return {
15
+ name: 'Select Xcode version',
16
+ run: 'sudo xcode-select -s /Applications/Xcode.app',
17
+ };
18
+ }
19
+ function installFastlaneStep() {
20
+ return {
21
+ name: 'Install Fastlane',
22
+ run: 'gem install fastlane --no-document',
23
+ };
24
+ }
25
+ /** Common env vars required for Apple API authentication. */
26
+ function appleApiEnv() {
27
+ return {
28
+ APPLE_API_KEY: '${{ secrets.APPLE_API_KEY }}',
29
+ APPLE_API_ISSUER_ID: '${{ secrets.APPLE_API_ISSUER_ID }}',
30
+ APPLE_API_KEY_ID: '${{ secrets.APPLE_API_KEY_ID }}',
31
+ };
32
+ }
33
+ function resolveScheme(config) {
34
+ return config.scheme ?? 'MyApp';
35
+ }
36
+ // -- Job builders -------------------------------------------------------------
37
+ /**
38
+ * Build a basic Xcode Cloud setup job that compiles and runs unit tests.
39
+ * Uses macos-latest runner with Apple API key authentication.
40
+ */
41
+ export function buildXcodeCloudJob(config) {
42
+ const scheme = resolveScheme(config);
43
+ const steps = [
44
+ checkoutStep(),
45
+ selectXcodeStep(),
46
+ {
47
+ name: 'Build and test (Xcode)',
48
+ run: [
49
+ `xcodebuild clean build test \\`,
50
+ ` -scheme "${scheme}" \\`,
51
+ ` -destination 'platform=iOS Simulator,name=iPhone 15,OS=latest' \\`,
52
+ ` CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO \\`,
53
+ ' | xcpretty && exit "${PIPESTATUS[0]}"',
54
+ ].join('\n'),
55
+ env: appleApiEnv(),
56
+ },
57
+ ];
58
+ return {
59
+ name: 'iOS — Xcode Build & Test',
60
+ runsOn: 'macos-latest',
61
+ steps,
62
+ env: appleApiEnv(),
63
+ };
64
+ }
65
+ /**
66
+ * Build a Fastlane TestFlight job that compiles a signed IPA and uploads it.
67
+ * Requires MATCH_PASSWORD secret for code signing via Fastlane Match.
68
+ */
69
+ export function buildFastlaneTestFlightJob(config) {
70
+ const scheme = resolveScheme(config);
71
+ const steps = [
72
+ checkoutStep(),
73
+ selectXcodeStep(),
74
+ rubySetupStep(),
75
+ installFastlaneStep(),
76
+ {
77
+ name: 'Build IPA',
78
+ run: [
79
+ `fastlane gym \\`,
80
+ ` --scheme "${scheme}" \\`,
81
+ ` --export_method app-store \\`,
82
+ ` --output_directory ./build`,
83
+ ].join('\n'),
84
+ env: {
85
+ MATCH_PASSWORD: '${{ secrets.MATCH_PASSWORD }}',
86
+ },
87
+ },
88
+ {
89
+ name: 'Upload to TestFlight',
90
+ run: 'fastlane pilot upload --ipa ./build/*.ipa --skip_waiting_for_build_processing true',
91
+ env: appleApiEnv(),
92
+ },
93
+ ];
94
+ const fullEnv = {
95
+ ...appleApiEnv(),
96
+ MATCH_PASSWORD: '${{ secrets.MATCH_PASSWORD }}',
97
+ };
98
+ return {
99
+ name: 'iOS — TestFlight Upload',
100
+ runsOn: 'macos-latest',
101
+ steps,
102
+ env: fullEnv,
103
+ };
104
+ }
105
+ /**
106
+ * Build a production App Store submission job via Fastlane Deliver.
107
+ * Runs only on main branch. Requires Apple API credentials and signing secrets.
108
+ */
109
+ export function buildAppStoreDeployJob(config) {
110
+ const scheme = resolveScheme(config);
111
+ const steps = [
112
+ checkoutStep(),
113
+ selectXcodeStep(),
114
+ rubySetupStep(),
115
+ installFastlaneStep(),
116
+ {
117
+ name: 'Build IPA (production)',
118
+ run: [
119
+ `fastlane gym \\`,
120
+ ` --scheme "${scheme}" \\`,
121
+ ` --configuration Release \\`,
122
+ ` --export_method app-store \\`,
123
+ ` --output_directory ./build`,
124
+ ].join('\n'),
125
+ env: {
126
+ MATCH_PASSWORD: '${{ secrets.MATCH_PASSWORD }}',
127
+ },
128
+ },
129
+ {
130
+ name: 'Submit to App Store',
131
+ run: [
132
+ 'fastlane deliver \\',
133
+ ' --ipa ./build/*.ipa \\',
134
+ ' --submit_for_review false \\',
135
+ ' --automatic_release false',
136
+ ].join('\n'),
137
+ env: appleApiEnv(),
138
+ },
139
+ ];
140
+ const fullEnv = {
141
+ ...appleApiEnv(),
142
+ MATCH_PASSWORD: '${{ secrets.MATCH_PASSWORD }}',
143
+ };
144
+ return {
145
+ name: 'iOS — App Store Submission',
146
+ runsOn: 'macos-latest',
147
+ steps,
148
+ env: fullEnv,
149
+ };
150
+ }
151
+ //# sourceMappingURL=ios-jobs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ios-jobs.js","sourceRoot":"","sources":["../../../src/engine/ci-generator/ios-jobs.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import type { CIJob, CIJobType, CISeverityThreshold, CIStackContext, CITriggerEvent, CIWorkflow, DriftJobOptions } from '../../types/index.js';
1
+ import type { CIJob, CIJobType, CISeverityThreshold, CIStackContext, CITriggerEvent, CIWorkflow, DriftJobOptions, MobileCiConfig } from '../../types/index.js';
2
2
  export type { DriftJobOptions };
3
3
  /** Serialize a CIWorkflow to a YAML string. */
4
4
  export declare function serializeWorkflow(workflow: CIWorkflow): string;
@@ -10,4 +10,13 @@ export declare function buildDriftJob(specsDir: string, threshold: CISeverityThr
10
10
  * Build a complete CIWorkflow from the stack context and job/trigger options.
11
11
  */
12
12
  export declare function buildWorkflow(ctx: CIStackContext, jobs: CIJobType[], triggers: CITriggerEvent[], workflowName: string, driftOptions?: DriftJobOptions): CIWorkflow;
13
+ /**
14
+ * Build a CIWorkflow that contains iOS and/or Android CI/CD jobs.
15
+ * iOS and Android jobs run as parallel workstreams in the same workflow.
16
+ *
17
+ * @param mobileConfigs - One or more mobile platform configs (ios, android, or both)
18
+ * @param triggers - GitHub Actions trigger events
19
+ * @param workflowName - Display name of the workflow
20
+ */
21
+ export declare function buildMobileWorkflow(mobileConfigs: MobileCiConfig[], triggers: CITriggerEvent[], workflowName: string): CIWorkflow;
13
22
  //# sourceMappingURL=yaml-builder.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"yaml-builder.d.ts","sourceRoot":"","sources":["../../../src/engine/ci-generator/yaml-builder.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,KAAK,EACL,SAAS,EACT,mBAAmB,EACnB,cAAc,EAEd,cAAc,EACd,UAAU,EACV,eAAe,EAChB,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EAAE,eAAe,EAAE,CAAC;AAuGhC,+CAA+C;AAC/C,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,UAAU,GAAG,MAAM,CAe9D;AA4KD;;GAEG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,mBAAmB,EAC9B,SAAS,EAAE,MAAM,EAAE,GAClB,KAAK,CAyCP;AAID;;GAEG;AACH,wBAAgB,aAAa,CAC3B,GAAG,EAAE,cAAc,EACnB,IAAI,EAAE,SAAS,EAAE,EACjB,QAAQ,EAAE,cAAc,EAAE,EAC1B,YAAY,EAAE,MAAM,EACpB,YAAY,CAAC,EAAE,eAAe,GAC7B,UAAU,CA4CZ"}
1
+ {"version":3,"file":"yaml-builder.d.ts","sourceRoot":"","sources":["../../../src/engine/ci-generator/yaml-builder.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,KAAK,EACL,SAAS,EACT,mBAAmB,EACnB,cAAc,EAEd,cAAc,EACd,UAAU,EACV,eAAe,EACf,cAAc,EACf,MAAM,sBAAsB,CAAC;AAW9B,YAAY,EAAE,eAAe,EAAE,CAAC;AAuGhC,+CAA+C;AAC/C,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,UAAU,GAAG,MAAM,CAe9D;AA4KD;;GAEG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,mBAAmB,EAC9B,SAAS,EAAE,MAAM,EAAE,GAClB,KAAK,CAyCP;AAID;;GAEG;AACH,wBAAgB,aAAa,CAC3B,GAAG,EAAE,cAAc,EACnB,IAAI,EAAE,SAAS,EAAE,EACjB,QAAQ,EAAE,cAAc,EAAE,EAC1B,YAAY,EAAE,MAAM,EACpB,YAAY,CAAC,EAAE,eAAe,GAC7B,UAAU,CA4CZ;AAID;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,aAAa,EAAE,cAAc,EAAE,EAC/B,QAAQ,EAAE,cAAc,EAAE,EAC1B,YAAY,EAAE,MAAM,GACnB,UAAU,CAoCZ"}