Files
dsh/upstream/container/platform/test/system-skills.test.mjs
T

114 lines
5.3 KiB
JavaScript

import assert from 'node:assert/strict'
import { lstat, mkdir, readFile, readlink, writeFile } from 'node:fs/promises'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { mkdtemp } from 'node:fs/promises'
import test from 'node:test'
import {
readSystemSkillCatalog,
SystemSkillManager,
} from '../../control-plane/modules/skill-manager/index.mjs'
async function fixture() {
const root = await mkdtemp(join(tmpdir(), 'dsh-system-skills-'))
const sourceRoot = join(root, 'source')
const bundle = join(sourceRoot, 'operations')
await mkdir(join(bundle, 'references'), { recursive: true })
await writeFile(join(sourceRoot, 'catalog.json'), JSON.stringify({
schema: 1,
skills: [{
id: 'operations',
source: 'operations',
description: { en: 'Operate DSH.', zh: '操作 DSH。' },
}],
}))
await writeFile(join(bundle, 'SKILL.md'), '---\nname: operations\ndescription: Operate DSH.\n---\n\n# Operations\n')
await writeFile(join(bundle, 'references', 'guide.md'), '# Guide\n')
return {
root,
sourceRoot,
viewRoot: join(root, 'run', 'skills'),
statePath: join(root, 'state', 'skills.json'),
}
}
test('System Skills are identified by signed catalog ID and content hash', async () => {
const { sourceRoot } = await fixture()
const catalog = await readSystemSkillCatalog(sourceRoot)
assert.equal(catalog.length, 1)
assert.equal(catalog[0].id, 'operations')
assert.match(catalog[0].sha256, /^[0-9a-f]{64}$/)
assert.deepEqual(catalog[0].description, { en: 'Operate DSH.', zh: '操作 DSH。' })
})
test('System Skill selection hot-updates one stable view and persists install state', async () => {
const paths = await fixture()
const manager = new SystemSkillManager(paths)
assert.deepEqual(await manager.initialize(), [{
id: 'operations',
sha256: (await manager.list())[0].sha256,
description: { en: 'Operate DSH.', zh: '操作 DSH。' },
installed: true,
enabled: true,
}])
assert.equal(await readlink(join(paths.viewRoot, 'operations')), join(paths.sourceRoot, 'operations'))
assert.equal((await manager.configure('operations', 'disable'))[0].enabled, false)
await assert.rejects(lstat(join(paths.viewRoot, 'operations')), { code: 'ENOENT' })
assert.equal((await manager.configure('operations', 'enable'))[0].enabled, true)
assert.equal(await readlink(join(paths.viewRoot, 'operations')), join(paths.sourceRoot, 'operations'))
const uninstalled = (await manager.configure('operations', 'uninstall'))[0]
assert.deepEqual({ installed: uninstalled.installed, enabled: uninstalled.enabled }, { installed: false, enabled: false })
await assert.rejects(manager.configure('operations', 'enable'), /must be installed/)
assert.equal((await new SystemSkillManager(paths).initialize())[0].installed, false)
assert.equal((await manager.configure('operations', 'install'))[0].enabled, true)
})
test('System Skill state ignores removed entries and defaults newly signed skills on', async () => {
const paths = await fixture()
const manager = new SystemSkillManager(paths)
await manager.initialize()
await manager.configure('operations', 'uninstall')
const second = join(paths.sourceRoot, 'second')
await mkdir(second)
await writeFile(join(second, 'SKILL.md'), '---\nname: second\ndescription: Second.\n---\n\n# Second\n')
await writeFile(join(paths.sourceRoot, 'catalog.json'), JSON.stringify({
schema: 1,
skills: [{ id: 'second', source: 'second', description: { en: 'Second.', zh: '第二个。' } }],
}))
const listed = await manager.initialize()
assert.deepEqual(listed.map(skill => ({ id: skill.id, installed: skill.installed, enabled: skill.enabled })), [
{ id: 'second', installed: true, enabled: true },
])
const saved = JSON.parse(await readFile(paths.statePath, 'utf8'))
assert.deepEqual(Object.keys(saved.skills), ['second'])
})
test('System Skill manager switches to a newly selected Environment catalog', async () => {
const paths = await fixture()
const manager = new SystemSkillManager(paths)
await manager.initialize()
const replacementRoot = join(paths.root, 'replacement')
const replacement = join(replacementRoot, 'replacement')
await mkdir(replacement, { recursive: true })
await writeFile(join(replacement, 'SKILL.md'), '---\nname: replacement\ndescription: Replacement.\n---\n')
await writeFile(join(replacementRoot, 'catalog.json'), JSON.stringify({
schema: 1,
skills: [{ id: 'replacement', source: 'replacement', description: { en: 'Replacement.', zh: '替代。' } }],
}))
assert.deepEqual((await manager.useSourceRoot(replacementRoot)).map(skill => skill.id), ['replacement'])
await assert.rejects(lstat(join(paths.viewRoot, 'operations')), { code: 'ENOENT' })
assert.equal(await readlink(join(paths.viewRoot, 'replacement')), replacement)
await assert.rejects(manager.configure('operations', 'enable'), /current Environment/)
})
test('System Skill catalog rejects source aliases and mismatched frontmatter', async () => {
const paths = await fixture()
const document = JSON.parse(await readFile(join(paths.sourceRoot, 'catalog.json'), 'utf8'))
document.skills[0].source = '../operations'
await writeFile(join(paths.sourceRoot, 'catalog.json'), JSON.stringify(document))
await assert.rejects(readSystemSkillCatalog(paths.sourceRoot), /source is invalid/)
})