feat(server): enhance frontmatter parsing for skill descriptions
Some checks failed
Deploy skills-market-server / deploy (push) Has been cancelled

- Integrated a new utility function `parseFrontmatterScalarKey` to streamline the extraction of the description from skill files.
- Improved the logic for handling frontmatter, ensuring more robust parsing and trimming of description values.
This commit is contained in:
hjjjj 2026-04-13 13:55:36 +08:00
parent 33a59df4ae
commit de65426d64
2 changed files with 83 additions and 5 deletions

77
lib/frontmatter-scalar.js Normal file
View File

@ -0,0 +1,77 @@
/**
* frontmatter 文本里读一个顶层标量整块 metadata 已由调用方从 --- --- 切好
* 多行块description: > / | metadata
*/
function escapeRegExp(s) {
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
}
/** 下一行若是顶层键 `foo:`(行首无缩进),则当前块结束。 */
function isTopLevelKeyLine(line) {
const t = line.trimStart()
if (!t || t.startsWith('#')) return false
return /^[A-Za-z_][\w-]*\s*:\s/.test(t)
}
function minIndentOfNonEmpty(lines) {
let min = Infinity
for (const l of lines) {
if (!l.trim()) continue
const n = l.match(/^(\s*)/)[1].length
if (n < min) min = n
}
return min === Infinity ? 0 : min
}
function dedent(lines) {
const min = minIndentOfNonEmpty(lines)
return lines.map((l) => (l.length === 0 ? '' : l.slice(min)))
}
function parseFrontmatterScalarKey(fmBlock, key) {
if (!fmBlock || !key) return null
const lines = fmBlock.split(/\r?\n/)
const keyRe = new RegExp(`^${escapeRegExp(key)}:\\s*(.*)$`)
for (let i = 0; i < lines.length; i++) {
const m = lines[i].match(keyRe)
if (!m) continue
let after = m[1].replace(/\s+$/, '')
const blockHead = after.match(/^([>|])([-+]?)\s*(.*)$/)
if (blockHead) {
const mode = blockHead[1]
const sameLine = (blockHead[3] || '').trimEnd()
const raw = []
if (sameLine) raw.push(sameLine)
for (let j = i + 1; j < lines.length; j++) {
const line = lines[j]
if (line.length > 0 && !/^\s/.test(line) && isTopLevelKeyLine(line)) break
raw.push(line)
}
const body = dedent(raw)
if (mode === '>') {
return body
.map((l) => l.trim())
.filter(Boolean)
.join(' ')
.trim()
}
return body.join('\n').trim()
}
const t = after.trim()
if ((t.startsWith('"') && t.endsWith('"')) || (t.startsWith("'") && t.endsWith("'"))) {
return t.slice(1, -1)
}
if (t) return t.replace(/^["']|["']$/g, '')
return ''
}
return null
}
module.exports = { parseFrontmatterScalarKey }

View File

@ -3,6 +3,7 @@ const express = require('express')
const cors = require('cors')
const path = require('path')
const { MongoClient, ObjectId } = require('mongodb')
const { parseFrontmatterScalarKey } = require('./lib/frontmatter-scalar')
const { createAuthRoutes } = require('./routes/auth')
const app = express()
@ -196,16 +197,16 @@ function canUserAccessTaggedResource(user, resourceTags) {
function extractDescription(files) {
const skillFile = files.find(f => f.path === 'SKILL.md' || f.path.endsWith('SKILL.md'))
if (!skillFile) return ''
const content = skillFile.content
const fmMatch = content.match(/^---\s*\r?\n([\s\S]*?)\r?\n---/)
if (fmMatch) {
const descMatch = fmMatch[1].match(/^description:\s*(.+)$/m)
if (descMatch) {
return descMatch[1].trim().replace(/^["']|["']$/g, '')
const fromFm = parseFrontmatterScalarKey(fmMatch[1], 'description')
if (fromFm != null && String(fromFm).trim() !== '') {
return String(fromFm).trim()
}
}
const lines = content.split('\n')
let inFrontmatter = false
for (const line of lines) {