@1agh/maude 0.17.1 → 0.17.2
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/cli/cli-wrapper.cjs +0 -0
- package/cli/commands/design.mjs +156 -14
- package/package.json +8 -8
- package/plugins/design/dev-server/build.ts +118 -6
- package/plugins/design/dev-server/canvas-pipeline.ts +5 -0
- package/plugins/design/dev-server/dist/client.bundle.js +3 -3
- package/plugins/design/dev-server/test/compile-entry.test.ts +134 -0
package/cli/cli-wrapper.cjs
CHANGED
|
File without changes
|
package/cli/commands/design.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { spawn } from 'node:child_process';
|
|
1
|
+
import { execSync, spawn } from 'node:child_process';
|
|
2
2
|
import { mkdir, readFile, readdir, stat, writeFile } from 'node:fs/promises';
|
|
3
|
-
import {
|
|
3
|
+
import { createRequire } from 'node:module';
|
|
4
|
+
import { basename, dirname, join, resolve } from 'node:path';
|
|
4
5
|
import { parseArgs } from '../lib/argv.mjs';
|
|
5
6
|
|
|
6
7
|
const SUBCOMMANDS = new Set(['serve', 'init', 'export', 'help']);
|
|
@@ -60,23 +61,42 @@ function usage() {
|
|
|
60
61
|
|
|
61
62
|
async function runServe({ args, pkgRoot }) {
|
|
62
63
|
const forwarded = args.slice(args.indexOf('serve') + 1);
|
|
64
|
+
const fs = await import('node:fs');
|
|
63
65
|
|
|
64
66
|
// Resolution order:
|
|
65
|
-
// 1. Side-channel from postinstall (cli/.platform-binary-path)
|
|
66
|
-
//
|
|
67
|
-
//
|
|
68
|
-
// 3.
|
|
69
|
-
//
|
|
67
|
+
// 1. Side-channel cache from postinstall (cli/.platform-binary-path).
|
|
68
|
+
// 2. Lazy resolve of @1agh/maude-<slug>/maude (postinstall was skipped
|
|
69
|
+
// — Bun global, --ignore-scripts, Docker layer without scripts, etc.).
|
|
70
|
+
// 3. (only in local dev tree) Bun + server.ts from source.
|
|
71
|
+
// 4. Hard-fail with actionable hint.
|
|
72
|
+
// Maintainers hacking on the dev-server source can force #3 with
|
|
73
|
+
// MAUDE_FORCE_SOURCE=1.
|
|
74
|
+
const forceSource = process.env.MAUDE_FORCE_SOURCE === '1';
|
|
70
75
|
const sideChannel = resolve(pkgRoot, 'cli', '.platform-binary-path');
|
|
71
76
|
let binPath = null;
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
+
|
|
78
|
+
if (!forceSource) {
|
|
79
|
+
try {
|
|
80
|
+
if (fs.existsSync(sideChannel)) {
|
|
81
|
+
const candidate = fs.readFileSync(sideChannel, 'utf8').trim();
|
|
82
|
+
if (candidate && fs.existsSync(candidate)) binPath = candidate;
|
|
83
|
+
}
|
|
84
|
+
} catch {
|
|
85
|
+
/* fall through to lazy resolve */
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (!binPath) {
|
|
89
|
+
const resolved = lazyResolveBinary({ pkgRoot, fs });
|
|
90
|
+
if (resolved.binPath) {
|
|
91
|
+
binPath = resolved.binPath;
|
|
92
|
+
// Cache for next invocation (best-effort — read-only fs is fine).
|
|
93
|
+
try {
|
|
94
|
+
fs.writeFileSync(sideChannel, binPath, 'utf8');
|
|
95
|
+
} catch {
|
|
96
|
+
/* read-only fs / no permission — non-fatal */
|
|
97
|
+
}
|
|
98
|
+
}
|
|
77
99
|
}
|
|
78
|
-
} catch {
|
|
79
|
-
/* fall through */
|
|
80
100
|
}
|
|
81
101
|
|
|
82
102
|
if (binPath) {
|
|
@@ -89,6 +109,30 @@ async function runServe({ args, pkgRoot }) {
|
|
|
89
109
|
return;
|
|
90
110
|
}
|
|
91
111
|
|
|
112
|
+
// No binary found. Two possibilities:
|
|
113
|
+
// - Production install missing platform package — hard-fail with guidance.
|
|
114
|
+
// - Local dev tree (claude-design checkout) — fall through to source.
|
|
115
|
+
const inDevTree = isLocalDevTree(pkgRoot, fs);
|
|
116
|
+
|
|
117
|
+
if (!inDevTree && !forceSource) {
|
|
118
|
+
const slug = detectPlatformSlug();
|
|
119
|
+
const siblingHint = slug ? resolve(pkgRoot, '..', `maude-${slug}`) : '(unknown platform)';
|
|
120
|
+
process.stderr.write(
|
|
121
|
+
`maude design serve: platform binary not found.\n\n Expected: @1agh/maude-${slug || '<platform>'}/maude\n Looked in: ${siblingHint}\n\nLikely causes:\n • Installer skipped postinstall (Bun global, npm --ignore-scripts,\n pnpm strict-scripts, Docker layer rebuilds).\n • Optional dependency for your platform did not install.\n • Global 'maude' is a leftover 'npm link' to a source checkout.\n\nFix (clean reinstall):\n cd ~ # NOT inside a maude source repo\n npm uninstall -g @1agh/maude # remove any stale link\n npm i -g @1agh/maude # real tarball install + postinstall\n\nOr re-run postinstall on the existing install:\n npm rebuild -g @1agh/maude\n\nPlatform: ${process.platform}-${process.arch}\n`
|
|
122
|
+
);
|
|
123
|
+
process.exit(1);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Local dev tree (or forced source). Verify deps before invoking source —
|
|
127
|
+
// catches the npm/pnpm/oxc-parser native-binding bug (npm#4828) up front.
|
|
128
|
+
const missing = checkDevDeps({ pkgRoot });
|
|
129
|
+
if (missing.length) {
|
|
130
|
+
process.stderr.write(
|
|
131
|
+
`maude design serve: missing dev-server dependencies in local checkout.\n\n Missing: ${missing.join(', ')}\n Repo: ${pkgRoot}\n\nThis repo uses pnpm (see packageManager in package.json). Install deps:\n cd ${pkgRoot} && pnpm install\n\nIf you already ran 'npm install' here, the npm optional-deps bug\n(npm#4828) may have left native bindings broken. Reset first:\n rm -rf node_modules package-lock.json && pnpm install\n`
|
|
132
|
+
);
|
|
133
|
+
process.exit(1);
|
|
134
|
+
}
|
|
135
|
+
|
|
92
136
|
const tsEntry = resolve(pkgRoot, 'plugins', 'design', 'dev-server', 'server.ts');
|
|
93
137
|
const mjsEntry = resolve(pkgRoot, 'plugins', 'design', 'dev-server', 'server.mjs');
|
|
94
138
|
|
|
@@ -108,6 +152,104 @@ async function runServe({ args, pkgRoot }) {
|
|
|
108
152
|
});
|
|
109
153
|
}
|
|
110
154
|
|
|
155
|
+
// Mirrors cli/install.cjs:detectSlug — kept in sync intentionally. Both forms
|
|
156
|
+
// run during the lifecycle of a single install (postinstall + first serve).
|
|
157
|
+
function detectPlatformSlug() {
|
|
158
|
+
const p = process.platform;
|
|
159
|
+
const a = process.arch;
|
|
160
|
+
if (p === 'darwin') {
|
|
161
|
+
if (a === 'arm64') return 'darwin-arm64';
|
|
162
|
+
try {
|
|
163
|
+
const t = execSync('sysctl -n sysctl.proc_translated', {
|
|
164
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
165
|
+
})
|
|
166
|
+
.toString()
|
|
167
|
+
.trim();
|
|
168
|
+
if (t === '1') return 'darwin-arm64';
|
|
169
|
+
} catch {
|
|
170
|
+
/* not under Rosetta */
|
|
171
|
+
}
|
|
172
|
+
return 'darwin-x64';
|
|
173
|
+
}
|
|
174
|
+
if (p === 'linux') {
|
|
175
|
+
let isMusl = false;
|
|
176
|
+
try {
|
|
177
|
+
const report = process.report?.getReport?.();
|
|
178
|
+
isMusl = !report?.header?.glibcVersionRuntime;
|
|
179
|
+
} catch {
|
|
180
|
+
/* default to glibc */
|
|
181
|
+
}
|
|
182
|
+
if (a === 'arm64') return isMusl ? 'linux-arm64-musl' : 'linux-arm64';
|
|
183
|
+
return isMusl ? 'linux-x64-musl' : 'linux-x64';
|
|
184
|
+
}
|
|
185
|
+
if (p === 'win32') return 'win32-x64';
|
|
186
|
+
return null;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function lazyResolveBinary({ pkgRoot, fs }) {
|
|
190
|
+
const slug = detectPlatformSlug();
|
|
191
|
+
if (!slug) return { binPath: null, slug: null };
|
|
192
|
+
const filename = process.platform === 'win32' ? 'maude.exe' : 'maude';
|
|
193
|
+
|
|
194
|
+
// Flat layout — production npm/bun global install. pkgRoot is
|
|
195
|
+
// <node_modules>/@1agh/maude, sibling is <node_modules>/@1agh/maude-<slug>.
|
|
196
|
+
const sibling = resolve(pkgRoot, '..', `maude-${slug}`, filename);
|
|
197
|
+
if (fs.existsSync(sibling)) {
|
|
198
|
+
try {
|
|
199
|
+
fs.chmodSync(sibling, 0o755);
|
|
200
|
+
} catch {
|
|
201
|
+
/* read-only — ignore */
|
|
202
|
+
}
|
|
203
|
+
return { binPath: sibling, slug };
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Nested layout — pnpm with isolation, or dev tree's own node_modules.
|
|
207
|
+
try {
|
|
208
|
+
const require = createRequire(import.meta.url);
|
|
209
|
+
const manifest = require.resolve(`@1agh/maude-${slug}/package.json`, {
|
|
210
|
+
paths: [pkgRoot, resolve(pkgRoot, 'cli')],
|
|
211
|
+
});
|
|
212
|
+
const fromManifest = resolve(dirname(manifest), filename);
|
|
213
|
+
if (fs.existsSync(fromManifest)) {
|
|
214
|
+
try {
|
|
215
|
+
fs.chmodSync(fromManifest, 0o755);
|
|
216
|
+
} catch {
|
|
217
|
+
/* ignore */
|
|
218
|
+
}
|
|
219
|
+
return { binPath: fromManifest, slug };
|
|
220
|
+
}
|
|
221
|
+
} catch {
|
|
222
|
+
/* platform package not installed */
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
return { binPath: null, slug };
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Mirrors cli/install.cjs:isLocalDev — the `packages/` directory is only present
|
|
229
|
+
// in the source checkout, never in a published npm tarball (excluded from
|
|
230
|
+
// package.json:files).
|
|
231
|
+
function isLocalDevTree(pkgRoot, fs) {
|
|
232
|
+
return fs.existsSync(resolve(pkgRoot, 'packages', 'maude-darwin-arm64', 'package.json'));
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
function checkDevDeps({ pkgRoot }) {
|
|
236
|
+
const require = createRequire(import.meta.url);
|
|
237
|
+
// The dev-server source path imports these as bare specifiers. If they
|
|
238
|
+
// resolve, bun/node will load them; if they don't, the spawn will fail
|
|
239
|
+
// with a less actionable error.
|
|
240
|
+
const required = ['magic-string', 'oxc-parser'];
|
|
241
|
+
const missing = [];
|
|
242
|
+
const paths = [resolve(pkgRoot, 'plugins', 'design', 'dev-server'), resolve(pkgRoot)];
|
|
243
|
+
for (const dep of required) {
|
|
244
|
+
try {
|
|
245
|
+
require.resolve(dep, { paths });
|
|
246
|
+
} catch {
|
|
247
|
+
missing.push(dep);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
return missing;
|
|
251
|
+
}
|
|
252
|
+
|
|
111
253
|
async function runExport({ args }) {
|
|
112
254
|
// `maude design export <format> [--scope ...] [--port N] [--out <path>] [--option key=value]`
|
|
113
255
|
const subArgs = args.slice(args.indexOf('export') + 1);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@1agh/maude",
|
|
3
|
-
"version": "0.17.
|
|
3
|
+
"version": "0.17.2",
|
|
4
4
|
"description": "Marketplace of Claude Code plugins by Michal Dovrtěl: `design` (canvas-first design iteration) + `flow` (generic agentic workflow loop with .ai second brain). Ships the `maude` CLI (with `mdcc` legacy alias) to scaffold workspace, run the design dev server, and manage configs.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -41,13 +41,13 @@
|
|
|
41
41
|
"prepublishOnly": "bash scripts/check-version-parity.sh"
|
|
42
42
|
},
|
|
43
43
|
"optionalDependencies": {
|
|
44
|
-
"@1agh/maude-darwin-arm64": "0.17.
|
|
45
|
-
"@1agh/maude-darwin-x64": "0.17.
|
|
46
|
-
"@1agh/maude-linux-arm64": "0.17.
|
|
47
|
-
"@1agh/maude-linux-arm64-musl": "0.17.
|
|
48
|
-
"@1agh/maude-linux-x64": "0.17.
|
|
49
|
-
"@1agh/maude-linux-x64-musl": "0.17.
|
|
50
|
-
"@1agh/maude-win32-x64": "0.17.
|
|
44
|
+
"@1agh/maude-darwin-arm64": "0.17.2",
|
|
45
|
+
"@1agh/maude-darwin-x64": "0.17.2",
|
|
46
|
+
"@1agh/maude-linux-arm64": "0.17.2",
|
|
47
|
+
"@1agh/maude-linux-arm64-musl": "0.17.2",
|
|
48
|
+
"@1agh/maude-linux-x64": "0.17.2",
|
|
49
|
+
"@1agh/maude-linux-x64-musl": "0.17.2",
|
|
50
|
+
"@1agh/maude-win32-x64": "0.17.2"
|
|
51
51
|
},
|
|
52
52
|
"files": [
|
|
53
53
|
"cli",
|
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
//
|
|
16
16
|
// Per DDR-009 (Bun runtime authoritative) + DDR-012 (React 19 unified) + DDR-014 (Lightning CSS).
|
|
17
17
|
|
|
18
|
-
import { existsSync, mkdirSync } from 'node:fs';
|
|
19
|
-
import { dirname, join, resolve } from 'node:path';
|
|
18
|
+
import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs';
|
|
19
|
+
import { dirname, join, relative, resolve } from 'node:path';
|
|
20
20
|
import { fileURLToPath } from 'node:url';
|
|
21
21
|
|
|
22
22
|
import { browserslistToTargets, bundle as lcssBundle } from 'lightningcss';
|
|
@@ -122,14 +122,117 @@ async function buildCss(): Promise<{ outBytes: number; outPath: string }> {
|
|
|
122
122
|
|
|
123
123
|
// ---------- (c) Server binary (bun build --compile, per-platform) ----------
|
|
124
124
|
|
|
125
|
+
// Per-target oxc-parser binding embed. Bun 1.3.4+ regressed `--compile` NAPI
|
|
126
|
+
// native-binding embedding (see DDR-042-oxc-parser-bun-compile-workaround.md).
|
|
127
|
+
// `with { type: 'file' }` requires a literal string path, so we generate one
|
|
128
|
+
// thin entry file per --target whose only purpose is to (1) embed the matching
|
|
129
|
+
// platform binding as an asset, (2) set NAPI_RS_NATIVE_LIBRARY_PATH from the
|
|
130
|
+
// runtime virtual path, then (3) hand off to the real server.ts. ESM
|
|
131
|
+
// evaluation order guarantees the env var is set before any downstream module
|
|
132
|
+
// touches oxc-parser.
|
|
133
|
+
|
|
134
|
+
// oxc-parser's NAPI-RS binding packages use a richer slug than our build
|
|
135
|
+
// target slug — Linux needs the libc kind suffix, Windows needs the toolchain
|
|
136
|
+
// suffix. Mirrored from oxc-parser/src-js/bindings.js loader cases.
|
|
137
|
+
function oxcBindingSlug(slug: string): string {
|
|
138
|
+
if (slug === 'linux-x64') return 'linux-x64-gnu';
|
|
139
|
+
if (slug === 'linux-arm64') return 'linux-arm64-gnu';
|
|
140
|
+
if (slug === 'win32-x64') return 'win32-x64-msvc';
|
|
141
|
+
// darwin-arm64 / darwin-x64 / linux-x64-musl / linux-arm64-musl already match.
|
|
142
|
+
return slug;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// npm/bun's installer respects each package's `os`/`cpu` fields and skips
|
|
146
|
+
// platform sub-packages whose filter doesn't match the host (the bindings
|
|
147
|
+
// declare e.g. `"cpu": ["x64"]`). For cross-compile targets — most notably
|
|
148
|
+
// darwin-x64 built on a darwin-arm64 CI runner — this means the matching
|
|
149
|
+
// `@oxc-parser/binding-<oxcSlug>` is NOT in node_modules even though it's
|
|
150
|
+
// listed as a direct devDependency. Fetch + extract the tarball manually so
|
|
151
|
+
// `with { type: 'file' }` resolution succeeds during `bun build --compile`.
|
|
152
|
+
async function ensureBindingForTarget(oxcSlug: string): Promise<void> {
|
|
153
|
+
const bindingDir = join(ROOT, 'node_modules', '@oxc-parser', `binding-${oxcSlug}`);
|
|
154
|
+
const bindingFile = join(bindingDir, `parser.${oxcSlug}.node`);
|
|
155
|
+
if (existsSync(bindingFile)) return; // host install already placed it
|
|
156
|
+
|
|
157
|
+
// Read the installed oxc-parser version so the tarball URL stays in sync.
|
|
158
|
+
// Walk up from build.ts to find the workspace-visible oxc-parser package.json
|
|
159
|
+
// (pnpm hoists it under node_modules/.pnpm, then symlinks at workspace level).
|
|
160
|
+
let oxcVersion = '0.131.0';
|
|
161
|
+
const candidates = [
|
|
162
|
+
join(ROOT, 'node_modules', 'oxc-parser', 'package.json'),
|
|
163
|
+
join(ROOT, '..', '..', '..', 'node_modules', 'oxc-parser', 'package.json'),
|
|
164
|
+
];
|
|
165
|
+
for (const c of candidates) {
|
|
166
|
+
if (existsSync(c)) {
|
|
167
|
+
oxcVersion = JSON.parse(readFileSync(c, 'utf8')).version;
|
|
168
|
+
break;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
console.log(`[build] cross-compile: fetching @oxc-parser/binding-${oxcSlug}@${oxcVersion}`);
|
|
173
|
+
const tarballUrl = `https://registry.npmjs.org/@oxc-parser/binding-${oxcSlug}/-/binding-${oxcSlug}-${oxcVersion}.tgz`;
|
|
174
|
+
const response = await fetch(tarballUrl);
|
|
175
|
+
if (!response.ok) {
|
|
176
|
+
throw new Error(`failed to fetch ${tarballUrl}: HTTP ${response.status}`);
|
|
177
|
+
}
|
|
178
|
+
const tmpTgz = join(ROOT, `.binding-${oxcSlug}.tgz`);
|
|
179
|
+
await Bun.write(tmpTgz, await response.arrayBuffer());
|
|
180
|
+
mkdirSync(bindingDir, { recursive: true });
|
|
181
|
+
// npm pack output: `package/parser.<oxcSlug>.node` + `package/package.json`.
|
|
182
|
+
// --strip-components=1 drops the leading `package/` so files land in bindingDir.
|
|
183
|
+
const tarProc = Bun.spawn(['tar', 'xf', tmpTgz, '-C', bindingDir, '--strip-components=1'], {
|
|
184
|
+
stdout: 'inherit',
|
|
185
|
+
stderr: 'inherit',
|
|
186
|
+
});
|
|
187
|
+
const tarCode = await tarProc.exited;
|
|
188
|
+
if (tarCode !== 0)
|
|
189
|
+
throw new Error(`tar extraction failed for binding-${oxcSlug} (exit ${tarCode})`);
|
|
190
|
+
unlinkSync(tmpTgz);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export function writeCompileEntry(target: PlatformTarget): string {
|
|
194
|
+
const slug = platformSlug(target);
|
|
195
|
+
const oxcSlug = oxcBindingSlug(slug);
|
|
196
|
+
const entryDir = join(DIST, '.compile-entries');
|
|
197
|
+
mkdirSync(entryDir, { recursive: true });
|
|
198
|
+
|
|
199
|
+
// ESM hoists `import` statements above top-level code, so the env-var
|
|
200
|
+
// assignment MUST live in a separate leaf module that's imported BEFORE
|
|
201
|
+
// server.ts — otherwise server.ts (and transitively oxc-parser) evaluates
|
|
202
|
+
// first and reads NAPI_RS_NATIVE_LIBRARY_PATH before we set it.
|
|
203
|
+
const initPath = join(entryDir, `init-oxc-${slug}.ts`);
|
|
204
|
+
const entryPath = join(entryDir, `server-${slug}.ts`);
|
|
205
|
+
const bindingSpec = `@oxc-parser/binding-${oxcSlug}/parser.${oxcSlug}.node`;
|
|
206
|
+
const initContent = `// AUTO-GENERATED by build.ts — do not edit by hand.
|
|
207
|
+
// Per-target oxc-parser binding embed (Bun 1.3.4+ --compile NAPI regression
|
|
208
|
+
// workaround — see .ai/decisions/DDR-042-oxc-parser-bun-compile-workaround.md).
|
|
209
|
+
// Side-effect module: must be imported BEFORE any oxc-parser usage.
|
|
210
|
+
import bindingPath from ${JSON.stringify(bindingSpec)} with { type: 'file' };
|
|
211
|
+
process.env.NAPI_RS_NATIVE_LIBRARY_PATH = bindingPath;
|
|
212
|
+
`;
|
|
213
|
+
writeFileSync(initPath, initContent);
|
|
214
|
+
|
|
215
|
+
// Forward slashes for the import specifier even on Windows hosts — ESM uses
|
|
216
|
+
// POSIX-style paths, not the host's filesystem separator.
|
|
217
|
+
const realServerRel = relative(entryDir, join(ROOT, 'server.ts')).split('\\').join('/');
|
|
218
|
+
const entryContent = `// AUTO-GENERATED by build.ts — do not edit by hand.
|
|
219
|
+
// Per-target compile entry — see DDR-042-oxc-parser-bun-compile-workaround.md.
|
|
220
|
+
import './init-oxc-${slug}.ts';
|
|
221
|
+
import ${JSON.stringify(realServerRel)};
|
|
222
|
+
`;
|
|
223
|
+
writeFileSync(entryPath, entryContent);
|
|
224
|
+
return entryPath;
|
|
225
|
+
}
|
|
226
|
+
|
|
125
227
|
async function buildServerBinary(target: PlatformTarget): Promise<{ outPath: string }> {
|
|
126
228
|
ensureDist();
|
|
127
229
|
const slug = platformSlug(target);
|
|
128
230
|
const ext = slug.startsWith('win32') ? '.exe' : '';
|
|
129
231
|
const outPath = join(DIST, `maude-${slug}${ext}`);
|
|
130
|
-
const
|
|
131
|
-
if (!existsSync(
|
|
132
|
-
//
|
|
232
|
+
const realEntry = join(ROOT, 'server.ts');
|
|
233
|
+
if (!existsSync(realEntry)) {
|
|
234
|
+
// Legacy fallback — pre-DDR-009 .mjs path. Doesn't use oxc-parser, so the
|
|
235
|
+
// 1.3.4+ regression doesn't apply; entry stub generator is skipped.
|
|
133
236
|
const legacy = join(ROOT, 'server.mjs');
|
|
134
237
|
if (!existsSync(legacy)) throw new Error(`Neither server.ts nor server.mjs exists in ${ROOT}`);
|
|
135
238
|
const proc = Bun.spawn(
|
|
@@ -150,6 +253,10 @@ async function buildServerBinary(target: PlatformTarget): Promise<{ outPath: str
|
|
|
150
253
|
throw new Error(`bun build --compile (legacy) failed for ${target} (exit ${code})`);
|
|
151
254
|
return { outPath };
|
|
152
255
|
}
|
|
256
|
+
// Make sure the target's NAPI binding is on disk even if bun/npm's os/cpu
|
|
257
|
+
// filter skipped it (cross-compile case — see ensureBindingForTarget docs).
|
|
258
|
+
await ensureBindingForTarget(oxcBindingSlug(slug));
|
|
259
|
+
const entry = writeCompileEntry(target);
|
|
153
260
|
const proc = Bun.spawn(
|
|
154
261
|
[
|
|
155
262
|
'bun',
|
|
@@ -262,6 +369,11 @@ async function main() {
|
|
|
262
369
|
}
|
|
263
370
|
}
|
|
264
371
|
|
|
265
|
-
|
|
372
|
+
// Only run the build when invoked directly — importers (e.g. the test suite,
|
|
373
|
+
// which calls `writeCompileEntry` from build.ts) should not trigger a dev
|
|
374
|
+
// build as a side effect.
|
|
375
|
+
if (import.meta.main) {
|
|
376
|
+
await main();
|
|
377
|
+
}
|
|
266
378
|
|
|
267
379
|
export { buildClient, buildCss, buildServerBinary, PLATFORM_MATRIX, type PlatformTarget };
|
|
@@ -16,6 +16,11 @@
|
|
|
16
16
|
// Toolchain matches scripts/migrate-canvases.ts (codemod) and canvas-edit.ts
|
|
17
17
|
// (AST-aware /design:edit element edits) — same oxc-parser + magic-string pair
|
|
18
18
|
// in three call sites, one mental model.
|
|
19
|
+
//
|
|
20
|
+
// `bun build --compile` requires a per-target entry stub that sets
|
|
21
|
+
// NAPI_RS_NATIVE_LIBRARY_PATH before this file's transitive imports load
|
|
22
|
+
// oxc-parser. The pipeline itself is unaware of the workaround — it's a
|
|
23
|
+
// build-layer concern. See DDR-042-oxc-parser-bun-compile-workaround.md.
|
|
19
24
|
|
|
20
25
|
import MagicString from 'magic-string';
|
|
21
26
|
import { parseSync } from 'oxc-parser';
|