mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-26 12:26:38 -06:00
fix(crabbox): keep packaged commands runnable without dev dependencies (#125419)
This commit is contained in:
committed by
GitHub
parent
8954634b15
commit
570072f090
@@ -370,12 +370,6 @@
|
||||
"!docs/releases/**",
|
||||
"!docs/**/*.jpg",
|
||||
"!docs/**/*.png",
|
||||
"scripts/crabbox-routing-policy.mts",
|
||||
"scripts/crabbox-wrapper-providers.mts",
|
||||
"scripts/crabbox-wrapper.mjs",
|
||||
"scripts/crabbox-wrapper.mts",
|
||||
"scripts/testbox-lease-freshness.mts",
|
||||
"scripts/lib/tsx-cli-shim.mjs",
|
||||
"patches/",
|
||||
"skills/",
|
||||
"custodian-skills/",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
// Temporarily removes private workspace dependencies from the published manifest.
|
||||
// Temporarily prepares source-only package metadata for publishing.
|
||||
import { existsSync } from "node:fs";
|
||||
import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
@@ -8,29 +8,45 @@ import { fileURLToPath } from "node:url";
|
||||
|
||||
const PACKAGE_JSON_PATH = "package.json";
|
||||
const BACKUP_PATH = path.join(".artifacts", "package-manifest", "package.json.prepack-backup");
|
||||
// Source checkouts use TS tooling; production installs omit dev dependencies.
|
||||
// Rewrite only during prepack so published commands load the bundled runtime.
|
||||
const CRABBOX_SOURCE_LAUNCHER = "node scripts/crabbox-wrapper.mjs";
|
||||
const CRABBOX_PUBLISHED_LAUNCHER = "node dist/crabbox-wrapper.js";
|
||||
|
||||
function preparedPackageManifest(content) {
|
||||
const packageJson = JSON.parse(content);
|
||||
let changed = false;
|
||||
|
||||
for (const [name, command] of Object.entries(packageJson.scripts ?? {})) {
|
||||
if (
|
||||
typeof command === "string" &&
|
||||
(command === CRABBOX_SOURCE_LAUNCHER || command.startsWith(`${CRABBOX_SOURCE_LAUNCHER} `))
|
||||
) {
|
||||
packageJson.scripts[name] =
|
||||
`${CRABBOX_PUBLISHED_LAUNCHER}${command.slice(CRABBOX_SOURCE_LAUNCHER.length)}`;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
const devDependencies = packageJson.devDependencies;
|
||||
if (!devDependencies || typeof devDependencies !== "object" || Array.isArray(devDependencies)) {
|
||||
return content;
|
||||
if (devDependencies && typeof devDependencies === "object" && !Array.isArray(devDependencies)) {
|
||||
const devDependencyEntries = Object.entries(devDependencies);
|
||||
const publishedDevDependencyEntries = devDependencyEntries.filter(
|
||||
([, spec]) => typeof spec !== "string" || !spec.startsWith("workspace:"),
|
||||
);
|
||||
if (publishedDevDependencyEntries.length !== devDependencyEntries.length) {
|
||||
changed = true;
|
||||
if (publishedDevDependencyEntries.length === 0) {
|
||||
delete packageJson.devDependencies;
|
||||
} else {
|
||||
packageJson.devDependencies = Object.fromEntries(publishedDevDependencyEntries);
|
||||
}
|
||||
}
|
||||
}
|
||||
const devDependencyEntries = Object.entries(devDependencies);
|
||||
const publishedDevDependencyEntries = devDependencyEntries.filter(
|
||||
([, spec]) => typeof spec !== "string" || !spec.startsWith("workspace:"),
|
||||
);
|
||||
if (publishedDevDependencyEntries.length === devDependencyEntries.length) {
|
||||
return content;
|
||||
}
|
||||
if (publishedDevDependencyEntries.length === 0) {
|
||||
delete packageJson.devDependencies;
|
||||
} else {
|
||||
packageJson.devDependencies = Object.fromEntries(publishedDevDependencyEntries);
|
||||
}
|
||||
return `${JSON.stringify(packageJson, null, 2)}\n`;
|
||||
return changed ? `${JSON.stringify(packageJson, null, 2)}\n` : content;
|
||||
}
|
||||
|
||||
/** Restore package.json after prepack removed private workspace dependencies. */
|
||||
/** Restore package.json after prepack prepared it for publishing. */
|
||||
export async function restorePackageManifest(cwd = process.cwd()) {
|
||||
const backupPath = path.join(cwd, BACKUP_PATH);
|
||||
if (!existsSync(backupPath)) {
|
||||
@@ -51,7 +67,7 @@ export async function restorePackageManifest(cwd = process.cwd()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Remove private workspace dependencies while recording restorable source bytes. */
|
||||
/** Prepare published package metadata while recording restorable source bytes. */
|
||||
export async function preparePackageManifest(cwd = process.cwd()) {
|
||||
const packageJsonPath = path.join(cwd, PACKAGE_JSON_PATH);
|
||||
const backupPath = path.join(cwd, BACKUP_PATH);
|
||||
|
||||
@@ -224,6 +224,7 @@ describe("collectSourcePackWorkspaceDependencyErrors", () => {
|
||||
scripts: {
|
||||
prepack: "node scripts/package-manifest.mjs prepare",
|
||||
postpack: "node scripts/package-manifest.mjs restore",
|
||||
"crabbox:run": "node scripts/crabbox-wrapper.mjs run",
|
||||
},
|
||||
devDependencies: {
|
||||
"@openclaw/session-url-contract": "workspace:*",
|
||||
@@ -258,8 +259,9 @@ describe("collectSourcePackWorkspaceDependencyErrors", () => {
|
||||
|
||||
const packedPackageJson = JSON.parse(
|
||||
readFileSync(path.join(extractDir, "package", "package.json"), "utf8"),
|
||||
) as { devDependencies?: Record<string, string> };
|
||||
) as { devDependencies?: Record<string, string>; scripts?: Record<string, string> };
|
||||
expect(packedPackageJson.devDependencies).toEqual({ vitest: "4.1.10" });
|
||||
expect(packedPackageJson.scripts?.["crabbox:run"]).toBe("node dist/crabbox-wrapper.js run");
|
||||
expect(readFileSync(path.join(rootDir, "package.json"), "utf8")).toBe(originalPackageJson);
|
||||
expect(
|
||||
existsSync(
|
||||
|
||||
@@ -64,19 +64,19 @@ describe("package manager build policy", () => {
|
||||
expect(packageJson.files).toContain("THIRD_PARTY_NOTICES.md");
|
||||
});
|
||||
|
||||
it("includes the Crabbox wrapper runtime modules in the published root package", () => {
|
||||
it("omits source-only Crabbox wrapper modules from the published root package", () => {
|
||||
const packageJson = readJson("package.json") as RootPackageJson;
|
||||
|
||||
expect(packageJson.files).toEqual(
|
||||
expect.arrayContaining([
|
||||
"scripts/crabbox-wrapper.mjs",
|
||||
"scripts/crabbox-wrapper.mts",
|
||||
"scripts/crabbox-wrapper-providers.mts",
|
||||
"scripts/crabbox-routing-policy.mts",
|
||||
"scripts/testbox-lease-freshness.mts",
|
||||
"scripts/lib/tsx-cli-shim.mjs",
|
||||
]),
|
||||
);
|
||||
for (const sourcePath of [
|
||||
"scripts/crabbox-wrapper.mjs",
|
||||
"scripts/crabbox-wrapper.mts",
|
||||
"scripts/crabbox-wrapper-providers.mts",
|
||||
"scripts/crabbox-routing-policy.mts",
|
||||
"scripts/testbox-lease-freshness.mts",
|
||||
"scripts/lib/tsx-cli-shim.mjs",
|
||||
]) {
|
||||
expect(packageJson.files).not.toContain(sourcePath);
|
||||
}
|
||||
});
|
||||
|
||||
it("pins forked transitive dependencies with parent-scoped npm-lock overrides", () => {
|
||||
|
||||
@@ -346,6 +346,7 @@ function buildCoreDistEntries(): Record<string, string> {
|
||||
return {
|
||||
index: "src/index.ts",
|
||||
entry: "src/entry.ts",
|
||||
"crabbox-wrapper": "scripts/crabbox-wrapper.mts",
|
||||
"docker-healthcheck": "src/docker-healthcheck.ts",
|
||||
// Ensure this module is bundled as an entry so legacy CLI shims can resolve its exports.
|
||||
"cli/daemon-cli": "src/cli/daemon-cli.ts",
|
||||
|
||||
Reference in New Issue
Block a user