Repository navigation
fix(server): recover skill frontmatter Claude Code itself accepts #7814
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
aa2385d
32046f3
071246a
9921e46
613ce44
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -69,18 +69,38 @@ function parseFrontmatterBoolean(value: unknown): boolean | undefined { | |
| } | ||
| } | ||
|
|
||
| function parseSkillFrontmatter(contents: string): SkillFrontmatter { | ||
| const match = FRONTMATTER_PATTERN.exec(contents); | ||
| if (!match) { | ||
| return { kind: "missing" }; | ||
| } | ||
| /** | ||
| * Repairs the one YAML dialect difference observed in Claude Code: it accepts | ||
| * an unquoted scalar containing a `: ` sequence where the YAML parser rejects | ||
| * the whole document as an ambiguous nested mapping. Re-run the real parser | ||
| * after quoting only those top-level scalar values so all other fields keep | ||
| * normal YAML validation and parsed metadata. | ||
| */ | ||
| function parseSkillFrontmatterLeniently(yamlSource: string): SkillFrontmatter { | ||
| const repairedSource = yamlSource | ||
| .split(/\r?\n/) | ||
| .map((line) => { | ||
| const match = /^(\s*[A-Za-z0-9_-]+:\s+)(.*)$/.exec(line); | ||
| const value = match?.[2]; | ||
| if (!match || value === undefined || !value.includes(": ")) { | ||
| return line; | ||
| } | ||
| if (value.startsWith('"') || value.startsWith("'")) { | ||
| return line; | ||
| } | ||
| const escaped = value.replaceAll("\\", "\\\\").replaceAll('"', '\\"'); | ||
| return `${match[1]}"${escaped}"`; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win 🔎 Supported by static analysis🏁 Script executed: sed -n '55,150p' apps/server/src/provider/Drivers/ClaudeSkills.ts
sed -n '180,320p' apps/server/src/provider/Drivers/ClaudeSkills.test.ts
rg -n 'description: .*#|trailing comment|parseSkillFrontmatterLeniently|discoverClaudeSkills' apps/server/src/provider/DriversRepository: pingdotgg/t3code Length of output: 13138 🏁 Script executed: sed -n '1,150p' apps/server/src/provider/Drivers/ClaudeSkills.ts
sed -n '330,410p' apps/server/src/provider/Drivers/ClaudeSkills.ts
sed -n '1,35p' apps/server/src/provider/Drivers/ClaudeSkills.test.ts
rg -n 'function parseYamlDocument|const parseYamlDocument|parseYamlDocument|from "yaml"|from .*yaml' apps/server/src apps/server/package.json package.jsonRepository: pingdotgg/t3code Length of output: 10904 🤖 get_repo_knowledge executed:
Length of output: 1777 🏁 Script executed: set -eu
printf '%s\n' '--- yaml dependency declarations ---'
rg -n '"yaml"|yaml@' package.json apps/server/package.json pnpm-lock.yaml yarn.lock package-lock.json 2>/dev/null || true
printf '%s\n' '--- parser probe ---'
node --input-type=module <<'JS'
import { parse } from "yaml";
const source = "description: tool: run # note";
const match = /^(\\s*[A-Za-z0-9_-]+:\\s+)(.*)$/.exec(source);
if (!match) throw new Error("regex did not match");
const value = match[2];
const escaped = value.replaceAll("\\\\", "\\\\\\\\").replaceAll('"', '\\\\"');
const repaired = `${match[1]}"${escaped}"`;
console.log(JSON.stringify({ source, repaired, parsed: parse(repaired) }));
JSRepository: pingdotgg/t3code Length of output: 28941 Keep trailing YAML comments outside the repaired value. When a recovered description ends with a YAML comment, such as Detect the comment boundary before quoting the scalar. Preserve 🤖 Prompt for AI Agents |
||
| }) | ||
| .join("\n"); | ||
|
|
||
| let parsed: unknown; | ||
| try { | ||
| parsed = parseYamlDocument(match[1] ?? ""); | ||
| return parseParsedSkillFrontmatter(parseYamlDocument(repairedSource)); | ||
| } catch { | ||
| return { kind: "malformed" }; | ||
| } | ||
| } | ||
|
|
||
| function parseParsedSkillFrontmatter(parsed: unknown): SkillFrontmatter { | ||
| if (typeof parsed !== "object" || parsed === null) { | ||
| return { kind: "malformed" }; | ||
| } | ||
|
|
@@ -99,6 +119,22 @@ function parseSkillFrontmatter(contents: string): SkillFrontmatter { | |
| }; | ||
| } | ||
|
|
||
| function parseSkillFrontmatter(contents: string): SkillFrontmatter { | ||
| const match = FRONTMATTER_PATTERN.exec(contents); | ||
| if (!match) { | ||
| return { kind: "missing" }; | ||
| } | ||
| const yamlSource = match[1] ?? ""; | ||
|
|
||
| let parsed: unknown; | ||
| try { | ||
| parsed = parseYamlDocument(yamlSource); | ||
| } catch { | ||
| return parseSkillFrontmatterLeniently(yamlSource); | ||
| } | ||
| return parseParsedSkillFrontmatter(parsed); | ||
| } | ||
|
|
||
| /** | ||
| * Where an administrator installs the policy file whose settings outrank every | ||
| * user and project one. Absent on almost every machine, which is why a missing | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Expect the directory-based command name.
discoverClaudeSkillspublishes the directory name, not frontmattername. This assertion receives"commented"but expects"demo", so the test fails. Change the expected name to"commented".🤖 Prompt for AI Agents