@lynxship/cli 0.1.20 → 0.1.21
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 -5
- package/dist/android/signing.d.ts +16 -0
- package/dist/android/signing.d.ts.map +1 -0
- package/dist/android/signing.js +131 -0
- package/dist/android/types.d.ts +12 -0
- package/dist/android/types.d.ts.map +1 -0
- package/dist/android/types.js +1 -0
- package/dist/android-build.d.ts +4 -13
- package/dist/android-build.d.ts.map +1 -1
- package/dist/android-build.js +14 -133
- package/dist/android-toolchain/inspection.d.ts +3 -0
- package/dist/android-toolchain/inspection.d.ts.map +1 -0
- package/dist/android-toolchain/inspection.js +122 -0
- package/dist/android-toolchain/probes.d.ts +23 -0
- package/dist/android-toolchain/probes.d.ts.map +1 -0
- package/dist/android-toolchain/probes.js +183 -0
- package/dist/android-toolchain/types.d.ts +20 -0
- package/dist/android-toolchain/types.d.ts.map +1 -0
- package/dist/android-toolchain/types.js +1 -0
- package/dist/android-toolchain.d.ts +4 -20
- package/dist/android-toolchain.d.ts.map +1 -1
- package/dist/android-toolchain.js +4 -300
- package/dist/app-config.d.ts +25 -0
- package/dist/app-config.d.ts.map +1 -0
- package/dist/app-config.js +106 -0
- package/dist/bundle-build.d.ts.map +1 -1
- package/dist/bundle-build.js +11 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +66 -0
- package/dist/commands/build-execution.d.ts +41 -0
- package/dist/commands/build-execution.d.ts.map +1 -0
- package/dist/commands/build-execution.js +182 -0
- package/dist/commands/configuration.d.ts +19 -0
- package/dist/commands/configuration.d.ts.map +1 -0
- package/dist/commands/configuration.js +174 -0
- package/dist/commands/development.d.ts +22 -0
- package/dist/commands/development.d.ts.map +1 -0
- package/dist/commands/development.js +132 -0
- package/dist/commands/device.d.ts +3 -0
- package/dist/commands/device.d.ts.map +1 -0
- package/dist/commands/device.js +86 -0
- package/dist/commands/doctor.d.ts +18 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +320 -0
- package/dist/commands/help.d.ts +2 -0
- package/dist/commands/help.d.ts.map +1 -0
- package/dist/commands/help.js +118 -0
- package/dist/commands/i18n.d.ts +14 -0
- package/dist/commands/i18n.d.ts.map +1 -0
- package/dist/commands/i18n.js +88 -0
- package/dist/commands/logs.d.ts +3 -0
- package/dist/commands/logs.d.ts.map +1 -0
- package/dist/commands/logs.js +51 -0
- package/dist/commands/metadata.d.ts +3 -0
- package/dist/commands/metadata.d.ts.map +1 -0
- package/dist/commands/metadata.js +45 -0
- package/dist/commands/ota.d.ts +28 -0
- package/dist/commands/ota.d.ts.map +1 -0
- package/dist/commands/ota.js +203 -0
- package/dist/commands/project.d.ts +14 -0
- package/dist/commands/project.d.ts.map +1 -0
- package/dist/commands/project.js +122 -0
- package/dist/commands/remote-build.d.ts +35 -0
- package/dist/commands/remote-build.d.ts.map +1 -0
- package/dist/commands/remote-build.js +73 -0
- package/dist/commands/submit.d.ts +27 -0
- package/dist/commands/submit.d.ts.map +1 -0
- package/dist/commands/submit.js +92 -0
- package/dist/ecosystem.d.ts +9 -0
- package/dist/ecosystem.d.ts.map +1 -0
- package/dist/ecosystem.js +95 -0
- package/dist/frameworks.d.ts.map +1 -1
- package/dist/frameworks.js +5 -1
- package/dist/guidance/catalog.d.ts +3 -0
- package/dist/guidance/catalog.d.ts.map +1 -0
- package/dist/guidance/catalog.js +504 -0
- package/dist/guidance/types.d.ts +10 -0
- package/dist/guidance/types.d.ts.map +1 -0
- package/dist/guidance/types.js +1 -0
- package/dist/guidance.d.ts +2 -9
- package/dist/guidance.d.ts.map +1 -1
- package/dist/guidance.js +1 -502
- package/dist/i18n/discovery.d.ts +14 -0
- package/dist/i18n/discovery.d.ts.map +1 -0
- package/dist/i18n/discovery.js +106 -0
- package/dist/i18n/plan.d.ts +12 -0
- package/dist/i18n/plan.d.ts.map +1 -0
- package/dist/i18n/plan.js +95 -0
- package/dist/i18n/setup.d.ts +11 -0
- package/dist/i18n/setup.d.ts.map +1 -0
- package/dist/i18n/setup.js +47 -0
- package/dist/i18n/types.d.ts +17 -0
- package/dist/i18n/types.d.ts.map +1 -0
- package/dist/i18n/types.js +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -2069
- package/dist/ios/assets.d.ts +19 -0
- package/dist/ios/assets.d.ts.map +1 -0
- package/dist/ios/assets.js +128 -0
- package/dist/ios/production-build.d.ts +6 -0
- package/dist/ios/production-build.d.ts.map +1 -0
- package/dist/ios/production-build.js +200 -0
- package/dist/ios/project.d.ts +4 -0
- package/dist/ios/project.d.ts.map +1 -0
- package/dist/ios/project.js +43 -0
- package/dist/ios/simulator-build.d.ts +8 -0
- package/dist/ios/simulator-build.d.ts.map +1 -0
- package/dist/ios/simulator-build.js +188 -0
- package/dist/ios/simulator.d.ts +5 -0
- package/dist/ios/simulator.d.ts.map +1 -0
- package/dist/ios/simulator.js +60 -0
- package/dist/ios/types.d.ts +14 -0
- package/dist/ios/types.d.ts.map +1 -0
- package/dist/ios/types.js +1 -0
- package/dist/ios-build.d.ts +4 -37
- package/dist/ios-build.d.ts.map +1 -1
- package/dist/ios-build.js +3 -575
- package/dist/ios-host.d.ts.map +1 -1
- package/dist/ios-toolchain/inspection.d.ts +4 -0
- package/dist/ios-toolchain/inspection.d.ts.map +1 -0
- package/dist/ios-toolchain/inspection.js +211 -0
- package/dist/ios-toolchain/probes.d.ts +24 -0
- package/dist/ios-toolchain/probes.d.ts.map +1 -0
- package/dist/ios-toolchain/probes.js +127 -0
- package/dist/ios-toolchain/types.d.ts +17 -0
- package/dist/ios-toolchain/types.d.ts.map +1 -0
- package/dist/ios-toolchain/types.js +1 -0
- package/dist/ios-toolchain.d.ts +3 -18
- package/dist/ios-toolchain.d.ts.map +1 -1
- package/dist/ios-toolchain.js +1 -333
- package/dist/plugins/contracts.d.ts +28 -0
- package/dist/plugins/contracts.d.ts.map +1 -0
- package/dist/plugins/contracts.js +1 -0
- package/dist/plugins/discovery.d.ts +19 -0
- package/dist/plugins/discovery.d.ts.map +1 -0
- package/dist/plugins/discovery.js +250 -0
- package/dist/plugins/native-operations.d.ts +28 -0
- package/dist/plugins/native-operations.d.ts.map +1 -0
- package/dist/plugins/native-operations.js +217 -0
- package/dist/plugins/operations.d.ts +9 -0
- package/dist/plugins/operations.d.ts.map +1 -0
- package/dist/plugins/operations.js +76 -0
- package/dist/plugins/validation.d.ts +9 -0
- package/dist/plugins/validation.d.ts.map +1 -0
- package/dist/plugins/validation.js +52 -0
- package/dist/plugins.d.ts +3 -34
- package/dist/plugins.d.ts.map +1 -1
- package/dist/plugins.js +2 -595
- package/dist/process-runner.d.ts +4 -0
- package/dist/process-runner.d.ts.map +1 -1
- package/dist/process-runner.js +14 -0
- package/dist/remote.d.ts +22 -1
- package/dist/remote.d.ts.map +1 -1
- package/dist/remote.js +141 -2
- package/dist/rspeedy-app-config.d.ts +4 -0
- package/dist/rspeedy-app-config.d.ts.map +1 -0
- package/dist/rspeedy-app-config.js +32 -0
- package/dist/runtime/args.d.ts +3 -0
- package/dist/runtime/args.d.ts.map +1 -0
- package/dist/runtime/args.js +11 -0
- package/dist/runtime/build-commands.d.ts +3 -0
- package/dist/runtime/build-commands.d.ts.map +1 -0
- package/dist/runtime/build-commands.js +282 -0
- package/dist/runtime/context.d.ts +63 -0
- package/dist/runtime/context.d.ts.map +1 -0
- package/dist/runtime/context.js +179 -0
- package/dist/runtime/early-commands.d.ts +4 -0
- package/dist/runtime/early-commands.d.ts.map +1 -0
- package/dist/runtime/early-commands.js +284 -0
- package/dist/runtime/project.d.ts +8 -0
- package/dist/runtime/project.d.ts.map +1 -0
- package/dist/runtime/project.js +38 -0
- package/dist/runtime/state.d.ts +47 -0
- package/dist/runtime/state.d.ts.map +1 -0
- package/dist/runtime/state.js +33 -0
- package/dist/secure-store/backends.d.ts +20 -0
- package/dist/secure-store/backends.d.ts.map +1 -0
- package/dist/secure-store/backends.js +248 -0
- package/dist/secure-store/types.d.ts +27 -0
- package/dist/secure-store/types.d.ts.map +1 -0
- package/dist/secure-store/types.js +1 -0
- package/dist/secure-store.d.ts +2 -26
- package/dist/secure-store.d.ts.map +1 -1
- package/dist/secure-store.js +3 -245
- package/package.json +7 -4
- package/templates/android-host/app/build.gradle +1 -0
- package/templates/android-host/app/src/main/java/template/MainActivity.java +98 -3
- package/templates/ios-host/__IOS_TARGET_NAME__/DemoLynxProvider.swift +26 -16
- package/templates/ios-host/__IOS_TARGET_NAME__/ViewController.swift +107 -19
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"development.d.ts","sourceRoot":"","sources":["../../src/commands/development.ts"],"names":[],"mappings":"AAEA,OAAO,EAAU,KAAK,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAQlE,OAAO,EAEL,KAAK,qBAAqB,EAC3B,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAEpD,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACxB,EAAE,EAAE,KAAK,CAAC;IACV,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,KAAK,MAAM,GAAG,IAAI,CAAC;IAChE,OAAO,EAAE,qBAAqB,CAAC;IAC/B,UAAU,EAAE,CACV,KAAK,EAAE,OAAO,EACd,IAAI,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,EAAE,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,KACnD,IAAI,CAAC;IACV,mBAAmB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,cAAc,CAAC;CACxD;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,EAAE,CA8BrE;AAED,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,yBAAyB,EAClC,UAAU,EAAE,KAAK,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,EACnD,WAAW,CAAC,EAAE,MAAM,CAAC,UAAU,GAC9B,OAAO,CAAC,IAAI,CAAC,CAkDf;AAED,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,yBAAyB,GACjC,OAAO,CAAC,IAAI,CAAC,CA8Bf;AAED,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,yBAAyB,EAClC,IAAI,EAAE,SAAS,GAAG,OAAO,GAAG,UAAU,GACrC,OAAO,CAAC,IAAI,CAAC,CAgCf"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { join, resolve } from "node:path";
|
|
3
|
+
import { assert } from "@lynxship/contracts";
|
|
4
|
+
import { packageManagerCommand, runProcess, runRspeedy, } from "../process-runner.js";
|
|
5
|
+
import { extractDevServerUrl, shouldPrintDevServerQr } from "../dev-qr.js";
|
|
6
|
+
import { formatDevToolFailure, inspectLynxDevTool } from "../lynx-devtool.js";
|
|
7
|
+
import { initializeBuildProject, } from "./project.js";
|
|
8
|
+
export function forwardedToolArgs(values) {
|
|
9
|
+
const result = [];
|
|
10
|
+
const valueFlags = new Set([
|
|
11
|
+
"--project-dir",
|
|
12
|
+
"--platform",
|
|
13
|
+
"--profile",
|
|
14
|
+
"--context.json",
|
|
15
|
+
]);
|
|
16
|
+
for (let index = 0; index < values.length; index += 1) {
|
|
17
|
+
const value = values[index];
|
|
18
|
+
if (!value)
|
|
19
|
+
continue;
|
|
20
|
+
if (valueFlags.has(value)) {
|
|
21
|
+
index += 1;
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
if ([
|
|
25
|
+
"--quiet",
|
|
26
|
+
"--verbose",
|
|
27
|
+
"--no-color",
|
|
28
|
+
"--non-interactive",
|
|
29
|
+
"--banner",
|
|
30
|
+
"--local",
|
|
31
|
+
].includes(value))
|
|
32
|
+
continue;
|
|
33
|
+
if (value.startsWith("--project-dir="))
|
|
34
|
+
continue;
|
|
35
|
+
result.push(value);
|
|
36
|
+
}
|
|
37
|
+
return result;
|
|
38
|
+
}
|
|
39
|
+
export async function runRspeedyCommand(context, subcommand, environment) {
|
|
40
|
+
await initializeBuildProject(context.project);
|
|
41
|
+
const forwarded = forwardedToolArgs(context.args);
|
|
42
|
+
context.ui.info(`Running local Rspeedy ${subcommand}…`);
|
|
43
|
+
if (subcommand === "dev") {
|
|
44
|
+
context.ui.info("Lynx Explorer mode: no Android or iOS native host is required. Scan the QR code printed by Rspeedy; source changes reload automatically.");
|
|
45
|
+
}
|
|
46
|
+
let devUrl;
|
|
47
|
+
let devQrPrinted = false;
|
|
48
|
+
let devQrTimer;
|
|
49
|
+
const printDevQr = async () => {
|
|
50
|
+
if (!devUrl || devQrPrinted || context.json || context.ui.options.quiet)
|
|
51
|
+
return;
|
|
52
|
+
devQrPrinted = true;
|
|
53
|
+
if (devQrTimer)
|
|
54
|
+
clearTimeout(devQrTimer);
|
|
55
|
+
await context.ui.devServerQr(devUrl);
|
|
56
|
+
};
|
|
57
|
+
await runRspeedy(context.root, subcommand, forwarded, {
|
|
58
|
+
env: environment,
|
|
59
|
+
quiet: context.json,
|
|
60
|
+
onOutput: (line) => {
|
|
61
|
+
context.ui.info(`│ ${line}`);
|
|
62
|
+
if (subcommand !== "dev")
|
|
63
|
+
return;
|
|
64
|
+
const url = extractDevServerUrl(line);
|
|
65
|
+
if (url && (!devUrl || url.includes("fullscreen=true"))) {
|
|
66
|
+
devUrl = url;
|
|
67
|
+
if (devQrTimer)
|
|
68
|
+
clearTimeout(devQrTimer);
|
|
69
|
+
devQrTimer = setTimeout(() => {
|
|
70
|
+
void printDevQr();
|
|
71
|
+
}, 500);
|
|
72
|
+
}
|
|
73
|
+
if (devUrl && shouldPrintDevServerQr(line))
|
|
74
|
+
void printDevQr();
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
context.printValue({ status: "success", command: `rspeedy ${subcommand}` }, {
|
|
78
|
+
title: `Rspeedy ${subcommand}`,
|
|
79
|
+
rows: [
|
|
80
|
+
{
|
|
81
|
+
label: "Command",
|
|
82
|
+
value: `rspeedy ${subcommand}`,
|
|
83
|
+
valueColor: "blue",
|
|
84
|
+
},
|
|
85
|
+
],
|
|
86
|
+
done: `Rspeedy ${subcommand} completed successfully.`,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
export async function runAutolinkCodegen(context) {
|
|
90
|
+
const libraryDirectory = resolve(context.root, context.flag("--library-dir", "."));
|
|
91
|
+
const packageJson = JSON.parse(await readFile(join(libraryDirectory, "package.context.json"), "utf8"));
|
|
92
|
+
assert(packageJson.scripts?.codegen, "LYNX_CODEGEN_SCRIPT_REQUIRED", "No codegen script was found. Add the official lynx-autolink-codegen script to the native library package.");
|
|
93
|
+
const manager = packageManagerCommand(libraryDirectory);
|
|
94
|
+
context.ui.info("Running the project's official Native Module codegen script…");
|
|
95
|
+
await runProcess(manager.command, ["run", "codegen"], {
|
|
96
|
+
cwd: libraryDirectory,
|
|
97
|
+
quiet: context.json,
|
|
98
|
+
onOutput: (line) => context.ui.info(`│ ${line}`),
|
|
99
|
+
});
|
|
100
|
+
context.printValue({ status: "success", directory: libraryDirectory }, {
|
|
101
|
+
title: "Lynx Autolink codegen",
|
|
102
|
+
rows: [{ label: "Library", value: libraryDirectory, valueColor: "blue" }],
|
|
103
|
+
done: "Native Module specifications were generated successfully.",
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
export async function runDevToolDoctor(context, kind) {
|
|
107
|
+
await initializeBuildProject(context.project);
|
|
108
|
+
const platform = context.mobilePlatformValue(context.flag("--platform", "android"));
|
|
109
|
+
const status = await inspectLynxDevTool(context.root, platform);
|
|
110
|
+
const ready = kind === "devtool"
|
|
111
|
+
? status.ok
|
|
112
|
+
: kind === "trace"
|
|
113
|
+
? status.traceReady
|
|
114
|
+
: status.recorderReady;
|
|
115
|
+
if (!ready)
|
|
116
|
+
process.exitCode = 1;
|
|
117
|
+
context.printValue({ ...status, requested: kind, ready }, {
|
|
118
|
+
title: `Lynx ${kind === "devtool" ? "DevTool" : kind[0].toUpperCase() + kind.slice(1)} · ${platform}`,
|
|
119
|
+
rows: status.checks.map((item) => ({
|
|
120
|
+
label: item.name,
|
|
121
|
+
value: `${item.status} · ${item.value}${item.fix && item.status !== "pass" ? ` · fix: ${item.fix}` : ""}`,
|
|
122
|
+
valueColor: item.status === "pass"
|
|
123
|
+
? "green"
|
|
124
|
+
: item.status === "warn"
|
|
125
|
+
? "yellow"
|
|
126
|
+
: "red",
|
|
127
|
+
})),
|
|
128
|
+
done: ready
|
|
129
|
+
? `${kind} prerequisites are ready. Open Lynx DevTool Desktop and connect the target device by USB.`
|
|
130
|
+
: `Lynx ${kind} prerequisites are incomplete: ${formatDevToolFailure(status) || "review the failed checks"}`,
|
|
131
|
+
});
|
|
132
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"device.d.ts","sourceRoot":"","sources":["../../src/commands/device.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,kBAAkB,CAAC;AAElE,wBAAsB,SAAS,CAC7B,OAAO,EAAE,yBAAyB,GACjC,OAAO,CAAC,IAAI,CAAC,CAsHf"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { resolve } from "node:path";
|
|
2
|
+
import { assert } from "@lynxship/contracts";
|
|
3
|
+
import { commandExists, runProcess } from "../process-runner.js";
|
|
4
|
+
import { loadState } from "../runtime/state.js";
|
|
5
|
+
import { launchIosSimulatorApp } from "../ios-build.js";
|
|
6
|
+
import { platformValue } from "../config.js";
|
|
7
|
+
export async function runDevice(context) {
|
|
8
|
+
const platform = platformValue(context.flag("--platform", "android"));
|
|
9
|
+
const artifact = context.flag("--artifact");
|
|
10
|
+
const artifactPath = artifact
|
|
11
|
+
? resolve(context.root, artifact)
|
|
12
|
+
: (await loadState(context.root)).builds
|
|
13
|
+
.list()
|
|
14
|
+
.filter((job) => job.platform === platform && job.state === "success")
|
|
15
|
+
.at(-1)?.artifact?.path;
|
|
16
|
+
assert(artifactPath, "DEVICE_ARTIFACT_REQUIRED", "Pass --artifact or create a successful build first");
|
|
17
|
+
if (platform === "android") {
|
|
18
|
+
assert(commandExists("adb"), "ANDROID_ADB_REQUIRED", "adb was not found in PATH");
|
|
19
|
+
const device = context.flag("--device");
|
|
20
|
+
const argsForAdb = device
|
|
21
|
+
? ["-s", device, "install", "-r", artifactPath]
|
|
22
|
+
: ["install", "-r", artifactPath];
|
|
23
|
+
await runProcess("adb", argsForAdb, {
|
|
24
|
+
cwd: context.root,
|
|
25
|
+
quiet: context.json,
|
|
26
|
+
onOutput: (line) => context.ui.info(`│ ${line}`),
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
else if (platform === "ios") {
|
|
30
|
+
assert(process.platform === "darwin", "IOS_MACOS_REQUIRED", "iOS device/simulator commands require macOS");
|
|
31
|
+
assert(commandExists("xcrun"), "IOS_XCRUN_REQUIRED", "xcrun was not found in PATH");
|
|
32
|
+
const device = context.flag("--device", "booted");
|
|
33
|
+
const simulator = context.args.includes("--simulator");
|
|
34
|
+
if (simulator || artifactPath.endsWith(".app")) {
|
|
35
|
+
await runProcess("xcrun", ["simctl", "install", device, artifactPath], {
|
|
36
|
+
cwd: context.root,
|
|
37
|
+
quiet: context.json,
|
|
38
|
+
onOutput: (line) => context.ui.info(`│ ${line}`),
|
|
39
|
+
});
|
|
40
|
+
if (context.args.includes("--launch")) {
|
|
41
|
+
await launchIosSimulatorApp(context.root, device, artifactPath, {
|
|
42
|
+
quiet: context.json,
|
|
43
|
+
onEvent: (line) => context.ui.info(`│ ${line}`),
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
assert(device !== "booted", "IOS_DEVICE_REQUIRED", "A physical iOS install requires --device <device-identifier>; use --simulator for a booted simulator.");
|
|
49
|
+
await runProcess("xcrun", [
|
|
50
|
+
"devicectl",
|
|
51
|
+
"device",
|
|
52
|
+
"install",
|
|
53
|
+
"app",
|
|
54
|
+
"--device",
|
|
55
|
+
device,
|
|
56
|
+
artifactPath,
|
|
57
|
+
], {
|
|
58
|
+
cwd: context.root,
|
|
59
|
+
quiet: context.json,
|
|
60
|
+
onOutput: (line) => context.ui.info(`│ ${line}`),
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
else if (platform === "harmony") {
|
|
65
|
+
assert(commandExists("hdc"), "HARMONY_HDC_REQUIRED", "hdc was not found in PATH. Install the OpenHarmony SDK platform tools before installing a HAP.");
|
|
66
|
+
assert(artifactPath.endsWith(".hap"), "DEVICE_ARTIFACT_INVALID", "HarmonyOS run requires a signed .hap artifact.");
|
|
67
|
+
const device = context.flag("--device");
|
|
68
|
+
await runProcess("hdc", device
|
|
69
|
+
? ["-t", device, "install", "-r", artifactPath]
|
|
70
|
+
: ["install", "-r", artifactPath], {
|
|
71
|
+
cwd: context.root,
|
|
72
|
+
quiet: context.json,
|
|
73
|
+
onOutput: (line) => context.ui.info(`│ ${line}`),
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
assert(false, "TARGET_RUN_UNSUPPORTED", platform === "web"
|
|
78
|
+
? "Web artifacts are previewed with `lynxship preview` or served by the project; they are not installed on a device."
|
|
79
|
+
: "Desktop installers are launched by the operating system after packaging; LynxShip does not claim a cross-platform install command.");
|
|
80
|
+
}
|
|
81
|
+
context.printValue({ status: "installed", platform, artifact: artifactPath }, {
|
|
82
|
+
title: "Device install",
|
|
83
|
+
rows: [{ label: "Artifact", value: artifactPath, valueColor: "green" }],
|
|
84
|
+
done: "Artifact installed on the selected target.",
|
|
85
|
+
});
|
|
86
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { BoxRow, CliUi } from "../ui/index.js";
|
|
2
|
+
export interface DoctorCommandContext {
|
|
3
|
+
root: string;
|
|
4
|
+
args: readonly string[];
|
|
5
|
+
ui: CliUi;
|
|
6
|
+
flag: (name: string, fallback?: string | null) => string | null;
|
|
7
|
+
printValue: (value: unknown, view?: {
|
|
8
|
+
title: string;
|
|
9
|
+
rows: BoxRow[];
|
|
10
|
+
done: string;
|
|
11
|
+
}) => void;
|
|
12
|
+
readConfigurationStatus: () => Promise<{
|
|
13
|
+
r2: boolean;
|
|
14
|
+
android: boolean;
|
|
15
|
+
}>;
|
|
16
|
+
}
|
|
17
|
+
export declare function runDoctor(context: DoctorCommandContext): Promise<void>;
|
|
18
|
+
//# sourceMappingURL=doctor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAEpD,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACxB,EAAE,EAAE,KAAK,CAAC;IACV,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,KAAK,MAAM,GAAG,IAAI,CAAC;IAChE,UAAU,EAAE,CACV,KAAK,EAAE,OAAO,EACd,IAAI,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,EAAE,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,KACnD,IAAI,CAAC;IACV,uBAAuB,EAAE,MAAM,OAAO,CAAC;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;CAC3E;AAED,wBAAsB,SAAS,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CA2V5E"}
|
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { join, resolve } from "node:path";
|
|
3
|
+
import { microHsHostTriple } from "@lynxship/microhs";
|
|
4
|
+
import { assert } from "@lynxship/contracts";
|
|
5
|
+
import { detectLynxFramework } from "../frameworks.js";
|
|
6
|
+
import { loadConfig, platformValue, resolveProfile } from "../config.js";
|
|
7
|
+
import { hasAndroidHost } from "../android-build.js";
|
|
8
|
+
import { hasIosHost } from "../ios-build.js";
|
|
9
|
+
import { credentialStorageDescription } from "../secure-store.js";
|
|
10
|
+
import { inspectAutolink } from "../autolink.js";
|
|
11
|
+
import { commandExists } from "../process-runner.js";
|
|
12
|
+
import { confirm } from "../prompt.js";
|
|
13
|
+
import { fixAndroidToolchain, inspectAndroidToolchain, } from "../android-toolchain.js";
|
|
14
|
+
import { inspectIosToolchain } from "../ios-toolchain.js";
|
|
15
|
+
import { inspectProjectPlugins } from "../plugins.js";
|
|
16
|
+
import { inspectDesktopTarget, inspectHarmonyTarget, inspectWebTarget, } from "../target-toolchain.js";
|
|
17
|
+
import { findLockfile, exists } from "../runtime/project.js";
|
|
18
|
+
export async function runDoctor(context) {
|
|
19
|
+
const { root, args, ui, flag, printValue, readConfigurationStatus } = context;
|
|
20
|
+
const config = await loadConfig(root);
|
|
21
|
+
const configuration = await readConfigurationStatus();
|
|
22
|
+
const doctorPlatform = platformValue(flag("--platform", "android"));
|
|
23
|
+
const autolink = doctorPlatform === "android" || doctorPlatform === "ios"
|
|
24
|
+
? await inspectAutolink(root)
|
|
25
|
+
: undefined;
|
|
26
|
+
const autolinkForPlatform = autolink && (doctorPlatform === "android" || doctorPlatform === "ios")
|
|
27
|
+
? autolink[doctorPlatform]
|
|
28
|
+
: undefined;
|
|
29
|
+
const framework = await detectLynxFramework(root);
|
|
30
|
+
const packageLockfile = await findLockfile(root);
|
|
31
|
+
const lockfile = packageLockfile ??
|
|
32
|
+
(framework.framework === "miso" && (await exists(join(root, "flake.lock")))
|
|
33
|
+
? join(root, "flake.lock")
|
|
34
|
+
: null);
|
|
35
|
+
const credentialStore = credentialStorageDescription();
|
|
36
|
+
const nativeCredentialStore = !credentialStore.includes("owner-only");
|
|
37
|
+
const androidHost = doctorPlatform === "android" ? await hasAndroidHost(root) : false;
|
|
38
|
+
const doctorProfileName = flag("--profile", "production");
|
|
39
|
+
const doctorProfile = resolveProfile(config, doctorProfileName);
|
|
40
|
+
const targetToolchain = doctorPlatform === "web"
|
|
41
|
+
? await inspectWebTarget(root, doctorProfile)
|
|
42
|
+
: doctorPlatform === "harmony"
|
|
43
|
+
? await inspectHarmonyTarget(root, doctorProfile)
|
|
44
|
+
: doctorPlatform === "desktop"
|
|
45
|
+
? await inspectDesktopTarget(root, doctorProfile)
|
|
46
|
+
: undefined;
|
|
47
|
+
assert(!args.includes("--fix") || doctorPlatform === "android", "CLI_DOCTOR_FIX_PLATFORM", "`doctor --fix` currently repairs Android SDK packages; run it with `--platform android`.");
|
|
48
|
+
assert(!args.includes("--fix") || ui.interactive, "CLI_INTERACTIVE_REQUIRED", "Run `lynxship doctor --platform android --fix` in an interactive terminal.");
|
|
49
|
+
let androidToolchain = doctorPlatform === "android"
|
|
50
|
+
? await inspectAndroidToolchain(root)
|
|
51
|
+
: undefined;
|
|
52
|
+
const iosToolchain = doctorPlatform === "ios"
|
|
53
|
+
? await inspectIosToolchain(root, doctorProfile, doctorProfile.ios?.simulator || doctorProfileName === "simulator"
|
|
54
|
+
? "simulator"
|
|
55
|
+
: "device")
|
|
56
|
+
: undefined;
|
|
57
|
+
if (androidToolchain && args.includes("--fix")) {
|
|
58
|
+
await fixAndroidToolchain(root, androidToolchain, (message) => confirm(message), (line) => ui.info(line));
|
|
59
|
+
androidToolchain = await inspectAndroidToolchain(root);
|
|
60
|
+
}
|
|
61
|
+
const nodeMajor = Number(process.versions.node.split(".")[0]);
|
|
62
|
+
const nodeSupported = nodeMajor >= 22;
|
|
63
|
+
const nodeRecommended = nodeMajor % 2 === 0;
|
|
64
|
+
const misoCompiler = framework.framework === "miso"
|
|
65
|
+
? (doctorProfile.miso?.compiler ?? "ghcjs")
|
|
66
|
+
: undefined;
|
|
67
|
+
const microhsConfig = doctorProfile.miso?.microhs;
|
|
68
|
+
const microhsBinary = microhsConfig?.binary ?? process.env.LYNXSHIP_MICROHS_BINARY;
|
|
69
|
+
const microhsBinaryReady = Boolean(microhsBinary && existsSync(resolve(root, microhsBinary)));
|
|
70
|
+
const microhsManifestPath = microhsConfig?.manifest ?? process.env.LYNXSHIP_MICROHS_MANIFEST;
|
|
71
|
+
const microhsManifestReady = Boolean((microhsManifestPath && existsSync(resolve(root, microhsManifestPath))) ||
|
|
72
|
+
microhsConfig?.manifestUrl ||
|
|
73
|
+
process.env.LYNXSHIP_MICROHS_MANIFEST_URL);
|
|
74
|
+
let microhsHost;
|
|
75
|
+
try {
|
|
76
|
+
microhsHost = microHsHostTriple();
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
microhsHost = undefined;
|
|
80
|
+
}
|
|
81
|
+
const pluginReport = await inspectProjectPlugins(root, config);
|
|
82
|
+
const invalidPlugins = pluginReport.plugins.filter((plugin) => plugin.status !== "ready");
|
|
83
|
+
const checks = [
|
|
84
|
+
{
|
|
85
|
+
name: "lynx-framework",
|
|
86
|
+
ok: framework.framework !== "unknown",
|
|
87
|
+
status: framework.framework === "unknown"
|
|
88
|
+
? "warn"
|
|
89
|
+
: framework.experimental
|
|
90
|
+
? "warn"
|
|
91
|
+
: "pass",
|
|
92
|
+
value: framework.framework === "unknown"
|
|
93
|
+
? "unknown · verify the official Lynx/Rspeedy integration"
|
|
94
|
+
: framework.label +
|
|
95
|
+
" · " +
|
|
96
|
+
framework.evidence +
|
|
97
|
+
(framework.experimental ? " · early access" : ""),
|
|
98
|
+
},
|
|
99
|
+
...(framework.framework === "miso" && misoCompiler !== "microhs"
|
|
100
|
+
? [
|
|
101
|
+
{
|
|
102
|
+
name: "miso-nix",
|
|
103
|
+
ok: commandExists("nix"),
|
|
104
|
+
status: commandExists("nix")
|
|
105
|
+
? "pass"
|
|
106
|
+
: "fail",
|
|
107
|
+
value: commandExists("nix")
|
|
108
|
+
? "Nix detected"
|
|
109
|
+
: "missing · fix: install Nix and rerun doctor",
|
|
110
|
+
},
|
|
111
|
+
]
|
|
112
|
+
: framework.framework === "miso"
|
|
113
|
+
? [
|
|
114
|
+
{
|
|
115
|
+
name: "miso-compiler",
|
|
116
|
+
ok: true,
|
|
117
|
+
status: "pass",
|
|
118
|
+
value: "MicroHs selected explicitly",
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
name: "miso-microhs-host",
|
|
122
|
+
ok: Boolean(microhsHost),
|
|
123
|
+
status: microhsHost ? "pass" : "fail",
|
|
124
|
+
value: microhsHost ??
|
|
125
|
+
"unsupported host architecture · fix: use a supported MicroHs host or compiler=ghcjs",
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
name: "miso-microhs-toolchain",
|
|
129
|
+
ok: microhsBinaryReady || microhsManifestReady,
|
|
130
|
+
status: microhsBinaryReady || microhsManifestReady
|
|
131
|
+
? "pass"
|
|
132
|
+
: "fail",
|
|
133
|
+
value: microhsBinaryReady
|
|
134
|
+
? "external MicroHs binary found"
|
|
135
|
+
: microhsManifestReady
|
|
136
|
+
? "pinned release manifest configured · downloaded on build"
|
|
137
|
+
: "missing · fix: configure build.<profile>.miso.microhs.binary or manifestUrl",
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
name: "miso-microhs-adapter",
|
|
141
|
+
ok: Boolean(microhsConfig?.adapter?.command),
|
|
142
|
+
status: microhsConfig?.adapter?.command
|
|
143
|
+
? "pass"
|
|
144
|
+
: "fail",
|
|
145
|
+
value: microhsConfig?.adapter?.command
|
|
146
|
+
? "adapter command configured"
|
|
147
|
+
: "missing · fix: configure build.<profile>.miso.microhs.adapter",
|
|
148
|
+
},
|
|
149
|
+
]
|
|
150
|
+
: []),
|
|
151
|
+
{
|
|
152
|
+
name: "node",
|
|
153
|
+
ok: nodeSupported,
|
|
154
|
+
status: !nodeSupported
|
|
155
|
+
? "fail"
|
|
156
|
+
: nodeRecommended
|
|
157
|
+
? "pass"
|
|
158
|
+
: "warn",
|
|
159
|
+
value: !nodeSupported
|
|
160
|
+
? `${process.version} · fix: use Node 24 LTS`
|
|
161
|
+
: nodeRecommended
|
|
162
|
+
? process.version
|
|
163
|
+
: `${process.version} · recommended: Node 24 LTS`,
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
name: "dependency-lockfile",
|
|
167
|
+
ok: Boolean(lockfile),
|
|
168
|
+
status: lockfile ? "pass" : "fail",
|
|
169
|
+
value: lockfile ?? "missing · fix: pnpm install (or npm install)",
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
name: "lynxship.json",
|
|
173
|
+
ok: config.projectId !== undefined,
|
|
174
|
+
status: config.projectId ? "pass" : "fail",
|
|
175
|
+
value: config.projectId ? "found" : "missing · fix: lynxship init",
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
name: "lynxship-plugins",
|
|
179
|
+
ok: invalidPlugins.length === 0,
|
|
180
|
+
status: invalidPlugins.length === 0 ? "pass" : "fail",
|
|
181
|
+
value: invalidPlugins.length === 0
|
|
182
|
+
? pluginReport.configured === 0
|
|
183
|
+
? "none configured"
|
|
184
|
+
: `${pluginReport.configured} plugin(s) ready`
|
|
185
|
+
: `${invalidPlugins.map((plugin) => plugin.name).join(", ")} · fix: lynxship plugin doctor`,
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
name: "credential-store",
|
|
189
|
+
ok: true,
|
|
190
|
+
status: nativeCredentialStore ? "pass" : "warn",
|
|
191
|
+
value: nativeCredentialStore
|
|
192
|
+
? credentialStore
|
|
193
|
+
: `${credentialStore} · use CI secret variables or install Linux Secret Service`,
|
|
194
|
+
},
|
|
195
|
+
...(doctorPlatform === "android"
|
|
196
|
+
? [
|
|
197
|
+
{
|
|
198
|
+
name: "android-host",
|
|
199
|
+
ok: androidHost,
|
|
200
|
+
status: androidHost ? "pass" : "fail",
|
|
201
|
+
value: androidHost
|
|
202
|
+
? "Gradle host found"
|
|
203
|
+
: "missing · fix: lynxship android host init --application-id com.example.myapp",
|
|
204
|
+
},
|
|
205
|
+
...(androidToolchain?.checks ?? []).map((toolchainCheck) => ({
|
|
206
|
+
name: toolchainCheck.name,
|
|
207
|
+
ok: toolchainCheck.ok,
|
|
208
|
+
status: toolchainCheck.status,
|
|
209
|
+
value: toolchainCheck.fix && toolchainCheck.status !== "pass"
|
|
210
|
+
? `${toolchainCheck.value} · fix: ${toolchainCheck.fix}`
|
|
211
|
+
: toolchainCheck.value,
|
|
212
|
+
})),
|
|
213
|
+
]
|
|
214
|
+
: doctorPlatform === "ios"
|
|
215
|
+
? (iosToolchain?.checks ?? [])
|
|
216
|
+
.filter((toolchainCheck) => toolchainCheck.name !== "ios-host")
|
|
217
|
+
.map((toolchainCheck) => ({
|
|
218
|
+
name: toolchainCheck.name,
|
|
219
|
+
ok: toolchainCheck.ok,
|
|
220
|
+
status: toolchainCheck.status,
|
|
221
|
+
value: toolchainCheck.fix && toolchainCheck.status !== "pass"
|
|
222
|
+
? `${toolchainCheck.value} · fix: ${toolchainCheck.fix}`
|
|
223
|
+
: toolchainCheck.value,
|
|
224
|
+
}))
|
|
225
|
+
: (targetToolchain?.checks ?? []).map((toolchainCheck) => ({
|
|
226
|
+
name: toolchainCheck.name,
|
|
227
|
+
ok: toolchainCheck.ok,
|
|
228
|
+
status: toolchainCheck.status,
|
|
229
|
+
value: toolchainCheck.fix && toolchainCheck.status !== "pass"
|
|
230
|
+
? `${toolchainCheck.value} · fix: ${toolchainCheck.fix}`
|
|
231
|
+
: toolchainCheck.value,
|
|
232
|
+
}))),
|
|
233
|
+
{
|
|
234
|
+
name: "cloudflare-r2",
|
|
235
|
+
ok: doctorPlatform === "ios" && doctorProfile.ios?.simulator
|
|
236
|
+
? true
|
|
237
|
+
: configuration.r2,
|
|
238
|
+
status: doctorPlatform === "ios" && doctorProfile.ios?.simulator
|
|
239
|
+
? "pass"
|
|
240
|
+
: configuration.r2
|
|
241
|
+
? "pass"
|
|
242
|
+
: "fail",
|
|
243
|
+
value: doctorPlatform === "ios" && doctorProfile.ios?.simulator
|
|
244
|
+
? "not required for iOS Simulator"
|
|
245
|
+
: configuration.r2
|
|
246
|
+
? "configured"
|
|
247
|
+
: "missing · fix: lynxship storage configure",
|
|
248
|
+
},
|
|
249
|
+
...(doctorPlatform === "android"
|
|
250
|
+
? [
|
|
251
|
+
{
|
|
252
|
+
name: "android-signing",
|
|
253
|
+
ok: configuration.android,
|
|
254
|
+
status: configuration.android
|
|
255
|
+
? "pass"
|
|
256
|
+
: "fail",
|
|
257
|
+
value: configuration.android
|
|
258
|
+
? "configured"
|
|
259
|
+
: "missing · fix: lynxship android configure",
|
|
260
|
+
},
|
|
261
|
+
]
|
|
262
|
+
: doctorPlatform === "ios"
|
|
263
|
+
? [
|
|
264
|
+
{
|
|
265
|
+
name: "ios-host",
|
|
266
|
+
ok: process.platform === "darwin" && hasIosHost(root),
|
|
267
|
+
status: process.platform === "darwin" && hasIosHost(root)
|
|
268
|
+
? "pass"
|
|
269
|
+
: "fail",
|
|
270
|
+
value: process.platform === "darwin" && hasIosHost(root)
|
|
271
|
+
? "Xcode host found"
|
|
272
|
+
: "missing · fix: use macOS, then lynxship ios host init --bundle-identifier com.example.myapp",
|
|
273
|
+
},
|
|
274
|
+
]
|
|
275
|
+
: []),
|
|
276
|
+
...(autolinkForPlatform
|
|
277
|
+
? [
|
|
278
|
+
{
|
|
279
|
+
name: `lynx-autolink-${doctorPlatform}`,
|
|
280
|
+
ok: autolinkForPlatform.ready,
|
|
281
|
+
status: autolinkForPlatform.ready
|
|
282
|
+
? "pass"
|
|
283
|
+
: "fail",
|
|
284
|
+
value: autolinkForPlatform.ready
|
|
285
|
+
? autolinkForPlatform.reason
|
|
286
|
+
: `${autolinkForPlatform.reason} · fix: install the native plugin, then run autolink codegen`,
|
|
287
|
+
},
|
|
288
|
+
]
|
|
289
|
+
: []),
|
|
290
|
+
];
|
|
291
|
+
const result = {
|
|
292
|
+
ok: checks.every((check) => check.status !== "fail"),
|
|
293
|
+
checks,
|
|
294
|
+
};
|
|
295
|
+
const hasWarnings = checks.some((check) => check.status === "warn");
|
|
296
|
+
if (!result.ok)
|
|
297
|
+
ui.warn("One or more environment checks failed");
|
|
298
|
+
else if (hasWarnings)
|
|
299
|
+
ui.warn("Environment is usable, but one recommendation needs attention");
|
|
300
|
+
if (!result.ok)
|
|
301
|
+
process.exitCode = 1;
|
|
302
|
+
printValue(result, {
|
|
303
|
+
title: "Doctor result",
|
|
304
|
+
rows: checks.map((check) => ({
|
|
305
|
+
label: check.name,
|
|
306
|
+
value: `${check.status} · ${check.value}`,
|
|
307
|
+
valueColor: check.status === "pass"
|
|
308
|
+
? "green"
|
|
309
|
+
: check.status === "warn"
|
|
310
|
+
? "yellow"
|
|
311
|
+
: "red",
|
|
312
|
+
})),
|
|
313
|
+
done: result.ok
|
|
314
|
+
? hasWarnings
|
|
315
|
+
? "Environment is usable; review the recommendation when convenient."
|
|
316
|
+
: "Environment looks ready."
|
|
317
|
+
: "Fix the failed checks before building.",
|
|
318
|
+
});
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"help.d.ts","sourceRoot":"","sources":["../../src/commands/help.ts"],"names":[],"mappings":"AAAA,wBAAgB,QAAQ,IAAI,MAAM,CAqHjC"}
|