@daemux/store-automator 0.5.3 → 0.6.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.
@@ -5,14 +5,14 @@
5
5
  },
6
6
  "metadata": {
7
7
  "description": "App Store & Google Play automation for Flutter apps",
8
- "version": "0.5.3"
8
+ "version": "0.6.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.5.3",
15
+ "version": "0.6.0",
16
16
  "keywords": ["flutter", "app-store", "google-play", "fastlane", "codemagic"]
17
17
  }
18
18
  ]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@daemux/store-automator",
3
- "version": "0.5.3",
3
+ "version": "0.6.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.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "App Store & Google Play automation agents for Flutter app publishing",
5
5
  "author": {
6
6
  "name": "Daemux"
@@ -0,0 +1,23 @@
1
+ import { readFileSync, writeFileSync, existsSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+
4
+ const CI_CONFIG_FILE = 'ci.config.yaml';
5
+ const APP_ID_PATTERN = /^(\s*app_id:\s*)"[^"]*"/m;
6
+
7
+ export function writeCiAppId(projectDir, appId) {
8
+ const configPath = join(projectDir, CI_CONFIG_FILE);
9
+ if (!existsSync(configPath)) return false;
10
+
11
+ try {
12
+ const content = readFileSync(configPath, 'utf8');
13
+ if (!APP_ID_PATTERN.test(content)) return false;
14
+
15
+ const updated = content.replace(APP_ID_PATTERN, `$1"${appId}"`);
16
+ if (updated === content) return false;
17
+
18
+ writeFileSync(configPath, updated, 'utf8');
19
+ return true;
20
+ } catch {
21
+ return false;
22
+ }
23
+ }
@@ -1,20 +1,13 @@
1
1
  import { findAppByRepo, addApp, startBuild, getBuildStatus, normalizeRepoUrl } from './codemagic-api.mjs';
2
- import { exec } from './utils.mjs';
2
+ import { exec, resolveToken } from './utils.mjs';
3
3
  import { execFileSync } from 'child_process';
4
+ import { writeCiAppId } from './ci-config.mjs';
5
+ import { updateMcpAppId } from './mcp-setup.mjs';
4
6
 
5
7
  const POLL_INTERVAL_MS = 30_000;
6
8
  const POLL_TIMEOUT_MS = 15 * 60 * 1000;
7
9
  const TERMINAL_STATUSES = new Set(['finished', 'failed', 'canceled']);
8
10
 
9
- function resolveToken(tokenArg) {
10
- const token = process.env.CM_API_TOKEN || tokenArg;
11
- if (!token) {
12
- console.error('Codemagic API token required. Set CM_API_TOKEN or pass --token=...');
13
- process.exit(1);
14
- }
15
- return token;
16
- }
17
-
18
11
  function resolveRepoUrl() {
19
12
  const url = exec('git remote get-url origin');
20
13
  if (!url) {
@@ -130,12 +123,18 @@ export async function runCodemagicSetup(options) {
130
123
  }
131
124
 
132
125
  const appId = app._id;
126
+ const appIdWritten = writeCiAppId(process.cwd(), appId);
127
+ updateMcpAppId(process.cwd(), appId);
133
128
 
134
129
  if (!trigger) {
135
130
  console.log('\nSetup complete. Use --trigger to start a build.\n');
131
+ if (appIdWritten) {
132
+ console.log('codemagic.app_id written to ci.config.yaml.');
133
+ } else {
134
+ console.log('Fill codemagic.app_id in ci.config.yaml manually.');
135
+ }
136
136
  console.log('To enable GitHub Actions auto-trigger:');
137
- console.log(' 1. Fill codemagic.app_id in ci.config.yaml');
138
- console.log(' 2. Run: npx @daemux/store-automator --github-setup');
137
+ console.log(' Run: npx @daemux/store-automator --github-setup');
139
138
  return { appId, buildId: null, status: null };
140
139
  }
141
140
 
@@ -1,15 +1,6 @@
1
- import { exec } from './utils.mjs';
1
+ import { exec, resolveToken } from './utils.mjs';
2
2
  import { execFileSync } from 'child_process';
3
3
 
4
- function resolveToken(tokenArg) {
5
- const token = process.env.CM_API_TOKEN || tokenArg;
6
- if (!token) {
7
- console.error('Codemagic API token required. Set CM_API_TOKEN or pass --token=...');
8
- process.exit(1);
9
- }
10
- return token;
11
- }
12
-
13
4
  function checkGhCli() {
14
5
  const ghPath = exec('which gh');
15
6
  if (!ghPath) {
@@ -47,6 +38,6 @@ export async function runGitHubSetup(options) {
47
38
  setGitHubSecret('CM_API_TOKEN', token);
48
39
 
49
40
  console.log('\nGitHub Actions setup complete.');
50
- console.log('Next: Fill codemagic.app_id in ci.config.yaml.');
41
+ console.log('Next: Verify codemagic.app_id in ci.config.yaml (auto-configured during install).');
51
42
  console.log('GitHub Actions will trigger configured Codemagic workflows on push to main.');
52
43
  }
package/src/install.mjs CHANGED
@@ -9,8 +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 } from './mcp-setup.mjs';
12
+ import { getMcpServers, writeMcpJson, updateMcpAppId } 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 } from './ci-config.mjs';
14
16
 
15
17
  function checkClaudeCli() {
16
18
  const result = exec('command -v claude') || exec('which claude');
@@ -110,6 +112,41 @@ function setupGitHubActions(codemagicToken) {
110
112
  }
111
113
  }
112
114
 
115
+ async function setupCodemagicApp(projectDir, codemagicToken) {
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);
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
+ } catch (err) {
146
+ console.log(`Codemagic auto-setup skipped: ${err.message || err}`);
147
+ }
148
+ }
149
+
113
150
  export async function runInstall(scope, isPostinstall = false, cliTokens = {}) {
114
151
  checkClaudeCli();
115
152
 
@@ -141,6 +178,8 @@ export async function runInstall(scope, isPostinstall = false, cliTokens = {}) {
141
178
  installCiTemplates(projectDir, packageDir);
142
179
  installFirebaseTemplates(projectDir, packageDir);
143
180
 
181
+ await setupCodemagicApp(projectDir, tokens.codemagicToken);
182
+
144
183
  const scopeLabel = scope === 'user' ? 'global' : 'project';
145
184
  console.log(`Configuring ${scopeLabel} settings...`);
146
185
  const settingsPath = join(baseDir, 'settings.json');
@@ -157,7 +196,7 @@ export async function runInstall(scope, isPostinstall = false, cliTokens = {}) {
157
196
  printSummary(scope, oldVersion, newVersion);
158
197
  console.log('');
159
198
  console.log('Next steps:');
160
- console.log(' 1. Fill ci.config.yaml (including codemagic.app_id)');
199
+ console.log(' 1. Fill ci.config.yaml (codemagic.app_id is auto-configured if token was provided)');
161
200
  console.log(' 2. Add creds/AuthKey.p8 and creds/play-service-account.json');
162
201
  console.log(' 3. Start Claude Code');
163
202
  if (!ghConfigured) {
package/src/mcp-setup.mjs CHANGED
@@ -33,10 +33,12 @@ export function getMcpServers(tokens) {
33
33
  }
34
34
 
35
35
  if (tokens.codemagicToken) {
36
+ const codemagicEnv = { CODEMAGIC_API_TOKEN: tokens.codemagicToken };
37
+ if (tokens.codemagicAppId) codemagicEnv.CODEMAGIC_APP_ID = tokens.codemagicAppId;
36
38
  servers.codemagic = {
37
39
  command: 'npx',
38
40
  args: ['-y', '@daemux/codemagic-mcp@latest'],
39
- env: { CODEMAGIC_API_TOKEN: tokens.codemagicToken },
41
+ env: codemagicEnv,
40
42
  };
41
43
  }
42
44
 
@@ -75,6 +77,21 @@ export function writeMcpJson(projectDir, servers) {
75
77
  }
76
78
  }
77
79
 
80
+ export function updateMcpAppId(projectDir, appId) {
81
+ const mcpPath = join(projectDir, '.mcp.json');
82
+ if (!existsSync(mcpPath)) return false;
83
+
84
+ try {
85
+ const data = readJson(mcpPath);
86
+ if (!data.mcpServers?.codemagic?.env) return false;
87
+ data.mcpServers.codemagic.env.CODEMAGIC_APP_ID = appId;
88
+ writeJson(mcpPath, data);
89
+ return true;
90
+ } catch {
91
+ return false;
92
+ }
93
+ }
94
+
78
95
  export function removeMcpServers(projectDir) {
79
96
  const mcpPath = join(projectDir, '.mcp.json');
80
97
  if (!existsSync(mcpPath)) return;
package/src/utils.mjs CHANGED
@@ -44,3 +44,12 @@ export function readJson(filePath) {
44
44
  export function writeJson(filePath, data) {
45
45
  writeFileSync(filePath, JSON.stringify(data, null, 2) + '\n', 'utf8');
46
46
  }
47
+
48
+ export function resolveToken(tokenArg) {
49
+ const token = process.env.CM_API_TOKEN || tokenArg;
50
+ if (!token) {
51
+ console.error('Codemagic API token required. Set CM_API_TOKEN or pass --token=...');
52
+ process.exit(1);
53
+ }
54
+ return token;
55
+ }