@lynxship/cli 0.1.16 → 0.1.19
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 +66 -6
- package/dist/bundle-build.d.ts +13 -0
- package/dist/bundle-build.d.ts.map +1 -1
- package/dist/bundle-build.js +69 -10
- package/dist/config.d.ts +15 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +60 -0
- package/dist/guidance.d.ts.map +1 -1
- package/dist/guidance.js +75 -0
- package/dist/index.js +180 -6
- package/dist/plugin-api.d.ts +2 -0
- package/dist/plugin-api.d.ts.map +1 -0
- package/dist/plugin-api.js +1 -0
- package/dist/plugins.d.ts +35 -0
- package/dist/plugins.d.ts.map +1 -0
- package/dist/plugins.js +595 -0
- package/package.json +15 -9
package/dist/index.js
CHANGED
|
@@ -10,6 +10,7 @@ import { assert, createId, sha256, } from "@lynxship/contracts";
|
|
|
10
10
|
import { createSigningKey, signManifest, } from "@lynxship/signing";
|
|
11
11
|
import { AppStoreConnectApiProvider, GooglePlayApiProvider, SubmissionService, } from "@lynxship/submit";
|
|
12
12
|
import { DEFAULT_CONFIG, loadConfig, platformValue, resolveProfile, } from "./config.js";
|
|
13
|
+
import { microHsHostTriple } from "@lynxship/microhs";
|
|
13
14
|
import { hasAndroidHost, isSupportedAndroidPlatform, runRealAndroidBuild, } from "./android-build.js";
|
|
14
15
|
import { initializeAndroidHost, suggestedAndroidApplicationId, } from "./android-host.js";
|
|
15
16
|
import { initializeIosHost, suggestedIosBundleIdentifier } from "./ios-host.js";
|
|
@@ -35,6 +36,7 @@ import { hasHarmonyHost, runRealHarmonyBuild } from "./harmony-build.js";
|
|
|
35
36
|
import { hasWebConfiguration, runRealWebBuild } from "./web-build.js";
|
|
36
37
|
import { hasDesktopHost, runRealDesktopBuild } from "./desktop-build.js";
|
|
37
38
|
import { extractDevServerUrl, shouldPrintDevServerQr } from "./dev-qr.js";
|
|
39
|
+
import { applyProjectPlugins, inspectProjectPlugins } from "./plugins.js";
|
|
38
40
|
import { inspectDesktopTarget, inspectHarmonyTarget, inspectWebTarget, } from "./target-toolchain.js";
|
|
39
41
|
const rawArgs = process.argv.slice(2);
|
|
40
42
|
const args = [...rawArgs];
|
|
@@ -216,7 +218,20 @@ async function executeBuild(options, showResult = true) {
|
|
|
216
218
|
// Host initialization can write lynxship.json (for example, the generated
|
|
217
219
|
// iOS scheme). Always read it again before resolving the build profile so a
|
|
218
220
|
// first build uses the host that was just created in the same invocation.
|
|
219
|
-
const
|
|
221
|
+
const loadedConfig = wait && !local ? await loadConfig(root) : config;
|
|
222
|
+
const pluginApplication = wait && !local
|
|
223
|
+
? await applyProjectPlugins(root, loadedConfig, { platform, profile })
|
|
224
|
+
: {
|
|
225
|
+
config: loadedConfig,
|
|
226
|
+
report: { configured: 0, plugins: [] },
|
|
227
|
+
applied: [],
|
|
228
|
+
templates: [],
|
|
229
|
+
cloud: [],
|
|
230
|
+
build: [],
|
|
231
|
+
changes: [],
|
|
232
|
+
autolink: [],
|
|
233
|
+
};
|
|
234
|
+
const effectiveConfig = pluginApplication.config;
|
|
220
235
|
if (platform === "android" || platform === "ios")
|
|
221
236
|
await requireAutolinkReady(root, platform);
|
|
222
237
|
const runtime = await inspectRuntimeFingerprint(root, platform, effectiveConfig);
|
|
@@ -418,6 +433,7 @@ function commandTitle(command) {
|
|
|
418
433
|
devtool: "Lynx DevTool diagnostics",
|
|
419
434
|
trace: "Lynx Trace diagnostics",
|
|
420
435
|
recorder: "Lynx Recorder diagnostics",
|
|
436
|
+
plugin: "LynxShip plugins",
|
|
421
437
|
}[command] ?? command);
|
|
422
438
|
}
|
|
423
439
|
function helpText() {
|
|
@@ -433,6 +449,10 @@ Commands:
|
|
|
433
449
|
devtool doctor Check Lynx DevTool integration and dev runtime
|
|
434
450
|
trace doctor Check Lynx Trace prerequisites
|
|
435
451
|
recorder doctor Check Lynx Recorder prerequisites
|
|
452
|
+
plugin list List project plugins and their capabilities
|
|
453
|
+
plugin doctor Validate plugin packages without modifying native files
|
|
454
|
+
plugin apply Apply project plugin native changes for a platform
|
|
455
|
+
plugin apply --dry-run Preview plugin native changes without writing files
|
|
436
456
|
autolink check Check Lynx native-library Autolink wiring
|
|
437
457
|
autolink codegen Run the project's Native Module codegen script
|
|
438
458
|
ota doctor Check native OTA host integration
|
|
@@ -514,6 +534,14 @@ Global options:
|
|
|
514
534
|
--simulator Build/install an iOS .app or install one with simctl
|
|
515
535
|
--help Show this complete command reference
|
|
516
536
|
|
|
537
|
+
Miso compiler profiles:
|
|
538
|
+
ghcjs (default) Use the official Miso GHC/Nix workflow
|
|
539
|
+
microhs Use a pinned MicroHs binary and a real adapter command
|
|
540
|
+
|
|
541
|
+
MicroHs is opt-in. Configure build.<profile>.miso.microhs with either a
|
|
542
|
+
binary path or a pinned manifest, plus an adapter command that writes the
|
|
543
|
+
configured main.lynx.bundle. It is not a drop-in GHCJS replacement.
|
|
544
|
+
|
|
517
545
|
Node support: Node 22/24 LTS or Node 26 Current. Use Node 24 LTS for production.`;
|
|
518
546
|
}
|
|
519
547
|
async function looksLikeLynxProject() {
|
|
@@ -905,6 +933,80 @@ async function main() {
|
|
|
905
933
|
});
|
|
906
934
|
return;
|
|
907
935
|
}
|
|
936
|
+
if (command === "plugin") {
|
|
937
|
+
const subcommand = args.shift() ?? "list";
|
|
938
|
+
assert(["list", "doctor", "apply"].includes(subcommand), "CLI_PLUGIN_COMMAND", "Use \`lynxship plugin list\`, \`lynxship plugin doctor\` or \`lynxship plugin apply\`.");
|
|
939
|
+
await requireProjectRoot();
|
|
940
|
+
const config = await loadConfig(root);
|
|
941
|
+
const report = await inspectProjectPlugins(root, config);
|
|
942
|
+
if (subcommand === "apply") {
|
|
943
|
+
const platform = platformValue(flag("--platform", "android"));
|
|
944
|
+
const profile = flag("--profile", "production");
|
|
945
|
+
const dryRun = args.includes("--dry-run");
|
|
946
|
+
const result = await applyProjectPlugins(root, config, {
|
|
947
|
+
platform,
|
|
948
|
+
profile,
|
|
949
|
+
mode: dryRun ? "plan" : "apply",
|
|
950
|
+
});
|
|
951
|
+
printValue({
|
|
952
|
+
status: dryRun ? "planned" : "applied",
|
|
953
|
+
platform,
|
|
954
|
+
profile,
|
|
955
|
+
plugins: result.applied,
|
|
956
|
+
nativeChanges: result.changes.filter((change) => change.changed)
|
|
957
|
+
.length,
|
|
958
|
+
changes: result.changes,
|
|
959
|
+
templates: result.templates,
|
|
960
|
+
cloud: result.cloud,
|
|
961
|
+
build: result.build,
|
|
962
|
+
}, {
|
|
963
|
+
title: `LynxShip plugins · ${platform}`,
|
|
964
|
+
rows: [
|
|
965
|
+
{
|
|
966
|
+
label: "Applied",
|
|
967
|
+
value: result.applied.length ? result.applied.join(", ") : "none",
|
|
968
|
+
valueColor: "green",
|
|
969
|
+
},
|
|
970
|
+
{
|
|
971
|
+
label: "Native changes",
|
|
972
|
+
value: String(result.changes.filter((change) => change.changed).length),
|
|
973
|
+
valueColor: "blue",
|
|
974
|
+
},
|
|
975
|
+
],
|
|
976
|
+
done: dryRun
|
|
977
|
+
? "No native files were modified; review the planned changes."
|
|
978
|
+
: "Project plugin changes are applied atomically and idempotently.",
|
|
979
|
+
});
|
|
980
|
+
return;
|
|
981
|
+
}
|
|
982
|
+
const invalid = report.plugins.filter((plugin) => plugin.status !== "ready");
|
|
983
|
+
printValue(report, {
|
|
984
|
+
title: `LynxShip plugins · ${subcommand}`,
|
|
985
|
+
rows: report.plugins.length > 0
|
|
986
|
+
? report.plugins.map((plugin) => ({
|
|
987
|
+
label: plugin.name,
|
|
988
|
+
value: `${plugin.status} · ${plugin.capabilities.join(", ") || "no capabilities"} · ${plugin.reason}`,
|
|
989
|
+
valueColor: plugin.status === "ready"
|
|
990
|
+
? "green"
|
|
991
|
+
: plugin.status === "missing"
|
|
992
|
+
? "red"
|
|
993
|
+
: "yellow",
|
|
994
|
+
}))
|
|
995
|
+
: [
|
|
996
|
+
{
|
|
997
|
+
label: "Plugins",
|
|
998
|
+
value: "none configured",
|
|
999
|
+
valueColor: "muted",
|
|
1000
|
+
},
|
|
1001
|
+
],
|
|
1002
|
+
done: invalid.length === 0
|
|
1003
|
+
? "All project plugin manifests are valid."
|
|
1004
|
+
: "Fix the invalid plugin package before building.",
|
|
1005
|
+
});
|
|
1006
|
+
if (subcommand === "doctor" && invalid.length > 0)
|
|
1007
|
+
process.exitCode = 1;
|
|
1008
|
+
return;
|
|
1009
|
+
}
|
|
908
1010
|
if (command === "doctor") {
|
|
909
1011
|
const config = await loadConfig(root);
|
|
910
1012
|
const configuration = await readConfigurationStatus();
|
|
@@ -915,7 +1017,13 @@ async function main() {
|
|
|
915
1017
|
const autolinkForPlatform = autolink && (doctorPlatform === "android" || doctorPlatform === "ios")
|
|
916
1018
|
? autolink[doctorPlatform]
|
|
917
1019
|
: undefined;
|
|
918
|
-
const
|
|
1020
|
+
const framework = await detectLynxFramework(root);
|
|
1021
|
+
const packageLockfile = await findLockfile(root);
|
|
1022
|
+
const lockfile = packageLockfile ??
|
|
1023
|
+
(framework.framework === "miso" &&
|
|
1024
|
+
(await exists(join(root, "flake.lock")))
|
|
1025
|
+
? join(root, "flake.lock")
|
|
1026
|
+
: null);
|
|
919
1027
|
const credentialStore = credentialStorageDescription();
|
|
920
1028
|
const nativeCredentialStore = !credentialStore.includes("owner-only");
|
|
921
1029
|
const androidHost = doctorPlatform === "android" ? await hasAndroidHost(root) : false;
|
|
@@ -945,7 +1053,25 @@ async function main() {
|
|
|
945
1053
|
const nodeMajor = Number(process.versions.node.split(".")[0]);
|
|
946
1054
|
const nodeSupported = nodeMajor >= 22;
|
|
947
1055
|
const nodeRecommended = nodeMajor % 2 === 0;
|
|
948
|
-
const
|
|
1056
|
+
const misoCompiler = framework.framework === "miso"
|
|
1057
|
+
? (doctorProfile.miso?.compiler ?? "ghcjs")
|
|
1058
|
+
: undefined;
|
|
1059
|
+
const microhsConfig = doctorProfile.miso?.microhs;
|
|
1060
|
+
const microhsBinary = microhsConfig?.binary ?? process.env.LYNXSHIP_MICROHS_BINARY;
|
|
1061
|
+
const microhsBinaryReady = Boolean(microhsBinary && existsSync(resolve(root, microhsBinary)));
|
|
1062
|
+
const microhsManifestPath = microhsConfig?.manifest ?? process.env.LYNXSHIP_MICROHS_MANIFEST;
|
|
1063
|
+
const microhsManifestReady = Boolean((microhsManifestPath && existsSync(resolve(root, microhsManifestPath))) ||
|
|
1064
|
+
microhsConfig?.manifestUrl ||
|
|
1065
|
+
process.env.LYNXSHIP_MICROHS_MANIFEST_URL);
|
|
1066
|
+
let microhsHost;
|
|
1067
|
+
try {
|
|
1068
|
+
microhsHost = microHsHostTriple();
|
|
1069
|
+
}
|
|
1070
|
+
catch {
|
|
1071
|
+
microhsHost = undefined;
|
|
1072
|
+
}
|
|
1073
|
+
const pluginReport = await inspectProjectPlugins(root, config);
|
|
1074
|
+
const invalidPlugins = pluginReport.plugins.filter((plugin) => plugin.status !== "ready");
|
|
949
1075
|
const checks = [
|
|
950
1076
|
{
|
|
951
1077
|
name: "lynx-framework",
|
|
@@ -962,7 +1088,7 @@ async function main() {
|
|
|
962
1088
|
framework.evidence +
|
|
963
1089
|
(framework.experimental ? " · early access" : ""),
|
|
964
1090
|
},
|
|
965
|
-
...(framework.framework === "miso"
|
|
1091
|
+
...(framework.framework === "miso" && misoCompiler !== "microhs"
|
|
966
1092
|
? [
|
|
967
1093
|
{
|
|
968
1094
|
name: "miso-nix",
|
|
@@ -975,7 +1101,45 @@ async function main() {
|
|
|
975
1101
|
: "missing · fix: install Nix and rerun doctor",
|
|
976
1102
|
},
|
|
977
1103
|
]
|
|
978
|
-
:
|
|
1104
|
+
: framework.framework === "miso"
|
|
1105
|
+
? [
|
|
1106
|
+
{
|
|
1107
|
+
name: "miso-compiler",
|
|
1108
|
+
ok: true,
|
|
1109
|
+
status: "pass",
|
|
1110
|
+
value: "MicroHs selected explicitly",
|
|
1111
|
+
},
|
|
1112
|
+
{
|
|
1113
|
+
name: "miso-microhs-host",
|
|
1114
|
+
ok: Boolean(microhsHost),
|
|
1115
|
+
status: microhsHost ? "pass" : "fail",
|
|
1116
|
+
value: microhsHost ??
|
|
1117
|
+
"unsupported host architecture · fix: use a supported MicroHs host or compiler=ghcjs",
|
|
1118
|
+
},
|
|
1119
|
+
{
|
|
1120
|
+
name: "miso-microhs-toolchain",
|
|
1121
|
+
ok: microhsBinaryReady || microhsManifestReady,
|
|
1122
|
+
status: microhsBinaryReady || microhsManifestReady
|
|
1123
|
+
? "pass"
|
|
1124
|
+
: "fail",
|
|
1125
|
+
value: microhsBinaryReady
|
|
1126
|
+
? "external MicroHs binary found"
|
|
1127
|
+
: microhsManifestReady
|
|
1128
|
+
? "pinned release manifest configured · downloaded on build"
|
|
1129
|
+
: "missing · fix: configure build.<profile>.miso.microhs.binary or manifestUrl",
|
|
1130
|
+
},
|
|
1131
|
+
{
|
|
1132
|
+
name: "miso-microhs-adapter",
|
|
1133
|
+
ok: Boolean(microhsConfig?.adapter?.command),
|
|
1134
|
+
status: microhsConfig?.adapter?.command
|
|
1135
|
+
? "pass"
|
|
1136
|
+
: "fail",
|
|
1137
|
+
value: microhsConfig?.adapter?.command
|
|
1138
|
+
? "adapter command configured"
|
|
1139
|
+
: "missing · fix: configure build.<profile>.miso.microhs.adapter",
|
|
1140
|
+
},
|
|
1141
|
+
]
|
|
1142
|
+
: []),
|
|
979
1143
|
{
|
|
980
1144
|
name: "node",
|
|
981
1145
|
ok: nodeSupported,
|
|
@@ -991,7 +1155,7 @@ async function main() {
|
|
|
991
1155
|
: `${process.version} · recommended: Node 24 LTS`,
|
|
992
1156
|
},
|
|
993
1157
|
{
|
|
994
|
-
name: "
|
|
1158
|
+
name: "dependency-lockfile",
|
|
995
1159
|
ok: Boolean(lockfile),
|
|
996
1160
|
status: lockfile ? "pass" : "fail",
|
|
997
1161
|
value: lockfile ?? "missing · fix: pnpm install (or npm install)",
|
|
@@ -1002,6 +1166,16 @@ async function main() {
|
|
|
1002
1166
|
status: config.projectId ? "pass" : "fail",
|
|
1003
1167
|
value: config.projectId ? "found" : "missing · fix: lynxship init",
|
|
1004
1168
|
},
|
|
1169
|
+
{
|
|
1170
|
+
name: "lynxship-plugins",
|
|
1171
|
+
ok: invalidPlugins.length === 0,
|
|
1172
|
+
status: invalidPlugins.length === 0 ? "pass" : "fail",
|
|
1173
|
+
value: invalidPlugins.length === 0
|
|
1174
|
+
? pluginReport.configured === 0
|
|
1175
|
+
? "none configured"
|
|
1176
|
+
: `${pluginReport.configured} plugin(s) ready`
|
|
1177
|
+
: `${invalidPlugins.map((plugin) => plugin.name).join(", ")} · fix: lynxship plugin doctor`,
|
|
1178
|
+
},
|
|
1005
1179
|
{
|
|
1006
1180
|
name: "credential-store",
|
|
1007
1181
|
ok: true,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-api.d.ts","sourceRoot":"","sources":["../src/plugin-api.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "@lynxship/plugin-api";
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { Platform } from "@lynxship/contracts";
|
|
2
|
+
import { type BuildContribution, type CloudIntegrationContribution, type PluginCapability, type AutolinkContribution, type PluginPermission, type PluginPlanChange, type TemplateContribution } from "@lynxship/plugin-api";
|
|
3
|
+
import type { LynxShipConfig } from "./config.js";
|
|
4
|
+
export interface ProjectPluginInfo {
|
|
5
|
+
name: string;
|
|
6
|
+
version?: string;
|
|
7
|
+
packagePath?: string;
|
|
8
|
+
entry?: string;
|
|
9
|
+
apiVersion?: number;
|
|
10
|
+
capabilities: PluginCapability[];
|
|
11
|
+
permissions: PluginPermission[];
|
|
12
|
+
status: "ready" | "missing" | "invalid";
|
|
13
|
+
reason: string;
|
|
14
|
+
}
|
|
15
|
+
export interface PluginReport {
|
|
16
|
+
configured: number;
|
|
17
|
+
plugins: ProjectPluginInfo[];
|
|
18
|
+
}
|
|
19
|
+
export interface PluginApplication {
|
|
20
|
+
config: LynxShipConfig;
|
|
21
|
+
report: PluginReport;
|
|
22
|
+
applied: string[];
|
|
23
|
+
templates: TemplateContribution[];
|
|
24
|
+
cloud: CloudIntegrationContribution[];
|
|
25
|
+
build: BuildContribution[];
|
|
26
|
+
changes: PluginPlanChange[];
|
|
27
|
+
autolink: AutolinkContribution[];
|
|
28
|
+
}
|
|
29
|
+
export declare function inspectProjectPlugins(root: string, config: LynxShipConfig): Promise<PluginReport>;
|
|
30
|
+
export declare function applyProjectPlugins(root: string, config: LynxShipConfig, target: {
|
|
31
|
+
platform: Platform;
|
|
32
|
+
profile: string;
|
|
33
|
+
mode?: "plan" | "apply";
|
|
34
|
+
}): Promise<PluginApplication>;
|
|
35
|
+
//# sourceMappingURL=plugins.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugins.d.ts","sourceRoot":"","sources":["../src/plugins.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAEL,KAAK,iBAAiB,EACtB,KAAK,4BAA4B,EAKjC,KAAK,gBAAgB,EAErB,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EAGrB,KAAK,oBAAoB,EAC1B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAclD,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,gBAAgB,EAAE,CAAC;IACjC,WAAW,EAAE,gBAAgB,EAAE,CAAC;IAChC,MAAM,EAAE,OAAO,GAAG,SAAS,GAAG,SAAS,CAAC;IACxC,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,iBAAiB,EAAE,CAAC;CAC9B;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,cAAc,CAAC;IACvB,MAAM,EAAE,YAAY,CAAC;IACrB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,SAAS,EAAE,oBAAoB,EAAE,CAAC;IAClC,KAAK,EAAE,4BAA4B,EAAE,CAAC;IACtC,KAAK,EAAE,iBAAiB,EAAE,CAAC;IAC3B,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,QAAQ,EAAE,oBAAoB,EAAE,CAAC;CAClC;AAqUD,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,cAAc,GACrB,OAAO,CAAC,YAAY,CAAC,CAQvB;AA+XD,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,cAAc,EACtB,MAAM,EAAE;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,GACvE,OAAO,CAAC,iBAAiB,CAAC,CAqF5B"}
|