mirror of
https://github.com/openclaw/openclaw.git
synced 2026-06-06 05:51:15 +08:00
docs: document package boundary scripts
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
#!/usr/bin/env node
|
||||
// Prevents runtime action paths from loading global config directly.
|
||||
import { collectRuntimeActionLoadConfigViolations } from "./lib/config-boundary-guard.mjs";
|
||||
|
||||
function main() {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#!/usr/bin/env node
|
||||
// Checks built package dist files for imports outside package boundaries.
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { collectPackageDistImportErrors } from "./lib/package-dist-imports.mjs";
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
// Guards pnpm package patches against unapproved additions.
|
||||
import { execFileSync } from "node:child_process";
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
@@ -110,6 +111,9 @@ function collectPatchFileViolations(cwd, violations) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects disallowed package patch declarations and patch files.
|
||||
*/
|
||||
export function collectPackagePatchViolations(cwd = process.cwd()) {
|
||||
const violations = [];
|
||||
collectWorkspacePatchViolations(cwd, violations);
|
||||
@@ -119,6 +123,9 @@ export function collectPackagePatchViolations(cwd = process.cwd()) {
|
||||
return violations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the package patch guard.
|
||||
*/
|
||||
export async function main() {
|
||||
const violations = collectPackagePatchViolations();
|
||||
if (violations.length === 0) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
// Checks pairing config logic for account-scoped allowlist handling.
|
||||
import ts from "typescript";
|
||||
import { createPairingGuardContext } from "./lib/pairing-guard-context.mjs";
|
||||
import {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
// Inventories core plugin imports that cross into bundled extension files.
|
||||
import { promises as fs } from "node:fs";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
@@ -158,6 +159,9 @@ function shouldSkipFile(filePath) {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cached inventory of src/plugins imports that cross into bundled extensions.
|
||||
*/
|
||||
export const collectPluginExtensionImportBoundaryInventory = createCachedAsync(async () => {
|
||||
const files = (await collectTypeScriptFilesFromRoots(scanRoots))
|
||||
.filter((filePath) => !shouldSkipFile(filePath))
|
||||
@@ -177,10 +181,16 @@ export const collectPluginExtensionImportBoundaryInventory = createCachedAsync(a
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Cached expected plugin-extension import inventory baseline.
|
||||
*/
|
||||
export const readExpectedInventory = createCachedAsync(async () =>
|
||||
JSON.parse(await fs.readFile(baselinePath, "utf8")),
|
||||
);
|
||||
|
||||
/**
|
||||
* Diffs expected and actual plugin-extension boundary inventory entries.
|
||||
*/
|
||||
export function diffInventory(expected, actual) {
|
||||
return diffInventoryEntries(expected, actual, compareEntries);
|
||||
}
|
||||
@@ -199,6 +209,9 @@ function formatEntry(entry) {
|
||||
return `${entry.file}:${entry.line} [${entry.kind}] ${entry.reason} (${entry.specifier} -> ${entry.resolvedPath})`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the plugin-extension import boundary baseline check.
|
||||
*/
|
||||
export async function runPluginExtensionImportBoundaryCheck(argv, io) {
|
||||
return await runBaselineInventoryCheck({
|
||||
argv: argv ?? process.argv.slice(2),
|
||||
@@ -211,6 +224,9 @@ export async function runPluginExtensionImportBoundaryCheck(argv, io) {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Entrypoint wrapper for the plugin-extension import boundary check.
|
||||
*/
|
||||
export async function main(argv, io) {
|
||||
const exitCode = await runPluginExtensionImportBoundaryCheck(argv, io);
|
||||
if (!io && exitCode !== 0) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
// Runs plugin lifecycle and gateway QA gauntlet probes with timing metrics.
|
||||
import { spawn } from "node:child_process";
|
||||
import fs from "node:fs";
|
||||
import os from "node:os";
|
||||
@@ -34,6 +35,9 @@ const DEFAULT_QA_PLUGIN_CHUNK_SIZE = 12;
|
||||
const COMMAND_OUTPUT_MAX_BUFFER_BYTES = 16 * 1024 * 1024;
|
||||
const ANSI_PATTERN = new RegExp(String.raw`\u001B\[[0-9;]*m`, "gu");
|
||||
|
||||
/**
|
||||
* Parses plugin gateway gauntlet CLI arguments and env defaults.
|
||||
*/
|
||||
export function parseArgs(argv) {
|
||||
const args = stripLeadingPackageManagerSeparator(argv);
|
||||
const options = {
|
||||
@@ -226,6 +230,9 @@ function readOptionalNonNegativeIntEnv(name) {
|
||||
return raw ? parseNonNegativeInt(raw, name) : undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the command that prepares QA runtime artifacts before gauntlet probes.
|
||||
*/
|
||||
export function createGauntletPrebuildCommand(repoRoot) {
|
||||
return {
|
||||
command: process.execPath,
|
||||
@@ -255,6 +262,9 @@ function chunkArray(values, chunkSize) {
|
||||
return chunks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an output path to a repo-relative path, rejecting paths outside the repo.
|
||||
*/
|
||||
export function toRepoRelativePath(repoRoot, absolutePath) {
|
||||
const relativePath = path.relative(repoRoot, absolutePath);
|
||||
if (!relativePath || relativePath.startsWith("..") || path.isAbsolute(relativePath)) {
|
||||
@@ -303,6 +313,9 @@ function timeWrapperArgs(command, args) {
|
||||
return { command: "/usr/bin/time", args: ["-v", command, ...args], mode: "gnu" };
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses `/usr/bin/time` output into wall, CPU, and RSS metrics.
|
||||
*/
|
||||
export function parseTimedMetrics(stderr, wallMs, mode) {
|
||||
let userSeconds = null;
|
||||
let systemSeconds = null;
|
||||
@@ -374,10 +387,16 @@ function writeCommandLog(params) {
|
||||
return logPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a measured command through the live process implementation.
|
||||
*/
|
||||
export async function runMeasuredCommand(params) {
|
||||
return await runMeasuredCommandLive(params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs one command with optional timing wrapper, bounded output, and log capture.
|
||||
*/
|
||||
export function runMeasuredCommandLive(params) {
|
||||
const { command, args, mode } =
|
||||
params.timeMode === "none"
|
||||
@@ -600,6 +619,9 @@ export function runMeasuredCommandLive(params) {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports whether gauntlet result rows contain work beyond the prebuild step.
|
||||
*/
|
||||
export function hasGauntletWorkRows(rows) {
|
||||
return rows.some((row) => row.phase !== "prebuild");
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
// Verifies publishable plugin packages can build their npm runtime outputs.
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { pathToFileURL } from "node:url";
|
||||
@@ -30,6 +31,9 @@ function parseArgs(argv) {
|
||||
return { packageDirs };
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds publishable plugin npm runtimes and verifies declared outputs exist.
|
||||
*/
|
||||
export async function checkPluginNpmRuntimeBuilds(params = {}) {
|
||||
const repoRoot = path.resolve(params.repoRoot ?? ".");
|
||||
const packageDirs =
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
// Verifies plugin SDK subpath exports and generated entrypoint metadata.
|
||||
import { readFileSync } from "node:fs";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
// Rejects wildcard plugin SDK re-exports in extension API barrels.
|
||||
import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
@@ -34,6 +35,9 @@ async function listExtensionApiFiles(rootDir = extensionsRoot) {
|
||||
return files.toSorted((left, right) => left.localeCompare(right));
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds wildcard plugin SDK re-export lines in an extension API barrel.
|
||||
*/
|
||||
export function findPluginSdkWildcardReexports(source) {
|
||||
return source
|
||||
.split(/\r?\n/u)
|
||||
@@ -41,6 +45,9 @@ export function findPluginSdkWildcardReexports(source) {
|
||||
.filter(({ text }) => WILDCARD_PLUGIN_SDK_REEXPORT_PATTERN.test(text));
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects extension API barrels that wildcard re-export plugin SDK subpaths.
|
||||
*/
|
||||
export async function collectPluginSdkWildcardReexports(rootDir = repoRoot) {
|
||||
const files = await listExtensionApiFiles(path.join(rootDir, "extensions"));
|
||||
const violations = [];
|
||||
@@ -57,6 +64,9 @@ export async function collectPluginSdkWildcardReexports(rootDir = repoRoot) {
|
||||
return violations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the plugin SDK wildcard re-export guard.
|
||||
*/
|
||||
export async function main(argv = process.argv.slice(2), io = process) {
|
||||
const json = argv.includes("--json");
|
||||
const violations = await collectPluginSdkWildcardReexports();
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#!/usr/bin/env node
|
||||
// Validates release metadata-only changed scopes for CI routing.
|
||||
import { execFileSync } from "node:child_process";
|
||||
import { existsSync, readFileSync } from "node:fs";
|
||||
import { RELEASE_METADATA_PATHS } from "./changed-lanes.mjs";
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
// Finds hidden local runtime sidecar loaders missing tsdown entries.
|
||||
import { promises as fs } from "node:fs";
|
||||
import path from "node:path";
|
||||
import ts from "typescript";
|
||||
@@ -79,6 +80,9 @@ function readObjectEntrySources(entry) {
|
||||
return Object.values(entry).filter((value) => typeof value === "string");
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects explicit source entry files from tsdown configuration.
|
||||
*/
|
||||
export function collectTsdownEntrySources(config) {
|
||||
const configs = Array.isArray(config) ? config : [config];
|
||||
return new Set(
|
||||
@@ -86,6 +90,9 @@ export function collectTsdownEntrySources(config) {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds local runtime require loaders not represented as explicit tsdown entries.
|
||||
*/
|
||||
export function findRuntimeSidecarLoaderViolations(content, importerPath, explicitEntrySources) {
|
||||
const sourceFile = ts.createSourceFile(importerPath, content, ts.ScriptTarget.Latest, true);
|
||||
const createRequireNames = new Set();
|
||||
@@ -220,6 +227,9 @@ export function findRuntimeSidecarLoaderViolations(content, importerPath, explic
|
||||
return violations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects runtime sidecar loader violations across configured roots.
|
||||
*/
|
||||
export async function collectRuntimeSidecarLoaderViolations(params) {
|
||||
const files = await collectTypeScriptFilesFromRoots(params.sourceRoots, {
|
||||
extraTestSuffixes: [".test-support.ts", ".test-helpers.ts"],
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
// Runs the SDK-package extension import boundary checker.
|
||||
import { createExtensionImportBoundaryChecker } from "./lib/extension-import-boundary-checker.mjs";
|
||||
import { runAsScript } from "./lib/ts-guard-utils.mjs";
|
||||
|
||||
@@ -15,6 +16,9 @@ const checker = createExtensionImportBoundaryChecker({
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Entrypoint for the SDK-package extension import boundary checker.
|
||||
*/
|
||||
export const main = checker.main;
|
||||
|
||||
runAsScript(import.meta.url, main);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
// Runs the src/** extension import boundary checker.
|
||||
import { createExtensionImportBoundaryChecker } from "./lib/extension-import-boundary-checker.mjs";
|
||||
import { runAsScript } from "./lib/ts-guard-utils.mjs";
|
||||
|
||||
@@ -25,6 +26,9 @@ const checker = createExtensionImportBoundaryChecker({
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Entrypoint for the src extension import boundary checker.
|
||||
*/
|
||||
export const main = checker.main;
|
||||
|
||||
runAsScript(import.meta.url, main);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#!/usr/bin/env node
|
||||
// Prevents Telegram runtime imports from grammy type-only modules.
|
||||
import { readdirSync, readFileSync } from "node:fs";
|
||||
import path from "node:path";
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
// Runs the test-helper extension import boundary checker.
|
||||
import { createExtensionImportBoundaryChecker } from "./lib/extension-import-boundary-checker.mjs";
|
||||
import { runAsScript } from "./lib/ts-guard-utils.mjs";
|
||||
|
||||
@@ -11,7 +12,13 @@ const checker = createExtensionImportBoundaryChecker({
|
||||
inventoryTitle: "Test-helper extension import boundary inventory:",
|
||||
});
|
||||
|
||||
/**
|
||||
* Collects test-helper extension import boundary inventory.
|
||||
*/
|
||||
export const collectTestHelperExtensionImportBoundaryInventory = checker.collectInventory;
|
||||
/**
|
||||
* Entrypoint for the test-helper extension import boundary checker.
|
||||
*/
|
||||
export const main = checker.main;
|
||||
|
||||
runAsScript(import.meta.url, main);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// Wraps the aggregate check command with timing behavior.
|
||||
import { main } from "./check.mjs";
|
||||
|
||||
await main([...process.argv.slice(2), "--timed"]);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
// Enforces core tsgo project boundaries and sparse-checkout safety.
|
||||
import { spawnSync } from "node:child_process";
|
||||
import path from "node:path";
|
||||
import { createManagedCommandInvocation } from "./lib/managed-child-process.mjs";
|
||||
|
||||
Reference in New Issue
Block a user