feat: add static repository plugin format

This commit is contained in:
Tianyi Cui
2026-07-30 04:15:07 +08:00
parent fd4d369907
commit fa7051a9d1
35 changed files with 1310 additions and 27 deletions

View File

@@ -47,6 +47,10 @@ export const inject = ['skills']
/** Local filesystem skill provider configuration. */
export interface Config {
/** Unique provider name. Defaults to `local`. */
providerName?: string
/** Whether project and user roots are included around custom roots. */
includeDefaultRoots?: boolean
/** DeepSeek Harness config root. Defaults to `$DSH_HOME` or `~/.dsh`. */
dshHome?: string
/** Shared agent config root. Defaults to `$DSH_AGENTS_HOME` or `~/.agents`. */
@@ -70,6 +74,8 @@ export interface Config {
}
export const Config: Schema<Config> = z.object({
providerName: z.string().min(1).default('local'),
includeDefaultRoots: z.boolean().default(true),
dshHome: z.string(),
agentsHome: z.string(),
customSkillDirs: z.array(z.string()).default([]),
@@ -138,7 +144,8 @@ export function apply(ctx: Context, config: Config = {}): void {
/** Provider that maps local project/user skill roots into `ctx.skills`. */
export class LocalSkillProvider implements SkillProvider {
readonly name = 'local'
readonly name: string
private readonly includeDefaultRoots: boolean
private readonly dshHome: string
private readonly agentsHome: string
private readonly customSkillDirs: string[]
@@ -151,6 +158,8 @@ export class LocalSkillProvider implements SkillProvider {
control: SkillProviderControl,
config: Config = {},
) {
this.name = config.providerName ?? 'local'
this.includeDefaultRoots = config.includeDefaultRoots ?? true
this.dshHome = resolveDshHome(config.dshHome)
this.agentsHome = resolve(config.agentsHome ?? process.env.DSH_AGENTS_HOME ?? join(homedir(), '.agents'))
this.customSkillDirs = (config.customSkillDirs ?? []).map(root => resolve(root))
@@ -177,7 +186,7 @@ export class LocalSkillProvider implements SkillProvider {
}
const candidates: SkillCandidate[] = []
for (const root of roots) {
for (const skill of await discoverRoot(root, this.ctx)) {
for (const skill of await discoverRoot(root, this.ctx, this.name)) {
candidates.push(skill)
}
}
@@ -227,21 +236,23 @@ export class LocalSkillProvider implements SkillProvider {
private async roots(cwd: string | undefined): Promise<SkillRoot[]> {
const roots: SkillRoot[] = []
if (cwd !== undefined) {
if (this.includeDefaultRoots && cwd !== undefined) {
const projectRoot = await findProjectRoot(resolve(cwd), optionalFileSystem(this.ctx))
roots.push(
{ path: join(projectRoot, '.dsh/skills'), source: 'project-dsh', rank: PROJECT_DSH_RANK, projectRoot },
{ path: join(projectRoot, '.agents/skills'), source: 'project-agents', rank: PROJECT_AGENTS_RANK, projectRoot },
)
}
roots.push(
...this.customSkillDirs.map(path => ({ path, source: 'custom' as const, rank: CUSTOM_RANK })),
{ path: join(this.dshHome, 'skills'), source: 'user-dsh', rank: USER_DSH_RANK, skipSystem: true },
{ path: join(this.agentsHome, 'skills'), source: 'user-agents', rank: USER_AGENTS_RANK },
...this.bundledSkillDir === undefined
? []
: [{ path: this.bundledSkillDir, source: 'bundled' as const, rank: BUNDLED_RANK, trustedHost: true }],
)
roots.push(...this.customSkillDirs.map(path => ({ path, source: 'custom' as const, rank: CUSTOM_RANK })))
if (this.includeDefaultRoots) {
roots.push(
{ path: join(this.dshHome, 'skills'), source: 'user-dsh', rank: USER_DSH_RANK, skipSystem: true },
{ path: join(this.agentsHome, 'skills'), source: 'user-agents', rank: USER_AGENTS_RANK },
)
}
if (this.bundledSkillDir !== undefined) {
roots.push({ path: this.bundledSkillDir, source: 'bundled', rank: BUNDLED_RANK, trustedHost: true })
}
return roots
}
}
@@ -693,7 +704,7 @@ function hasErrorCode(error: unknown, code: string): boolean {
return typeof error === 'object' && error !== null && 'code' in error && error.code === code
}
async function discoverRoot(root: SkillRoot, ctx: Context): Promise<SkillCandidate[]> {
async function discoverRoot(root: SkillRoot, ctx: Context, provider: string): Promise<SkillCandidate[]> {
const skills: SkillCandidate[] = []
const entries = await listSkillRootEntries(root, ctx)
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
@@ -711,7 +722,7 @@ async function discoverRoot(root: SkillRoot, ctx: Context): Promise<SkillCandida
description: parsed.description,
...parsed.whenToUse !== undefined ? { whenToUse: parsed.whenToUse } : {},
invocation: parsed.invocation,
provider: 'local',
provider,
source: root.source,
rank: root.rank,
locator,