import { execFileSync } from "node:child_process";import { existsSync, readdirSync, readFileSync, statSync,} from "node:fs";import { join, relative, sep } from "node:path"; const root = process.cwd();const failures = []; const fail = (message) => failures.push(message);const rel = (path) => relative(root, path).split(sep).join("/");const readJson = (path) => JSON.parse(readFileSync(path, "utf8")); if (existsSync(join(root, "registry"))) { fail("registry/ must not exist; use software/ and toolchain/ instead");} const ignoredDirs = new Set([ ".git", "node_modules", "target", "dist", "build", "vendor", ".turbo",]); const walk = (dir, visit) => { for (const entry of readdirSync(dir, { withFileTypes: true })) { const path = join(dir, entry.name); if ( entry.isDirectory() && (ignoredDirs.has(entry.name) || rel(path) === ".claude/worktrees") ) { continue; } if (entry.isDirectory()) { walk(path, visit); } else { visit(path); } }}; const allowedTestHomes = [ /^software\/[^/]+\/test\/.+\.test\.ts$/, /^toolchain\/conformance\/.+\.test\.ts$/, /^packages\/[^/]+\/tests\/.+\.test\.ts$/, /^scripts\/.+\.test\.ts$/,]; walk(root, (path) => { const normalized = rel(path); if (!normalized.endsWith(".test.ts")) return; if (!allowedTestHomes.some((pattern) => pattern.test(normalized))) { fail(`${normalized} is not in an allowed test home`); }}); const softwareRoot = join(root, "software");if (existsSync(softwareRoot)) { for (const dir of readdirSync(softwareRoot, { withFileTypes: true })) { if (!dir.isDirectory()) continue; const packageDir = join(softwareRoot, dir.name); const manifestPath = join(packageDir, "agentos-package.json"); if (!existsSync(manifestPath)) continue; const manifest = readJson(manifestPath); const commands = manifest.commands ?? []; if (commands.length > 0 && !existsSync(join(packageDir, "test"))) { fail(`software/${dir.name} declares commands but has no test/ directory`); } if (manifest.registry && !manifest.registry.category) { fail(`software/${dir.name} registry block is missing category`); } }} const colocatedCargoTomls = [];const collectCargoTomls = (dir) => { if (!existsSync(dir)) return; for (const entry of readdirSync(dir, { withFileTypes: true })) { const path = join(dir, entry.name); if (entry.isDirectory()) { collectCargoTomls(path); } else if (entry.name === "Cargo.toml") { colocatedCargoTomls.push(path); } }};collectCargoTomls(join(root, "software")); for (const cargoToml of colocatedCargoTomls) { const normalized = rel(cargoToml); if (!/\/native\/crates\/[^/]+\/Cargo\.toml$/.test(normalized)) continue; const text = readFileSync(cargoToml, "utf8"); if (!/^\[package\]\nworkspace = "\.\.\/\.\.\/\.\.\/\.\.\/\.\.\/toolchain"/m.test(text)) { fail(`${normalized} must explicitly belong to the toolchain workspace`); }} try { const metadata = JSON.parse( execFileSync("cargo", ["metadata", "--format-version", "1", "--no-deps"], { cwd: root, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"], }), ); for (const pkg of metadata.packages ?? []) { const manifestPath = pkg.manifest_path.split(sep).join("/"); if (manifestPath.includes("/software/")) { fail(`main Cargo workspace claims colocated crate ${manifestPath}`); } }} catch (error) { fail(`cargo metadata failed for root workspace: ${error.message}`);} if (failures.length > 0) { for (const failure of failures) { console.error(`check-layout: ${failure}`); } process.exit(1);} console.log( `check-layout: OK (${colocatedCargoTomls.length} colocated Cargo.toml files checked)`,);
import { execFileSync } from "node:child_process";
import {
existsSync,
readdirSync,
readFileSync,
statSync,
} from "node:fs";
import { join, relative, sep } from "node:path";
const root = process.cwd();
const failures = [];
const fail = (message) => failures.push(message);
const rel = (path) => relative(root, path).split(sep).join("/");
const readJson = (path) => JSON.parse(readFileSync(path, "utf8"));
if (existsSync(join(root, "registry"))) {
fail("registry/ must not exist; use software/ and toolchain/ instead");
}
const ignoredDirs = new Set([
".git",
"node_modules",
"target",
"dist",
"build",
"vendor",
".turbo",
]);
const walk = (dir, visit) => {
for (const entry of readdirSync(dir, { withFileTypes: true })) {
const path = join(dir, entry.name);
if (
entry.isDirectory() &&
(ignoredDirs.has(entry.name) || rel(path) === ".claude/worktrees")
) {
continue;
}
if (entry.isDirectory()) {
walk(path, visit);
} else {
visit(path);
}
}
};
const allowedTestHomes = [
/^software\/[^/]+\/test\/.+\.test\.ts$/,
/^toolchain\/conformance\/.+\.test\.ts$/,
/^packages\/[^/]+\/tests\/.+\.test\.ts$/,
/^scripts\/.+\.test\.ts$/,
];
walk(root, (path) => {
const normalized = rel(path);
if (!normalized.endsWith(".test.ts")) return;
if (!allowedTestHomes.some((pattern) => pattern.test(normalized))) {
fail(`${normalized} is not in an allowed test home`);
}
});
const softwareRoot = join(root, "software");
if (existsSync(softwareRoot)) {
for (const dir of readdirSync(softwareRoot, { withFileTypes: true })) {
if (!dir.isDirectory()) continue;
const packageDir = join(softwareRoot, dir.name);
const manifestPath = join(packageDir, "agentos-package.json");
if (!existsSync(manifestPath)) continue;
const manifest = readJson(manifestPath);
const commands = manifest.commands ?? [];
if (commands.length > 0 && !existsSync(join(packageDir, "test"))) {
fail(`software/${dir.name} declares commands but has no test/ directory`);
}
if (manifest.registry && !manifest.registry.category) {
fail(`software/${dir.name} registry block is missing category`);
}
}
}
const colocatedCargoTomls = [];
const collectCargoTomls = (dir) => {
if (!existsSync(dir)) return;
for (const entry of readdirSync(dir, { withFileTypes: true })) {
const path = join(dir, entry.name);
if (entry.isDirectory()) {
collectCargoTomls(path);
} else if (entry.name === "Cargo.toml") {
colocatedCargoTomls.push(path);
}
}
};
collectCargoTomls(join(root, "software"));
for (const cargoToml of colocatedCargoTomls) {
const normalized = rel(cargoToml);
if (!/\/native\/crates\/[^/]+\/Cargo\.toml$/.test(normalized)) continue;
const text = readFileSync(cargoToml, "utf8");
if (!/^\[package\]\nworkspace = "\.\.\/\.\.\/\.\.\/\.\.\/\.\.\/toolchain"/m.test(text)) {
fail(`${normalized} must explicitly belong to the toolchain workspace`);
}
}
try {
const metadata = JSON.parse(
execFileSync("cargo", ["metadata", "--format-version", "1", "--no-deps"], {
cwd: root,
encoding: "utf8",
stdio: ["ignore", "pipe", "pipe"],
}),
);
for (const pkg of metadata.packages ?? []) {
const manifestPath = pkg.manifest_path.split(sep).join("/");
if (manifestPath.includes("/software/")) {
fail(`main Cargo workspace claims colocated crate ${manifestPath}`);
}
}
} catch (error) {
fail(`cargo metadata failed for root workspace: ${error.message}`);
}
if (failures.length > 0) {
for (const failure of failures) {
console.error(`check-layout: ${failure}`);
}
process.exit(1);
}
console.log(
`check-layout: OK (${colocatedCargoTomls.length} colocated Cargo.toml files checked)`,
);