mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: add personal skills settings UI and docs (#25066)
> Mux updated this PR on behalf of Mike. ## Summary - Add experimental personal skills API helpers and an Agents settings UI for listing, creating, editing, deleting, and importing SKILL.md content. - Add docs, Storybook coverage, and unit tests for backend-compatible SKILL.md parsing. - Address review feedback by simplifying frontmatter scalar parsing, clarifying the UI parser scope, defaulting personal skill queries to `me`, and patching React Query caches after create, update, and delete. - Merge latest `main` and resolve the Agents sidebar refactor conflicts. ## Validation - pre-commit hook - `go test ./codersdk/workspacesdk -run TestParseSkillFrontmatter -count=1` - `go test ./coderd/x/chatd/chattool -run 'Test' -count=1` - `cd site && pnpm test -- src/pages/AgentsPage/utils/personalSkills.test.ts src/api/queries/userSkills.test.ts src/utils/fileSize.test.ts --runInBand` - `cd site && pnpm lint:types` - `cd site && pnpm lint:check`
This commit is contained in:
@@ -24,6 +24,29 @@ var markdownCommentRe = regexp.MustCompile(`<!--[\s\S]*?-->`)
|
||||
// the frontmatter is missing a required name field.
|
||||
var ErrFrontmatterNameRequired = xerrors.New("frontmatter missing required 'name' field")
|
||||
|
||||
func unquoteFrontmatterScalar(value string) string {
|
||||
if len(value) < 2 {
|
||||
return value
|
||||
}
|
||||
|
||||
quote := value[0]
|
||||
if quote != value[len(value)-1] {
|
||||
return value
|
||||
}
|
||||
|
||||
inner := value[1 : len(value)-1]
|
||||
switch quote {
|
||||
case '"':
|
||||
// This parser supports a small SKILL.md scalar subset, not full
|
||||
// YAML. Double quotes only unescape quoted text and Windows paths.
|
||||
return strings.NewReplacer(`\"`, `"`, `\\`, `\`).Replace(inner)
|
||||
case '\'':
|
||||
return inner
|
||||
default:
|
||||
return value
|
||||
}
|
||||
}
|
||||
|
||||
// ParseSkillFrontmatter extracts name, description, and the
|
||||
// remaining body from a skill meta file. The expected format is
|
||||
// YAML-ish frontmatter delimited by "---" lines:
|
||||
@@ -62,13 +85,7 @@ func ParseSkillFrontmatter(content string) (name, description, body string, err
|
||||
}
|
||||
key = strings.TrimSpace(key)
|
||||
value = strings.TrimSpace(value)
|
||||
// Strip surrounding quotes from YAML string values.
|
||||
if len(value) >= 2 {
|
||||
if (value[0] == '"' && value[len(value)-1] == '"') ||
|
||||
(value[0] == '\'' && value[len(value)-1] == '\'') {
|
||||
value = value[1 : len(value)-1]
|
||||
}
|
||||
}
|
||||
value = unquoteFrontmatterScalar(value)
|
||||
switch strings.ToLower(key) {
|
||||
case "name":
|
||||
name = value
|
||||
|
||||
@@ -32,6 +32,24 @@ func TestParseSkillFrontmatter(t *testing.T) {
|
||||
require.Equal(t, "single-quoted", desc)
|
||||
})
|
||||
|
||||
t.Run("EscapedDoubleQuotedValue", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, desc, _, err := workspacesdk.ParseSkillFrontmatter(
|
||||
"---\nname: escaped\ndescription: \"Review \\\"critical\\\" C:\\\\paths.\"\n---\nBody\n",
|
||||
)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "Review \"critical\" C:\\paths.", desc)
|
||||
})
|
||||
|
||||
t.Run("PlainHashValue", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, desc, _, err := workspacesdk.ParseSkillFrontmatter(
|
||||
"---\nname: plain-hash\ndescription: Build # test\n---\nBody\n",
|
||||
)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "Build # test", desc)
|
||||
})
|
||||
|
||||
t.Run("NoDescription", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
name, desc, body, err := workspacesdk.ParseSkillFrontmatter(
|
||||
|
||||
Reference in New Issue
Block a user