fix(router-gate): stream A todowrite-verifier — unicode boundary for cyrillic mention patterns + DRY + tests
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -8,8 +8,8 @@ export const SKILL_MENTION_PATTERNS = [
|
||||
/superpowers:[a-z-]+/g,
|
||||
/Skill\(([^)]+)\)/g,
|
||||
/\binvoke\s+([a-z][a-z0-9-]*)/gi,
|
||||
/\bвызови\s+([a-z][a-z0-9-]*)/giu,
|
||||
/\bделай\s+([a-z][a-z0-9-]*)/giu,
|
||||
/(?<![\p{L}\p{N}_])вызови\s+([a-z][a-z0-9-]*)/giu,
|
||||
/(?<![\p{L}\p{N}_])делай\s+([a-z][a-z0-9-]*)/giu,
|
||||
];
|
||||
|
||||
function normSkill(name) {
|
||||
@@ -26,13 +26,14 @@ export function extractSkillMentions(todoItems) {
|
||||
const text = itemText(item);
|
||||
const status = item.status || 'pending';
|
||||
const found = new Set();
|
||||
// superpowers: full names
|
||||
for (const m of text.matchAll(/superpowers:[a-z-]+/g)) found.add(normSkill(m[0]));
|
||||
// Skill(...)
|
||||
for (const m of text.matchAll(/Skill\(([^)]+)\)/g)) found.add(normSkill(m[1]));
|
||||
// invoke / вызови / делай <name>
|
||||
for (const re of [/\binvoke\s+([a-z][a-z0-9-]*)/gi, /\bвызови\s+([a-z][a-z0-9-]*)/giu, /\bделай\s+([a-z][a-z0-9-]*)/giu]) {
|
||||
for (const m of text.matchAll(re)) found.add(normSkill(m[1]));
|
||||
for (const pat of SKILL_MENTION_PATTERNS) {
|
||||
const re = new RegExp(pat.source, pat.flags);
|
||||
for (const m of String(text).matchAll(re)) {
|
||||
// superpowers: and Skill() use m[0] / m[1] respectively
|
||||
// invoke/вызови/делай capture group 1 for skill name
|
||||
const val = m[1] !== undefined ? m[1] : m[0];
|
||||
found.add(normSkill(val));
|
||||
}
|
||||
}
|
||||
for (const skill_name of found) out.push({ skill_name, text, status });
|
||||
}
|
||||
|
||||
@@ -103,3 +103,18 @@ describe('extractSkillMentions — dedup', () => {
|
||||
expect(names.filter((n) => n === 'superpowers:writing-plans').length).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('extractSkillMentions — cyrillic patterns', () => {
|
||||
it('вызови pattern detects skill mention', () => {
|
||||
const m = extractSkillMentions([{ content: 'вызови brain-retro', status: 'pending' }]);
|
||||
expect(m.some((x) => x.skill_name === 'brain-retro')).toBe(true);
|
||||
});
|
||||
it('делай pattern detects skill mention', () => {
|
||||
const m = extractSkillMentions([{ content: 'делай subagent-driven-development', status: 'pending' }]);
|
||||
expect(m.some((x) => x.skill_name === 'subagent-driven-development')).toBe(true);
|
||||
});
|
||||
it('no match inside longer word (перевызови)', () => {
|
||||
const m = extractSkillMentions([{ content: 'перевызови foo', status: 'pending' }]);
|
||||
expect(m.some((x) => x.skill_name === 'foo')).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user