Merge pull request #1696 from deepseek-harness/codex/dsh-badge-plugin
feat: add optional dsh badge skill provider
This commit is contained in:
@@ -218,6 +218,10 @@
|
||||
- id: skill-local
|
||||
name: '@deepseek-ai/dsh-skill-local'
|
||||
|
||||
- id: skill-badge
|
||||
name: '@deepseek-ai/dsh-skill-badge'
|
||||
disabled: true
|
||||
|
||||
- id: tool-skill
|
||||
name: '@deepseek-ai/dsh-tool-skill'
|
||||
|
||||
|
||||
@@ -70,6 +70,7 @@
|
||||
"@deepseek-ai/dsh-session-title-first-message-llm": "workspace:^",
|
||||
"@deepseek-ai/dsh-settings-local": "workspace:^",
|
||||
"@deepseek-ai/dsh-skill": "workspace:^",
|
||||
"@deepseek-ai/dsh-skill-badge": "workspace:^",
|
||||
"@deepseek-ai/dsh-skill-local": "workspace:^",
|
||||
"@deepseek-ai/dsh-spill-local": "workspace:^",
|
||||
"@deepseek-ai/dsh-spill-policy": "workspace:^",
|
||||
|
||||
1
packages/bundle/base/tests/fixtures/root.cordis.yml
vendored
Normal file
1
packages/bundle/base/tests/fixtures/root.cordis.yml
vendored
Normal file
@@ -0,0 +1 @@
|
||||
[]
|
||||
@@ -2,5 +2,5 @@
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write packages/skill/README.md
|
||||
README.md: d10049ac3e741350fddb42f430b70f063da1d12d
|
||||
README.zh.md: 67f2da6f75edecd180ff861122c6392684ed9bdb
|
||||
README.md: 533904859ad998de4f371a073fde98b68660097b
|
||||
README.zh.md: 1fad581cc61a05251f671577dcb7edab37281283
|
||||
|
||||
@@ -7,6 +7,7 @@ This family discovers reusable agent instructions and exposes them to the model
|
||||
| Package | Role | ctx key |
|
||||
|---|---|---|
|
||||
| [`skill/`](skill/README.md) | Defines skill provider registration and lookup | `ctx.skills` |
|
||||
| [`skill-badge/`](skill-badge/README.md) | Contributes the optional bundled dsh badge skill | registers on `ctx.skills` |
|
||||
| [`skill-local/`](skill-local/README.md) | Discovers skills from local filesystems | registers on `ctx.skills` |
|
||||
| [`tool-skill/`](tool-skill/README.md) | Publishes the skill catalog and model-facing loader | registers on `ctx.tools` |
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
| 包 | 职责 | ctx 键 |
|
||||
|---|---|---|
|
||||
| [`skill/`](skill/README.md) | 定义 skill 提供方注册和查找 | `ctx.skills` |
|
||||
| [`skill-badge/`](skill-badge/README.md) | 贡献可选的内置 dsh 徽章 skill | 注册到 `ctx.skills` |
|
||||
| [`skill-local/`](skill-local/README.md) | 从本地文件系统发现 skill | 注册到 `ctx.skills` |
|
||||
| [`tool-skill/`](tool-skill/README.md) | 发布 skill 目录和面向模型的 loader | 注册到 `ctx.tools` |
|
||||
|
||||
|
||||
6
packages/skill/skill-badge/README.i18n.yaml
Normal file
6
packages/skill/skill-badge/README.i18n.yaml
Normal file
@@ -0,0 +1,6 @@
|
||||
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write packages/skill/skill-badge/README.md
|
||||
README.md: 49b38023a7c110bb52bb351668905c702e251216
|
||||
README.zh.md: bf7eb0d7d4c0552c07f9cdf5665f8a20df829483
|
||||
22
packages/skill/skill-badge/README.md
Normal file
22
packages/skill/skill-badge/README.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# @deepseek-ai/dsh-skill-badge
|
||||
|
||||
English | [中文](README.zh.md)
|
||||
|
||||
Optional bundled skill provider that contributes `dsh-badge` to `ctx.skills`. The skill supplies the official “powered by dsh” Markdown snippets and the packaged PNG for systems that cannot import a remote image reliably.
|
||||
|
||||
Mount the plugin to enable the provider. It has no configuration. The shipped CLI composition includes the plugin as `disabled: true`; users must explicitly enable its `skill-badge` row before the skill enters a catalog.
|
||||
|
||||
The provider exposes its packaged `assets/` directory as the skill resource base. `dsh-badge.png` is the 726×120 source asset, and consumers render it at 121×20.
|
||||
|
||||
## Model Experience
|
||||
|
||||
Indirectly, through `@deepseek-ai/dsh-tool-skill`, which renders the catalog entry and selected skill body.
|
||||
|
||||
#### KV Cache effect
|
||||
|
||||
Disabled by default, the plugin changes no request. When enabled, its catalog entry and any loaded body change the provider KV prefix at their insertion points.
|
||||
|
||||
## Known Limitations and Deferred Work
|
||||
|
||||
- The provider contributes one fixed skill and has no runtime customization.
|
||||
- Remote Markdown uses Shields.io; use the packaged PNG when the target cannot fetch remote images reliably.
|
||||
22
packages/skill/skill-badge/README.zh.md
Normal file
22
packages/skill/skill-badge/README.zh.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# @deepseek-ai/dsh-skill-badge
|
||||
|
||||
[English](README.md) | 中文
|
||||
|
||||
可选的内置 skill(技能)提供方,向 `ctx.skills` 贡献 `dsh-badge`。该 skill 提供官方「powered by dsh」Markdown 片段和随包分发的 PNG,供无法可靠导入远程图片的系统使用。
|
||||
|
||||
挂载该插件即可启用提供方。它没有配置。交付的 CLI(命令行界面)组合以 `disabled: true` 包含该插件;用户必须显式启用其 `skill-badge` 配置行,该 skill 才会进入目录。
|
||||
|
||||
该提供方将随包分发的 `assets/` 目录作为 skill 资源基底公开。`dsh-badge.png` 是尺寸为 726×120 的源图资源,消费方以 121×20 的尺寸渲染。
|
||||
|
||||
## 模型体验
|
||||
|
||||
通过 `@deepseek-ai/dsh-tool-skill` 间接影响模型;该包会渲染目录条目和所选 skill 的正文。
|
||||
|
||||
#### KV Cache 影响
|
||||
|
||||
该插件默认禁用,不会改变任何请求。启用后,其目录条目和任何已加载正文都会在各自插入点改变提供方的 KV 前缀。
|
||||
|
||||
## 已知限制与暂缓事项
|
||||
|
||||
- 该提供方只贡献一个固定 skill,不提供运行时自定义。
|
||||
- 远程 Markdown 使用 Shields.io;当目标环境无法可靠获取远程图片时,请使用随包分发的 PNG。
|
||||
31
packages/skill/skill-badge/assets/dsh-badge.md
Normal file
31
packages/skill/skill-badge/assets/dsh-badge.md
Normal file
@@ -0,0 +1,31 @@
|
||||
# dsh Badge
|
||||
|
||||
Add the official “powered by dsh” badge without recreating or restyling it.
|
||||
|
||||
## Assets
|
||||
|
||||
- Local PNG: [`dsh-badge.png`](dsh-badge.png), 726×120 source image; render at 121×20
|
||||
- Shields.io image URL: `https://img.shields.io/badge/powered_by-dsh-4D6BFE?style=flat-square&logo=deepseek&logoColor=white`
|
||||
- Project URL: `https://github.com/deepseek-ai/deepseek-harness-sdk`
|
||||
|
||||
## Markdown
|
||||
|
||||
Use this linked badge in Markdown:
|
||||
|
||||
```markdown
|
||||
[](https://github.com/deepseek-ai/deepseek-harness-sdk)
|
||||
```
|
||||
|
||||
If attribution should not be linked, use:
|
||||
|
||||
```markdown
|
||||

|
||||
```
|
||||
|
||||
## Usage rules
|
||||
|
||||
- For GitHub or GitLab Markdown, use the Shields.io URL and link it to the project URL unless the user asks for an unlinked image.
|
||||
- For Feishu and other systems that import remote images unreliably, upload `dsh-badge.png` from this skill directory instead of generating another badge.
|
||||
- Preserve the badge's 121×20 dimensions and aspect ratio.
|
||||
- Place the badge at the end of the attributed document or section unless the user specifies another position.
|
||||
- Do not substitute another color, logo, label, or project URL.
|
||||
BIN
packages/skill/skill-badge/assets/dsh-badge.png
Normal file
BIN
packages/skill/skill-badge/assets/dsh-badge.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
37
packages/skill/skill-badge/package.json
Normal file
37
packages/skill/skill-badge/package.json
Normal file
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"name": "@deepseek-ai/dsh-skill-badge",
|
||||
"description": "Bundled dsh badge skill provider for DeepSeek Harness",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "lib/index.js",
|
||||
"types": "lib/types/index.d.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./lib/types/index.d.ts",
|
||||
"default": "./lib/index.js"
|
||||
},
|
||||
"./invariant": {
|
||||
"types": "./lib/types/invariant.d.ts",
|
||||
"default": "./lib/invariant.js"
|
||||
},
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"files": [
|
||||
"lib/index.js",
|
||||
"lib/invariant.js",
|
||||
"assets",
|
||||
"lib/types/**/*.d.ts"
|
||||
],
|
||||
"license": "BSD-3-Clause",
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/dsh-invariants": "^0.0.1",
|
||||
"@deepseek-ai/dsh-skill": "^0.0.1",
|
||||
"cordis": "^4.0.0-rc.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/dsh-skill": "workspace:^",
|
||||
"cordis": "^4.0.0-rc.7"
|
||||
}
|
||||
}
|
||||
60
packages/skill/skill-badge/src/index.ts
Normal file
60
packages/skill/skill-badge/src/index.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* Bundled `dsh-badge` skill provider.
|
||||
*
|
||||
* @module @deepseek-ai/dsh-skill-badge
|
||||
*/
|
||||
|
||||
import { readFile } from 'node:fs/promises'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import type { Context } from 'cordis'
|
||||
import {
|
||||
BUNDLED_SKILL_RANK,
|
||||
type SkillCandidate,
|
||||
type SkillDefinition,
|
||||
type SkillProvider,
|
||||
} from '@deepseek-ai/dsh-skill'
|
||||
|
||||
const PROVIDER_NAME = 'dsh-badge'
|
||||
const SKILL_BODY_URL = new URL('../assets/dsh-badge.md', import.meta.url)
|
||||
const RESOURCE_BASE = {
|
||||
kind: 'directory',
|
||||
path: fileURLToPath(new URL('../assets/', import.meta.url)),
|
||||
} as const
|
||||
const INVOCATION = { modelInvocable: true, userInvocable: true } as const
|
||||
const DESCRIPTION = 'Add the official “powered by dsh” badge to documents, pull requests, merge requests, and other content produced with DeepSeek Harness. Use whenever creating a pull request or merge request. Also use when the user asks for a dsh badge, powered-by-dsh attribution, or a reusable dsh badge asset or snippet.'
|
||||
const CANDIDATE: SkillCandidate = {
|
||||
name: 'dsh-badge',
|
||||
description: DESCRIPTION,
|
||||
invocation: INVOCATION,
|
||||
provider: PROVIDER_NAME,
|
||||
source: 'bundled',
|
||||
resourceBase: RESOURCE_BASE,
|
||||
rank: BUNDLED_SKILL_RANK,
|
||||
locator: SKILL_BODY_URL,
|
||||
}
|
||||
|
||||
const provider: SkillProvider = {
|
||||
name: PROVIDER_NAME,
|
||||
list: () => Promise.resolve([CANDIDATE]),
|
||||
async get(_candidate): Promise<SkillDefinition> {
|
||||
return {
|
||||
name: CANDIDATE.name,
|
||||
description: CANDIDATE.description,
|
||||
invocation: CANDIDATE.invocation,
|
||||
provider: CANDIDATE.provider,
|
||||
source: CANDIDATE.source,
|
||||
resourceBase: RESOURCE_BASE,
|
||||
content: await readFile(SKILL_BODY_URL, 'utf8'),
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
/** Cordis plugin name. */
|
||||
export const name = 'skill-badge'
|
||||
/** Service required by the bundled provider. */
|
||||
export const inject = ['skills']
|
||||
|
||||
/** Register the bundled `dsh-badge` provider on `ctx.skills`. */
|
||||
export function apply(ctx: Context): void {
|
||||
ctx.skills.registerProvider(() => provider)
|
||||
}
|
||||
30
packages/skill/skill-badge/src/invariant.ts
Normal file
30
packages/skill/skill-badge/src/invariant.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Package-owned invariant companion for `@deepseek-ai/dsh-skill-badge`.
|
||||
* @module @deepseek-ai/dsh-skill-badge/invariant
|
||||
*/
|
||||
|
||||
/* jscpd:ignore-start */
|
||||
import type { Context } from 'cordis'
|
||||
import type { InvariantInstaller } from '@deepseek-ai/dsh-invariants'
|
||||
|
||||
const PACKAGE_NAME = '@deepseek-ai/dsh-skill-badge'
|
||||
|
||||
/** Cordis companion plugin name. */
|
||||
export const name = 'skill-badge-invariant'
|
||||
/** Service required before the companion can reserve package ownership. */
|
||||
export const inject = ['invariants']
|
||||
|
||||
/**
|
||||
* No runtime invariant: the package owns one immutable provider registration,
|
||||
* while the skill registry owns registration uniqueness and lifecycle checks.
|
||||
*/
|
||||
const install: InvariantInstaller = () => {}
|
||||
|
||||
/**
|
||||
* Register this package's invariant companion.
|
||||
* @param ctx - Cordis context carrying the invariant service.
|
||||
* @returns the installed registration's disposer after setup succeeds.
|
||||
*/
|
||||
export const apply = (ctx: Context): Promise<() => void> =>
|
||||
Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install))
|
||||
/* jscpd:ignore-end */
|
||||
40
packages/skill/skill-badge/tests/skill-badge.spec.ts
Normal file
40
packages/skill/skill-badge/tests/skill-badge.spec.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { createHash } from 'node:crypto'
|
||||
import { readFile } from 'node:fs/promises'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { Context } from 'cordis'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import SkillService from '@deepseek-ai/dsh-skill'
|
||||
import * as SkillBadge from '@deepseek-ai/dsh-skill-badge'
|
||||
|
||||
describe('dsh-skill-badge', () => {
|
||||
it('registers and disposes the bundled badge skill', async () => {
|
||||
const ctx = new Context()
|
||||
await ctx.plugin(SkillService)
|
||||
const fiber = await ctx.plugin(SkillBadge)
|
||||
const resourcePath = fileURLToPath(new URL('../assets/', import.meta.url))
|
||||
|
||||
expect(await ctx.skills.list()).toEqual([{
|
||||
name: 'dsh-badge',
|
||||
description: 'Add the official “powered by dsh” badge to documents, pull requests, merge requests, and other content produced with DeepSeek Harness. Use whenever creating a pull request or merge request. Also use when the user asks for a dsh badge, powered-by-dsh attribution, or a reusable dsh badge asset or snippet.',
|
||||
invocation: { modelInvocable: true, userInvocable: true },
|
||||
provider: 'dsh-badge',
|
||||
source: 'bundled',
|
||||
resourceBase: { kind: 'directory', path: resourcePath },
|
||||
}])
|
||||
const loaded = await ctx.skills.get('dsh-badge')
|
||||
expect(loaded?.content).toContain('Preserve the badge\'s 121×20 dimensions')
|
||||
expect(loaded?.resourceBase).toEqual({ kind: 'directory', path: resourcePath })
|
||||
|
||||
await fiber.dispose()
|
||||
expect(await ctx.skills.list()).toEqual([])
|
||||
})
|
||||
|
||||
it('ships the official 726×120 PNG unchanged', async () => {
|
||||
const image = await readFile(new URL('../assets/dsh-badge.png', import.meta.url))
|
||||
expect(image.readUInt32BE(16)).toBe(726)
|
||||
expect(image.readUInt32BE(20)).toBe(120)
|
||||
expect(createHash('sha256').update(image).digest('hex')).toBe(
|
||||
'f2c4f5ec9cbe847c0c763545c4d839efa8485bc74203733d0a0e8259f233c653',
|
||||
)
|
||||
})
|
||||
})
|
||||
14
packages/skill/skill-badge/tsconfig.json
Normal file
14
packages/skill/skill-badge/tsconfig.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"extends": "../../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "src",
|
||||
"outDir": "lib/types"
|
||||
},
|
||||
"include": ["src"],
|
||||
"references": [
|
||||
{ "path": "../../../vendor/cosmokit" },
|
||||
{ "path": "../../../vendor/cordis" },
|
||||
{ "path": "../skill" },
|
||||
{ "path": "../../support/invariants" }
|
||||
]
|
||||
}
|
||||
@@ -21,6 +21,7 @@ import { parse as parseYaml } from 'yaml'
|
||||
import type { FileSystem, FsDirEntry, FsTarget } from '@deepseek-ai/dsh-fs'
|
||||
import { resolveDshHome } from '@deepseek-ai/dsh-paths'
|
||||
import {
|
||||
BUNDLED_SKILL_RANK,
|
||||
isSkillName,
|
||||
type SkillCandidate,
|
||||
type SkillDefinition,
|
||||
@@ -40,7 +41,6 @@ const USER_AGENTS_RANK = 500
|
||||
const DEFAULT_WATCH_STABILITY_THRESHOLD_MS = 200
|
||||
const DEFAULT_WATCH_POLL_INTERVAL_MS = 100
|
||||
const DEFAULT_WATCH_MAX_PROJECTS = 128
|
||||
const BUNDLED_RANK = 600
|
||||
|
||||
export const name = 'skill-local'
|
||||
export const inject = ['skills']
|
||||
@@ -256,7 +256,7 @@ export class LocalSkillProvider implements SkillProvider {
|
||||
)
|
||||
}
|
||||
if (this.bundledSkillDir !== undefined) {
|
||||
roots.push({ path: this.bundledSkillDir, source: 'bundled', rank: BUNDLED_RANK, trustedHost: true })
|
||||
roots.push({ path: this.bundledSkillDir, source: 'bundled', rank: BUNDLED_SKILL_RANK, trustedHost: true })
|
||||
}
|
||||
return roots
|
||||
}
|
||||
|
||||
@@ -20,6 +20,9 @@ const MAX_COLLECT_ATTEMPTS = 2
|
||||
const RUNTIME_PROVIDER = 'runtime'
|
||||
const RUNTIME_RANK = 250
|
||||
|
||||
/** Standard precedence rank for packaged skill providers and local bundled roots. */
|
||||
export const BUNDLED_SKILL_RANK = 600
|
||||
|
||||
/**
|
||||
* Return whether a string is a valid kebab-case skill name.
|
||||
* @param name - candidate skill name to validate.
|
||||
|
||||
Reference in New Issue
Block a user