@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.
- package/.claude-plugin/marketplace.json +2 -2
- package/bin/cli.mjs +38 -14
- package/package.json +1 -1
- package/plugins/store-automator/.claude-plugin/plugin.json +1 -1
- package/plugins/store-automator/agents/appstore-meta-creator.md +13 -8
- package/plugins/store-automator/agents/architect.md +42 -1
- package/plugins/store-automator/agents/devops.md +26 -27
- package/scripts/check_google_play.py +1 -1
- package/scripts/manage_version_ios.py +1 -1
- package/src/ci-config.mjs +21 -0
- package/src/install-paths.mjs +92 -0
- package/src/install.mjs +33 -78
- package/src/templates.mjs +71 -1
- package/templates/CLAUDE.md.template +70 -16
- package/templates/Matchfile.template +8 -0
- package/templates/ci.config.yaml.template +3 -0
- package/templates/codemagic.template.yaml +131 -96
- package/templates/fastlane/android/Fastfile.template +23 -5
- package/templates/fastlane/ios/Fastfile.template +4 -3
- package/templates/github/workflows/android-release.yml +141 -0
- package/templates/github/workflows/codemagic-trigger.yml +15 -5
- package/templates/github/workflows/ios-release.yml +119 -0
- package/templates/scripts/check_google_play.py +1 -1
- package/templates/scripts/ci/android/build.sh +50 -0
- package/templates/scripts/ci/android/check-readiness.sh +93 -0
- package/templates/scripts/ci/android/manage-version.sh +134 -0
- package/templates/scripts/ci/android/setup-keystore.sh +80 -0
- package/templates/scripts/ci/android/sync-iap.sh +63 -0
- package/templates/scripts/ci/android/update-data-safety.sh +65 -0
- package/templates/scripts/ci/android/upload-binary.sh +62 -0
- package/templates/scripts/ci/android/upload-metadata.sh +77 -0
- package/templates/scripts/ci/common/check-changed.sh +74 -0
- package/templates/scripts/ci/common/flutter-setup.sh +22 -0
- package/templates/scripts/ci/common/install-fastlane.sh +39 -0
- package/templates/scripts/ci/common/link-fastlane.sh +56 -0
- package/templates/scripts/ci/common/read-config.sh +74 -0
- package/templates/scripts/ci/ios/build.sh +91 -0
- package/templates/scripts/ci/ios/manage-version.sh +64 -0
- package/templates/scripts/ci/ios/set-build-number.sh +92 -0
- package/templates/scripts/ci/ios/setup-signing.sh +283 -0
- package/templates/scripts/ci/ios/sync-iap.sh +80 -0
- package/templates/scripts/ci/ios/upload-binary.sh +43 -0
- package/templates/scripts/ci/ios/upload-metadata.sh +82 -0
- package/templates/scripts/create_app_record.py +1 -1
- package/templates/scripts/manage_version_ios.py +1 -1
- 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.
|
|
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.
|
|
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
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
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 (
|
|
122
|
-
npx @daemux/store-automator --bundle-id=
|
|
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
|
@@ -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.
|
|
156
|
-
-
|
|
157
|
-
-
|
|
158
|
-
-
|
|
159
|
-
-
|
|
160
|
-
-
|
|
161
|
-
|
|
162
|
-
|
|
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 +
|
|
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 +
|
|
288
|
+
## Mode: database + deploy
|
|
287
289
|
|
|
288
|
-
|
|
290
|
+
Deploy Firestore security rules, indexes, and run data migration scripts. Firestore is NoSQL -- there are no SQL migrations.
|
|
289
291
|
|
|
290
|
-
### Security Rules
|
|
292
|
+
### Security Rules Deployment
|
|
291
293
|
|
|
292
|
-
1.
|
|
293
|
-
2.
|
|
294
|
-
3.
|
|
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
|
|
298
|
+
### Index Deployment
|
|
299
299
|
|
|
300
|
-
1.
|
|
301
|
-
2.
|
|
302
|
-
3.
|
|
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
|
|
304
|
+
### Data Migration Execution
|
|
306
305
|
|
|
307
|
-
For
|
|
308
|
-
1.
|
|
309
|
-
2. Run against
|
|
310
|
-
3.
|
|
311
|
-
4. Log progress and
|
|
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
|
|
317
|
-
CHANGES: [list of
|
|
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
|
|
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
|
|
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
|
|
12
|
+
import { getMcpServers, writeMcpJson } from './mcp-setup.mjs';
|
|
13
13
|
import { installClaudeMd, installCiTemplates, installFirebaseTemplates } from './templates.mjs';
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
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
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
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
|
|
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
|
-
|
|
164
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
}
|