tsai-registry
Version:
Community-driven registry CLI for Mastra/AI agents, workflows, and tools
216 lines (213 loc) • 7.93 kB
JavaScript
// @bun
var __create = Object.create;
var __getProtoOf = Object.getPrototypeOf;
var __defProp = Object.defineProperty;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __toESM = (mod, isNodeMode, target) => {
target = mod != null ? __create(__getProtoOf(mod)) : {};
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
for (let key of __getOwnPropNames(mod))
if (!__hasOwnProp.call(to, key))
__defProp(to, key, {
get: () => mod[key],
enumerable: true
});
return to;
};
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
var __require = import.meta.require;
// utils.ts
import fs from "fs";
import path from "path";
async function loadSettings(settingsPath) {
let data;
let overrideLocalPath;
if (!settingsPath) {
const localOverride = path.join(process.cwd(), "settings-registry.json");
if (fs.existsSync(localOverride)) {
overrideLocalPath = JSON.parse(fs.readFileSync(localOverride, "utf-8")).settings?.local;
}
settingsPath = process.env.TSAR_SETTINGS_URL || "https://raw.githubusercontent.com/aidalinfo/tsai-registry/refs/heads/main/settings.json";
}
if (settingsPath.startsWith("http://") || settingsPath.startsWith("https://")) {
const res = await fetch(settingsPath);
if (!res.ok)
throw new Error(`Erreur lors du chargement distant: ${res.statusText}`);
data = await res.text();
} else {
const resolvedPath = path.isAbsolute(settingsPath) ? settingsPath : path.join(process.cwd(), settingsPath);
if (!fs.existsSync(resolvedPath))
throw new Error(`Fichier introuvable: ${resolvedPath}`);
data = fs.readFileSync(resolvedPath, "utf-8");
}
const base = JSON.parse(data);
if (overrideLocalPath) {
base.settings = base.settings || {};
base.settings.local = overrideLocalPath;
}
if (!base.settings)
base.settings = {};
if (!base.settings.local) {
let distantSettingsUrl = process.env.TSAR_SETTINGS_URL || "https://raw.githubusercontent.com/aidalinfo/tsai-registry/refs/heads/main/settings.json";
try {
let distantData;
if (distantSettingsUrl.startsWith("http://") || distantSettingsUrl.startsWith("https://")) {
const res = await fetch(distantSettingsUrl);
if (res.ok) {
distantData = await res.text();
const distantJson = JSON.parse(distantData);
if (distantJson.settings && distantJson.settings.local) {
base.settings.local = distantJson.settings.local;
}
}
} else if (fs.existsSync(distantSettingsUrl)) {
distantData = fs.readFileSync(distantSettingsUrl, "utf-8");
const distantJson = JSON.parse(distantData);
if (distantJson.settings && distantJson.settings.local) {
base.settings.local = distantJson.settings.local;
}
}
} catch (e) {}
if (!base.settings.local)
base.settings.local = "src/mastra/registry";
}
return base;
}
async function loadRegistry(registryPath, settingsUrl) {
let data;
if (!registryPath.startsWith("http://") && !registryPath.startsWith("https://") && settingsUrl) {
let repo = settingsUrl.replace("https://github.com/", "");
const branch = "main";
registryPath = `https://raw.githubusercontent.com/${repo}/refs/heads/${branch}/${registryPath}`;
}
if (registryPath.startsWith("http://") || registryPath.startsWith("https://")) {
const res = await fetch(registryPath);
if (!res.ok)
throw new Error(`Erreur lors du chargement du registry: ${res.statusText}`);
data = await res.text();
} else {
const resolvedPath = path.isAbsolute(registryPath) ? registryPath : path.join(process.cwd(), registryPath);
if (!fs.existsSync(resolvedPath))
throw new Error(`Registry introuvable: ${resolvedPath}`);
data = fs.readFileSync(resolvedPath, "utf-8");
}
return JSON.parse(data);
}
// build.ts
import fs2 from "fs";
import path2 from "path";
var {write } = globalThis.Bun;
(async () => {
const settings = await loadSettings();
const ignoreExtensions = settings.build?.ignoreExtensions || [];
const registryArg = process.argv[2] || "app/src/mastra/registry";
const REGISTRY_ROOT = path2.isAbsolute(registryArg) ? registryArg : path2.join(process.cwd(), registryArg);
const OUTPUT_PATH = path2.join(process.cwd(), "registry.json");
const SUPPORTED_TYPES = ["agents", "workflows", "tools", "mcp"];
function listFilesRecursive(dir) {
let results = [];
const list = fs2.readdirSync(dir);
list.forEach((file) => {
const filePath = path2.join(dir, file);
const stat = fs2.statSync(filePath);
if (stat && stat.isDirectory()) {
results = results.concat(listFilesRecursive(filePath));
} else {
if (!ignoreExtensions.some((ext) => filePath.endsWith(ext))) {
results.push(filePath);
}
}
});
return results;
}
function extractDependencies(fileContent) {
const importRegex = /import\s+(?:[^'\"]+from\s+)?["']([^"']+)["']/g;
const deps = new Set;
let match;
while (match = importRegex.exec(fileContent)) {
const dep = match[1];
if (dep && !dep.startsWith(".") && !dep.startsWith("/")) {
const depParts = dep.split("/");
if (depParts[0]) {
if (depParts[0].startsWith("@")) {
if (depParts[1])
deps.add(depParts.slice(0, 2).join("/"));
} else {
deps.add(depParts[0]);
}
}
}
}
return Array.from(deps);
}
function extractEnvs(fileContent) {
const envRegex = /process\.env\.([A-Z0-9_]+)/g;
const envs = new Set;
let match;
while (match = envRegex.exec(fileContent)) {
if (match[1])
envs.add(match[1]);
}
return Array.from(envs);
}
const PROVIDER_MODULES = {
"@ai-sdk/xai": "xai",
"@ai-sdk/openai": "openai",
"@ai-sdk/anthropic": "anthropic",
"@ai-sdk/google": "google",
"@ai-sdk/azure": "azure",
"@ai-sdk/amazon-bedrock": "bedrock",
"@ai-sdk/groq": "groq",
"@ai-sdk/mistral": "mistral",
"@ai-sdk/deepseek": "deepseek"
};
function extractAIProviders(fileContent) {
const fromRegex = /from\s+['"]([^'"]+)['"]/g;
const providers = new Set;
let match;
while (match = fromRegex.exec(fileContent)) {
const mod = match[1];
const provider = PROVIDER_MODULES[mod];
if (provider)
providers.add(provider);
}
return Array.from(providers);
}
const registry = {};
for (const type of SUPPORTED_TYPES) {
const typeDir = path2.join(REGISTRY_ROOT, type);
if (!fs2.existsSync(typeDir))
continue;
const names = fs2.readdirSync(typeDir);
for (const name of names) {
const objDir = path2.join(typeDir, name);
if (!fs2.statSync(objDir).isDirectory())
continue;
const files = listFilesRecursive(objDir);
const relFiles = files.map((f) => path2.relative(process.cwd(), f));
let allDeps = [];
let allEnvs = [];
let providers = [];
for (const filePath of files) {
const content = fs2.readFileSync(filePath, "utf-8");
allDeps = allDeps.concat(extractDependencies(content));
allEnvs = allEnvs.concat(extractEnvs(content));
providers = providers.concat(extractAIProviders(content));
}
allDeps = Array.from(new Set(allDeps));
allEnvs = Array.from(new Set(allEnvs));
providers = Array.from(new Set(providers));
registry[name] = {
type,
name,
files: relFiles,
dependencies: allDeps,
envs: allEnvs,
aiprovider: providers
};
}
}
await write(OUTPUT_PATH, JSON.stringify(registry, null, 2));
console.log("registry.json generate with success.");
})();