Skip to content

Commit 1b703ae

Browse files
committed
fix(scripts): satisfy validate-scripts checks for skills list updates
1 parent 903332d commit 1b703ae

File tree

3 files changed

+40
-15
lines changed

3 files changed

+40
-15
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,8 +285,9 @@ Capture Fusion skill workflow failure context and guide a draft-first bug report
285285
In this repository, use `fusion-<skill-name>` as the default skill naming convention.
286286

287287
Some conventions you may see:
288+
- `skills/` 👍 Working skills
288289
- `skills/.experimental/` 🧪 preview / in-development skills
289-
- `skills/.curated/` curated, broadly reusable skills
290+
- `skills/.curated/` 👌 curated, broadly reusable skills
290291
- `skills/.system/` ⚙️ internal/system skills and shared building blocks
291292

292293
## 🔖 Versioning

scripts/list-skills/parse-frontmatter.ts

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,30 +19,50 @@ export function parseFrontmatter(frontmatter: string): Record<string, string> {
1919
* @returns Line with YAML inline comment removed when applicable.
2020
*/
2121
function stripInlineComment(line: string): string {
22-
let inSingleQuote = false;
23-
let inDoubleQuote = false;
24-
let escaped = false;
22+
const quoteState = { inSingleQuote: false, inDoubleQuote: false, escaped: false };
23+
const characters = Array.from(line);
2524

26-
for (let index = 0; index < line.length; index += 1) {
27-
const char = line[index];
28-
const previous = index > 0 ? line[index - 1] : "";
25+
/**
26+
* Determines whether a single-character token should count as whitespace.
27+
*
28+
* @param value - Single-character token.
29+
* @returns True when the token is whitespace.
30+
*/
31+
function isWhitespace(value: string): boolean {
32+
return value.trim().length === 0;
33+
}
34+
35+
// Walk the line left-to-right so we can stop at the first valid inline comment marker.
36+
for (const [index, char] of characters.entries()) {
37+
const previous = index > 0 ? characters[index - 1] : "";
2938

30-
if (char === "\\" && inDoubleQuote && !escaped) {
31-
escaped = true;
39+
// Track escapes only inside double-quoted strings so escaped quotes do not toggle quote state.
40+
if (char === "\\" && quoteState.inDoubleQuote && !quoteState.escaped) {
41+
quoteState.escaped = true;
3242
continue;
3343
}
3444

35-
if (char === "'" && !inDoubleQuote) {
36-
inSingleQuote = !inSingleQuote;
37-
} else if (char === '"' && !inSingleQuote && !escaped) {
38-
inDoubleQuote = !inDoubleQuote;
45+
// Toggle quote tracking so # inside quoted text is preserved as literal content.
46+
if (char === "'" && !quoteState.inDoubleQuote) {
47+
quoteState.inSingleQuote = !quoteState.inSingleQuote;
48+
}
49+
50+
// Toggle double-quote tracking so escaped quotes do not prematurely end quoted text.
51+
if (char === '"' && !quoteState.inSingleQuote && !quoteState.escaped) {
52+
quoteState.inDoubleQuote = !quoteState.inDoubleQuote;
3953
}
4054

41-
if (char === "#" && !inSingleQuote && !inDoubleQuote && (!previous || /\s/.test(previous))) {
55+
// Treat # as an inline comment marker only when it appears outside quotes after whitespace.
56+
if (
57+
char === "#" &&
58+
!quoteState.inSingleQuote &&
59+
!quoteState.inDoubleQuote &&
60+
(!previous || isWhitespace(previous))
61+
) {
4262
return line.slice(0, index).trimEnd();
4363
}
4464

45-
escaped = false;
65+
quoteState.escaped = false;
4666
}
4767

4868
return line;

scripts/release-prepare/update-readme-skills-table.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,17 @@ type SkillRow = {
2222
* @returns Type icon for the README skills list.
2323
*/
2424
function getSkillTypeIcon(relativePath: string): string {
25+
// Match experimental skill paths first so preview entries get the dedicated icon.
2526
if (relativePath.startsWith("skills/.experimental/")) {
2627
return "🧪";
2728
}
2829

30+
// Match curated skill paths to keep curated content visually distinct.
2931
if (relativePath.startsWith("skills/.curated/")) {
3032
return "👌";
3133
}
3234

35+
// Match system skill paths to separate platform/internal skills from defaults.
3336
if (relativePath.startsWith("skills/.system/")) {
3437
return "⚙️";
3538
}
@@ -93,6 +96,7 @@ export function updateReadmeSkillsTable(repoRoot: string): number {
9396
const name = frontmatter.name?.trim();
9497
const description = frontmatter.description?.trim();
9598
const version = frontmatter["metadata.version"]?.trim();
99+
// This regex normalizes Windows separators to POSIX separators for markdown links.
96100
const relativePath = relative(repoRoot, skillFile).replace(/\\/g, "/");
97101

98102
// Fail fast here so the remaining logic can assume valid input.

0 commit comments

Comments
 (0)