appship-cli 0.1.1 → 0.1.3
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/README.md +1 -1
- package/dist/{chunk-TLOV7VBN.js → chunk-3AIOX537.js} +1 -1
- package/dist/{chunk-WWHJBKI3.js → chunk-5TUBDRZQ.js} +22 -6
- package/dist/{chunk-CVYD5FVI.js → chunk-RKHEDQIO.js} +1 -1
- package/dist/{flutter-D6ZOT4JJ.js → flutter-Q36WBCAC.js} +2 -2
- package/dist/index.js +14 -8
- package/dist/{native-RCWBM6UF.js → native-AVSHQSRP.js} +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -53,7 +53,7 @@ Store policies change between releases, so the doctor rules and SDK signature da
|
|
|
53
53
|
|
|
54
54
|
`generate`, `localize`, and `review analyze` call an AI provider — Anthropic by default (`ANTHROPIC_API_KEY` or `ant auth login`), and any OpenAI-compatible endpoint via `ai.provider` in appship.yml: `gemini` (free keys at [aistudio.google.com](https://aistudio.google.com/apikey), `GEMINI_API_KEY`, default model `gemini-2.5-flash`), `openai` (`OPENAI_API_KEY`), `ollama` (local, set `ai.model`), or `openai-compatible` (set `ai.base_url` + `ai.model` — works with OpenRouter, Groq, and self-hosted servers). Store character limits are validated with retry regardless of provider. `init` and `doctor` run fully offline. Translations go through the same validation as generation; App Review notes are copied, not translated.
|
|
55
55
|
|
|
56
|
-
Supported projects: React Native CLI, Expo (managed), Flutter, native iOS (`.xcodeproj` at the root), and native Android (`settings.gradle` + `app/` module) — identity and permissions are read from native files (`Info.plist`, `AndroidManifest.xml`, `project.pbxproj`, `build.gradle`), from the Expo config (`app.json` or a dynamic `app.config.js`/`.cjs`/`.mjs`, evaluated the
|
|
56
|
+
Supported projects: React Native CLI, Expo (managed), Flutter, native iOS (`.xcodeproj` at the root), and native Android (`settings.gradle` + `app/` module) — identity and permissions are read from native files (`Info.plist`, `AndroidManifest.xml`, `project.pbxproj`, `build.gradle`), from the Expo config (`app.json` or a dynamic `app.config.ts`/`.js`/`.cjs`/`.mjs`, evaluated by the project's Expo config loader), or from `pubspec.yaml`. SDK detection matches npm packages, Dart/Flutter packages, CocoaPods, and Gradle Maven coordinates, plus source patterns in JS/TS, Dart, Swift, Kotlin, and Java.
|
|
57
57
|
|
|
58
58
|
## Using doctor as a CI gate
|
|
59
59
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
APPSHIP_VERSION
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-RKHEDQIO.js";
|
|
5
5
|
|
|
6
6
|
// src/core/project/flutter.ts
|
|
7
7
|
import { readFile as readFile4 } from "fs/promises";
|
|
@@ -32,11 +32,11 @@ async function detectProjectType(projectRoot) {
|
|
|
32
32
|
if (pkg && "react-native" in deps) {
|
|
33
33
|
return "react-native";
|
|
34
34
|
}
|
|
35
|
-
const { readPubspec: readPubspec2, isFlutterPubspec: isFlutterPubspec2 } = await import("./flutter-
|
|
35
|
+
const { readPubspec: readPubspec2, isFlutterPubspec: isFlutterPubspec2 } = await import("./flutter-Q36WBCAC.js");
|
|
36
36
|
if (isFlutterPubspec2(await readPubspec2(projectRoot))) {
|
|
37
37
|
return "flutter";
|
|
38
38
|
}
|
|
39
|
-
const { findRootPbxproj, hasNativeAndroidLayout } = await import("./native-
|
|
39
|
+
const { findRootPbxproj, hasNativeAndroidLayout } = await import("./native-AVSHQSRP.js");
|
|
40
40
|
const { existsSync: existsSync2 } = await import("fs");
|
|
41
41
|
if (hasNativeAndroidLayout(projectRoot, existsSync2)) {
|
|
42
42
|
return "native-android";
|
|
@@ -52,9 +52,10 @@ async function detectProjectType(projectRoot) {
|
|
|
52
52
|
// src/core/project/expo.ts
|
|
53
53
|
import { readFile as readFile2 } from "fs/promises";
|
|
54
54
|
import { existsSync } from "fs";
|
|
55
|
+
import { createRequire } from "module";
|
|
55
56
|
import { join as join2 } from "path";
|
|
56
57
|
import { pathToFileURL } from "url";
|
|
57
|
-
var DYNAMIC_CONFIG_FILES = ["app.config.js", "app.config.cjs", "app.config.mjs"];
|
|
58
|
+
var DYNAMIC_CONFIG_FILES = ["app.config.ts", "app.config.js", "app.config.cjs", "app.config.mjs"];
|
|
58
59
|
async function readAppJsonExpo(projectRoot) {
|
|
59
60
|
try {
|
|
60
61
|
const raw = await readFile2(join2(projectRoot, "app.json"), "utf8");
|
|
@@ -72,11 +73,24 @@ function unwrap(value) {
|
|
|
72
73
|
}
|
|
73
74
|
return record;
|
|
74
75
|
}
|
|
76
|
+
function readConfigWithProjectExpo(projectRoot) {
|
|
77
|
+
try {
|
|
78
|
+
const requireFromProject = createRequire(join2(projectRoot, "package.json"));
|
|
79
|
+
const expoConfig = requireFromProject("expo/config");
|
|
80
|
+
const resolved = expoConfig.getConfig?.(projectRoot, { skipSDKVersionRequirement: true });
|
|
81
|
+
return unwrap(resolved?.exp);
|
|
82
|
+
} catch {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
75
86
|
async function readExpoConfig(projectRoot) {
|
|
76
87
|
const staticConfig = await readAppJsonExpo(projectRoot);
|
|
77
88
|
for (const file of DYNAMIC_CONFIG_FILES) {
|
|
78
89
|
const path = join2(projectRoot, file);
|
|
79
90
|
if (!existsSync(path)) continue;
|
|
91
|
+
if (file === "app.config.ts") {
|
|
92
|
+
return readConfigWithProjectExpo(projectRoot) ?? staticConfig;
|
|
93
|
+
}
|
|
80
94
|
try {
|
|
81
95
|
const mod = await import(pathToFileURL(path).href);
|
|
82
96
|
let exported = mod.default ?? mod;
|
|
@@ -161,8 +175,10 @@ async function analyzeReactNativeProject(projectRoot) {
|
|
|
161
175
|
]);
|
|
162
176
|
return {
|
|
163
177
|
projectType: "react-native",
|
|
164
|
-
|
|
165
|
-
|
|
178
|
+
// Expo's resolved config is the release source of truth. In particular it
|
|
179
|
+
// may intentionally differ from the JavaScript package name.
|
|
180
|
+
appName: expo?.name ?? appName ?? pkg?.name ?? null,
|
|
181
|
+
version: expo?.version ?? pkg?.version ?? null,
|
|
166
182
|
ios: { bundleId },
|
|
167
183
|
android: { packageName },
|
|
168
184
|
scannedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
package/dist/index.js
CHANGED
|
@@ -9,12 +9,14 @@ import {
|
|
|
9
9
|
readExpoConfig,
|
|
10
10
|
readPackageJson,
|
|
11
11
|
readPubspec
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-5TUBDRZQ.js";
|
|
13
13
|
import {
|
|
14
14
|
analyzeNativeAndroidProject,
|
|
15
15
|
analyzeNativeIosProject
|
|
16
|
-
} from "./chunk-
|
|
17
|
-
import
|
|
16
|
+
} from "./chunk-3AIOX537.js";
|
|
17
|
+
import {
|
|
18
|
+
APPSHIP_VERSION
|
|
19
|
+
} from "./chunk-RKHEDQIO.js";
|
|
18
20
|
import {
|
|
19
21
|
UploadError,
|
|
20
22
|
assertUploadLane,
|
|
@@ -1864,23 +1866,27 @@ async function builtInChecks(ctx, findings) {
|
|
|
1864
1866
|
message: ok ? passMessage : failMessage,
|
|
1865
1867
|
...extra
|
|
1866
1868
|
});
|
|
1869
|
+
const iosBundleId = scan.project.ios?.bundleId ?? config.platforms.ios?.bundle_id;
|
|
1870
|
+
const androidPackageName = scan.project.android?.packageName ?? config.platforms.android?.package_name;
|
|
1867
1871
|
push(
|
|
1868
1872
|
"app-store",
|
|
1869
1873
|
"bundle-id-configured",
|
|
1870
1874
|
"required",
|
|
1871
1875
|
"error",
|
|
1872
|
-
|
|
1876
|
+
iosBundleId != null,
|
|
1873
1877
|
"Bundle ID configured",
|
|
1874
|
-
"iOS bundle ID could not be detected"
|
|
1878
|
+
"iOS bundle ID could not be detected",
|
|
1879
|
+
iosBundleId && scan.project.ios?.bundleId == null ? { detail: `using appship.yml fallback: ${iosBundleId}` } : {}
|
|
1875
1880
|
);
|
|
1876
1881
|
push(
|
|
1877
1882
|
"google-play",
|
|
1878
1883
|
"package-name-configured",
|
|
1879
1884
|
"required",
|
|
1880
1885
|
"error",
|
|
1881
|
-
|
|
1886
|
+
androidPackageName != null,
|
|
1882
1887
|
"Android package name configured",
|
|
1883
|
-
"Android package name could not be detected"
|
|
1888
|
+
"Android package name could not be detected",
|
|
1889
|
+
androidPackageName && scan.project.android?.packageName == null ? { detail: `using appship.yml fallback: ${androidPackageName}` } : {}
|
|
1884
1890
|
);
|
|
1885
1891
|
const appIcon = await glob4("ios/**/AppIcon.appiconset", {
|
|
1886
1892
|
cwd: projectRoot,
|
|
@@ -3683,7 +3689,7 @@ var rulesCommand = new Command10("rules").description("Manage the store policy r
|
|
|
3683
3689
|
var program = new Command11();
|
|
3684
3690
|
program.name("appship").description(
|
|
3685
3691
|
"AI release assistant that analyzes your mobile app and prepares everything required for App Store and Google Play submission"
|
|
3686
|
-
).version(
|
|
3692
|
+
).version(APPSHIP_VERSION);
|
|
3687
3693
|
program.addCommand(initCommand);
|
|
3688
3694
|
program.addCommand(generateCommand);
|
|
3689
3695
|
program.addCommand(localizeCommand);
|
|
@@ -4,8 +4,8 @@ import {
|
|
|
4
4
|
analyzeNativeIosProject,
|
|
5
5
|
findRootPbxproj,
|
|
6
6
|
hasNativeAndroidLayout
|
|
7
|
-
} from "./chunk-
|
|
8
|
-
import "./chunk-
|
|
7
|
+
} from "./chunk-3AIOX537.js";
|
|
8
|
+
import "./chunk-RKHEDQIO.js";
|
|
9
9
|
export {
|
|
10
10
|
analyzeNativeAndroidProject,
|
|
11
11
|
analyzeNativeIosProject,
|
package/package.json
CHANGED