源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
This commit is contained in:
@@ -0,0 +1,132 @@
|
||||
import { readFile, readdir } from "node:fs/promises";
|
||||
import { join } from "node:path";
|
||||
|
||||
const packageRoot = new URL("..", import.meta.url);
|
||||
const workspaceRoot = new URL("../../../../", import.meta.url);
|
||||
const distRoot = new URL("dist/", packageRoot);
|
||||
|
||||
for (const path of await listFiles(distRoot, ".js")) {
|
||||
const runtime = await readFile(new URL(path, distRoot), "utf8");
|
||||
if (/(?:from\s+|import\s*)["']react(?:\/[^"']*)?["']/.test(runtime)) {
|
||||
throw new Error(
|
||||
`@tutti-os/workbench-host emitted a React runtime import: ${path}`
|
||||
);
|
||||
}
|
||||
if (
|
||||
/(?:from\s+|import\s*)["']@tutti-os\/workbench-surface["']/.test(runtime)
|
||||
) {
|
||||
throw new Error(
|
||||
`@tutti-os/workbench-host emitted a Workbench surface runtime import: ${path}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const surfaceRoot = new URL("packages/workbench/surface/", workspaceRoot);
|
||||
for (const path of await listFiles(surfaceRoot, ".json", ".ts", ".tsx")) {
|
||||
const source = await readFile(new URL(path, surfaceRoot), "utf8");
|
||||
if (source.includes("@tutti-os/workbench-host")) {
|
||||
throw new Error(
|
||||
`@tutti-os/workbench-surface must not depend on host: ${path}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
await assertNoSurfaceHostDependencyCycle();
|
||||
|
||||
console.log("workbench host built boundary check passed");
|
||||
|
||||
async function assertNoSurfaceHostDependencyCycle() {
|
||||
const packageManifests = new Map();
|
||||
const packagesRoot = new URL("packages/", workspaceRoot);
|
||||
for (const group of await readdir(packagesRoot, { withFileTypes: true })) {
|
||||
if (!group.isDirectory()) {
|
||||
continue;
|
||||
}
|
||||
const groupRoot = new URL(`${group.name}/`, packagesRoot);
|
||||
for (const packageEntry of await readdir(groupRoot, {
|
||||
withFileTypes: true
|
||||
})) {
|
||||
if (!packageEntry.isDirectory()) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
const manifest = JSON.parse(
|
||||
await readFile(
|
||||
new URL(`${packageEntry.name}/package.json`, groupRoot),
|
||||
"utf8"
|
||||
)
|
||||
);
|
||||
if (typeof manifest.name === "string") {
|
||||
packageManifests.set(manifest.name, manifest);
|
||||
}
|
||||
} catch (error) {
|
||||
if (error?.code !== "ENOENT") {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const pending = [
|
||||
{
|
||||
name: "@tutti-os/workbench-surface",
|
||||
path: ["@tutti-os/workbench-surface"]
|
||||
}
|
||||
];
|
||||
const visited = new Set();
|
||||
while (pending.length > 0) {
|
||||
const current = pending.shift();
|
||||
if (!current || visited.has(current.name)) {
|
||||
continue;
|
||||
}
|
||||
visited.add(current.name);
|
||||
const manifest = packageManifests.get(current.name);
|
||||
if (!manifest) {
|
||||
continue;
|
||||
}
|
||||
for (const field of [
|
||||
"dependencies",
|
||||
"optionalDependencies",
|
||||
"peerDependencies"
|
||||
]) {
|
||||
for (const dependencyName of Object.keys(manifest[field] ?? {})) {
|
||||
if (dependencyName === "@tutti-os/workbench-host") {
|
||||
throw new Error(
|
||||
`Workbench package dependency cycle: ${[
|
||||
...current.path,
|
||||
dependencyName
|
||||
].join(" -> ")}`
|
||||
);
|
||||
}
|
||||
if (packageManifests.has(dependencyName)) {
|
||||
pending.push({
|
||||
name: dependencyName,
|
||||
path: [...current.path, dependencyName]
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function listFiles(root, ...extensions) {
|
||||
const paths = [];
|
||||
await visit("");
|
||||
return paths;
|
||||
|
||||
async function visit(relativeDirectory) {
|
||||
const entries = await readdir(new URL(relativeDirectory, root), {
|
||||
withFileTypes: true
|
||||
});
|
||||
for (const entry of entries) {
|
||||
const relativePath = join(relativeDirectory, entry.name);
|
||||
if (entry.isDirectory()) {
|
||||
await visit(`${relativePath}/`);
|
||||
} else if (
|
||||
extensions.some((extension) => entry.name.endsWith(extension))
|
||||
) {
|
||||
paths.push(relativePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user