validator.test.js 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. import { test } from 'node:test'
  2. import assert from 'node:assert/strict'
  3. import os from 'node:os'
  4. import path from 'node:path'
  5. import { promises as fs } from 'node:fs'
  6. import { fileURLToPath } from 'node:url'
  7. import { validatePackage, driftCheck } from '../../src/host-shells/validator.js'
  8. const V7 = fileURLToPath(new URL('../../', import.meta.url))
  9. async function makePkg() {
  10. const root = await fs.mkdtemp(path.join(os.tmpdir(), 'wnw-pkg-'))
  11. const w = async (rel, c) => {
  12. const full = path.join(root, rel)
  13. await fs.mkdir(path.dirname(full), { recursive: true })
  14. await fs.writeFile(full, c, 'utf8')
  15. }
  16. await w('adapters/registry.json', JSON.stringify({ schema_version: 'webnovel-host-registry/v2', hosts: { 'claude-code': { tier: 1, agentCapable: true, hasHooks: true } } }))
  17. await w('adapters/claude-code/support.md', '# claude-code 核验\n')
  18. await w('roles/事实审查.md', '---\nname: 事实审查\ndescription: d\n---\nbody {{categories.factCheck}}')
  19. await w('skills/webnovel-writer/SKILL.md', '---\nname: webnovel-writer\ndescription: d\n---\nbody')
  20. return { root, w, cleanup: () => fs.rm(root, { recursive: true, force: true }) }
  21. }
  22. test('validatePackage:真实 v7 资产通过', async () => {
  23. const r = await validatePackage(V7)
  24. assert.equal(r.ok, true, '真实资产应过 validator:' + r.errors.join(';'))
  25. })
  26. test('validatePackage:一级宿主缺 support.md → 报错', async () => {
  27. const { root, cleanup } = await makePkg()
  28. try {
  29. await fs.rm(path.join(root, 'adapters/claude-code/support.md'))
  30. const r = await validatePackage(root)
  31. assert.equal(r.ok, false)
  32. assert.ok(r.errors.some((e) => e.includes('support.md')))
  33. } finally { await cleanup() }
  34. })
  35. test('validatePackage:角色缺 description → 报错', async () => {
  36. const { root, w, cleanup } = await makePkg()
  37. try {
  38. await w('roles/事实审查.md', '---\nname: 事实审查\n---\nbody')
  39. const r = await validatePackage(root)
  40. assert.equal(r.ok, false)
  41. assert.ok(r.errors.some((e) => e.includes('description')))
  42. } finally { await cleanup() }
  43. })
  44. test('validatePackage:SKILL description 超 8k → 报错', async () => {
  45. const { root, w, cleanup } = await makePkg()
  46. try {
  47. await w('skills/webnovel-writer/SKILL.md', `---\nname: w\ndescription: ${'描'.repeat(9000)}\n---\nbody`)
  48. const r = await validatePackage(root)
  49. assert.equal(r.ok, false)
  50. assert.ok(r.errors.some((e) => e.includes('8k') || e.includes('预算')))
  51. } finally { await cleanup() }
  52. })
  53. test('validatePackage:含本机绝对路径 → 报错', async () => {
  54. const { root, w, cleanup } = await makePkg()
  55. try {
  56. await w('roles/事实审查.md', '---\nname: 事实审查\ndescription: d\n---\n见 C:\\\\Users\\\\x\\\\a.md')
  57. const r = await validatePackage(root)
  58. assert.equal(r.ok, false)
  59. assert.ok(r.errors.some((e) => e.includes('绝对路径')))
  60. } finally { await cleanup() }
  61. })
  62. test('driftCheck:真实 v7 确定性 + validator 通过', async () => {
  63. const r = await driftCheck(V7)
  64. assert.equal(r.ok, true, r.error)
  65. })