@daemux/store-automator 0.7.1 → 0.9.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 (46) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/bin/cli.mjs +38 -14
  3. package/package.json +1 -1
  4. package/plugins/store-automator/.claude-plugin/plugin.json +1 -1
  5. package/plugins/store-automator/agents/appstore-meta-creator.md +13 -8
  6. package/plugins/store-automator/agents/architect.md +42 -1
  7. package/plugins/store-automator/agents/devops.md +26 -27
  8. package/scripts/check_google_play.py +1 -1
  9. package/scripts/manage_version_ios.py +1 -1
  10. package/src/ci-config.mjs +21 -0
  11. package/src/install-paths.mjs +92 -0
  12. package/src/install.mjs +33 -78
  13. package/src/templates.mjs +71 -1
  14. package/templates/CLAUDE.md.template +70 -16
  15. package/templates/Matchfile.template +8 -0
  16. package/templates/ci.config.yaml.template +3 -0
  17. package/templates/codemagic.template.yaml +131 -96
  18. package/templates/fastlane/android/Fastfile.template +23 -5
  19. package/templates/fastlane/ios/Fastfile.template +4 -3
  20. package/templates/github/workflows/android-release.yml +141 -0
  21. package/templates/github/workflows/codemagic-trigger.yml +15 -5
  22. package/templates/github/workflows/ios-release.yml +119 -0
  23. package/templates/scripts/check_google_play.py +1 -1
  24. package/templates/scripts/ci/android/build.sh +50 -0
  25. package/templates/scripts/ci/android/check-readiness.sh +93 -0
  26. package/templates/scripts/ci/android/manage-version.sh +134 -0
  27. package/templates/scripts/ci/android/setup-keystore.sh +80 -0
  28. package/templates/scripts/ci/android/sync-iap.sh +63 -0
  29. package/templates/scripts/ci/android/update-data-safety.sh +65 -0
  30. package/templates/scripts/ci/android/upload-binary.sh +62 -0
  31. package/templates/scripts/ci/android/upload-metadata.sh +77 -0
  32. package/templates/scripts/ci/common/check-changed.sh +74 -0
  33. package/templates/scripts/ci/common/flutter-setup.sh +22 -0
  34. package/templates/scripts/ci/common/install-fastlane.sh +39 -0
  35. package/templates/scripts/ci/common/link-fastlane.sh +56 -0
  36. package/templates/scripts/ci/common/read-config.sh +74 -0
  37. package/templates/scripts/ci/ios/build.sh +91 -0
  38. package/templates/scripts/ci/ios/manage-version.sh +64 -0
  39. package/templates/scripts/ci/ios/set-build-number.sh +92 -0
  40. package/templates/scripts/ci/ios/setup-signing.sh +283 -0
  41. package/templates/scripts/ci/ios/sync-iap.sh +80 -0
  42. package/templates/scripts/ci/ios/upload-binary.sh +43 -0
  43. package/templates/scripts/ci/ios/upload-metadata.sh +82 -0
  44. package/templates/scripts/create_app_record.py +1 -1
  45. package/templates/scripts/manage_version_ios.py +1 -1
  46. package/templates/scripts/update_data_safety.py +220 -0
@@ -5,14 +5,14 @@
5
5
  },
6
6
  "metadata": {
7
7
  "description": "App Store & Google Play automation for Flutter apps",
8
- "version": "0.7.1"
8
+ "version": "0.9.0"
9
9
  },
10
10
  "plugins": [
11
11
  {
12
12
  "name": "store-automator",
13
13
  "source": "./plugins/store-automator",
14
14
  "description": "3 agents for app store publishing: reviewer, meta-creator, media-designer",
15
- "version": "0.7.1",
15
+ "version": "0.9.0",
16
16
  "keywords": ["flutter", "app-store", "google-play", "fastlane", "codemagic"]
17
17
  }
18
18
  ]
package/bin/cli.mjs CHANGED
@@ -34,6 +34,8 @@ const valueFlags = {
34
34
  '--cloudflare-token=': 'cloudflareToken',
35
35
  '--cloudflare-account-id=': 'cloudflareAccountId',
36
36
  '--bundle-id=': 'bundleId',
37
+ '--match-deploy-key=': 'matchDeployKey',
38
+ '--match-git-url=': 'matchGitUrl',
37
39
  };
38
40
 
39
41
  for (const arg of args) {
@@ -42,15 +44,11 @@ for (const arg of args) {
42
44
  if ((v = flagValue(arg, '--branch=')) !== undefined) { cmBranch = v; continue; }
43
45
  if ((v = flagValue(arg, '--workflow=')) !== undefined) { cmWorkflowId = v; continue; }
44
46
 
45
- let matched = false;
46
- for (const [prefix, key] of Object.entries(valueFlags)) {
47
- if ((v = flagValue(arg, prefix)) !== undefined) {
48
- cliTokens[key] = v;
49
- matched = true;
50
- break;
51
- }
47
+ const valueFlagEntry = Object.entries(valueFlags).find(([prefix]) => arg.startsWith(prefix));
48
+ if (valueFlagEntry) {
49
+ cliTokens[valueFlagEntry[1]] = arg.slice(valueFlagEntry[0].length);
50
+ continue;
52
51
  }
53
- if (matched) continue;
54
52
 
55
53
  switch (arg) {
56
54
  case '-g':
@@ -70,6 +68,9 @@ for (const arg of args) {
70
68
  case '--github-setup':
71
69
  action = 'github-setup';
72
70
  break;
71
+ case '--github-actions':
72
+ cliTokens.githubActions = true;
73
+ break;
73
74
  case '--trigger':
74
75
  cmTrigger = true;
75
76
  break;
@@ -105,34 +106,57 @@ Codemagic:
105
106
  --trigger Trigger build after setup
106
107
  --wait Wait for build completion (implies --trigger)
107
108
 
109
+ GitHub Actions CI mode:
110
+ --github-actions Use GitHub Actions instead of Codemagic (skip MCP setup)
111
+ --match-deploy-key=PATH Path to Match deploy key file (required with --github-actions)
112
+ --match-git-url=URL Git URL for Match certificates repo (required with --github-actions)
113
+
108
114
  GitHub Actions (auto-configured during install if gh CLI available):
109
115
  --github-setup Set CM_API_TOKEN secret for GitHub Actions
110
116
  --token=TOKEN API token (or set CM_API_TOKEN env var)
111
117
 
112
118
  Examples:
113
- npx @daemux/store-automator Install for project
119
+ npx @daemux/store-automator Install for project (Codemagic)
114
120
  npx @daemux/store-automator -g Install globally
115
121
  npx @daemux/store-automator -u Uninstall from project
116
122
  npx @daemux/store-automator -g -u Uninstall globally
117
123
  npx @daemux/store-automator --codemagic-setup Register with Codemagic
118
124
  npx @daemux/store-automator --codemagic-setup --trigger --wait Trigger and wait
119
- npx @daemux/store-automator --github-setup Configure GitHub Actions
125
+ npx @daemux/store-automator --github-setup Configure GitHub Actions secret
126
+
127
+ GitHub Actions install:
128
+ npx @daemux/store-automator --github-actions --bundle-id=ID --match-deploy-key=PATH --match-git-url=URL
120
129
 
121
- Non-interactive install (CI/CD):
122
- npx @daemux/store-automator --bundle-id=com.company.app --codemagic-token=TOKEN --codemagic-team-id=ID --stitch-key=KEY
130
+ Non-interactive install (Codemagic):
131
+ npx @daemux/store-automator --bundle-id=ID --codemagic-token=TOKEN --stitch-key=KEY
123
132
  npx @daemux/store-automator --cloudflare-token=TOKEN --cloudflare-account-id=ID`);
124
133
  process.exit(0);
125
- break; // eslint: no-fallthrough
126
134
  case '-v':
127
135
  case '--version':
128
136
  console.log(pkg.version);
129
137
  process.exit(0);
130
- break; // eslint: no-fallthrough
131
138
  }
132
139
  }
133
140
 
134
141
  if (cmWait) cmTrigger = true;
135
142
 
143
+ if (cliTokens.githubActions) {
144
+ const missing = [];
145
+ if (!cliTokens.matchDeployKey) missing.push('--match-deploy-key');
146
+ if (!cliTokens.matchGitUrl) missing.push('--match-git-url');
147
+ if (!cliTokens.bundleId) missing.push('--bundle-id');
148
+ if (missing.length > 0) {
149
+ console.error(`Error: --github-actions requires: ${missing.join(', ')}`);
150
+ console.error('');
151
+ console.error('Example:');
152
+ console.error(' npx @daemux/store-automator --github-actions \\');
153
+ console.error(' --bundle-id=com.company.app \\');
154
+ console.error(' --match-deploy-key=creds/match_deploy_key \\');
155
+ console.error(' --match-git-url=git@github.com:org/certs.git');
156
+ process.exit(1);
157
+ }
158
+ }
159
+
136
160
  notifier.notify();
137
161
 
138
162
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@daemux/store-automator",
3
- "version": "0.7.1",
3
+ "version": "0.9.0",
4
4
  "description": "Full App Store & Google Play automation for Flutter apps with Claude Code agents",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "store-automator",
3
- "version": "0.7.1",
3
+ "version": "0.9.0",
4
4
  "description": "App Store & Google Play automation agents for Flutter app publishing",
5
5
  "author": {
6
6
  "name": "Daemux"
@@ -152,14 +152,19 @@ af, am, ar, hy-AM, az-AZ, eu-ES, be, bn-BD, bg, my-MM, ca, zh-HK, zh-CN, zh-TW,
152
152
  ## Translation Process
153
153
 
154
154
  1. Create complete English (en-US) metadata for both platforms first
155
- 2. For EACH target language from ci.config.yaml metadata.languages, spawn a sub-agent (Task tool) with:
156
- - The complete English source texts for all files
157
- - Target locale code (Apple and Google variants)
158
- - Platform (ios and android)
159
- - Character limits per field (critical -- translations often expand 20-40%)
160
- - Translation instructions (see below)
161
- 3. Launch up to 10 sub-agents in parallel for speed
162
- 4. Each sub-agent writes files directly to the correct locale directory
155
+ 2. Group target languages from ci.config.yaml metadata.languages by similarity:
156
+ - Romance: es-ES, es-MX, fr-FR, fr-CA, it, pt-BR, pt-PT, ro, ca, gl-ES
157
+ - Germanic: de-DE, nl-NL, sv, da, no, fi
158
+ - Slavic: ru, uk, pl, cs, sk, hr, bg, sr, sl, mk-MK, be
159
+ - CJK: ja, ko, zh-Hans, zh-Hant, zh-Hant-HK, zh-CN, zh-TW, zh-HK
160
+ - South/Southeast Asian: hi, th, vi, id, ms, bn-BD, ta-IN, te-IN, ml-IN, mr-IN, kn-IN, gu, my-MM, km-KH, lo-LA, si-LK
161
+ - Middle Eastern: ar, ar-SA, he, tr, fa, ur
162
+ - Other: hu, el, et, lv, lt, ka-GE, hy-AM, az-AZ, kk, ky-KG, mn-MN, ne-NP, af, am, sw, zu, fil, is-IS, eu-ES, rm, pa
163
+ 3. Create a translation team using TeamCreate with 2-5 teammates:
164
+ - Each teammate handles 2-5 language groups (based on total languages configured)
165
+ - Teammate prompt includes: English source texts, target locale codes (Apple + Google variants), character limits per field, translation instructions
166
+ - Each teammate writes files directly to the correct locale directories
167
+ 4. Wait for all teammates to complete, then verify all languages are covered
163
168
 
164
169
  ### Translation Instructions for Sub-Agents
165
170
 
@@ -138,7 +138,48 @@ If a `.claude/.tasks/` file path is provided, read ONLY that file for requiremen
138
138
  Scan the codebase for already-implemented items. Pick 3-5 UNIMPLEMENTED
139
139
  related requirements. Design only those. Report: "Batch: N of ~M remaining."
140
140
 
141
+ ## Team Composition Recommendation
142
+
143
+ **MANDATORY section in your output.** The orchestrator uses this to create teams.
144
+
145
+ After your architecture design, include this section:
146
+
147
+ ```
148
+ ### Team Recommendations for Orchestrator
149
+
150
+ **Files touched:** {count}
151
+
152
+ #### Developer Team (Flutter)
153
+ - **Teammates:** {N} (based on file count: 3-4 files → 2, 5-7 → 3, 8+ → 4)
154
+ - **Teammate 1 scope:** Screens and widgets — {list of files}
155
+ - **Teammate 2 scope:** Providers and repositories — {list of files}
156
+ - **Teammate 3 scope:** Firebase/backend services — {list of files} (if applicable)
157
+ - **Rationale:** {why this split works}
158
+
159
+ #### Reviewer Team
160
+ - **Teammates:** 2-3
161
+ - **Reviewer 1 focus:** Dart code quality, patterns, maintainability — files: {list}
162
+ - **Reviewer 2 focus:** Security, Firebase rules, data validation — files: {list}
163
+ - **Reviewer 3 focus:** Performance, store compliance — files: {list} (if 5+ files)
164
+
165
+ #### Tester Team
166
+ - **Teammates:** 2-4
167
+ - **Tester 1 focus:** Flutter unit and widget tests — {scope}
168
+ - **Tester 2 focus:** Mobile UI testing (iOS) — {scope}
169
+ - **Tester 3 focus:** Mobile UI testing (Android) — {scope} (if applicable)
170
+
171
+ #### App Designer Team (if design stage applies)
172
+ - **Teammates:** 2-3
173
+ - **Designer 1 scope:** App screen designs — {deliverables}
174
+ - **Designer 2 scope:** Store screenshots — {deliverables}
175
+ - **Designer 3 scope:** Web page design — {deliverables} (if applicable)
176
+
177
+ **TEAM EXCEPTION:** If task touches <3 files, output: "Files touched: {N} — below team threshold, single agents recommended."
178
+ ```
179
+
180
+ Include concrete file assignments. The orchestrator will use this to create `TeamCreate` with the exact scopes you specify.
181
+
141
182
  ## Output Footer
142
183
  ```
143
- NEXT: product-manager(PRE) to validate approach before implementation
184
+ NEXT: product-manager(PRE) to validate approach and team composition before implementation
144
185
  ```
@@ -4,16 +4,18 @@ description: "DevOps operations: Codemagic CI/CD builds, Firebase deployment, Cl
4
4
  model: opus
5
5
  hooks:
6
6
  PreToolUse:
7
- - matcher: "Edit|Write"
8
- hooks:
9
- - type: command
10
- command: "exit 0"
11
7
  - matcher: "Bash"
12
8
  hooks:
13
9
  - type: command
14
10
  command: "exit 0"
15
11
  ---
16
12
 
13
+ **SCOPE RESTRICTION:**
14
+ - You CANNOT edit or create ANY local project files (no Edit/Write tools)
15
+ - This includes: source code, CI/CD configs, GitHub Actions workflows, scripts, codemagic.yaml, etc.
16
+ - You CAN only: run deployments, check logs, monitor builds, manage infrastructure via Bash and MCP tools
17
+ - If ANY local file changes are needed (code, configs, CI/CD, scripts), report what needs changing and ask the developer agent to make the edits
18
+
17
19
  # DevOps Agent
18
20
 
19
21
  Handles Codemagic CI/CD builds, Firebase deployment, Cloudflare Pages deployment, and Firestore management for Flutter mobile apps.
@@ -24,7 +26,7 @@ Handles Codemagic CI/CD builds, Firebase deployment, Cloudflare Pages deployment
24
26
  - `codemagic` - Build monitoring, deployment tracking, log analysis, build triggering
25
27
  - `firebase` - Deploy Cloud Functions, security rules, Firestore indexes
26
28
  - `cloudflare` - Deploy web pages via Cloudflare Pages
27
- - `database + migrate` - Firestore security rules updates, index management, data migration scripts
29
+ - `database + deploy` - Deploy Firestore security rules, indexes, and run data migration scripts
28
30
  - `database + optimize` - Firestore query optimization, index analysis, security rules audit
29
31
 
30
32
  Additional parameters vary by mode (see each section).
@@ -283,38 +285,35 @@ RECOMMENDATION: [action if needed]
283
285
 
284
286
  ---
285
287
 
286
- ## Mode: database + migrate
288
+ ## Mode: database + deploy
287
289
 
288
- Manage Firestore security rules, indexes, and data migration scripts. Firestore is NoSQL -- there are no SQL migrations.
290
+ Deploy Firestore security rules, indexes, and run data migration scripts. Firestore is NoSQL -- there are no SQL migrations.
289
291
 
290
- ### Security Rules Updates
292
+ ### Security Rules Deployment
291
293
 
292
- 1. Read current rules in `firestore.rules`
293
- 2. Read task file for new access requirements
294
- 3. Update rules with proper authenticated read/write and per-document ownership checks
295
- 4. Test rules locally: `firebase emulators:start --only firestore`
296
- 5. Deploy: `firebase deploy --only firestore:rules`
294
+ 1. Deploy rules: `firebase deploy --only firestore:rules`
295
+ 2. Verify deployment succeeded in Firebase Console or CLI output
296
+ 3. Test rules against expected access patterns
297
297
 
298
- ### Index Management
298
+ ### Index Deployment
299
299
 
300
- 1. Review `firestore.indexes.json` for existing composite indexes
301
- 2. Add new indexes for query patterns that require them
302
- 3. Deploy: `firebase deploy --only firestore:indexes`
303
- 4. Monitor index build status (can take minutes for large collections)
300
+ 1. Deploy indexes: `firebase deploy --only firestore:indexes`
301
+ 2. Monitor index build status (can take minutes for large collections)
302
+ 3. Verify all indexes reach READY state
304
303
 
305
- ### Data Migration Scripts
304
+ ### Data Migration Execution
306
305
 
307
- For schema-like changes in Firestore documents:
308
- 1. Write a migration script (Node.js) that reads and updates documents
309
- 2. Run against local emulator first for testing
310
- 3. Run against production with batched writes (max 500 per batch)
311
- 4. Log progress and handle partial failures gracefully
306
+ For running migration scripts (created by the developer agent):
307
+ 1. Run migration script against local emulator first: `firebase emulators:start --only firestore`
308
+ 2. Run against production with monitoring
309
+ 3. Verify data integrity after migration completes
310
+ 4. Log progress and report any failures
312
311
 
313
312
  ### Output
314
313
 
315
314
  ```
316
- OPERATION: Firestore Migration
317
- CHANGES: [list of rule/index/data changes]
315
+ OPERATION: Firestore Deploy
316
+ CHANGES: [list of deployed rules/indexes/migrations]
318
317
  EMULATOR TEST: Passed | Failed
319
318
  DEPLOYED: [rules | indexes | data migration]
320
319
  RESULT: Success | Failed
@@ -390,5 +389,5 @@ After editing `ci.config.yaml`, regenerate the Codemagic config:
390
389
  ## Output Footer
391
390
 
392
391
  ```
393
- NEXT: [context-dependent - for migrations: simplifier -> reviewer -> product-manager(POST)]
392
+ NEXT: [context-dependent - for database deploy: verify deployment succeeded]
394
393
  ```
@@ -25,7 +25,7 @@ except ImportError:
25
25
  print("Installing dependencies...", file=sys.stderr)
26
26
  import subprocess
27
27
  subprocess.check_call(
28
- [sys.executable, "-m", "pip", "install", "PyJWT", "cryptography", "requests"],
28
+ [sys.executable, "-m", "pip", "install", "--break-system-packages", "PyJWT", "cryptography", "requests"],
29
29
  stdout=subprocess.DEVNULL,
30
30
  )
31
31
  import jwt
@@ -32,7 +32,7 @@ except ImportError:
32
32
  print("Installing dependencies...", file=sys.stderr)
33
33
  import subprocess
34
34
  subprocess.check_call([
35
- sys.executable, "-m", "pip", "install",
35
+ sys.executable, "-m", "pip", "install", "--break-system-packages",
36
36
  "PyJWT", "cryptography", "requests"
37
37
  ], stdout=subprocess.DEVNULL)
38
38
  import jwt
package/src/ci-config.mjs CHANGED
@@ -7,6 +7,8 @@ const FIELD_PATTERNS = {
7
7
  team_id: /^(\s*team_id:\s*)"[^"]*"/m,
8
8
  bundle_id: /^(\s*bundle_id:\s*)"[^"]*"/m,
9
9
  package_name: /^(\s*package_name:\s*)"[^"]*"/m,
10
+ deploy_key_path: /^(\s*deploy_key_path:\s*)"[^"]*"/m,
11
+ git_url: /^(\s*git_url:\s*)"[^"]*"/m,
10
12
  };
11
13
 
12
14
  function writeCiField(projectDir, field, value) {
@@ -44,3 +46,22 @@ export function writeCiBundleId(projectDir, bundleId) {
44
46
  export function writeCiPackageName(projectDir, packageName) {
45
47
  return writeCiField(projectDir, 'package_name', packageName);
46
48
  }
49
+
50
+ export function writeMatchConfig(projectDir, { deployKeyPath, gitUrl }) {
51
+ const wrote1 = writeCiField(projectDir, 'deploy_key_path', deployKeyPath);
52
+ const wrote2 = writeCiField(projectDir, 'git_url', gitUrl);
53
+ return wrote1 || wrote2;
54
+ }
55
+
56
+ export function readFlutterRoot(projectDir) {
57
+ const configPath = join(projectDir, CI_CONFIG_FILE);
58
+ if (!existsSync(configPath)) return '.';
59
+
60
+ try {
61
+ const content = readFileSync(configPath, 'utf8');
62
+ const match = content.match(/^flutter_root:\s*"([^"]*)"/m);
63
+ return match ? match[1] : '.';
64
+ } catch {
65
+ return '.';
66
+ }
67
+ }
@@ -0,0 +1,92 @@
1
+ import { execSync, execFileSync } from 'node:child_process';
2
+ import { installGitHubActionsTemplates, installMatchfile } from './templates.mjs';
3
+ import { findAppByRepo, addApp, normalizeRepoUrl } from './codemagic-api.mjs';
4
+ import {
5
+ writeCiAppId, writeCiTeamId, writeMatchConfig,
6
+ } from './ci-config.mjs';
7
+ import { updateMcpAppId, updateMcpTeamId } from './mcp-setup.mjs';
8
+
9
+ function setupGitHubActionsSecret(codemagicToken) {
10
+ if (!codemagicToken) return false;
11
+
12
+ try {
13
+ execFileSync('which', ['gh'], { encoding: 'utf8', stdio: 'pipe' });
14
+ const authStatus = execFileSync('gh', ['auth', 'status'], { encoding: 'utf8', stdio: 'pipe' });
15
+ if (authStatus.includes('not logged')) return false;
16
+
17
+ execFileSync('gh', ['secret', 'set', 'CM_API_TOKEN', '--body', codemagicToken], {
18
+ encoding: 'utf8',
19
+ stdio: 'pipe',
20
+ });
21
+ return true;
22
+ } catch {
23
+ return false;
24
+ }
25
+ }
26
+
27
+ async function setupCodemagicApp(projectDir, codemagicToken, codemagicTeamId) {
28
+ if (!codemagicToken) return;
29
+
30
+ let repoUrl;
31
+ try {
32
+ const raw = execSync('git remote get-url origin', {
33
+ encoding: 'utf8',
34
+ stdio: ['pipe', 'pipe', 'pipe'],
35
+ }).trim();
36
+ if (!raw) return;
37
+ repoUrl = normalizeRepoUrl(raw);
38
+ } catch {
39
+ return;
40
+ }
41
+
42
+ try {
43
+ let app = await findAppByRepo(codemagicToken, repoUrl);
44
+ if (!app) {
45
+ app = await addApp(codemagicToken, repoUrl, codemagicTeamId);
46
+ console.log(`Codemagic app created: ${app.appName || app._id}`);
47
+ } else {
48
+ console.log(`Codemagic app found: ${app.appName || app._id}`);
49
+ }
50
+
51
+ const written = writeCiAppId(projectDir, app._id);
52
+ if (written) {
53
+ console.log(`Codemagic app_id written to ci.config.yaml`);
54
+ }
55
+
56
+ updateMcpAppId(projectDir, app._id);
57
+
58
+ if (codemagicTeamId) {
59
+ writeCiTeamId(projectDir, codemagicTeamId);
60
+ updateMcpTeamId(projectDir, codemagicTeamId);
61
+ }
62
+ } catch (err) {
63
+ console.log(`Codemagic auto-setup skipped: ${err.message || err}`);
64
+ }
65
+ }
66
+
67
+ export function installGitHubActionsPath(projectDir, packageDir, cliTokens) {
68
+ console.log('Configuring GitHub Actions mode...');
69
+ installGitHubActionsTemplates(projectDir, packageDir);
70
+
71
+ installMatchfile(projectDir, packageDir, {
72
+ matchGitUrl: cliTokens.matchGitUrl,
73
+ bundleId: cliTokens.bundleId,
74
+ });
75
+
76
+ const wrote = writeMatchConfig(projectDir, {
77
+ deployKeyPath: cliTokens.matchDeployKey,
78
+ gitUrl: cliTokens.matchGitUrl,
79
+ });
80
+ if (wrote) console.log('Match credentials written to ci.config.yaml');
81
+ }
82
+
83
+ export async function installCodemagicPath(projectDir, tokens) {
84
+ await setupCodemagicApp(projectDir, tokens.codemagicToken, tokens.codemagicTeamId);
85
+
86
+ const ghConfigured = setupGitHubActionsSecret(tokens.codemagicToken);
87
+ if (ghConfigured) {
88
+ console.log('GitHub Actions: CM_API_TOKEN secret configured.');
89
+ } else if (tokens.codemagicToken) {
90
+ console.log('GitHub Actions: secret not set (gh CLI unavailable or not authenticated).');
91
+ }
92
+ }
package/src/install.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import { existsSync, rmSync, cpSync } from 'node:fs';
2
2
  import { join } from 'node:path';
3
3
  import { homedir } from 'node:os';
4
- import { execSync, execFileSync } from 'node:child_process';
4
+ import { execSync } from 'node:child_process';
5
5
  import {
6
6
  MARKETPLACE_DIR, KNOWN_MP_PATH, CACHE_DIR,
7
7
  MARKETPLACE_NAME, PLUGIN_REF,
@@ -9,10 +9,10 @@ import {
9
9
  } from './utils.mjs';
10
10
  import { injectEnvVars, injectStatusLine } from './settings.mjs';
11
11
  import { promptForTokens } from './prompt.mjs';
12
- import { getMcpServers, writeMcpJson, updateMcpAppId, updateMcpTeamId } from './mcp-setup.mjs';
12
+ import { getMcpServers, writeMcpJson } from './mcp-setup.mjs';
13
13
  import { installClaudeMd, installCiTemplates, installFirebaseTemplates } from './templates.mjs';
14
- import { findAppByRepo, addApp, normalizeRepoUrl } from './codemagic-api.mjs';
15
- import { writeCiAppId, writeCiTeamId, writeCiBundleId, writeCiPackageName } from './ci-config.mjs';
14
+ import { writeCiBundleId, writeCiPackageName } from './ci-config.mjs';
15
+ import { installGitHubActionsPath, installCodemagicPath } from './install-paths.mjs';
16
16
 
17
17
  function checkClaudeCli() {
18
18
  const result = exec('command -v claude') || exec('which claude');
@@ -94,61 +94,19 @@ function printSummary(scope, oldVersion, newVersion) {
94
94
  }
95
95
  }
96
96
 
97
- function setupGitHubActions(codemagicToken) {
98
- if (!codemagicToken) return false;
99
-
100
- try {
101
- execFileSync('which', ['gh'], { encoding: 'utf8', stdio: 'pipe' });
102
- const authStatus = execFileSync('gh', ['auth', 'status'], { encoding: 'utf8', stdio: 'pipe' });
103
- if (authStatus.includes('not logged')) return false;
104
-
105
- execFileSync('gh', ['secret', 'set', 'CM_API_TOKEN', '--body', codemagicToken], {
106
- encoding: 'utf8',
107
- stdio: 'pipe',
108
- });
109
- return true;
110
- } catch {
111
- return false;
112
- }
113
- }
114
-
115
- async function setupCodemagicApp(projectDir, codemagicToken, codemagicTeamId) {
116
- if (!codemagicToken) return;
117
-
118
- let repoUrl;
119
- try {
120
- const raw = execSync('git remote get-url origin', {
121
- encoding: 'utf8',
122
- stdio: ['pipe', 'pipe', 'pipe'],
123
- }).trim();
124
- if (!raw) return;
125
- repoUrl = normalizeRepoUrl(raw);
126
- } catch {
127
- return;
128
- }
129
-
130
- try {
131
- let app = await findAppByRepo(codemagicToken, repoUrl);
132
- if (!app) {
133
- app = await addApp(codemagicToken, repoUrl, codemagicTeamId);
134
- console.log(`Codemagic app created: ${app.appName || app._id}`);
135
- } else {
136
- console.log(`Codemagic app found: ${app.appName || app._id}`);
137
- }
138
-
139
- const written = writeCiAppId(projectDir, app._id);
140
- if (written) {
141
- console.log(`Codemagic app_id written to ci.config.yaml`);
142
- }
143
-
144
- updateMcpAppId(projectDir, app._id);
145
-
146
- if (codemagicTeamId) {
147
- writeCiTeamId(projectDir, codemagicTeamId);
148
- updateMcpTeamId(projectDir, codemagicTeamId);
149
- }
150
- } catch (err) {
151
- console.log(`Codemagic auto-setup skipped: ${err.message || err}`);
97
+ function printNextSteps(isGitHubActions) {
98
+ console.log('');
99
+ console.log('Next steps:');
100
+ if (isGitHubActions) {
101
+ console.log(' 1. Fill ci.config.yaml with credentials');
102
+ console.log(' 2. Add creds/AuthKey.p8 and creds/play-service-account.json');
103
+ console.log(' 3. Set MATCH_PASSWORD secret in GitHub repository settings');
104
+ console.log(' 4. Start Claude Code');
105
+ } else {
106
+ console.log(' 1. Fill ci.config.yaml (codemagic.app_id is auto-configured if token was provided)');
107
+ console.log(' 2. Add creds/AuthKey.p8 and creds/play-service-account.json');
108
+ console.log(' 3. Start Claude Code');
109
+ console.log(' Note: For auto-trigger, install gh CLI and run "gh auth login"');
152
110
  }
153
111
  }
154
112
 
@@ -157,11 +115,18 @@ export async function runInstall(scope, isPostinstall = false, cliTokens = {}) {
157
115
 
158
116
  console.log('Installing/updating Daemux Store Automator...');
159
117
 
160
- const tokens = await promptForTokens(cliTokens);
118
+ const isGitHubActions = Boolean(cliTokens.githubActions);
119
+
120
+ const tokens = isGitHubActions
121
+ ? { bundleId: cliTokens.bundleId ?? '' }
122
+ : await promptForTokens(cliTokens);
161
123
 
162
124
  const projectDir = process.cwd();
163
- const servers = getMcpServers(tokens);
164
- writeMcpJson(projectDir, servers);
125
+
126
+ if (!isGitHubActions) {
127
+ const servers = getMcpServers(tokens);
128
+ writeMcpJson(projectDir, servers);
129
+ }
165
130
 
166
131
  const oldVersion = readMarketplaceVersion();
167
132
  const packageDir = getPackageDir();
@@ -189,7 +154,11 @@ export async function runInstall(scope, isPostinstall = false, cliTokens = {}) {
189
154
  writeCiPackageName(projectDir, tokens.bundleId);
190
155
  }
191
156
 
192
- await setupCodemagicApp(projectDir, tokens.codemagicToken, tokens.codemagicTeamId);
157
+ if (isGitHubActions) {
158
+ installGitHubActionsPath(projectDir, packageDir, cliTokens);
159
+ } else {
160
+ await installCodemagicPath(projectDir, tokens);
161
+ }
193
162
 
194
163
  const scopeLabel = scope === 'user' ? 'global' : 'project';
195
164
  console.log(`Configuring ${scopeLabel} settings...`);
@@ -197,20 +166,6 @@ export async function runInstall(scope, isPostinstall = false, cliTokens = {}) {
197
166
  injectEnvVars(settingsPath);
198
167
  injectStatusLine(settingsPath);
199
168
 
200
- const ghConfigured = setupGitHubActions(tokens.codemagicToken);
201
- if (ghConfigured) {
202
- console.log('GitHub Actions: CM_API_TOKEN secret configured.');
203
- } else if (tokens.codemagicToken) {
204
- console.log('GitHub Actions: secret not set (gh CLI unavailable or not authenticated).');
205
- }
206
-
207
169
  printSummary(scope, oldVersion, newVersion);
208
- console.log('');
209
- console.log('Next steps:');
210
- console.log(' 1. Fill ci.config.yaml (codemagic.app_id is auto-configured if token was provided)');
211
- console.log(' 2. Add creds/AuthKey.p8 and creds/play-service-account.json');
212
- console.log(' 3. Start Claude Code');
213
- if (!ghConfigured) {
214
- console.log(' Note: For auto-trigger, install gh CLI and run "gh auth login"');
215
- }
170
+ printNextSteps(isGitHubActions);
216
171
  }