@lynxship/cli 0.1.18 → 0.1.20

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 CHANGED
@@ -90,11 +90,50 @@ pnpm --filter @octanejs/rspeedy-plugin exec rspeedy dev \
90
90
  --root examples/gallery --environment lynx
91
91
  ```
92
92
 
93
- Miso uses the official Haskell/Nix flake rather than an npm build script.
94
- Install Nix and the project's Haskell toolchain, then let LynxShip use the
95
- flake's `default`/`bundle` output or configure a project-specific output in
96
- `lynxship.json`. Miso remains experimental; a successful bundle does not
97
- prove a signed Android or iOS production build.
93
+ Miso uses the official Haskell/Nix flake rather than an npm build script by
94
+ default. Install Nix and the project's Haskell toolchain, then let LynxShip
95
+ use the flake's `default`/`bundle` output or configure a project-specific
96
+ output in `lynxship.json`. Miso remains experimental; a successful bundle
97
+ does not prove a signed Android or iOS production build.
98
+
99
+ MicroHs is an explicit, experimental toolchain path. It is not silently
100
+ selected and it is not a drop-in GHCJS replacement: the project must provide
101
+ a real adapter command that understands the Miso/MicroHs compatibility layer
102
+ and writes the configured Lynx bundle. The acquisition layer accepts either a
103
+ local binary or a project-owned HTTPS manifest with a SHA-256 digest and,
104
+ optionally, an Ed25519 signature:
105
+
106
+ ```json
107
+ {
108
+ "build": {
109
+ "development": {
110
+ "miso": {
111
+ "compiler": "microhs",
112
+ "artifact": "result/main.lynx.bundle",
113
+ "microhs": {
114
+ "version": "0.16.6.0",
115
+ "manifest": "toolchains/microhs-manifest.json",
116
+ "publicKey": "-----BEGIN PUBLIC KEY-----\\n...\\n-----END PUBLIC KEY-----",
117
+ "adapter": {
118
+ "command": "node",
119
+ "args": ["tools/miso-microhs-adapter.mjs"]
120
+ }
121
+ }
122
+ }
123
+ }
124
+ }
125
+ }
126
+ ```
127
+
128
+ The manifest must contain an artifact for the current host (`darwin-arm64`,
129
+ `darwin-x64`, `linux-arm64`, `linux-x64` or `win32-x64`). LynxShip downloads
130
+ it to a user cache, verifies the digest before making it executable, and
131
+ never treats the host architecture as the Android/iOS packaging target. A
132
+ local binary can be used for development with
133
+ `build.<profile>.miso.microhs.binary`. The official MicroHs repository does
134
+ not currently publish a verified release fleet, so LynxShip does not invent
135
+ download URLs; teams must own and pin the manifest or keep using the official
136
+ GHCJS/Nix path.
98
137
 
99
138
  See the source-verified fixture notes in the repository's
100
139
  `examples/lynx-octane-fixture` and `examples/miso-lynx-fixture` directories,
@@ -5,8 +5,21 @@ export interface BundleBuildOptions {
5
5
  script?: string;
6
6
  rspeedyArgs?: string[];
7
7
  miso?: {
8
+ compiler?: "ghcjs" | "microhs";
8
9
  attribute?: string;
9
10
  artifact?: string;
11
+ microhs?: {
12
+ version?: string;
13
+ binary?: string;
14
+ manifest?: string;
15
+ manifestUrl?: string;
16
+ cacheDir?: string;
17
+ publicKey?: string;
18
+ adapter?: {
19
+ command: string;
20
+ args?: string[];
21
+ };
22
+ };
10
23
  };
11
24
  }
12
25
  export declare function resolveMisoBuildTarget(flake: string, configuredAttribute?: string): string | undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"bundle-build.d.ts","sourceRoot":"","sources":["../src/bundle-build.ts"],"names":[],"mappings":"AAgBA,MAAM,WAAW,kBAAkB;IACjC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,IAAI,CAAC,EAAE;QACL,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;CACH;AAED,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,MAAM,EACb,mBAAmB,CAAC,EAAE,MAAM,GAC3B,MAAM,GAAG,SAAS,CAWpB;AAcD,wBAAsB,eAAe,CACnC,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,IAAI,CAAC,CA8Df"}
1
+ {"version":3,"file":"bundle-build.d.ts","sourceRoot":"","sources":["../src/bundle-build.ts"],"names":[],"mappings":"AAgBA,MAAM,WAAW,kBAAkB;IACjC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,IAAI,CAAC,EAAE;QACL,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;QAC/B,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,OAAO,CAAC,EAAE;YACR,OAAO,CAAC,EAAE,MAAM,CAAC;YACjB,MAAM,CAAC,EAAE,MAAM,CAAC;YAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;YAClB,WAAW,CAAC,EAAE,MAAM,CAAC;YACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;YAClB,SAAS,CAAC,EAAE,MAAM,CAAC;YACnB,OAAO,CAAC,EAAE;gBAAE,OAAO,EAAE,MAAM,CAAC;gBAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;aAAE,CAAC;SAChD,CAAC;KACH,CAAC;CACH;AAED,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,MAAM,EACb,mBAAmB,CAAC,EAAE,MAAM,GAC3B,MAAM,GAAG,SAAS,CAWpB;AAuGD,wBAAsB,eAAe,CACnC,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,IAAI,CAAC,CA+Df"}
@@ -1,7 +1,7 @@
1
- import { copyFile, mkdir, readFile } from "node:fs/promises";
2
- import { existsSync } from "node:fs";
3
- import { basename, join, resolve } from "node:path";
4
- import { assert } from "@lynxship/contracts";
1
+ import { copyFile, mkdir, readFile, stat } from "node:fs/promises";
2
+ import { basename, isAbsolute, join, relative, resolve } from "node:path";
3
+ import { assert, LynxShipError } from "@lynxship/contracts";
4
+ import { acquireMicroHs } from "@lynxship/microhs";
5
5
  import { commandExists, packageManagerScriptCommand, runProcess, runRspeedy, } from "./process-runner.js";
6
6
  import { detectLynxFramework } from "./frameworks.js";
7
7
  export function resolveMisoBuildTarget(flake, configuredAttribute) {
@@ -29,8 +29,72 @@ async function resolveBundleScript(root) {
29
29
  }
30
30
  return "build";
31
31
  }
32
+ async function copyMisoBundle(root, artifactPath, onOutput) {
33
+ const artifact = resolve(root, artifactPath);
34
+ const relativeArtifact = relative(resolve(root), artifact);
35
+ assert(relativeArtifact !== "" &&
36
+ !relativeArtifact.startsWith("..") &&
37
+ !isAbsolute(relativeArtifact), "BUILD_MISO_ARTIFACT_OUTSIDE_PROJECT", "The Miso bundle artifact must remain inside the project directory: " +
38
+ artifactPath);
39
+ let artifactInfo;
40
+ try {
41
+ artifactInfo = await stat(artifact);
42
+ }
43
+ catch {
44
+ assert(false, "BUILD_MISO_BUNDLE_MISSING", "The Miso adapter did not produce the configured Lynx bundle: " +
45
+ artifact);
46
+ }
47
+ assert(artifactInfo?.isFile() && artifactInfo.size > 0, "BUILD_MISO_BUNDLE_INVALID", "The Miso adapter produced an empty or non-file Lynx bundle: " + artifact);
48
+ const output = join(root, "dist", basename(artifact));
49
+ await mkdir(join(root, "dist"), { recursive: true });
50
+ await copyFile(artifact, output);
51
+ onOutput?.("Miso bundle ready: " + output);
52
+ }
53
+ async function buildMisoWithMicroHs(root, options) {
54
+ const microhs = options.miso?.microhs;
55
+ assert(microhs?.adapter?.command, "BUILD_MISO_MICROHS_ADAPTER_REQUIRED", "MicroHs is not a drop-in GHCJS replacement. Configure build.<profile>.miso.microhs.adapter with the real Miso/MicroHs adapter command, or use compiler=ghcjs.");
56
+ const resolveProjectPath = (value) => value ? resolve(root, value) : undefined;
57
+ const configuredBinary = microhs.binary ?? process.env.LYNXSHIP_MICROHS_BINARY;
58
+ const configuredManifest = microhs.manifest ?? process.env.LYNXSHIP_MICROHS_MANIFEST;
59
+ const configuredCache = microhs.cacheDir ?? process.env.LYNXSHIP_MICROHS_CACHE;
60
+ const toolchain = await acquireMicroHs({
61
+ version: microhs.version ?? process.env.LYNXSHIP_MICROHS_VERSION,
62
+ binaryPath: resolveProjectPath(configuredBinary),
63
+ manifestPath: resolveProjectPath(configuredManifest),
64
+ manifestUrl: microhs.manifestUrl ?? process.env.LYNXSHIP_MICROHS_MANIFEST_URL,
65
+ cacheDir: resolveProjectPath(configuredCache),
66
+ publicKey: microhs.publicKey ?? process.env.LYNXSHIP_MICROHS_PUBLIC_KEY,
67
+ });
68
+ const artifact = options.miso?.artifact ?? "result/main.lynx.bundle";
69
+ try {
70
+ await runProcess(microhs.adapter.command, microhs.adapter.args ?? [], {
71
+ cwd: root,
72
+ env: {
73
+ ...options.env,
74
+ LYNXSHIP_MICROHS_BINARY: toolchain.binaryPath,
75
+ LYNXSHIP_MICROHS_VERSION: toolchain.version,
76
+ LYNXSHIP_MISO_COMPILER: "microhs",
77
+ LYNXSHIP_MISO_OUTPUT: resolve(root, artifact),
78
+ },
79
+ quiet: options.quiet,
80
+ onOutput: options.onOutput,
81
+ });
82
+ }
83
+ catch (error) {
84
+ const detail = error instanceof Error ? error.message : String(error);
85
+ throw new LynxShipError("BUILD_MISO_MICROHS_ADAPTER_FAILED", `The configured Miso/MicroHs adapter failed: ${detail}`, { cause: detail });
86
+ }
87
+ await copyMisoBundle(root, artifact, options.onOutput);
88
+ }
32
89
  export async function buildLynxBundle(root, options = {}) {
33
90
  const framework = await detectLynxFramework(root);
91
+ if (framework.framework === "miso" &&
92
+ options.miso?.compiler === "microhs" &&
93
+ !options.script &&
94
+ !options.rspeedyArgs) {
95
+ await buildMisoWithMicroHs(root, options);
96
+ return;
97
+ }
34
98
  if (framework.buildSystem === "miso-nix" &&
35
99
  !options.script &&
36
100
  !options.rspeedyArgs) {
@@ -44,12 +108,7 @@ export async function buildLynxBundle(root, options = {}) {
44
108
  quiet: options.quiet,
45
109
  onOutput: options.onOutput,
46
110
  });
47
- const artifact = resolve(root, options.miso?.artifact ?? "result/main.lynx.bundle");
48
- assert(existsSync(artifact), "BUILD_MISO_BUNDLE_MISSING", "Miso did not produce the configured Lynx bundle: " + artifact);
49
- const output = join(root, "dist", basename(artifact));
50
- await mkdir(join(root, "dist"), { recursive: true });
51
- await copyFile(artifact, output);
52
- options.onOutput?.("Miso bundle ready: " + output);
111
+ await copyMisoBundle(root, options.miso?.artifact ?? "result/main.lynx.bundle", options.onOutput);
53
112
  return;
54
113
  }
55
114
  if (!options.script && options.rspeedyArgs) {
package/dist/config.d.ts CHANGED
@@ -5,8 +5,21 @@ export interface BuildProfile {
5
5
  channel?: string;
6
6
  environment?: string;
7
7
  miso?: {
8
+ compiler?: "ghcjs" | "microhs";
8
9
  attribute?: string;
9
10
  artifact?: string;
11
+ microhs?: {
12
+ version?: string;
13
+ binary?: string;
14
+ manifest?: string;
15
+ manifestUrl?: string;
16
+ cacheDir?: string;
17
+ publicKey?: string;
18
+ adapter?: {
19
+ command: string;
20
+ args?: string[];
21
+ };
22
+ };
10
23
  };
11
24
  android?: {
12
25
  artifact?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
package/dist/config.js CHANGED
@@ -56,6 +56,51 @@ export function validateConfig(config, options = {}) {
56
56
  assert(validString || validTuple, "CONFIG_PLUGINS", "Each plugin must be a package name or [package name, JSON options]");
57
57
  }
58
58
  }
59
+ if (value.build !== undefined) {
60
+ assert(typeof value.build === "object" &&
61
+ value.build !== null &&
62
+ !Array.isArray(value.build), "CONFIG_BUILD", "build must be an object keyed by profile name");
63
+ }
64
+ for (const [profileName, profile] of Object.entries(value.build ?? {})) {
65
+ assert(profile !== null &&
66
+ typeof profile === "object" &&
67
+ !Array.isArray(profile), "CONFIG_PROFILE", `build.${profileName} must be an object`);
68
+ const miso = profile.miso;
69
+ if (!miso)
70
+ continue;
71
+ assert(typeof miso === "object" && !Array.isArray(miso), "CONFIG_MISO", `build.${profileName}.miso must be an object`);
72
+ assert(miso.compiler === undefined ||
73
+ miso.compiler === "ghcjs" ||
74
+ miso.compiler === "microhs", "CONFIG_MISO_COMPILER", `build.${profileName}.miso.compiler must be ghcjs or microhs`);
75
+ if (!miso.microhs)
76
+ continue;
77
+ const microhs = miso.microhs;
78
+ assert(typeof microhs === "object" && !Array.isArray(microhs), "CONFIG_MISO_MICROHS", `build.${profileName}.miso.microhs must be an object`);
79
+ assert(microhs.adapter === undefined ||
80
+ (typeof microhs.adapter.command === "string" &&
81
+ microhs.adapter.command.trim().length > 0 &&
82
+ (microhs.adapter.args === undefined ||
83
+ (Array.isArray(microhs.adapter.args) &&
84
+ microhs.adapter.args.every((arg) => typeof arg === "string")))), "CONFIG_MISO_MICROHS_ADAPTER", `build.${profileName}.miso.microhs.adapter must contain a command and string args`);
85
+ assert(microhs.version === undefined || typeof microhs.version === "string", "CONFIG_MISO_MICROHS_VERSION", `build.${profileName}.miso.microhs.version must be a string`);
86
+ assert(microhs.binary === undefined || typeof microhs.binary === "string", "CONFIG_MISO_MICROHS_BINARY", `build.${profileName}.miso.microhs.binary must be a file path`);
87
+ assert(microhs.manifest === undefined || typeof microhs.manifest === "string", "CONFIG_MISO_MICROHS_MANIFEST", `build.${profileName}.miso.microhs.manifest must be a file path`);
88
+ assert(microhs.manifestUrl === undefined ||
89
+ typeof microhs.manifestUrl === "string", "CONFIG_MISO_MICROHS_MANIFEST", `build.${profileName}.miso.microhs.manifestUrl must be a URL`);
90
+ if (microhs.manifestUrl) {
91
+ let parsedManifestUrl;
92
+ try {
93
+ parsedManifestUrl = new URL(microhs.manifestUrl);
94
+ }
95
+ catch {
96
+ // The assertion below emits the stable configuration error.
97
+ }
98
+ assert(parsedManifestUrl?.protocol === "https:", "CONFIG_MISO_MICROHS_MANIFEST", `build.${profileName}.miso.microhs.manifestUrl must be a valid HTTPS URL`);
99
+ }
100
+ assert(microhs.cacheDir === undefined || typeof microhs.cacheDir === "string", "CONFIG_MISO_MICROHS_CACHE", `build.${profileName}.miso.microhs.cacheDir must be a directory path`);
101
+ assert(microhs.publicKey === undefined || typeof microhs.publicKey === "string", "CONFIG_MISO_MICROHS_KEY", `build.${profileName}.miso.microhs.publicKey must be a PEM string`);
102
+ assert(!(microhs.manifest && microhs.manifestUrl), "CONFIG_MISO_MICROHS_MANIFEST", `build.${profileName}.miso.microhs must use either manifest or manifestUrl, not both`);
103
+ }
59
104
  assert(value.runtimeVersion?.policy === undefined ||
60
105
  ["fingerprint", "manual"].includes(value.runtimeVersion.policy), "CONFIG_RUNTIME_POLICY", "runtimeVersion.policy must be fingerprint or manual");
61
106
  if (value.runtimeVersion?.policy === "manual")
@@ -1 +1 @@
1
- {"version":3,"file":"guidance.d.ts","sourceRoot":"","sources":["../src/guidance.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC;CAChC;AAmoBD,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,OAAO,EACd,OAAO,GAAE,eAAoB,GAC5B,WAAW,CAEb"}
1
+ {"version":3,"file":"guidance.d.ts","sourceRoot":"","sources":["../src/guidance.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC;CAChC;AA8sBD,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,OAAO,EACd,OAAO,GAAE,eAAoB,GAC5B,WAAW,CAEb"}
package/dist/guidance.js CHANGED
@@ -127,6 +127,81 @@ const guidance = {
127
127
  ],
128
128
  note: "Check build.production.miso.artifact and the output produced by the Miso flake.",
129
129
  },
130
+ BUILD_MISO_MICROHS_ADAPTER_REQUIRED: {
131
+ commands: [
132
+ "lynxship doctor --platform android",
133
+ "lynxship inspect",
134
+ "lynxship build --platform android --profile production",
135
+ ],
136
+ note: "MicroHs is opt-in and is not a drop-in GHCJS replacement. Configure build.<profile>.miso.microhs with a pinned binary or manifest and a real adapter command, or set build.<profile>.miso.compiler to ghcjs.",
137
+ },
138
+ BUILD_MISO_MICROHS_ADAPTER_FAILED: {
139
+ commands: [
140
+ "lynxship doctor --platform android --profile production",
141
+ "lynxship inspect",
142
+ "lynxship build --platform android --profile production",
143
+ ],
144
+ note: "The real adapter or MicroHs compiler rejected the Miso source or failed to write the Lynx bundle. This does not prove Miso/MicroHs compatibility; use the official GHC/Nix workflow until the adapter supports the project's language extensions, packages, FFI and bundle output.",
145
+ },
146
+ BUILD_MISO_ARTIFACT_OUTSIDE_PROJECT: {
147
+ commands: ["lynxship inspect", "lynxship doctor --platform android"],
148
+ note: "Set build.<profile>.miso.artifact to a file inside the project, such as result/main.lynx.bundle.",
149
+ },
150
+ BUILD_MISO_BUNDLE_INVALID: {
151
+ commands: [
152
+ "lynxship inspect",
153
+ "lynxship build --platform android --profile production",
154
+ ],
155
+ note: "The configured Miso artifact must be a non-empty file produced by the adapter.",
156
+ },
157
+ MICROHS_MANIFEST_REQUIRED: {
158
+ commands: [
159
+ "lynxship doctor --platform android",
160
+ "lynxship inspect",
161
+ "lynxship build --platform android --profile production",
162
+ ],
163
+ note: "Provide build.<profile>.miso.microhs.binary for an existing verified mhs binary, or provide a pinned manifest/manifestUrl. LynxShip never downloads an unpinned compiler.",
164
+ },
165
+ MICROHS_HOST_UNSUPPORTED: {
166
+ commands: ["lynxship doctor --platform android", "lynxship inspect"],
167
+ note: "Use a verified MicroHs host binary for darwin-arm64, darwin-x64, linux-arm64, linux-x64 or win32-x64, or select the official ghcjs workflow.",
168
+ },
169
+ MICROHS_ARTIFACT_UNAVAILABLE: {
170
+ commands: ["lynxship doctor --platform android", "lynxship inspect"],
171
+ note: "Publish or select a manifest artifact for the current host architecture. The compiler host architecture is independent from the Android/iOS packaging target.",
172
+ },
173
+ MICROHS_BINARY_MISSING: {
174
+ commands: ["lynxship doctor --platform android", "lynxship inspect"],
175
+ note: "The configured MicroHs binary does not exist. Fix build.<profile>.miso.microhs.binary or use a pinned manifest.",
176
+ },
177
+ MICROHS_VERSION_MISMATCH: {
178
+ commands: ["lynxship inspect", "lynxship doctor --platform android"],
179
+ note: "The requested MicroHs version does not match the pinned manifest. Keep compiler and adapter versions aligned.",
180
+ },
181
+ MICROHS_MANIFEST_INVALID: {
182
+ commands: ["lynxship inspect", "lynxship doctor --platform android"],
183
+ note: "The MicroHs manifest is invalid. It must declare schemaVersion 1, a source commit and SHA-256-pinned artifacts.",
184
+ },
185
+ MICROHS_MANIFEST_READ_FAILED: {
186
+ commands: ["lynxship inspect", "lynxship doctor --platform android"],
187
+ note: "Check the configured local MicroHs manifest path and permissions.",
188
+ },
189
+ MICROHS_MANIFEST_FETCH_FAILED: {
190
+ commands: ["lynxship inspect", "lynxship doctor --platform android"],
191
+ note: "Check the pinned MicroHs manifest URL and network access. LynxShip does not silently fall back to an unverified download.",
192
+ },
193
+ MICROHS_HASH_MISMATCH: {
194
+ commands: ["lynxship inspect", "lynxship doctor --platform android"],
195
+ note: "The downloaded compiler did not match its pinned SHA-256. Do not reuse the cache; verify the release manifest and artifact source.",
196
+ },
197
+ MICROHS_SIGNATURE_INVALID: {
198
+ commands: ["lynxship inspect", "lynxship doctor --platform android"],
199
+ note: "The MicroHs artifact signature did not verify. Check the pinned release public key and manifest; the binary was rejected.",
200
+ },
201
+ MICROHS_SIGNATURE_KEY_REQUIRED: {
202
+ commands: ["lynxship inspect", "lynxship doctor --platform android"],
203
+ note: "The manifest declares a signed MicroHs artifact. Configure the pinned public key before using it.",
204
+ },
130
205
  WEB_BUNDLE_MISSING: {
131
206
  commands: [
132
207
  "lynxship doctor --platform web",
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";
@@ -533,6 +534,14 @@ Global options:
533
534
  --simulator Build/install an iOS .app or install one with simctl
534
535
  --help Show this complete command reference
535
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
+
536
545
  Node support: Node 22/24 LTS or Node 26 Current. Use Node 24 LTS for production.`;
537
546
  }
538
547
  async function looksLikeLynxProject() {
@@ -1008,7 +1017,13 @@ async function main() {
1008
1017
  const autolinkForPlatform = autolink && (doctorPlatform === "android" || doctorPlatform === "ios")
1009
1018
  ? autolink[doctorPlatform]
1010
1019
  : undefined;
1011
- const lockfile = await findLockfile(root);
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);
1012
1027
  const credentialStore = credentialStorageDescription();
1013
1028
  const nativeCredentialStore = !credentialStore.includes("owner-only");
1014
1029
  const androidHost = doctorPlatform === "android" ? await hasAndroidHost(root) : false;
@@ -1038,7 +1053,23 @@ async function main() {
1038
1053
  const nodeMajor = Number(process.versions.node.split(".")[0]);
1039
1054
  const nodeSupported = nodeMajor >= 22;
1040
1055
  const nodeRecommended = nodeMajor % 2 === 0;
1041
- const framework = await detectLynxFramework(root);
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
+ }
1042
1073
  const pluginReport = await inspectProjectPlugins(root, config);
1043
1074
  const invalidPlugins = pluginReport.plugins.filter((plugin) => plugin.status !== "ready");
1044
1075
  const checks = [
@@ -1057,7 +1088,7 @@ async function main() {
1057
1088
  framework.evidence +
1058
1089
  (framework.experimental ? " · early access" : ""),
1059
1090
  },
1060
- ...(framework.framework === "miso"
1091
+ ...(framework.framework === "miso" && misoCompiler !== "microhs"
1061
1092
  ? [
1062
1093
  {
1063
1094
  name: "miso-nix",
@@ -1070,7 +1101,45 @@ async function main() {
1070
1101
  : "missing · fix: install Nix and rerun doctor",
1071
1102
  },
1072
1103
  ]
1073
- : []),
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
+ : []),
1074
1143
  {
1075
1144
  name: "node",
1076
1145
  ok: nodeSupported,
@@ -1086,7 +1155,7 @@ async function main() {
1086
1155
  : `${process.version} · recommended: Node 24 LTS`,
1087
1156
  },
1088
1157
  {
1089
- name: "package-manager-lockfile",
1158
+ name: "dependency-lockfile",
1090
1159
  ok: Boolean(lockfile),
1091
1160
  status: lockfile ? "pass" : "fail",
1092
1161
  value: lockfile ?? "missing · fix: pnpm install (or npm install)",
@@ -1 +1 @@
1
- {"version":3,"file":"components.d.ts","sourceRoot":"","sources":["../../src/ui/components.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAK7C,MAAM,WAAW,MAAM;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,SAAS,CAAC;CACxB;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAEjD;AAED,eAAO,MAAM,GAAG;qBACG,MAAM,GAAG,IAAI;kBAGhB,MAAM,GAAG,IAAI;mBAGZ,MAAM,GAAG,IAAI;kBAGd,MAAM,GAAG,IAAI;mBAGZ,MAAM,GAAG,IAAI;CAG7B,CAAC;AAgBF,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CA6C9D;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,MAAM,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7C,IAAI,IAAI,IAAI,CAAC;CACd;AA6CD,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAoBnD;AA6BD,wBAAgB,cAAc,CAC5B,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,OAAO,GACf,cAAc,CAuEhB;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,IAAI,IAAI,IAAI,CAAC;CACd;AAED,wBAAgB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,aAAa,CA2BlE;AAYD,eAAO,MAAM,IAAI;oBACC,MAAM;iBACT,MAAM;iBACN,MAAM;kBACL,MAAM;CACrB,CAAC;AAEF,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,UAAO,GAAG,IAAI,CAE/D;AAED,wBAAgB,SAAS,CACvB,QAAQ,EAAE,MAAM,EAAE,EAClB,IAAI,CAAC,EAAE,MAAM,EACb,WAAW,CAAC,EAAE,MAAM,GACnB,IAAI,CAQN;AAED,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,MAAM,EACX,SAAS,CAAC,EAAE,MAAM,EAClB,OAAO,UAAO,GACb,IAAI,CAQN;AAED,wBAAsB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,UAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAmB5E"}
1
+ {"version":3,"file":"components.d.ts","sourceRoot":"","sources":["../../src/ui/components.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAK7C,MAAM,WAAW,MAAM;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,SAAS,CAAC;CACxB;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAEjD;AAED,eAAO,MAAM,GAAG;qBACG,MAAM,GAAG,IAAI;kBAGhB,MAAM,GAAG,IAAI;mBAGZ,MAAM,GAAG,IAAI;kBAGd,MAAM,GAAG,IAAI;mBAGZ,MAAM,GAAG,IAAI;CAG7B,CAAC;AAgBF,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CA6C9D;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,MAAM,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7C,IAAI,IAAI,IAAI,CAAC;CACd;AA6CD,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAoBnD;AA6BD,wBAAgB,cAAc,CAC5B,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,OAAO,GACf,cAAc,CAwEhB;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,IAAI,IAAI,IAAI,CAAC;CACd;AAED,wBAAgB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,aAAa,CA2BlE;AAYD,eAAO,MAAM,IAAI;oBACC,MAAM;iBACT,MAAM;iBACN,MAAM;kBACL,MAAM;CACrB,CAAC;AAEF,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,UAAO,GAAG,IAAI,CAE/D;AAED,wBAAgB,SAAS,CACvB,QAAQ,EAAE,MAAM,EAAE,EAClB,IAAI,CAAC,EAAE,MAAM,EACb,WAAW,CAAC,EAAE,MAAM,GACnB,IAAI,CAQN;AAED,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,MAAM,EACX,SAAS,CAAC,EAAE,MAAM,EAClB,OAAO,UAAO,GACb,IAAI,CAQN;AAED,wBAAsB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,UAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAmB5E"}
@@ -187,7 +187,8 @@ export function createProgress(label, enabled) {
187
187
  spinnerIndex = (spinnerIndex + 1) % spinnerFrames.length;
188
188
  bar.update(currentValue, payload(currentLabel));
189
189
  }, 120);
190
- timer.unref?.();
190
+ const nodeTimer = timer;
191
+ nodeTimer.unref?.();
191
192
  const untrack = trackAnimation(() => {
192
193
  clearInterval(timer);
193
194
  bar.stop();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lynxship/cli",
3
- "version": "0.1.18",
3
+ "version": "0.1.20",
4
4
  "description": "Build, sign, store, submit and update LynxJS applications from the terminal.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -71,21 +71,22 @@
71
71
  "@aws-sdk/client-s3": "3.1116.0",
72
72
  "@aws-sdk/lib-storage": "3.1116.0",
73
73
  "@aws-sdk/s3-request-presigner": "3.1116.0",
74
+ "@resvg/resvg-js": "2.6.2",
74
75
  "boxen": "8.0.1",
75
76
  "chalk": "5.4.1",
76
77
  "cli-progress": "3.12.0",
77
- "ora": "8.2.0",
78
- "qrcode-terminal": "0.12.0",
79
- "qr-code-styling": "1.9.2",
80
- "@resvg/resvg-js": "2.6.2",
81
78
  "jsdom": "29.1.1",
79
+ "ora": "8.2.0",
82
80
  "pngjs": "7.0.0",
81
+ "qr-code-styling": "1.9.2",
82
+ "qrcode-terminal": "0.12.0",
83
83
  "@lynxship/build-orchestrator": "0.1.0",
84
84
  "@lynxship/contracts": "0.1.0",
85
- "@lynxship/submit": "0.1.0",
86
85
  "@lynxship/plugin-api": "0.1.0",
86
+ "@lynxship/db": "0.1.0",
87
+ "@lynxship/submit": "0.1.0",
87
88
  "@lynxship/signing": "0.1.0",
88
- "@lynxship/db": "0.1.0"
89
+ "@lynxship/microhs": "0.1.0"
89
90
  },
90
91
  "devDependencies": {
91
92
  "@types/cli-progress": "3.11.6",