mirror of
https://github.com/Heretek-AI/openclaw.git
synced 2026-07-19 19:43:32 -04:00
a9ae1a6778
Matrix Protocol: - docker-compose.matrix.yml: Dendrite homeserver + PostgreSQL + Nginx TLS - src/channels/plugins/matrix-channel.ts: OpenClaw plugin implementation - docs/matrix-triad-setup.md: Setup guide with auth scheme (@tm1-4:triad.local) MCP Server Integration: - docs/mcp-triad-integration.md: SearXNG, Playwright, GitHub MCP configs - docs/mcp-curiosity-mapping.md: Gap-to-capability mapping Node Sync Architecture: - src/services/node-sync-service.ts: WebSocket peer sync + presence detection - src/services/node-sync-service.test.ts: Unit tests - docs/node-sync-architecture.md: Architecture docs Triad Resilience: - scripts/triad-corruption-check.mjs: SQLite + log + config + git integrity - docs/triad-resilience.md: Recovery procedures - .secure/deployment-logs/README.md: Schema v2 - skills/triad-heartbeat/SKILL.md: Corruption check integration NPM Publish Workflow: - scripts/npm-publish.mjs: version, changelog, validate, publish, rollback - .github/workflows/npm-publish.yml: GitHub Actions with provenance - docs/npm-publish-guide.md: Complete documentation All deliverables tested in Docker before production.
99 lines
2.8 KiB
JavaScript
Executable File
99 lines
2.8 KiB
JavaScript
Executable File
#!/usr/bin/env node
|
|
|
|
import { spawnSync } from "node:child_process";
|
|
import fs from "node:fs";
|
|
import path from "node:path";
|
|
|
|
const logLevel = process.env.OPENCLAW_BUILD_VERBOSE ? "info" : "warn";
|
|
const extraArgs = process.argv.slice(2);
|
|
const INEFFECTIVE_DYNAMIC_IMPORT_RE = /\[INEFFECTIVE_DYNAMIC_IMPORT\]/;
|
|
const UNRESOLVED_IMPORT_RE = /\[UNRESOLVED_IMPORT\]/;
|
|
const ANSI_ESCAPE_RE = new RegExp(String.raw`\u001B\[[0-9;]*m`, "g");
|
|
|
|
function removeDistPluginNodeModulesSymlinks(rootDir) {
|
|
const extensionsDir = path.join(rootDir, "extensions");
|
|
if (!fs.existsSync(extensionsDir)) {
|
|
return;
|
|
}
|
|
|
|
for (const dirent of fs.readdirSync(extensionsDir, { withFileTypes: true })) {
|
|
if (!dirent.isDirectory()) {
|
|
continue;
|
|
}
|
|
const nodeModulesPath = path.join(extensionsDir, dirent.name, "node_modules");
|
|
try {
|
|
if (fs.lstatSync(nodeModulesPath).isSymbolicLink()) {
|
|
fs.rmSync(nodeModulesPath, { force: true, recursive: true });
|
|
}
|
|
} catch {
|
|
// Skip missing or unreadable paths so the build can proceed.
|
|
}
|
|
}
|
|
}
|
|
|
|
function pruneStaleRuntimeSymlinks() {
|
|
const cwd = process.cwd();
|
|
// runtime-postbuild stages plugin-owned node_modules into dist/ and links the
|
|
// dist-runtime overlay back to that tree. Remove only those symlinks up front
|
|
// so tsdown's clean step cannot traverse stale runtime overlays on rebuilds.
|
|
removeDistPluginNodeModulesSymlinks(path.join(cwd, "dist"));
|
|
removeDistPluginNodeModulesSymlinks(path.join(cwd, "dist-runtime"));
|
|
}
|
|
|
|
pruneStaleRuntimeSymlinks();
|
|
|
|
function findFatalUnresolvedImport(lines) {
|
|
for (const line of lines) {
|
|
if (!UNRESOLVED_IMPORT_RE.test(line)) {
|
|
continue;
|
|
}
|
|
|
|
const normalizedLine = line.replace(ANSI_ESCAPE_RE, "");
|
|
if (!normalizedLine.includes("extensions/")) {
|
|
return normalizedLine;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
const result = spawnSync(
|
|
"pnpm",
|
|
["exec", "tsdown", "--config-loader", "unrun", "--logLevel", logLevel, ...extraArgs],
|
|
{
|
|
encoding: "utf8",
|
|
stdio: "pipe",
|
|
shell: process.platform === "win32",
|
|
},
|
|
);
|
|
|
|
const stdout = result.stdout ?? "";
|
|
const stderr = result.stderr ?? "";
|
|
if (stdout) {
|
|
process.stdout.write(stdout);
|
|
}
|
|
if (stderr) {
|
|
process.stderr.write(stderr);
|
|
}
|
|
|
|
if (result.status === 0 && INEFFECTIVE_DYNAMIC_IMPORT_RE.test(`${stdout}\n${stderr}`)) {
|
|
console.error(
|
|
"Build emitted [INEFFECTIVE_DYNAMIC_IMPORT]. Replace transparent runtime re-export facades with real runtime boundaries.",
|
|
);
|
|
process.exit(1);
|
|
}
|
|
|
|
const fatalUnresolvedImport =
|
|
result.status === 0 ? findFatalUnresolvedImport(`${stdout}\n${stderr}`.split("\n")) : null;
|
|
|
|
if (fatalUnresolvedImport) {
|
|
console.error(`Build emitted [UNRESOLVED_IMPORT] outside extensions: ${fatalUnresolvedImport}`);
|
|
process.exit(1);
|
|
}
|
|
|
|
if (typeof result.status === "number") {
|
|
process.exit(result.status);
|
|
}
|
|
|
|
process.exit(1);
|