fix(commands): load .agents skills into command config
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -48,6 +48,20 @@ export async function loadOpencodeProjectSkills(directory?: string): Promise<Rec
|
|||||||
return skillsToCommandDefinitionRecord(deduplicateSkillsByName(allSkills.flat()))
|
return skillsToCommandDefinitionRecord(deduplicateSkillsByName(allSkills.flat()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function loadProjectAgentsSkills(directory?: string): Promise<Record<string, CommandDefinition>> {
|
||||||
|
const agentsProjectSkillDirs = findProjectAgentsSkillDirs(directory ?? process.cwd())
|
||||||
|
const allSkills = await Promise.all(
|
||||||
|
agentsProjectSkillDirs.map((skillsDir) => loadSkillsFromDir({ skillsDir, scope: "project" })),
|
||||||
|
)
|
||||||
|
return skillsToCommandDefinitionRecord(deduplicateSkillsByName(allSkills.flat()))
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function loadGlobalAgentsSkills(): Promise<Record<string, CommandDefinition>> {
|
||||||
|
const agentsGlobalDir = join(homedir(), ".agents", "skills")
|
||||||
|
const skills = await loadSkillsFromDir({ skillsDir: agentsGlobalDir, scope: "user" })
|
||||||
|
return skillsToCommandDefinitionRecord(skills)
|
||||||
|
}
|
||||||
|
|
||||||
export interface DiscoverSkillsOptions {
|
export interface DiscoverSkillsOptions {
|
||||||
includeClaudeCodePaths?: boolean
|
includeClaudeCodePaths?: boolean
|
||||||
directory?: string
|
directory?: string
|
||||||
|
|||||||
@@ -0,0 +1,98 @@
|
|||||||
|
import { afterEach, beforeEach, describe, expect, spyOn, test } from "bun:test";
|
||||||
|
import * as builtinCommands from "../features/builtin-commands";
|
||||||
|
import * as commandLoader from "../features/claude-code-command-loader";
|
||||||
|
import * as skillLoader from "../features/opencode-skill-loader";
|
||||||
|
import type { OhMyOpenCodeConfig } from "../config";
|
||||||
|
import type { PluginComponents } from "./plugin-components-loader";
|
||||||
|
import { applyCommandConfig } from "./command-config-handler";
|
||||||
|
|
||||||
|
function createPluginComponents(): PluginComponents {
|
||||||
|
return {
|
||||||
|
commands: {},
|
||||||
|
skills: {},
|
||||||
|
agents: {},
|
||||||
|
mcpServers: {},
|
||||||
|
hooksConfigs: [],
|
||||||
|
plugins: [],
|
||||||
|
errors: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function createPluginConfig(): OhMyOpenCodeConfig {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("applyCommandConfig", () => {
|
||||||
|
let loadBuiltinCommandsSpy: ReturnType<typeof spyOn>;
|
||||||
|
let loadUserCommandsSpy: ReturnType<typeof spyOn>;
|
||||||
|
let loadProjectCommandsSpy: ReturnType<typeof spyOn>;
|
||||||
|
let loadOpencodeGlobalCommandsSpy: ReturnType<typeof spyOn>;
|
||||||
|
let loadOpencodeProjectCommandsSpy: ReturnType<typeof spyOn>;
|
||||||
|
let discoverConfigSourceSkillsSpy: ReturnType<typeof spyOn>;
|
||||||
|
let loadUserSkillsSpy: ReturnType<typeof spyOn>;
|
||||||
|
let loadProjectSkillsSpy: ReturnType<typeof spyOn>;
|
||||||
|
let loadOpencodeGlobalSkillsSpy: ReturnType<typeof spyOn>;
|
||||||
|
let loadOpencodeProjectSkillsSpy: ReturnType<typeof spyOn>;
|
||||||
|
let loadProjectAgentsSkillsSpy: ReturnType<typeof spyOn>;
|
||||||
|
let loadGlobalAgentsSkillsSpy: ReturnType<typeof spyOn>;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
loadBuiltinCommandsSpy = spyOn(builtinCommands, "loadBuiltinCommands").mockReturnValue({});
|
||||||
|
loadUserCommandsSpy = spyOn(commandLoader, "loadUserCommands").mockResolvedValue({});
|
||||||
|
loadProjectCommandsSpy = spyOn(commandLoader, "loadProjectCommands").mockResolvedValue({});
|
||||||
|
loadOpencodeGlobalCommandsSpy = spyOn(commandLoader, "loadOpencodeGlobalCommands").mockResolvedValue({});
|
||||||
|
loadOpencodeProjectCommandsSpy = spyOn(commandLoader, "loadOpencodeProjectCommands").mockResolvedValue({});
|
||||||
|
discoverConfigSourceSkillsSpy = spyOn(skillLoader, "discoverConfigSourceSkills").mockResolvedValue([]);
|
||||||
|
loadUserSkillsSpy = spyOn(skillLoader, "loadUserSkills").mockResolvedValue({});
|
||||||
|
loadProjectSkillsSpy = spyOn(skillLoader, "loadProjectSkills").mockResolvedValue({});
|
||||||
|
loadOpencodeGlobalSkillsSpy = spyOn(skillLoader, "loadOpencodeGlobalSkills").mockResolvedValue({});
|
||||||
|
loadOpencodeProjectSkillsSpy = spyOn(skillLoader, "loadOpencodeProjectSkills").mockResolvedValue({});
|
||||||
|
loadProjectAgentsSkillsSpy = spyOn(skillLoader, "loadProjectAgentsSkills").mockResolvedValue({});
|
||||||
|
loadGlobalAgentsSkillsSpy = spyOn(skillLoader, "loadGlobalAgentsSkills").mockResolvedValue({});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
loadBuiltinCommandsSpy.mockRestore();
|
||||||
|
loadUserCommandsSpy.mockRestore();
|
||||||
|
loadProjectCommandsSpy.mockRestore();
|
||||||
|
loadOpencodeGlobalCommandsSpy.mockRestore();
|
||||||
|
loadOpencodeProjectCommandsSpy.mockRestore();
|
||||||
|
discoverConfigSourceSkillsSpy.mockRestore();
|
||||||
|
loadUserSkillsSpy.mockRestore();
|
||||||
|
loadProjectSkillsSpy.mockRestore();
|
||||||
|
loadOpencodeGlobalSkillsSpy.mockRestore();
|
||||||
|
loadOpencodeProjectSkillsSpy.mockRestore();
|
||||||
|
loadProjectAgentsSkillsSpy.mockRestore();
|
||||||
|
loadGlobalAgentsSkillsSpy.mockRestore();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("includes .agents skills in command config", async () => {
|
||||||
|
// given
|
||||||
|
loadProjectAgentsSkillsSpy.mockResolvedValue({
|
||||||
|
"agents-project-skill": {
|
||||||
|
description: "(project - Skill) Agents project skill",
|
||||||
|
template: "template",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
loadGlobalAgentsSkillsSpy.mockResolvedValue({
|
||||||
|
"agents-global-skill": {
|
||||||
|
description: "(user - Skill) Agents global skill",
|
||||||
|
template: "template",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const config: Record<string, unknown> = { command: {} };
|
||||||
|
|
||||||
|
// when
|
||||||
|
await applyCommandConfig({
|
||||||
|
config,
|
||||||
|
pluginConfig: createPluginConfig(),
|
||||||
|
ctx: { directory: "/tmp" },
|
||||||
|
pluginComponents: createPluginComponents(),
|
||||||
|
});
|
||||||
|
|
||||||
|
// then
|
||||||
|
const commandConfig = config.command as Record<string, { description?: string }>;
|
||||||
|
expect(commandConfig["agents-project-skill"]?.description).toContain("Agents project skill");
|
||||||
|
expect(commandConfig["agents-global-skill"]?.description).toContain("Agents global skill");
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -9,6 +9,8 @@ import {
|
|||||||
import { loadBuiltinCommands } from "../features/builtin-commands";
|
import { loadBuiltinCommands } from "../features/builtin-commands";
|
||||||
import {
|
import {
|
||||||
discoverConfigSourceSkills,
|
discoverConfigSourceSkills,
|
||||||
|
loadGlobalAgentsSkills,
|
||||||
|
loadProjectAgentsSkills,
|
||||||
loadUserSkills,
|
loadUserSkills,
|
||||||
loadProjectSkills,
|
loadProjectSkills,
|
||||||
loadOpencodeGlobalSkills,
|
loadOpencodeGlobalSkills,
|
||||||
@@ -36,7 +38,9 @@ export async function applyCommandConfig(params: {
|
|||||||
opencodeGlobalCommands,
|
opencodeGlobalCommands,
|
||||||
opencodeProjectCommands,
|
opencodeProjectCommands,
|
||||||
userSkills,
|
userSkills,
|
||||||
|
globalAgentsSkills,
|
||||||
projectSkills,
|
projectSkills,
|
||||||
|
projectAgentsSkills,
|
||||||
opencodeGlobalSkills,
|
opencodeGlobalSkills,
|
||||||
opencodeProjectSkills,
|
opencodeProjectSkills,
|
||||||
] = await Promise.all([
|
] = await Promise.all([
|
||||||
@@ -49,7 +53,9 @@ export async function applyCommandConfig(params: {
|
|||||||
loadOpencodeGlobalCommands(),
|
loadOpencodeGlobalCommands(),
|
||||||
loadOpencodeProjectCommands(params.ctx.directory),
|
loadOpencodeProjectCommands(params.ctx.directory),
|
||||||
includeClaudeSkills ? loadUserSkills() : Promise.resolve({}),
|
includeClaudeSkills ? loadUserSkills() : Promise.resolve({}),
|
||||||
|
includeClaudeSkills ? loadGlobalAgentsSkills() : Promise.resolve({}),
|
||||||
includeClaudeSkills ? loadProjectSkills(params.ctx.directory) : Promise.resolve({}),
|
includeClaudeSkills ? loadProjectSkills(params.ctx.directory) : Promise.resolve({}),
|
||||||
|
includeClaudeSkills ? loadProjectAgentsSkills(params.ctx.directory) : Promise.resolve({}),
|
||||||
loadOpencodeGlobalSkills(),
|
loadOpencodeGlobalSkills(),
|
||||||
loadOpencodeProjectSkills(params.ctx.directory),
|
loadOpencodeProjectSkills(params.ctx.directory),
|
||||||
]);
|
]);
|
||||||
@@ -59,11 +65,13 @@ export async function applyCommandConfig(params: {
|
|||||||
...skillsToCommandDefinitionRecord(configSourceSkills),
|
...skillsToCommandDefinitionRecord(configSourceSkills),
|
||||||
...userCommands,
|
...userCommands,
|
||||||
...userSkills,
|
...userSkills,
|
||||||
|
...globalAgentsSkills,
|
||||||
...opencodeGlobalCommands,
|
...opencodeGlobalCommands,
|
||||||
...opencodeGlobalSkills,
|
...opencodeGlobalSkills,
|
||||||
...systemCommands,
|
...systemCommands,
|
||||||
...projectCommands,
|
...projectCommands,
|
||||||
...projectSkills,
|
...projectSkills,
|
||||||
|
...projectAgentsSkills,
|
||||||
...opencodeProjectCommands,
|
...opencodeProjectCommands,
|
||||||
...opencodeProjectSkills,
|
...opencodeProjectSkills,
|
||||||
...params.pluginComponents.commands,
|
...params.pluginComponents.commands,
|
||||||
|
|||||||
Reference in New Issue
Block a user