Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions skills/firecrawl-monitor/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
---
name: firecrawl-monitor
description: |
Alert by webhook/email on web changes — use for "monitor/watch/track/alert me when": recurring checks on known URLs (prefer over repeated one-off scrapes) or web-wide watches for new results (queries + goal).
description: >-
Monitor pages or the web for changes or new results and send notifications by
email or webhook on a recurring schedule. Use for page monitoring, web
monitoring, recurring checks, alerts, or requests to monitor, watch, or track
a URL or topic. Covers competitor pricing, jobs, blogs, docs, changelogs, and
status pages, plus new product launches, funding rounds, papers, news,
releases, and mentions across the web. Prefer monitors over repeated scrapes
whenever content must be checked more than once; use page monitors for known
URLs and web monitors with search queries plus a goal for new results.
allowed-tools:
- Bash(firecrawl *)
- Bash(npx firecrawl-cli *)
Expand Down
41 changes: 41 additions & 0 deletions src/__tests__/skills.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { readdirSync, readFileSync } from 'fs';
import path from 'path';
import { parse } from 'yaml';
import { describe, expect, it } from 'vitest';

const SKILLS_DIR = path.resolve(__dirname, '../../skills');
const MAX_DESCRIPTION_LENGTH = 1024;

describe('skill frontmatter', () => {
it('keeps every description within the Copilot CLI limit', () => {
const skillDirectories = readdirSync(SKILLS_DIR, { withFileTypes: true })
.filter((entry) => entry.isDirectory())
.map((entry) => entry.name);

for (const skillDirectory of skillDirectories) {
const skillPath = path.join(SKILLS_DIR, skillDirectory, 'SKILL.md');
const content = readFileSync(skillPath, 'utf8');
const frontmatterMatch = content.match(
/^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/
);

expect(
frontmatterMatch,
`${skillPath} must contain YAML frontmatter`
).not.toBeNull();

const frontmatter = parse(frontmatterMatch![1]) as Record<
string,
unknown
>;
expect(
typeof frontmatter.description,
`${skillPath} must have a description`
).toBe('string');
expect(
(frontmatter.description as string).length,
`${skillPath} description exceeds ${MAX_DESCRIPTION_LENGTH} characters`
).toBeLessThanOrEqual(MAX_DESCRIPTION_LENGTH);
}
});
});