Skip to content

Commit 0f0c465

Browse files
committed
fix(skills): reject structural plain scalars
1 parent 5deff4f commit 0f0c465

3 files changed

Lines changed: 35 additions & 2 deletions

File tree

src/chrome/src/agent/skills.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,11 @@ function inferName(content, index) {
9999

100100
function parseAgentSkillScalar(value) {
101101
const raw = String(value || '').trim();
102-
if (!raw || /^[!&*\[{]/.test(raw)) return null;
102+
if (
103+
!raw
104+
|| /^[!&*\[\]{},#|>%@`]/.test(raw)
105+
|| /^[?:-](?:[ \t]|$)/.test(raw)
106+
) return null;
103107
const singleQuoted = raw.match(/^'((?:''|[^'])*)'(?:\s+#.*)?$/);
104108
if (singleQuoted) return singleQuoted[1].replace(/''/g, "'");
105109
const doubleQuoted = raw.match(/^("(?:\\.|[^"\\])*")(?:\s+#.*)?$/);

src/firefox/src/agent/skills.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,11 @@ function inferName(content, index) {
9999

100100
function parseAgentSkillScalar(value) {
101101
const raw = String(value || '').trim();
102-
if (!raw || /^[!&*\[{]/.test(raw)) return null;
102+
if (
103+
!raw
104+
|| /^[!&*\[\]{},#|>%@`]/.test(raw)
105+
|| /^[?:-](?:[ \t]|$)/.test(raw)
106+
) return null;
103107
const singleQuoted = raw.match(/^'((?:''|[^'])*)'(?:\s+#.*)?$/);
104108
if (singleQuoted) return singleQuoted[1].replace(/''/g, "'");
105109
const doubleQuoted = raw.match(/^("(?:\\.|[^"\\])*")(?:\s+#.*)?$/);

test/run.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12934,6 +12934,27 @@ description: foo: bar
1293412934
# Safe fallback
1293512935

1293612936
Keep the invalid scalar source.`;
12937+
const invalidPlainSequence = `---
12938+
name: pdf-processing
12939+
description: - item
12940+
---
12941+
# Safe fallback
12942+
12943+
Keep the invalid sequence source.`;
12944+
const commentOnlyDescription = `---
12945+
name: pdf-processing
12946+
description: # comment
12947+
---
12948+
# Safe fallback
12949+
12950+
Keep the comment-only source.`;
12951+
const reservedPlainIndicator = `---
12952+
name: pdf-processing
12953+
description: @invalid
12954+
---
12955+
# Safe fallback
12956+
12957+
Keep the reserved-indicator source.`;
1293712958
const supportedRaw = '\uFEFF\r\n\r\n---\r\nname: pdf-processing\r\ndescription: Extract PDF text.\r\n---\r\n# PDF workflow\r\n\r\nFollow it.';
1293812959
const oversizedFrontmatter = `---
1293912960
name: pdf-processing
@@ -12970,6 +12991,9 @@ Keep the oversized source.`;
1297012991
['tab-indented block', tabIndent, 'Tab-indented content.'],
1297112992
['unknown top-level key', unknownKey, 'unexpected: value'],
1297212993
['plain scalar mapping separator', invalidPlainColon, 'description: foo: bar'],
12994+
['plain scalar sequence indicator', invalidPlainSequence, 'description: - item'],
12995+
['comment-only required scalar', commentOnlyDescription, 'description: # comment'],
12996+
['reserved plain scalar indicator', reservedPlainIndicator, 'description: @invalid'],
1297312997
]) {
1297412998
const id = `invalid-${caseName.replace(/\s+/g, '-')}`;
1297512999
const [skill] = normalizeSkills([{ id, content }]);
@@ -12988,6 +13012,7 @@ Keep the oversized source.`;
1298813012
['Chinese name', '技能', '技能', '处理技能。'],
1298913013
['Russian name', 'мой-навык', 'мой-навык', 'Обрабатывает задачи.'],
1299013014
['NFKC name', 'cafe\u0301', 'café', 'Handles café tasks.'],
13015+
['indicator-like plain string', 'plain-name', 'plain-name', '-item remains a string.'],
1299113016
]) {
1299213017
const [skill] = normalizeSkills([{
1299313018
id: `valid-${caseName}`,

0 commit comments

Comments
 (0)