@lynxship/cli 0.1.16 → 0.1.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +66 -6
- package/dist/bundle-build.d.ts +13 -0
- package/dist/bundle-build.d.ts.map +1 -1
- package/dist/bundle-build.js +69 -10
- package/dist/config.d.ts +15 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +60 -0
- package/dist/guidance.d.ts.map +1 -1
- package/dist/guidance.js +75 -0
- package/dist/index.js +180 -6
- package/dist/plugin-api.d.ts +2 -0
- package/dist/plugin-api.d.ts.map +1 -0
- package/dist/plugin-api.js +1 -0
- package/dist/plugins.d.ts +35 -0
- package/dist/plugins.d.ts.map +1 -0
- package/dist/plugins.js +595 -0
- package/package.json +15 -9
package/README.md
CHANGED
|
@@ -25,6 +25,26 @@ npx @lynxship/cli@latest doctor --project-dir ./my-lynx-app
|
|
|
25
25
|
|
|
26
26
|
The package exposes the `lynxship` executable.
|
|
27
27
|
|
|
28
|
+
## Plugin ecosystem
|
|
29
|
+
|
|
30
|
+
Install a community plugin as a normal project dependency, list it in
|
|
31
|
+
`lynxship.json`, then validate it before building:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npm install --save-dev @example/lynx-plugin
|
|
35
|
+
npx lynxship plugin doctor
|
|
36
|
+
npx lynxship plugin list
|
|
37
|
+
npx lynxship plugin apply --platform android --profile production
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
The public contract is exported by `@lynxship/plugin-api`. Plugins can make
|
|
41
|
+
JSON configuration contributions and bounded, idempotent Android/iOS/native
|
|
42
|
+
file changes. Autolink remains the official Lynx `lynx.lib.json` and codegen
|
|
43
|
+
workflow. Template and cloud contributions are discoverable metadata until a
|
|
44
|
+
reviewed provider or template service consumes them.
|
|
45
|
+
|
|
46
|
+
See the full contract in the repository `docs/plugin-ecosystem.md`.
|
|
47
|
+
|
|
28
48
|
## Vue Lynx projects
|
|
29
49
|
|
|
30
50
|
LynxShip supports projects created with the official Vue Lynx scaffold. Vue
|
|
@@ -70,11 +90,50 @@ pnpm --filter @octanejs/rspeedy-plugin exec rspeedy dev \
|
|
|
70
90
|
--root examples/gallery --environment lynx
|
|
71
91
|
```
|
|
72
92
|
|
|
73
|
-
Miso uses the official Haskell/Nix flake rather than an npm build script
|
|
74
|
-
Install Nix and the project's Haskell toolchain, then let LynxShip
|
|
75
|
-
flake's `default`/`bundle` output or configure a project-specific
|
|
76
|
-
`lynxship.json`. Miso remains experimental; a successful bundle
|
|
77
|
-
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.
|
|
78
137
|
|
|
79
138
|
See the source-verified fixture notes in the repository's
|
|
80
139
|
`examples/lynx-octane-fixture` and `examples/miso-lynx-fixture` directories,
|
|
@@ -514,7 +573,8 @@ actual recording and analysis.
|
|
|
514
573
|
|
|
515
574
|
## Package layout
|
|
516
575
|
|
|
517
|
-
The CLI is backed by public `@lynxship/*` runtime packages in this workspace
|
|
576
|
+
The CLI is backed by public `@lynxship/*` runtime packages in this workspace,
|
|
577
|
+
including the public `@lynxship/plugin-api` contract.
|
|
518
578
|
Their published versions may differ from the CLI version; workspace ranges are
|
|
519
579
|
rewritten to released versions when the package is packed. Publish a changed
|
|
520
580
|
runtime package before publishing the CLI when its source or version changed.
|
package/dist/bundle-build.d.ts
CHANGED
|
@@ -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;
|
|
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"}
|
package/dist/bundle-build.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { copyFile, mkdir, readFile } from "node:fs/promises";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
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
|
-
|
|
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
|
@@ -1,11 +1,25 @@
|
|
|
1
1
|
import { type Platform } from "@lynxship/contracts";
|
|
2
|
+
import type { PluginReference } from "@lynxship/plugin-api";
|
|
2
3
|
export interface BuildProfile {
|
|
3
4
|
distribution?: string;
|
|
4
5
|
channel?: string;
|
|
5
6
|
environment?: string;
|
|
6
7
|
miso?: {
|
|
8
|
+
compiler?: "ghcjs" | "microhs";
|
|
7
9
|
attribute?: string;
|
|
8
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
|
+
};
|
|
9
23
|
};
|
|
10
24
|
android?: {
|
|
11
25
|
artifact?: string;
|
|
@@ -43,6 +57,7 @@ export interface BuildProfile {
|
|
|
43
57
|
}
|
|
44
58
|
export interface LynxShipConfig {
|
|
45
59
|
projectId?: string;
|
|
60
|
+
plugins?: PluginReference[];
|
|
46
61
|
cli?: {
|
|
47
62
|
apiUrl?: string;
|
|
48
63
|
organizationId?: string;
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAEA,OAAO,EAAU,KAAK,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAE5D,MAAM,WAAW,YAAY;IAC3B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE;QACL,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/config.js
CHANGED
|
@@ -33,6 +33,7 @@ const allowedRootKeys = new Set([
|
|
|
33
33
|
"submit",
|
|
34
34
|
"update",
|
|
35
35
|
"artifacts",
|
|
36
|
+
"plugins",
|
|
36
37
|
]);
|
|
37
38
|
export function validateConfig(config, options = {}) {
|
|
38
39
|
assert(config && typeof config === "object" && !Array.isArray(config), "CONFIG_INVALID", "lynxship.json must contain an object");
|
|
@@ -41,6 +42,65 @@ export function validateConfig(config, options = {}) {
|
|
|
41
42
|
assert(!options.ci || unknown.length === 0, "CONFIG_UNKNOWN_KEY", `Unknown configuration key(s): ${unknown.join(", ")}`, { unknown });
|
|
42
43
|
if (value.projectId !== undefined)
|
|
43
44
|
assert(typeof value.projectId === "string" && value.projectId.length > 0, "CONFIG_PROJECT_ID", "projectId must be a non-empty string");
|
|
45
|
+
if (value.plugins !== undefined) {
|
|
46
|
+
assert(Array.isArray(value.plugins), "CONFIG_PLUGINS", "plugins must be an array of package names or [package, options] tuples");
|
|
47
|
+
for (const plugin of value.plugins) {
|
|
48
|
+
const validString = typeof plugin === "string" && plugin.length > 0;
|
|
49
|
+
const validTuple = Array.isArray(plugin) &&
|
|
50
|
+
plugin.length === 2 &&
|
|
51
|
+
typeof plugin[0] === "string" &&
|
|
52
|
+
plugin[0].length > 0 &&
|
|
53
|
+
plugin[1] !== null &&
|
|
54
|
+
typeof plugin[1] === "object" &&
|
|
55
|
+
!Array.isArray(plugin[1]);
|
|
56
|
+
assert(validString || validTuple, "CONFIG_PLUGINS", "Each plugin must be a package name or [package name, JSON options]");
|
|
57
|
+
}
|
|
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
|
+
}
|
|
44
104
|
assert(value.runtimeVersion?.policy === undefined ||
|
|
45
105
|
["fingerprint", "manual"].includes(value.runtimeVersion.policy), "CONFIG_RUNTIME_POLICY", "runtimeVersion.policy must be fingerprint or manual");
|
|
46
106
|
if (value.runtimeVersion?.policy === "manual")
|
package/dist/guidance.d.ts.map
CHANGED
|
@@ -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;
|
|
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",
|