@daemux/store-automator 0.10.62 → 0.10.63
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/README.md +38 -23
- package/bin/cli.mjs +10 -3
- package/package.json +1 -1
- package/plugins/store-automator/.claude-plugin/plugin.json +1 -1
- package/src/install.mjs +79 -78
- package/src/templates.mjs +1 -1
- package/src/uninstall.mjs +10 -6
|
@@ -5,14 +5,14 @@
|
|
|
5
5
|
},
|
|
6
6
|
"metadata": {
|
|
7
7
|
"description": "App Store & Google Play automation for Flutter apps",
|
|
8
|
-
"version": "0.10.
|
|
8
|
+
"version": "0.10.63"
|
|
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.10.
|
|
15
|
+
"version": "0.10.63",
|
|
16
16
|
"keywords": [
|
|
17
17
|
"flutter",
|
|
18
18
|
"app-store",
|
package/README.md
CHANGED
|
@@ -20,30 +20,46 @@ Plus CI/CD templates for GitHub Actions, Fastlane, web pages, and scripts.
|
|
|
20
20
|
|
|
21
21
|
## Installation
|
|
22
22
|
|
|
23
|
+
**Project (default):** Full install into your Flutter project -- agents, CI/CD templates, MCP servers, and interactive setup:
|
|
24
|
+
|
|
23
25
|
```bash
|
|
24
26
|
cd your-flutter-project
|
|
25
|
-
|
|
27
|
+
npx --yes @daemux/store-automator
|
|
26
28
|
```
|
|
27
29
|
|
|
28
|
-
The
|
|
30
|
+
The installer runs an interactive setup with five sections:
|
|
29
31
|
|
|
30
32
|
1. **App Identity** -- App name, bundle ID, package name, SKU, Apple ID
|
|
31
|
-
2. **Credentials** --
|
|
33
|
+
2. **Credentials** -- App Store Connect API key, Google Play service account, Android keystore, Match code signing
|
|
32
34
|
3. **Store Settings** -- iOS categories/pricing, Android track/rollout, metadata languages
|
|
33
35
|
4. **Web Settings** -- Domain, colors, company info, legal jurisdiction
|
|
34
|
-
5. **MCP Tokens** -- Stitch and Cloudflare API keys (optional
|
|
35
|
-
|
|
36
|
-
All values are written to `ci.config.yaml`. The installer also:
|
|
36
|
+
5. **MCP Tokens** -- Stitch and Cloudflare API keys (optional)
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
- Installs `.claude/CLAUDE.md` with your app name and agent configurations
|
|
40
|
-
- Copies CI/CD templates (Fastlane, scripts, web pages, GitHub Actions)
|
|
41
|
-
- Configures `.claude/settings.json` with required env vars
|
|
42
|
-
- Runs post-install guides for GitHub repo setup, secrets, and Firebase
|
|
38
|
+
All values are written to `ci.config.yaml`. The installer also configures `.mcp.json`, installs `.claude/CLAUDE.md`, copies CI/CD templates, and configures `.claude/settings.json`.
|
|
43
39
|
|
|
44
40
|
Re-running the installer reads existing `ci.config.yaml` values as defaults, so you can update individual fields without re-entering everything.
|
|
45
41
|
|
|
46
|
-
|
|
42
|
+
**Global (agents only):** Install the plugin into `~/.claude` for use across all projects, without touching the current directory:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
npx --yes @daemux/store-automator --global
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Global install:
|
|
49
|
+
|
|
50
|
+
- Registers the marketplace and installs the plugin at user scope
|
|
51
|
+
- Writes `~/.claude/CLAUDE.md` with agent configurations
|
|
52
|
+
- Adds required env vars and statusLine to `~/.claude/settings.json`
|
|
53
|
+
|
|
54
|
+
Global install does NOT:
|
|
55
|
+
|
|
56
|
+
- Create `ci.config.yaml`, `fastlane/`, `scripts/`, `web/`, `Gemfile`, `.github/workflows/`, or any other project files
|
|
57
|
+
- Write or modify `.mcp.json` in the current directory
|
|
58
|
+
- Run any interactive prompts or post-install guides
|
|
59
|
+
|
|
60
|
+
Use project install for any Flutter app you are actually publishing. Global install is for agent-only access from arbitrary directories.
|
|
61
|
+
|
|
62
|
+
## After Installation _(project scope only)_
|
|
47
63
|
|
|
48
64
|
1. Add any credential files not configured during the guided setup:
|
|
49
65
|
- `creds/AuthKey.p8` -- Apple App Store Connect API key
|
|
@@ -52,7 +68,7 @@ Re-running the installer reads existing `ci.config.yaml` values as defaults, so
|
|
|
52
68
|
2. Verify `ci.config.yaml` has all required values filled in
|
|
53
69
|
3. Start Claude Code and use the agents
|
|
54
70
|
|
|
55
|
-
## Manual Setup
|
|
71
|
+
## Manual Setup _(project scope only)_
|
|
56
72
|
|
|
57
73
|
If postinstall was skipped (CI environment), run manually:
|
|
58
74
|
|
|
@@ -240,19 +256,18 @@ web:
|
|
|
240
256
|
google_play_url: "" # Filled after first Android publish
|
|
241
257
|
```
|
|
242
258
|
|
|
243
|
-
##
|
|
259
|
+
## Uninstall
|
|
244
260
|
|
|
245
|
-
|
|
261
|
+
**Project uninstall:** Removes CI templates, `ci.config.yaml`, `.mcp.json` entries, `.claude/CLAUDE.md`, and settings from the current project. Marketplace files remain in `~/.claude/plugins/`.
|
|
246
262
|
|
|
247
263
|
```bash
|
|
248
|
-
npx @daemux/store-automator
|
|
264
|
+
npx --yes @daemux/store-automator --uninstall
|
|
249
265
|
```
|
|
250
266
|
|
|
251
|
-
|
|
267
|
+
**Global uninstall:** Removes the plugin from `~/.claude` and clears the marketplace. Does NOT touch the current project's `ci.config.yaml`, CI templates, or `.mcp.json`.
|
|
252
268
|
|
|
253
269
|
```bash
|
|
254
|
-
npx @daemux/store-automator
|
|
255
|
-
npx @daemux/store-automator -g -u # global scope
|
|
270
|
+
npx --yes @daemux/store-automator --global --uninstall
|
|
256
271
|
```
|
|
257
272
|
|
|
258
273
|
## Agents
|
|
@@ -269,7 +284,7 @@ Designs complete app UI screens, creates ASO-optimized store screenshots for all
|
|
|
269
284
|
|
|
270
285
|
Reviews all metadata, screenshots, privacy policy, and IAP configuration against Apple and Google guidelines. Returns APPROVED or REJECTED with specific issues.
|
|
271
286
|
|
|
272
|
-
## CI/CD Templates
|
|
287
|
+
## CI/CD Templates _(project scope only)_
|
|
273
288
|
|
|
274
289
|
The package installs these templates to your project:
|
|
275
290
|
|
|
@@ -282,7 +297,7 @@ The package installs these templates to your project:
|
|
|
282
297
|
| `web/` | Marketing, privacy, terms, and support page templates |
|
|
283
298
|
| `Gemfile` | Ruby gems for Fastlane |
|
|
284
299
|
|
|
285
|
-
## Workflow
|
|
300
|
+
## Workflow _(project scope only)_
|
|
286
301
|
|
|
287
302
|
1. Install the package (interactive setup fills `ci.config.yaml`)
|
|
288
303
|
2. Add any remaining credential files
|
|
@@ -291,7 +306,7 @@ The package installs these templates to your project:
|
|
|
291
306
|
5. Use `appstore-reviewer` to verify compliance
|
|
292
307
|
6. Push to GitHub -- GitHub Actions builds and publishes automatically
|
|
293
308
|
|
|
294
|
-
## MCP Servers
|
|
309
|
+
## MCP Servers _(project scope only)_
|
|
295
310
|
|
|
296
311
|
The package configures these MCP servers in `.mcp.json`:
|
|
297
312
|
|
|
@@ -302,7 +317,7 @@ The package configures these MCP servers in `.mcp.json`:
|
|
|
302
317
|
| stitch | AI design tool for screenshot generation | `STITCH_API_KEY` |
|
|
303
318
|
| cloudflare | Cloudflare Pages deployment | `CLOUDFLARE_API_TOKEN` + Account ID |
|
|
304
319
|
|
|
305
|
-
## Idempotency
|
|
320
|
+
## Idempotency _(project scope only)_
|
|
306
321
|
|
|
307
322
|
The installer is idempotent. Re-running it reads existing values from `ci.config.yaml` as defaults for each prompt. This means you can:
|
|
308
323
|
|
package/bin/cli.mjs
CHANGED
|
@@ -9,8 +9,6 @@ const __filename = fileURLToPath(import.meta.url);
|
|
|
9
9
|
const __dirname = dirname(__filename);
|
|
10
10
|
const pkg = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf8'));
|
|
11
11
|
|
|
12
|
-
const notifier = updateNotifier({ pkg });
|
|
13
|
-
|
|
14
12
|
const args = process.argv.slice(2);
|
|
15
13
|
let scope = 'project';
|
|
16
14
|
let action = 'install';
|
|
@@ -146,6 +144,13 @@ Examples:
|
|
|
146
144
|
}
|
|
147
145
|
}
|
|
148
146
|
|
|
147
|
+
if (scope === 'user' && cliTokens.githubActions) {
|
|
148
|
+
console.error('Error: --github-actions and --global are mutually exclusive.');
|
|
149
|
+
console.error(' --global targets ~/.claude (no CI templates).');
|
|
150
|
+
console.error(' --github-actions targets a project repo. Pick one.');
|
|
151
|
+
process.exit(1);
|
|
152
|
+
}
|
|
153
|
+
|
|
149
154
|
if (cliTokens.githubActions) {
|
|
150
155
|
const missing = [];
|
|
151
156
|
if (!cliTokens.matchDeployKey) missing.push('--match-deploy-key');
|
|
@@ -163,7 +168,9 @@ if (cliTokens.githubActions) {
|
|
|
163
168
|
}
|
|
164
169
|
}
|
|
165
170
|
|
|
166
|
-
|
|
171
|
+
if (!isPostinstall) {
|
|
172
|
+
updateNotifier({ pkg }).notify();
|
|
173
|
+
}
|
|
167
174
|
|
|
168
175
|
try {
|
|
169
176
|
if (action === 'uninstall') {
|
package/package.json
CHANGED
package/src/install.mjs
CHANGED
|
@@ -152,7 +152,39 @@ function printNextSteps(prompted) {
|
|
|
152
152
|
}
|
|
153
153
|
}
|
|
154
154
|
|
|
155
|
+
async function withReadline(fn) {
|
|
156
|
+
const { createInterface } = await import('node:readline');
|
|
157
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
158
|
+
try {
|
|
159
|
+
return await fn(rl);
|
|
160
|
+
} finally {
|
|
161
|
+
rl.close();
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function configureScopedSettings(baseDir, packageDir, appName, scopeLabel) {
|
|
166
|
+
ensureDir(baseDir);
|
|
167
|
+
installClaudeMd(join(baseDir, 'CLAUDE.md'), packageDir, appName);
|
|
168
|
+
console.log(`Configuring ${scopeLabel} settings...`);
|
|
169
|
+
const settingsPath = join(baseDir, 'settings.json');
|
|
170
|
+
injectEnvVars(settingsPath);
|
|
171
|
+
injectStatusLine(settingsPath);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function printGlobalNote() {
|
|
175
|
+
console.log('');
|
|
176
|
+
console.log('Note: Global install registers the marketplace and installs ~/.claude/CLAUDE.md only.');
|
|
177
|
+
console.log('To generate CI/CD templates, MCP config, and ci.config.yaml, run `npx @daemux/store-automator` inside a project directory.');
|
|
178
|
+
}
|
|
179
|
+
|
|
155
180
|
export async function runInstall(scope, isPostinstall = false, cliTokens = {}) {
|
|
181
|
+
const isGlobal = scope === 'user';
|
|
182
|
+
|
|
183
|
+
if (isPostinstall && isGlobal) {
|
|
184
|
+
console.log('Skipping postinstall in global scope.');
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
|
|
156
188
|
checkClaudeCli();
|
|
157
189
|
|
|
158
190
|
console.log('Installing/updating Daemux Store Automator...');
|
|
@@ -160,102 +192,71 @@ export async function runInstall(scope, isPostinstall = false, cliTokens = {}) {
|
|
|
160
192
|
const isGitHubActions = Boolean(cliTokens.githubActions);
|
|
161
193
|
const nonInteractive = Boolean(process.env.npm_config_yes) || process.argv.includes('--postinstall');
|
|
162
194
|
const projectDir = process.cwd();
|
|
163
|
-
const oldVersion = readMarketplaceVersion();
|
|
164
195
|
const packageDir = getPackageDir();
|
|
196
|
+
const oldVersion = readMarketplaceVersion();
|
|
165
197
|
|
|
166
|
-
// 1. Copy plugin files + register marketplace
|
|
167
198
|
copyPluginFiles(packageDir);
|
|
168
199
|
clearCache();
|
|
169
200
|
registerMarketplace();
|
|
170
201
|
runClaudeInstall(scope);
|
|
171
|
-
|
|
172
202
|
const newVersion = readMarketplaceVersion('unknown');
|
|
173
203
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
const currentConfig = readCiConfig(projectDir);
|
|
204
|
+
let prompted = {};
|
|
205
|
+
if (!isGlobal) {
|
|
206
|
+
installCiTemplates(projectDir, packageDir);
|
|
207
|
+
installFirebaseTemplates(projectDir, packageDir);
|
|
208
|
+
const currentConfig = readCiConfig(projectDir);
|
|
180
209
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
} else {
|
|
192
|
-
const { createInterface } = await import('node:readline');
|
|
193
|
-
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
194
|
-
try {
|
|
195
|
-
prompted = await promptAll(rl, cliTokens, currentConfig, projectDir);
|
|
196
|
-
} finally {
|
|
197
|
-
rl.close();
|
|
210
|
+
if (isGitHubActions) {
|
|
211
|
+
prompted = {
|
|
212
|
+
bundleId: cliTokens.bundleId ?? '',
|
|
213
|
+
matchDeployKeyPath: cliTokens.matchDeployKey,
|
|
214
|
+
matchGitUrl: cliTokens.matchGitUrl,
|
|
215
|
+
};
|
|
216
|
+
} else if (nonInteractive) {
|
|
217
|
+
prompted = { ...cliTokens };
|
|
218
|
+
} else {
|
|
219
|
+
prompted = await withReadline((rl) => promptAll(rl, cliTokens, currentConfig, projectDir));
|
|
198
220
|
}
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
// 5. Write all prompted values to ci.config.yaml
|
|
202
|
-
const ciFields = mapPromptsToCiFields(prompted);
|
|
203
|
-
const wrote = writeCiFields(projectDir, ciFields);
|
|
204
|
-
if (wrote) console.log('Configuration written to ci.config.yaml');
|
|
205
|
-
|
|
206
|
-
if (prompted.matchDeployKeyPath || prompted.matchGitUrl) {
|
|
207
|
-
const wroteMatch = writeMatchConfig(projectDir, {
|
|
208
|
-
deployKeyPath: prompted.matchDeployKeyPath,
|
|
209
|
-
gitUrl: prompted.matchGitUrl,
|
|
210
|
-
});
|
|
211
|
-
if (wroteMatch) console.log('Match credentials written to ci.config.yaml');
|
|
212
|
-
}
|
|
213
221
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
const langStr = Array.isArray(prompted.languages)
|
|
217
|
-
? prompted.languages.join(',')
|
|
218
|
-
: prompted.languages;
|
|
219
|
-
if (writeCiLanguages(projectDir, langStr)) {
|
|
220
|
-
console.log('Languages updated in ci.config.yaml');
|
|
222
|
+
if (writeCiFields(projectDir, mapPromptsToCiFields(prompted))) {
|
|
223
|
+
console.log('Configuration written to ci.config.yaml');
|
|
221
224
|
}
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
// 7. Configure MCP, CLAUDE.md, settings
|
|
225
|
-
if (!isGitHubActions) {
|
|
226
|
-
const servers = getMcpServers(prompted);
|
|
227
|
-
writeMcpJson(projectDir, servers);
|
|
228
|
-
}
|
|
229
225
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
226
|
+
if (prompted.matchDeployKeyPath || prompted.matchGitUrl) {
|
|
227
|
+
const wroteMatch = writeMatchConfig(projectDir, {
|
|
228
|
+
deployKeyPath: prompted.matchDeployKeyPath,
|
|
229
|
+
gitUrl: prompted.matchGitUrl,
|
|
230
|
+
});
|
|
231
|
+
if (wroteMatch) console.log('Match credentials written to ci.config.yaml');
|
|
232
|
+
}
|
|
237
233
|
|
|
238
|
-
|
|
234
|
+
if (prompted.languages) {
|
|
235
|
+
const langStr = Array.isArray(prompted.languages) ? prompted.languages.join(',') : prompted.languages;
|
|
236
|
+
if (writeCiLanguages(projectDir, langStr)) {
|
|
237
|
+
console.log('Languages updated in ci.config.yaml');
|
|
238
|
+
}
|
|
239
|
+
}
|
|
239
240
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
const settingsPath = join(baseDir, 'settings.json');
|
|
243
|
-
injectEnvVars(settingsPath);
|
|
244
|
-
injectStatusLine(settingsPath);
|
|
241
|
+
if (!isGitHubActions) writeMcpJson(projectDir, getMcpServers(prompted));
|
|
242
|
+
installGitHubActionsPath(projectDir, packageDir, prompted);
|
|
245
243
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
const { runPostInstallGuides } = await import('./prompts/store-settings.mjs');
|
|
252
|
-
await runPostInstallGuides(guideRl, currentConfig);
|
|
253
|
-
} finally {
|
|
254
|
-
guideRl.close();
|
|
244
|
+
if (!isGitHubActions && !nonInteractive) {
|
|
245
|
+
await withReadline(async (rl) => {
|
|
246
|
+
const { runPostInstallGuides } = await import('./prompts/store-settings.mjs');
|
|
247
|
+
await runPostInstallGuides(rl, currentConfig);
|
|
248
|
+
});
|
|
255
249
|
}
|
|
256
250
|
}
|
|
257
251
|
|
|
258
|
-
|
|
252
|
+
const baseDir = isGlobal ? join(homedir(), '.claude') : join(projectDir, '.claude');
|
|
253
|
+
const appName = prompted.appName || (isGlobal ? 'your app' : undefined);
|
|
254
|
+
configureScopedSettings(baseDir, packageDir, appName, isGlobal ? 'global' : 'project');
|
|
255
|
+
|
|
259
256
|
printSummary(scope, oldVersion, newVersion);
|
|
260
|
-
|
|
257
|
+
if (isGlobal) {
|
|
258
|
+
printGlobalNote();
|
|
259
|
+
} else {
|
|
260
|
+
printNextSteps(prompted);
|
|
261
|
+
}
|
|
261
262
|
}
|
package/src/templates.mjs
CHANGED
|
@@ -55,7 +55,7 @@ export function installClaudeMd(targetPath, packageDir, appName) {
|
|
|
55
55
|
|
|
56
56
|
let content = readFileSync(template, 'utf8');
|
|
57
57
|
if (appName) {
|
|
58
|
-
content = content.
|
|
58
|
+
content = content.split('{APP_NAME}').join(appName);
|
|
59
59
|
}
|
|
60
60
|
writeFileSync(targetPath, content, 'utf8');
|
|
61
61
|
}
|
package/src/uninstall.mjs
CHANGED
|
@@ -86,11 +86,15 @@ export async function runUninstall(scope) {
|
|
|
86
86
|
|
|
87
87
|
runClaudeUninstall(scope);
|
|
88
88
|
|
|
89
|
+
let doneMessage;
|
|
89
90
|
if (scope === 'user') {
|
|
90
91
|
console.log('Removing marketplace...');
|
|
91
92
|
rmSync(MARKETPLACE_DIR, { recursive: true, force: true });
|
|
92
93
|
rmSync(CACHE_DIR, { recursive: true, force: true });
|
|
93
94
|
unregisterMarketplace();
|
|
95
|
+
doneMessage = '\nDone! store-automator uninstalled globally.';
|
|
96
|
+
} else {
|
|
97
|
+
doneMessage = '\nDone! store-automator uninstalled from this project.\n\nNote: Marketplace files remain under ~/.claude/plugins/marketplaces.\nRun with --global --uninstall to remove marketplace completely.';
|
|
94
98
|
}
|
|
95
99
|
|
|
96
100
|
const isGlobal = scope === 'user';
|
|
@@ -98,15 +102,15 @@ export async function runUninstall(scope) {
|
|
|
98
102
|
const scopeLabel = isGlobal ? 'global' : 'project';
|
|
99
103
|
|
|
100
104
|
removeFileIfExists(join(baseDir, 'CLAUDE.md'), `${scopeLabel} CLAUDE.md`);
|
|
101
|
-
|
|
102
|
-
|
|
105
|
+
|
|
106
|
+
if (!isGlobal) {
|
|
107
|
+
removeCiTemplates(process.cwd());
|
|
108
|
+
removeMcpServers(process.cwd());
|
|
109
|
+
}
|
|
103
110
|
|
|
104
111
|
console.log(`Cleaning ${scopeLabel} settings...`);
|
|
105
112
|
removeEnvVars(join(baseDir, 'settings.json'));
|
|
106
113
|
removeStatusLine(join(baseDir, 'settings.json'));
|
|
107
114
|
|
|
108
|
-
console.log(
|
|
109
|
-
? '\nDone! store-automator uninstalled globally.'
|
|
110
|
-
: `\nDone! store-automator uninstalled from this project.\n\nNote: Marketplace files remain in ${MARKETPLACE_DIR}\nRun with --global --uninstall to remove marketplace completely.`
|
|
111
|
-
);
|
|
115
|
+
console.log(doneMessage);
|
|
112
116
|
}
|