Files
deepseek-harness/packages/preset/agent-presets/tests/metadata.spec.ts
Yichen Jiang 7281615d44 feat(agent-presets): give a preset a name and a description
A picker showed directory names, so the settings page could only ever list
`standard` / `core-web` / `cordis` and hope the reader knew what they meant.
A preset may now publish display text in an optional `preset.yml` beside
its composition, and the section renders cards — name, description, and the
one in use — instead of rows.

The file carries display text ONLY. `id` is the directory name and `trust`
comes from the root a preset was discovered under, so neither is writable
there: otherwise a locally authored preset could name itself into the
shipped set. It is a separate file because a composition is a top-level list
of plugin rows — YAML cannot carry sibling keys beside it, and a fake
metadata row would hand the Loader something to load.

Every read failure degrades to no metadata; absent, malformed, wrongly
typed, and blank all mean the same thing and the picker falls back to the
id. Presentation is not capability: a preset whose name is broken still
mounts.

The editor gained name and description fields above the YAML, and clearing
both removes the file rather than storing a blank name.
2026-08-07 00:41:50 +08:00

100 lines
4.0 KiB
TypeScript

/**
* Display metadata is presentation, never capability: every way of getting it
* wrong degrades to "this preset has no display text" rather than to a
* preset that cannot be discovered or mounted. It also cannot carry identity
* — `id` is the directory and `trust` is the root, so neither is readable
* from the file a user can write.
*/
import { mkdtemp, mkdir, writeFile } from 'node:fs/promises'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { describe, expect, it } from 'vitest'
import { METADATA_FILE, readPresetMetadata, renderPresetMetadata } from '../src/metadata.ts'
/** A preset directory holding exactly the given metadata text. */
async function presetDir(content?: string): Promise<string> {
const dir = await mkdtemp(join(tmpdir(), 'dsh-preset-meta-'))
await mkdir(dir, { recursive: true })
if (content !== undefined) await writeFile(join(dir, METADATA_FILE), content)
return dir
}
describe('reading display metadata', () => {
it('reads a name and a description', async () => {
const dir = await presetDir('name: 标准模式\ndescription: 完整的编码 agent。\n')
expect(await readPresetMetadata(dir)).toEqual({ name: '标准模式', description: '完整的编码 agent。' })
})
it('treats an absent file as no metadata', async () => {
// The common case: every preset authored by duplicating another starts
// without one, and a picker simply falls back to the id.
expect(await readPresetMetadata(await presetDir())).toEqual({})
})
it('treats malformed YAML as no metadata', async () => {
const dir = await presetDir('name: [unclosed\n')
// Display text is not worth failing discovery over — the composition
// beside it still mounts.
expect(await readPresetMetadata(dir)).toEqual({})
})
it.each([
['a list', '- name: x\n'],
['a scalar', 'just a string\n'],
['an empty document', ''],
])('treats %s as no metadata', async (_label, content) => {
expect(await readPresetMetadata(await presetDir(content))).toEqual({})
})
it('ignores fields that are not text', async () => {
const dir = await presetDir('name: 42\ndescription:\n nested: true\n')
expect(await readPresetMetadata(dir)).toEqual({})
})
it('ignores blank text rather than showing an empty name', async () => {
const dir = await presetDir('name: " "\ndescription: ""\n')
expect(await readPresetMetadata(dir)).toEqual({})
})
it('trims surrounding whitespace', async () => {
const dir = await presetDir('name: " 极简模式 "\n')
expect(await readPresetMetadata(dir)).toEqual({ name: '极简模式' })
})
it('cannot carry identity or trust', async () => {
const dir = await presetDir('name: mine\nid: standard\ntrust: system\n')
// A locally authored preset writing `trust: system` must not become a
// shipped one; identity comes from the directory and the root it sits in.
expect(await readPresetMetadata(dir)).toEqual({ name: 'mine' })
})
})
describe('rendering display metadata', () => {
it('round-trips through a read', async () => {
const rendered = renderPresetMetadata({ name: '创造模式', description: '可以改自己的组装。' })
const dir = await presetDir(rendered)
expect(await readPresetMetadata(dir)).toEqual({ name: '创造模式', description: '可以改自己的组装。' })
})
it('omits an absent field rather than writing it blank', () => {
expect(renderPresetMetadata({ name: '极简模式' })).toBe('name: 极简模式\n')
// Description without a name is legal too: the picker falls back to the id.
expect(renderPresetMetadata({ description: '只做检索。' })).toBe('description: 只做检索。\n')
})
it('renders nothing when there is nothing to store', () => {
// Clearing both fields removes the file; an empty document would read as
// an intentional blank name.
expect(renderPresetMetadata({})).toBeUndefined()
expect(renderPresetMetadata({ name: ' ', description: '' })).toBeUndefined()
})
})