mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-18 14:31:36 +00:00
refactor(agents): share top-level resource collection (#104988)
This commit is contained in:
@@ -133,14 +133,32 @@ describe("DefaultPackageManager", () => {
|
||||
const insidePrompt = join(configRoot, "prompts", "inside.md");
|
||||
const insideTheme = join(configRoot, "themes", "inside.json");
|
||||
const insideExtension = join(configRoot, "extensions", "inside.ts");
|
||||
const ignoredPrompt = join(configRoot, "prompts", "ignored.md");
|
||||
const ignoredTheme = join(configRoot, "themes", "ignored.json");
|
||||
const hiddenPrompt = join(configRoot, "prompts", ".hidden.md");
|
||||
const hiddenTheme = join(configRoot, "themes", ".hidden.json");
|
||||
const nestedPrompt = join(configRoot, "prompts", "nested", "nested.md");
|
||||
const nestedTheme = join(configRoot, "themes", "nested", "nested.json");
|
||||
const wrongPromptType = join(configRoot, "prompts", "wrong.json");
|
||||
const wrongThemeType = join(configRoot, "themes", "wrong.md");
|
||||
await mkdir(join(root, ".git"));
|
||||
await mkdir(join(configRoot, "prompts"), { recursive: true });
|
||||
await mkdir(join(configRoot, "themes"), { recursive: true });
|
||||
await mkdir(join(configRoot, "prompts", "nested"), { recursive: true });
|
||||
await mkdir(join(configRoot, "themes", "nested"), { recursive: true });
|
||||
await mkdir(join(configRoot, "extensions"), { recursive: true });
|
||||
await mkdir(outsideRoot, { recursive: true });
|
||||
await writeFile(insidePrompt, "# Inside\n", "utf-8");
|
||||
await writeFile(insideTheme, "{}\n", "utf-8");
|
||||
await writeFile(insideExtension, "export default {};\n", "utf-8");
|
||||
await writeFile(ignoredPrompt, "# Ignored\n", "utf-8");
|
||||
await writeFile(ignoredTheme, "{}\n", "utf-8");
|
||||
await writeFile(nestedPrompt, "# Nested\n", "utf-8");
|
||||
await writeFile(nestedTheme, "{}\n", "utf-8");
|
||||
await writeFile(hiddenPrompt, "# Hidden\n", "utf-8");
|
||||
await writeFile(hiddenTheme, "{}\n", "utf-8");
|
||||
await writeFile(wrongPromptType, "{}\n", "utf-8");
|
||||
await writeFile(wrongThemeType, "# Wrong\n", "utf-8");
|
||||
await writeFile(join(configRoot, "prompts", ".ignore"), "ignored.md\n", "utf-8");
|
||||
await writeFile(join(configRoot, "themes", ".ignore"), "ignored.json\n", "utf-8");
|
||||
await writeFile(join(outsideRoot, "outside.md"), "# Outside\n", "utf-8");
|
||||
await writeFile(join(outsideRoot, "outside.json"), "{}\n", "utf-8");
|
||||
await writeFile(join(outsideRoot, "outside.ts"), "export default {};\n", "utf-8");
|
||||
@@ -161,12 +179,22 @@ describe("DefaultPackageManager", () => {
|
||||
});
|
||||
|
||||
const resolved = await manager.resolve();
|
||||
const promptPaths = resolved.prompts.map((prompt) => prompt.path);
|
||||
const themePaths = resolved.themes.map((theme) => theme.path);
|
||||
|
||||
expect(resolved.prompts.map((prompt) => prompt.path)).toContain(insidePrompt);
|
||||
expect(resolved.themes.map((theme) => theme.path)).toContain(insideTheme);
|
||||
expect(promptPaths).toContain(insidePrompt);
|
||||
expect(themePaths).toContain(insideTheme);
|
||||
expect(promptPaths).not.toContain(ignoredPrompt);
|
||||
expect(themePaths).not.toContain(ignoredTheme);
|
||||
expect(promptPaths).not.toContain(nestedPrompt);
|
||||
expect(themePaths).not.toContain(nestedTheme);
|
||||
expect(promptPaths).not.toContain(hiddenPrompt);
|
||||
expect(themePaths).not.toContain(hiddenTheme);
|
||||
expect(promptPaths).not.toContain(wrongPromptType);
|
||||
expect(themePaths).not.toContain(wrongThemeType);
|
||||
expect(resolved.extensions.map((extension) => extension.path)).toContain(insideExtension);
|
||||
expect(resolved.prompts.some((prompt) => prompt.path.includes("linked"))).toBe(false);
|
||||
expect(resolved.themes.some((theme) => theme.path.includes("linked"))).toBe(false);
|
||||
expect(promptPaths.some((promptPath) => promptPath.includes("linked"))).toBe(false);
|
||||
expect(themePaths.some((themePath) => themePath.includes("linked"))).toBe(false);
|
||||
expect(resolved.extensions.some((extension) => extension.path.includes("linked"))).toBe(false);
|
||||
});
|
||||
|
||||
|
||||
@@ -110,6 +110,7 @@ interface PackageFilter {
|
||||
}
|
||||
|
||||
type ResourceType = "extensions" | "skills" | "prompts" | "themes";
|
||||
type TopLevelAutoResourceType = Extract<ResourceType, "prompts" | "themes">;
|
||||
|
||||
const RESOURCE_TYPES: ResourceType[] = ["extensions", "skills", "prompts", "themes"];
|
||||
|
||||
@@ -351,7 +352,10 @@ function collectAncestorAgentsSkillDirs(startDir: string): string[] {
|
||||
return skillDirs;
|
||||
}
|
||||
|
||||
function collectAutoPromptEntries(dir: string): string[] {
|
||||
function collectTopLevelAutoResourceEntries(
|
||||
dir: string,
|
||||
resourceType: TopLevelAutoResourceType,
|
||||
): string[] {
|
||||
const entries: string[] = [];
|
||||
if (!existsSync(dir)) {
|
||||
return entries;
|
||||
@@ -388,55 +392,7 @@ function collectAutoPromptEntries(dir: string): string[] {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isFile && entry.name.endsWith(".md")) {
|
||||
entries.push(fullPath);
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// Ignore errors
|
||||
}
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
function collectAutoThemeEntries(dir: string): string[] {
|
||||
const entries: string[] = [];
|
||||
if (!existsSync(dir)) {
|
||||
return entries;
|
||||
}
|
||||
|
||||
const ig = ignore();
|
||||
addIgnoreRules(ig, dir, dir);
|
||||
|
||||
try {
|
||||
const dirEntries = readdirSync(dir, { withFileTypes: true });
|
||||
for (const entry of dirEntries) {
|
||||
if (entry.name.startsWith(".")) {
|
||||
continue;
|
||||
}
|
||||
if (entry.name === "node_modules") {
|
||||
continue;
|
||||
}
|
||||
|
||||
const fullPath = join(dir, entry.name);
|
||||
if (!isRealPathWithinRoot(dir, fullPath)) {
|
||||
continue;
|
||||
}
|
||||
let isFile = entry.isFile();
|
||||
if (entry.isSymbolicLink()) {
|
||||
try {
|
||||
isFile = statSync(fullPath).isFile();
|
||||
} catch {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
const relPath = toPosixPath(relative(dir, fullPath));
|
||||
if (ig.ignores(relPath)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isFile && entry.name.endsWith(".json")) {
|
||||
if (isFile && FILE_PATTERNS[resourceType].test(entry.name)) {
|
||||
entries.push(fullPath);
|
||||
}
|
||||
}
|
||||
@@ -1415,14 +1371,14 @@ export class DefaultPackageManager implements PackageManager {
|
||||
|
||||
addResources(
|
||||
"prompts",
|
||||
collectAutoPromptEntries(projectDirs.prompts),
|
||||
collectTopLevelAutoResourceEntries(projectDirs.prompts, "prompts"),
|
||||
projectMetadata,
|
||||
projectOverrides.prompts,
|
||||
projectBaseDir,
|
||||
);
|
||||
addResources(
|
||||
"themes",
|
||||
collectAutoThemeEntries(projectDirs.themes),
|
||||
collectTopLevelAutoResourceEntries(projectDirs.themes, "themes"),
|
||||
projectMetadata,
|
||||
projectOverrides.themes,
|
||||
projectBaseDir,
|
||||
@@ -1462,14 +1418,14 @@ export class DefaultPackageManager implements PackageManager {
|
||||
|
||||
addResources(
|
||||
"prompts",
|
||||
collectAutoPromptEntries(userDirs.prompts),
|
||||
collectTopLevelAutoResourceEntries(userDirs.prompts, "prompts"),
|
||||
userMetadata,
|
||||
userOverrides.prompts,
|
||||
globalBaseDir,
|
||||
);
|
||||
addResources(
|
||||
"themes",
|
||||
collectAutoThemeEntries(userDirs.themes),
|
||||
collectTopLevelAutoResourceEntries(userDirs.themes, "themes"),
|
||||
userMetadata,
|
||||
userOverrides.themes,
|
||||
globalBaseDir,
|
||||
|
||||
Reference in New Issue
Block a user