@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.
Files changed (191) hide show
  1. package/README.md +66 -5
  2. package/dist/android/signing.d.ts +16 -0
  3. package/dist/android/signing.d.ts.map +1 -0
  4. package/dist/android/signing.js +131 -0
  5. package/dist/android/types.d.ts +12 -0
  6. package/dist/android/types.d.ts.map +1 -0
  7. package/dist/android/types.js +1 -0
  8. package/dist/android-build.d.ts +4 -13
  9. package/dist/android-build.d.ts.map +1 -1
  10. package/dist/android-build.js +14 -133
  11. package/dist/android-toolchain/inspection.d.ts +3 -0
  12. package/dist/android-toolchain/inspection.d.ts.map +1 -0
  13. package/dist/android-toolchain/inspection.js +122 -0
  14. package/dist/android-toolchain/probes.d.ts +23 -0
  15. package/dist/android-toolchain/probes.d.ts.map +1 -0
  16. package/dist/android-toolchain/probes.js +183 -0
  17. package/dist/android-toolchain/types.d.ts +20 -0
  18. package/dist/android-toolchain/types.d.ts.map +1 -0
  19. package/dist/android-toolchain/types.js +1 -0
  20. package/dist/android-toolchain.d.ts +4 -20
  21. package/dist/android-toolchain.d.ts.map +1 -1
  22. package/dist/android-toolchain.js +4 -300
  23. package/dist/app-config.d.ts +25 -0
  24. package/dist/app-config.d.ts.map +1 -0
  25. package/dist/app-config.js +106 -0
  26. package/dist/bundle-build.d.ts.map +1 -1
  27. package/dist/bundle-build.js +11 -0
  28. package/dist/cli.d.ts +3 -0
  29. package/dist/cli.d.ts.map +1 -0
  30. package/dist/cli.js +66 -0
  31. package/dist/commands/build-execution.d.ts +41 -0
  32. package/dist/commands/build-execution.d.ts.map +1 -0
  33. package/dist/commands/build-execution.js +182 -0
  34. package/dist/commands/configuration.d.ts +19 -0
  35. package/dist/commands/configuration.d.ts.map +1 -0
  36. package/dist/commands/configuration.js +174 -0
  37. package/dist/commands/development.d.ts +22 -0
  38. package/dist/commands/development.d.ts.map +1 -0
  39. package/dist/commands/development.js +132 -0
  40. package/dist/commands/device.d.ts +3 -0
  41. package/dist/commands/device.d.ts.map +1 -0
  42. package/dist/commands/device.js +86 -0
  43. package/dist/commands/doctor.d.ts +18 -0
  44. package/dist/commands/doctor.d.ts.map +1 -0
  45. package/dist/commands/doctor.js +320 -0
  46. package/dist/commands/help.d.ts +2 -0
  47. package/dist/commands/help.d.ts.map +1 -0
  48. package/dist/commands/help.js +118 -0
  49. package/dist/commands/i18n.d.ts +14 -0
  50. package/dist/commands/i18n.d.ts.map +1 -0
  51. package/dist/commands/i18n.js +88 -0
  52. package/dist/commands/logs.d.ts +3 -0
  53. package/dist/commands/logs.d.ts.map +1 -0
  54. package/dist/commands/logs.js +51 -0
  55. package/dist/commands/metadata.d.ts +3 -0
  56. package/dist/commands/metadata.d.ts.map +1 -0
  57. package/dist/commands/metadata.js +45 -0
  58. package/dist/commands/ota.d.ts +28 -0
  59. package/dist/commands/ota.d.ts.map +1 -0
  60. package/dist/commands/ota.js +203 -0
  61. package/dist/commands/project.d.ts +14 -0
  62. package/dist/commands/project.d.ts.map +1 -0
  63. package/dist/commands/project.js +122 -0
  64. package/dist/commands/remote-build.d.ts +35 -0
  65. package/dist/commands/remote-build.d.ts.map +1 -0
  66. package/dist/commands/remote-build.js +73 -0
  67. package/dist/commands/submit.d.ts +27 -0
  68. package/dist/commands/submit.d.ts.map +1 -0
  69. package/dist/commands/submit.js +92 -0
  70. package/dist/ecosystem.d.ts +9 -0
  71. package/dist/ecosystem.d.ts.map +1 -0
  72. package/dist/ecosystem.js +95 -0
  73. package/dist/frameworks.d.ts.map +1 -1
  74. package/dist/frameworks.js +5 -1
  75. package/dist/guidance/catalog.d.ts +3 -0
  76. package/dist/guidance/catalog.d.ts.map +1 -0
  77. package/dist/guidance/catalog.js +504 -0
  78. package/dist/guidance/types.d.ts +10 -0
  79. package/dist/guidance/types.d.ts.map +1 -0
  80. package/dist/guidance/types.js +1 -0
  81. package/dist/guidance.d.ts +2 -9
  82. package/dist/guidance.d.ts.map +1 -1
  83. package/dist/guidance.js +1 -502
  84. package/dist/i18n/discovery.d.ts +14 -0
  85. package/dist/i18n/discovery.d.ts.map +1 -0
  86. package/dist/i18n/discovery.js +106 -0
  87. package/dist/i18n/plan.d.ts +12 -0
  88. package/dist/i18n/plan.d.ts.map +1 -0
  89. package/dist/i18n/plan.js +95 -0
  90. package/dist/i18n/setup.d.ts +11 -0
  91. package/dist/i18n/setup.d.ts.map +1 -0
  92. package/dist/i18n/setup.js +47 -0
  93. package/dist/i18n/types.d.ts +17 -0
  94. package/dist/i18n/types.d.ts.map +1 -0
  95. package/dist/i18n/types.js +1 -0
  96. package/dist/index.d.ts +1 -1
  97. package/dist/index.d.ts.map +1 -1
  98. package/dist/index.js +4 -2069
  99. package/dist/ios/assets.d.ts +19 -0
  100. package/dist/ios/assets.d.ts.map +1 -0
  101. package/dist/ios/assets.js +128 -0
  102. package/dist/ios/production-build.d.ts +6 -0
  103. package/dist/ios/production-build.d.ts.map +1 -0
  104. package/dist/ios/production-build.js +200 -0
  105. package/dist/ios/project.d.ts +4 -0
  106. package/dist/ios/project.d.ts.map +1 -0
  107. package/dist/ios/project.js +43 -0
  108. package/dist/ios/simulator-build.d.ts +8 -0
  109. package/dist/ios/simulator-build.d.ts.map +1 -0
  110. package/dist/ios/simulator-build.js +188 -0
  111. package/dist/ios/simulator.d.ts +5 -0
  112. package/dist/ios/simulator.d.ts.map +1 -0
  113. package/dist/ios/simulator.js +60 -0
  114. package/dist/ios/types.d.ts +14 -0
  115. package/dist/ios/types.d.ts.map +1 -0
  116. package/dist/ios/types.js +1 -0
  117. package/dist/ios-build.d.ts +4 -37
  118. package/dist/ios-build.d.ts.map +1 -1
  119. package/dist/ios-build.js +3 -575
  120. package/dist/ios-host.d.ts.map +1 -1
  121. package/dist/ios-toolchain/inspection.d.ts +4 -0
  122. package/dist/ios-toolchain/inspection.d.ts.map +1 -0
  123. package/dist/ios-toolchain/inspection.js +211 -0
  124. package/dist/ios-toolchain/probes.d.ts +24 -0
  125. package/dist/ios-toolchain/probes.d.ts.map +1 -0
  126. package/dist/ios-toolchain/probes.js +127 -0
  127. package/dist/ios-toolchain/types.d.ts +17 -0
  128. package/dist/ios-toolchain/types.d.ts.map +1 -0
  129. package/dist/ios-toolchain/types.js +1 -0
  130. package/dist/ios-toolchain.d.ts +3 -18
  131. package/dist/ios-toolchain.d.ts.map +1 -1
  132. package/dist/ios-toolchain.js +1 -333
  133. package/dist/plugins/contracts.d.ts +28 -0
  134. package/dist/plugins/contracts.d.ts.map +1 -0
  135. package/dist/plugins/contracts.js +1 -0
  136. package/dist/plugins/discovery.d.ts +19 -0
  137. package/dist/plugins/discovery.d.ts.map +1 -0
  138. package/dist/plugins/discovery.js +250 -0
  139. package/dist/plugins/native-operations.d.ts +28 -0
  140. package/dist/plugins/native-operations.d.ts.map +1 -0
  141. package/dist/plugins/native-operations.js +217 -0
  142. package/dist/plugins/operations.d.ts +9 -0
  143. package/dist/plugins/operations.d.ts.map +1 -0
  144. package/dist/plugins/operations.js +76 -0
  145. package/dist/plugins/validation.d.ts +9 -0
  146. package/dist/plugins/validation.d.ts.map +1 -0
  147. package/dist/plugins/validation.js +52 -0
  148. package/dist/plugins.d.ts +3 -34
  149. package/dist/plugins.d.ts.map +1 -1
  150. package/dist/plugins.js +2 -595
  151. package/dist/process-runner.d.ts +4 -0
  152. package/dist/process-runner.d.ts.map +1 -1
  153. package/dist/process-runner.js +14 -0
  154. package/dist/remote.d.ts +22 -1
  155. package/dist/remote.d.ts.map +1 -1
  156. package/dist/remote.js +141 -2
  157. package/dist/rspeedy-app-config.d.ts +4 -0
  158. package/dist/rspeedy-app-config.d.ts.map +1 -0
  159. package/dist/rspeedy-app-config.js +32 -0
  160. package/dist/runtime/args.d.ts +3 -0
  161. package/dist/runtime/args.d.ts.map +1 -0
  162. package/dist/runtime/args.js +11 -0
  163. package/dist/runtime/build-commands.d.ts +3 -0
  164. package/dist/runtime/build-commands.d.ts.map +1 -0
  165. package/dist/runtime/build-commands.js +282 -0
  166. package/dist/runtime/context.d.ts +63 -0
  167. package/dist/runtime/context.d.ts.map +1 -0
  168. package/dist/runtime/context.js +179 -0
  169. package/dist/runtime/early-commands.d.ts +4 -0
  170. package/dist/runtime/early-commands.d.ts.map +1 -0
  171. package/dist/runtime/early-commands.js +284 -0
  172. package/dist/runtime/project.d.ts +8 -0
  173. package/dist/runtime/project.d.ts.map +1 -0
  174. package/dist/runtime/project.js +38 -0
  175. package/dist/runtime/state.d.ts +47 -0
  176. package/dist/runtime/state.d.ts.map +1 -0
  177. package/dist/runtime/state.js +33 -0
  178. package/dist/secure-store/backends.d.ts +20 -0
  179. package/dist/secure-store/backends.d.ts.map +1 -0
  180. package/dist/secure-store/backends.js +248 -0
  181. package/dist/secure-store/types.d.ts +27 -0
  182. package/dist/secure-store/types.d.ts.map +1 -0
  183. package/dist/secure-store/types.js +1 -0
  184. package/dist/secure-store.d.ts +2 -26
  185. package/dist/secure-store.d.ts.map +1 -1
  186. package/dist/secure-store.js +3 -245
  187. package/package.json +7 -4
  188. package/templates/android-host/app/build.gradle +1 -0
  189. package/templates/android-host/app/src/main/java/template/MainActivity.java +98 -3
  190. package/templates/ios-host/__IOS_TARGET_NAME__/DemoLynxProvider.swift +26 -16
  191. 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,3 @@
1
+ import type { DevelopmentCommandContext } from "./development.js";
2
+ export declare function runDevice(context: DevelopmentCommandContext): Promise<void>;
3
+ //# sourceMappingURL=device.d.ts.map
@@ -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,2 @@
1
+ export declare function helpText(): string;
2
+ //# sourceMappingURL=help.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"help.d.ts","sourceRoot":"","sources":["../../src/commands/help.ts"],"names":[],"mappings":"AAAA,wBAAgB,QAAQ,IAAI,MAAM,CAqHjC"}