beth-copilot 1.1.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +39 -1
- package/README.md +51 -62
- package/assets/beth-questioning.png +0 -0
- package/assets/yellowstone-beth.png +0 -0
- package/bin/cli.js +19 -410
- package/dist/__tests__/inject-skills.test.d.ts +9 -0
- package/dist/__tests__/inject-skills.test.d.ts.map +1 -0
- package/dist/__tests__/inject-skills.test.js +143 -0
- package/dist/__tests__/inject-skills.test.js.map +1 -0
- package/dist/__tests__/skills/disambiguation.test.d.ts +10 -0
- package/dist/__tests__/skills/disambiguation.test.d.ts.map +1 -0
- package/dist/__tests__/skills/disambiguation.test.js +192 -0
- package/dist/__tests__/skills/disambiguation.test.js.map +1 -0
- package/dist/__tests__/skills/hook-injection.test.d.ts +11 -0
- package/dist/__tests__/skills/hook-injection.test.d.ts.map +1 -0
- package/dist/__tests__/skills/hook-injection.test.js +173 -0
- package/dist/__tests__/skills/hook-injection.test.js.map +1 -0
- package/dist/__tests__/skills/mapping-completeness.test.d.ts +17 -0
- package/dist/__tests__/skills/mapping-completeness.test.d.ts.map +1 -0
- package/dist/__tests__/skills/mapping-completeness.test.js +281 -0
- package/dist/__tests__/skills/mapping-completeness.test.js.map +1 -0
- package/dist/__tests__/skills/pipeline-integration.test.d.ts +18 -0
- package/dist/__tests__/skills/pipeline-integration.test.d.ts.map +1 -0
- package/dist/__tests__/skills/pipeline-integration.test.js +234 -0
- package/dist/__tests__/skills/pipeline-integration.test.js.map +1 -0
- package/dist/__tests__/skills/skill-routing.test.d.ts +15 -0
- package/dist/__tests__/skills/skill-routing.test.d.ts.map +1 -0
- package/dist/__tests__/skills/skill-routing.test.js +723 -0
- package/dist/__tests__/skills/skill-routing.test.js.map +1 -0
- package/dist/__tests__/skills/trigger-coverage.test.d.ts +24 -0
- package/dist/__tests__/skills/trigger-coverage.test.d.ts.map +1 -0
- package/dist/__tests__/skills/trigger-coverage.test.js +746 -0
- package/dist/__tests__/skills/trigger-coverage.test.js.map +1 -0
- package/dist/__tests__/smoke.test.js +13 -0
- package/dist/__tests__/smoke.test.js.map +1 -1
- package/dist/__tests__/verify-skills.test.d.ts +9 -0
- package/dist/__tests__/verify-skills.test.d.ts.map +1 -0
- package/dist/__tests__/verify-skills.test.js +78 -0
- package/dist/__tests__/verify-skills.test.js.map +1 -0
- package/dist/cli/commands/beads.e2e.test.d.ts +4 -2
- package/dist/cli/commands/beads.e2e.test.d.ts.map +1 -1
- package/dist/cli/commands/beads.e2e.test.js +97 -38
- package/dist/cli/commands/beads.e2e.test.js.map +1 -1
- package/dist/cli/commands/cli-edge-cases.e2e.test.js +1 -1
- package/dist/cli/commands/cli-edge-cases.e2e.test.js.map +1 -1
- package/dist/cli/commands/close.d.ts +11 -46
- package/dist/cli/commands/close.d.ts.map +1 -1
- package/dist/cli/commands/close.e2e.test.d.ts +4 -20
- package/dist/cli/commands/close.e2e.test.d.ts.map +1 -1
- package/dist/cli/commands/close.e2e.test.js +23 -204
- package/dist/cli/commands/close.e2e.test.js.map +1 -1
- package/dist/cli/commands/close.js +26 -240
- package/dist/cli/commands/close.js.map +1 -1
- package/dist/cli/commands/close.test.d.ts +7 -9
- package/dist/cli/commands/close.test.d.ts.map +1 -1
- package/dist/cli/commands/close.test.js +44 -424
- package/dist/cli/commands/close.test.js.map +1 -1
- package/dist/cli/commands/doctor.d.ts +5 -22
- package/dist/cli/commands/doctor.d.ts.map +1 -1
- package/dist/cli/commands/doctor.e2e.test.js +3 -59
- package/dist/cli/commands/doctor.e2e.test.js.map +1 -1
- package/dist/cli/commands/doctor.js +38 -111
- package/dist/cli/commands/doctor.js.map +1 -1
- package/dist/cli/commands/doctor.test.js +32 -234
- package/dist/cli/commands/doctor.test.js.map +1 -1
- package/dist/cli/commands/framework-isolation.test.d.ts +1 -1
- package/dist/cli/commands/framework-isolation.test.js +2 -3
- package/dist/cli/commands/framework-isolation.test.js.map +1 -1
- package/dist/cli/commands/help.e2e.test.js +1 -5
- package/dist/cli/commands/help.e2e.test.js.map +1 -1
- package/dist/cli/commands/init-logic.e2e.test.js +12 -2
- package/dist/cli/commands/init-logic.e2e.test.js.map +1 -1
- package/dist/cli/commands/init.test.js +4 -21
- package/dist/cli/commands/init.test.js.map +1 -1
- package/dist/cli/commands/land.d.ts +3 -15
- package/dist/cli/commands/land.d.ts.map +1 -1
- package/dist/cli/commands/land.js +13 -68
- package/dist/cli/commands/land.js.map +1 -1
- package/dist/cli/commands/land.test.d.ts +0 -1
- package/dist/cli/commands/land.test.d.ts.map +1 -1
- package/dist/cli/commands/land.test.js +2 -57
- package/dist/cli/commands/land.test.js.map +1 -1
- package/dist/cli/commands/mcp.e2e.test.js +3 -3
- package/dist/cli/commands/mcp.e2e.test.js.map +1 -1
- package/dist/cli/commands/pipeline.e2e.test.js +23 -26
- package/dist/cli/commands/pipeline.e2e.test.js.map +1 -1
- package/dist/cli/commands/pre-push-guard.d.ts +2 -12
- package/dist/cli/commands/pre-push-guard.d.ts.map +1 -1
- package/dist/cli/commands/pre-push-guard.e2e.test.js +1 -1
- package/dist/cli/commands/pre-push-guard.e2e.test.js.map +1 -1
- package/dist/cli/commands/pre-push-guard.js +2 -47
- package/dist/cli/commands/pre-push-guard.js.map +1 -1
- package/dist/cli/commands/pre-push-guard.test.d.ts +0 -1
- package/dist/cli/commands/pre-push-guard.test.d.ts.map +1 -1
- package/dist/cli/commands/pre-push-guard.test.js +15 -98
- package/dist/cli/commands/pre-push-guard.test.js.map +1 -1
- package/dist/cli/commands/quickstart-expanded.e2e.test.d.ts +1 -1
- package/dist/cli/commands/quickstart-expanded.e2e.test.js +3 -30
- package/dist/cli/commands/quickstart-expanded.e2e.test.js.map +1 -1
- package/dist/cli/commands/quickstart.d.ts +0 -1
- package/dist/cli/commands/quickstart.d.ts.map +1 -1
- package/dist/cli/commands/quickstart.js +2 -60
- package/dist/cli/commands/quickstart.js.map +1 -1
- package/dist/cli/commands/quickstart.test.js +10 -104
- package/dist/cli/commands/quickstart.test.js.map +1 -1
- package/dist/cli/commands/update.d.ts +35 -0
- package/dist/cli/commands/update.d.ts.map +1 -0
- package/dist/cli/commands/update.e2e.test.d.ts +24 -0
- package/dist/cli/commands/update.e2e.test.d.ts.map +1 -0
- package/dist/cli/commands/update.e2e.test.js +240 -0
- package/dist/cli/commands/update.e2e.test.js.map +1 -0
- package/dist/cli/commands/update.js +255 -0
- package/dist/cli/commands/update.js.map +1 -0
- package/dist/core/agents/frontmatter.test.js +1 -1
- package/dist/core/agents/frontmatter.test.js.map +1 -1
- package/dist/core/agents/handoffs.test.js +1 -1
- package/dist/core/agents/handoffs.test.js.map +1 -1
- package/dist/core/agents/loader.d.ts +4 -2
- package/dist/core/agents/loader.d.ts.map +1 -1
- package/dist/core/agents/loader.js +5 -3
- package/dist/core/agents/loader.js.map +1 -1
- package/dist/core/agents/loader.test.js +42 -4
- package/dist/core/agents/loader.test.js.map +1 -1
- package/dist/core/agents/suite.test.js +8 -7
- package/dist/core/agents/suite.test.js.map +1 -1
- package/dist/core/agents/tools.test.js +10 -8
- package/dist/core/agents/tools.test.js.map +1 -1
- package/dist/core/agents/types.test.js +1 -1
- package/dist/core/agents/types.test.js.map +1 -1
- package/dist/core/skills/loader.test.js +1 -1
- package/dist/core/skills/loader.test.js.map +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -2
- package/dist/index.js.map +1 -1
- package/dist/lib/pathValidation.d.ts +0 -5
- package/dist/lib/pathValidation.d.ts.map +1 -1
- package/dist/lib/pathValidation.js +0 -11
- package/dist/lib/pathValidation.js.map +1 -1
- package/dist/lib/pathValidation.test.js +2 -14
- package/dist/lib/pathValidation.test.js.map +1 -1
- package/package.json +3 -6
- package/sbom.json +259 -371
- package/templates/.github/agents/beth.agent.md +194 -122
- package/templates/.github/agents/developer.agent.md +30 -22
- package/templates/.github/agents/product-manager.agent.md +15 -6
- package/templates/.github/agents/researcher.agent.md +10 -7
- package/templates/.github/agents/security-reviewer.agent.md +16 -7
- package/templates/.github/agents/tester.agent.md +16 -8
- package/templates/.github/agents/ux-designer.agent.md +12 -9
- package/templates/.github/copilot-instructions.md +33 -4
- package/templates/.github/copilot-mcp-config.json +12 -0
- package/templates/.github/dependabot.yml +68 -0
- package/templates/.github/hooks/scripts/inject-skills.mjs +139 -0
- package/templates/.github/hooks/scripts/verify-skills.mjs +47 -0
- package/templates/.github/hooks/skill-enforcement.json +18 -0
- package/templates/.github/pull_request_template.md +48 -0
- package/templates/.github/skills/framer-components/SKILL.md +0 -0
- package/templates/.github/skills/prd/SKILL.md +0 -0
- package/templates/.github/skills/security-analysis/SKILL.md +798 -798
- package/templates/.github/skills/shadcn-ui/SKILL.md +561 -561
- package/templates/.github/skills/vercel-react-best-practices/AGENTS.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/SKILL.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/advanced-event-handler-refs.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/advanced-use-latest.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/async-api-routes.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/async-defer-await.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/async-dependencies.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/async-parallel.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/async-suspense-boundaries.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/bundle-barrel-imports.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/bundle-conditional.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/bundle-defer-third-party.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/bundle-dynamic-imports.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/bundle-preload.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/client-event-listeners.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/client-localstorage-schema.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/client-passive-event-listeners.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/client-swr-dedup.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/js-batch-dom-css.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/js-cache-function-results.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/js-cache-property-access.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/js-cache-storage.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/js-combine-iterations.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/js-early-exit.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/js-hoist-regexp.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/js-index-maps.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/js-length-check-first.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/js-min-max-loop.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/js-set-map-lookups.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/js-tosorted-immutable.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/rendering-activity.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/rendering-animate-svg-wrapper.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/rendering-conditional-render.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/rendering-content-visibility.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/rendering-hoist-jsx.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/rendering-hydration-no-flicker.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/rendering-svg-precision.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/rerender-defer-reads.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/rerender-dependencies.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/rerender-derived-state.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/rerender-functional-setstate.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/rerender-lazy-state-init.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/rerender-memo.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/rerender-simple-expression-in-memo.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/rerender-transitions.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/server-after-nonblocking.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/server-auth-actions.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/server-cache-lru.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/server-cache-react.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/server-dedup-props.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/server-parallel-fetching.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/server-serialization.md +0 -0
- package/templates/.github/skills/web-design-guidelines/SKILL.md +0 -0
- package/templates/.vscode/settings.json +16 -16
- package/templates/AGENTS.md +59 -98
- package/templates/Backlog.md +80 -80
- package/assets/beth-portrait-small.txt +0 -13
- package/assets/beth-portrait.txt +0 -60
- package/bin/beth-animation.sh +0 -155
- package/bin/lib/animation.js +0 -189
- package/bin/lib/pathValidation.js +0 -233
- package/bin/lib/pathValidation.test.js +0 -280
|
@@ -0,0 +1,723 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill Routing Tests — Categories 2–10
|
|
3
|
+
*
|
|
4
|
+
* Verifies every skill in the test matrix:
|
|
5
|
+
* 1. Has a valid SKILL.md file on disk (exists and is non-empty)
|
|
6
|
+
* 2. Is mapped to a valid agent from the Beth team
|
|
7
|
+
*
|
|
8
|
+
* These tests validate the structural integrity of the skill system.
|
|
9
|
+
* They do NOT test LLM prompt inference or enforcement mechanisms
|
|
10
|
+
* (hook injection is tested in hook-injection.test.ts).
|
|
11
|
+
*
|
|
12
|
+
* Test plan reference: docs/E2E-SKILL-TESTS.md — Categories 2–10 (tests 10–72)
|
|
13
|
+
*/
|
|
14
|
+
import { describe, it, expect } from 'vitest';
|
|
15
|
+
import { join } from 'node:path';
|
|
16
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
17
|
+
const PROJECT_ROOT = process.cwd();
|
|
18
|
+
const SKILLS_DIR = join(PROJECT_ROOT, '.github/skills');
|
|
19
|
+
const EXTERNAL_SKILLS_DIR = join(process.env.HOME || '~', '.agents/skills');
|
|
20
|
+
// ─── Helpers ───────────────────────────────────────────────────────────────
|
|
21
|
+
function skillExists(test) {
|
|
22
|
+
if (test.external) {
|
|
23
|
+
return existsSync(test.skillPath);
|
|
24
|
+
}
|
|
25
|
+
return existsSync(join(PROJECT_ROOT, test.skillPath));
|
|
26
|
+
}
|
|
27
|
+
function readSkillContent(test) {
|
|
28
|
+
const fullPath = test.external ? test.skillPath : join(PROJECT_ROOT, test.skillPath);
|
|
29
|
+
return readFileSync(fullPath, 'utf8');
|
|
30
|
+
}
|
|
31
|
+
// Valid agents that Beth can route to
|
|
32
|
+
const VALID_AGENTS = [
|
|
33
|
+
'Beth',
|
|
34
|
+
'developer',
|
|
35
|
+
'product-manager',
|
|
36
|
+
'ux-designer',
|
|
37
|
+
'security-reviewer',
|
|
38
|
+
'tester',
|
|
39
|
+
'researcher',
|
|
40
|
+
];
|
|
41
|
+
// ─── Category 2: Azure Skills (tests 10–31) ───────────────────────────────
|
|
42
|
+
const AZURE_SKILLS = [
|
|
43
|
+
{
|
|
44
|
+
id: 10,
|
|
45
|
+
skill: 'azure-prepare',
|
|
46
|
+
skillPath: '.github/skills/azure-prepare/SKILL.md',
|
|
47
|
+
agent: 'developer',
|
|
48
|
+
testPrompt: 'Create a new containerized Node.js app and deploy it to Azure Container Apps',
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
id: 11,
|
|
52
|
+
skill: 'azure-validate',
|
|
53
|
+
skillPath: '.github/skills/azure-validate/SKILL.md',
|
|
54
|
+
agent: 'developer',
|
|
55
|
+
testPrompt: 'Validate my app\'s deployment readiness and check the Bicep configuration',
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
id: 12,
|
|
59
|
+
skill: 'azure-deploy',
|
|
60
|
+
skillPath: '.github/skills/azure-deploy/SKILL.md',
|
|
61
|
+
agent: 'developer',
|
|
62
|
+
testPrompt: 'Run azd up to push the app to production',
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
id: 13,
|
|
66
|
+
skill: 'azure-compute',
|
|
67
|
+
skillPath: '.github/skills/azure-compute/SKILL.md',
|
|
68
|
+
agent: 'developer',
|
|
69
|
+
testPrompt: 'Recommend the best VM size for our ML training workload on Azure',
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
id: 14,
|
|
73
|
+
skill: 'azure-storage',
|
|
74
|
+
skillPath: '.github/skills/azure-storage/SKILL.md',
|
|
75
|
+
agent: 'developer',
|
|
76
|
+
testPrompt: 'Set up blob storage with lifecycle management for our file upload service',
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
id: 15,
|
|
80
|
+
skill: 'azure-ai',
|
|
81
|
+
skillPath: '.github/skills/azure-ai/SKILL.md',
|
|
82
|
+
agent: 'developer',
|
|
83
|
+
testPrompt: 'Configure Azure AI Search with vector search for our product catalog',
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
id: 16,
|
|
87
|
+
skill: 'azure-aigateway',
|
|
88
|
+
skillPath: '.github/skills/azure-aigateway/SKILL.md',
|
|
89
|
+
agent: 'developer',
|
|
90
|
+
testPrompt: 'Set up semantic caching and token limits for our Azure OpenAI gateway',
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
id: 17,
|
|
94
|
+
skill: 'azure-kusto',
|
|
95
|
+
skillPath: '.github/skills/azure-kusto/SKILL.md',
|
|
96
|
+
agent: 'developer',
|
|
97
|
+
testPrompt: 'Write KQL queries to analyze the IoT telemetry in Azure Data Explorer',
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
id: 18,
|
|
101
|
+
skill: 'azure-messaging',
|
|
102
|
+
skillPath: '.github/skills/azure-messaging/SKILL.md',
|
|
103
|
+
agent: 'developer',
|
|
104
|
+
testPrompt: 'Troubleshoot this AMQP connection error with our Event Hub consumer',
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
id: 19,
|
|
108
|
+
skill: 'azure-hosted-copilot-sdk',
|
|
109
|
+
skillPath: '.github/skills/azure-hosted-copilot-sdk/SKILL.md',
|
|
110
|
+
agent: 'developer',
|
|
111
|
+
testPrompt: 'Build a copilot app using @github/copilot-sdk and deploy to Azure',
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
id: 20,
|
|
115
|
+
skill: 'appinsights-instrumentation',
|
|
116
|
+
skillPath: '.github/skills/appinsights-instrumentation/SKILL.md',
|
|
117
|
+
agent: 'developer',
|
|
118
|
+
testPrompt: 'Instrument our web app with Application Insights telemetry',
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
id: 21,
|
|
122
|
+
skill: 'microsoft-foundry',
|
|
123
|
+
skillPath: '.github/skills/microsoft-foundry/SKILL.md',
|
|
124
|
+
agent: 'developer',
|
|
125
|
+
testPrompt: 'Deploy our agent to Microsoft Foundry and run batch evaluation',
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
id: 22,
|
|
129
|
+
skill: 'azure-rbac',
|
|
130
|
+
skillPath: '.github/skills/azure-rbac/SKILL.md',
|
|
131
|
+
agent: 'security-reviewer',
|
|
132
|
+
testPrompt: 'Find the least privilege RBAC role for our managed identity to read blobs',
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
id: 23,
|
|
136
|
+
skill: 'azure-compliance',
|
|
137
|
+
skillPath: '.github/skills/azure-compliance/SKILL.md',
|
|
138
|
+
agent: 'security-reviewer',
|
|
139
|
+
testPrompt: 'Run a compliance scan and security audit on our Azure subscription',
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
id: 24,
|
|
143
|
+
skill: 'entra-app-registration',
|
|
144
|
+
skillPath: '.github/skills/entra-app-registration/SKILL.md',
|
|
145
|
+
agent: 'security-reviewer',
|
|
146
|
+
testPrompt: 'Create an Entra ID app registration with OAuth and MSAL configuration',
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
id: 25,
|
|
150
|
+
skill: 'azure-cost-optimization',
|
|
151
|
+
skillPath: '.github/skills/azure-cost-optimization/SKILL.md',
|
|
152
|
+
agent: 'product-manager',
|
|
153
|
+
testPrompt: 'Analyze our Azure spending and find cost optimization opportunities',
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
id: 26,
|
|
157
|
+
skill: 'azure-cloud-migrate',
|
|
158
|
+
skillPath: '.github/skills/azure-cloud-migrate/SKILL.md',
|
|
159
|
+
agent: 'product-manager',
|
|
160
|
+
testPrompt: 'Assess migrating our Lambda functions to Azure Functions',
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
id: 27,
|
|
164
|
+
skill: 'azure-diagnostics',
|
|
165
|
+
skillPath: '.github/skills/azure-diagnostics/SKILL.md',
|
|
166
|
+
agent: 'tester',
|
|
167
|
+
testPrompt: 'Troubleshoot why our Container App is failing health probes in production',
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
id: 28,
|
|
171
|
+
skill: 'azure-resource-lookup',
|
|
172
|
+
skillPath: '.github/skills/azure-resource-lookup/SKILL.md',
|
|
173
|
+
agent: 'Beth',
|
|
174
|
+
testPrompt: 'List all VMs and storage accounts across our Azure subscriptions',
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
id: 29,
|
|
178
|
+
skill: 'azure-resource-visualizer',
|
|
179
|
+
skillPath: '.github/skills/azure-resource-visualizer/SKILL.md',
|
|
180
|
+
agent: 'Beth',
|
|
181
|
+
testPrompt: 'Generate a Mermaid architecture diagram of our Azure resource group',
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
id: 30,
|
|
185
|
+
skill: 'azure-postgres',
|
|
186
|
+
skillPath: join(EXTERNAL_SKILLS_DIR, 'azure-postgres/SKILL.md'),
|
|
187
|
+
agent: 'developer',
|
|
188
|
+
testPrompt: 'Configure passwordless Entra ID authentication for our Postgres server',
|
|
189
|
+
external: true,
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
id: 31,
|
|
193
|
+
skill: 'azure-quotas',
|
|
194
|
+
skillPath: join(EXTERNAL_SKILLS_DIR, 'azure-quotas/SKILL.md'),
|
|
195
|
+
agent: 'developer',
|
|
196
|
+
testPrompt: 'Check our Azure subscription quotas and vCPU limits',
|
|
197
|
+
external: true,
|
|
198
|
+
},
|
|
199
|
+
];
|
|
200
|
+
// ─── Category 3: Design & Frontend (tests 32–35) ──────────────────────────
|
|
201
|
+
const DESIGN_SKILLS = [
|
|
202
|
+
{
|
|
203
|
+
id: 32,
|
|
204
|
+
skill: 'frontend-design',
|
|
205
|
+
skillPath: '.github/skills/frontend-design/SKILL.md',
|
|
206
|
+
agent: 'developer',
|
|
207
|
+
testPrompt: 'Build a distinctive, production-grade landing page with creative animations',
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
id: 33,
|
|
211
|
+
skill: 'brainstorming',
|
|
212
|
+
skillPath: '.github/skills/brainstorming/SKILL.md',
|
|
213
|
+
agent: 'ux-designer',
|
|
214
|
+
testPrompt: 'Let\'s brainstorm approaches for the new onboarding flow',
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
id: 34,
|
|
218
|
+
skill: 'document-review',
|
|
219
|
+
skillPath: '.github/skills/document-review/SKILL.md',
|
|
220
|
+
agent: 'ux-designer',
|
|
221
|
+
testPrompt: 'Review and refine this brainstorm document before we proceed to planning',
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
id: 35,
|
|
225
|
+
skill: 'every-style-editor',
|
|
226
|
+
skillPath: '.github/skills/every-style-editor/SKILL.md',
|
|
227
|
+
agent: 'product-manager',
|
|
228
|
+
testPrompt: 'Edit this blog post for grammar and style guide compliance',
|
|
229
|
+
},
|
|
230
|
+
];
|
|
231
|
+
// ─── Category 4: Product & Research (tests 36–39) ─────────────────────────
|
|
232
|
+
const PRODUCT_SKILLS = [
|
|
233
|
+
{
|
|
234
|
+
id: 36,
|
|
235
|
+
skill: 'prd',
|
|
236
|
+
skillPath: '.github/skills/prd/SKILL.md',
|
|
237
|
+
agent: 'product-manager',
|
|
238
|
+
testPrompt: 'Write a product requirements document for the billing dashboard feature',
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
id: 37,
|
|
242
|
+
skill: 'web-search',
|
|
243
|
+
skillPath: '.github/skills/web-search/SKILL.md',
|
|
244
|
+
agent: 'researcher',
|
|
245
|
+
testPrompt: 'Research the competitive landscape for AI code assistants',
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
id: 38,
|
|
249
|
+
skill: 'proof',
|
|
250
|
+
skillPath: '.github/skills/proof/SKILL.md',
|
|
251
|
+
agent: 'product-manager',
|
|
252
|
+
testPrompt: 'Create a proof document and share it for team review',
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
id: 39,
|
|
256
|
+
skill: 'changelog',
|
|
257
|
+
skillPath: '.github/skills/changelog/SKILL.md',
|
|
258
|
+
agent: 'developer',
|
|
259
|
+
testPrompt: 'Generate a changelog from recent commits',
|
|
260
|
+
},
|
|
261
|
+
];
|
|
262
|
+
// ─── Category 5: Developer Workflow (tests 40–53) ─────────────────────────
|
|
263
|
+
const DEVELOPER_WORKFLOW_SKILLS = [
|
|
264
|
+
{
|
|
265
|
+
id: 40,
|
|
266
|
+
skill: 'create-agent-skills',
|
|
267
|
+
skillPath: '.github/skills/create-agent-skills/SKILL.md',
|
|
268
|
+
agent: 'developer',
|
|
269
|
+
testPrompt: 'Create a new Claude Code skill for database migration workflows',
|
|
270
|
+
},
|
|
271
|
+
{
|
|
272
|
+
id: 41,
|
|
273
|
+
skill: 'git-worktree',
|
|
274
|
+
skillPath: '.github/skills/git-worktree/SKILL.md',
|
|
275
|
+
agent: 'developer',
|
|
276
|
+
testPrompt: 'Create a git worktree for isolated parallel development on the feature branch',
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
id: 42,
|
|
280
|
+
skill: 'feature-video',
|
|
281
|
+
skillPath: '.github/skills/feature-video/SKILL.md',
|
|
282
|
+
agent: 'developer',
|
|
283
|
+
testPrompt: 'Record a video walkthrough of the new settings feature for the PR',
|
|
284
|
+
},
|
|
285
|
+
{
|
|
286
|
+
id: 43,
|
|
287
|
+
skill: 'resolve_parallel',
|
|
288
|
+
skillPath: '.github/skills/resolve_parallel/SKILL.md',
|
|
289
|
+
agent: 'developer',
|
|
290
|
+
testPrompt: 'Resolve all code TODOs in the codebase using parallel processing',
|
|
291
|
+
},
|
|
292
|
+
{
|
|
293
|
+
id: 44,
|
|
294
|
+
skill: 'resolve_todo_parallel',
|
|
295
|
+
skillPath: '.github/skills/resolve_todo_parallel/SKILL.md',
|
|
296
|
+
agent: 'developer',
|
|
297
|
+
testPrompt: 'Resolve all pending CLI todos in my todo list',
|
|
298
|
+
},
|
|
299
|
+
{
|
|
300
|
+
id: 45,
|
|
301
|
+
skill: 'resolve-pr-parallel',
|
|
302
|
+
skillPath: '.github/skills/resolve-pr-parallel/SKILL.md',
|
|
303
|
+
agent: 'developer',
|
|
304
|
+
testPrompt: 'Address all PR review comments using parallel processing',
|
|
305
|
+
},
|
|
306
|
+
{
|
|
307
|
+
id: 46,
|
|
308
|
+
skill: 'lfg',
|
|
309
|
+
skillPath: '.github/skills/lfg/SKILL.md',
|
|
310
|
+
agent: 'developer',
|
|
311
|
+
testPrompt: 'Execute the work plan sequentially — let\'s go',
|
|
312
|
+
},
|
|
313
|
+
{
|
|
314
|
+
id: 47,
|
|
315
|
+
skill: 'slfg',
|
|
316
|
+
skillPath: '.github/skills/slfg/SKILL.md',
|
|
317
|
+
agent: 'developer',
|
|
318
|
+
testPrompt: 'Execute the work plan using swarm parallel processing',
|
|
319
|
+
},
|
|
320
|
+
{
|
|
321
|
+
id: 48,
|
|
322
|
+
skill: 'deepen-plan',
|
|
323
|
+
skillPath: '.github/skills/deepen-plan/SKILL.md',
|
|
324
|
+
agent: 'developer',
|
|
325
|
+
testPrompt: 'Enhance this plan with parallel research agents to add depth and best practices',
|
|
326
|
+
},
|
|
327
|
+
{
|
|
328
|
+
id: 49,
|
|
329
|
+
skill: 'agent-browser',
|
|
330
|
+
skillPath: '.github/skills/agent-browser/SKILL.md',
|
|
331
|
+
agent: 'developer',
|
|
332
|
+
testPrompt: 'Browse the staging site and fill out the signup form to test it',
|
|
333
|
+
},
|
|
334
|
+
{
|
|
335
|
+
id: 50,
|
|
336
|
+
skill: 'agent-native-architecture',
|
|
337
|
+
skillPath: '.github/skills/agent-native-architecture/SKILL.md',
|
|
338
|
+
agent: 'developer',
|
|
339
|
+
testPrompt: 'Design an application where agents are first-class citizens with MCP tools',
|
|
340
|
+
},
|
|
341
|
+
{
|
|
342
|
+
id: 51,
|
|
343
|
+
skill: 'rclone',
|
|
344
|
+
skillPath: '.github/skills/rclone/SKILL.md',
|
|
345
|
+
agent: 'developer',
|
|
346
|
+
testPrompt: 'Upload the generated video files to our S3 bucket',
|
|
347
|
+
},
|
|
348
|
+
{
|
|
349
|
+
id: 52,
|
|
350
|
+
skill: 'gemini-imagegen',
|
|
351
|
+
skillPath: '.github/skills/gemini-imagegen/SKILL.md',
|
|
352
|
+
agent: 'developer',
|
|
353
|
+
testPrompt: 'Generate a product mockup image using Gemini for the landing page',
|
|
354
|
+
},
|
|
355
|
+
{
|
|
356
|
+
id: 53,
|
|
357
|
+
skill: 'generate_command',
|
|
358
|
+
skillPath: '.github/skills/generate_command/SKILL.md',
|
|
359
|
+
agent: 'developer',
|
|
360
|
+
testPrompt: 'Generate a shell command to find all TypeScript files with TODO comments',
|
|
361
|
+
},
|
|
362
|
+
];
|
|
363
|
+
// ─── Category 6: Testing & QA (tests 54–58) ──────────────────────────────
|
|
364
|
+
const TESTING_SKILLS = [
|
|
365
|
+
{
|
|
366
|
+
id: 54,
|
|
367
|
+
skill: 'test-browser',
|
|
368
|
+
skillPath: '.github/skills/test-browser/SKILL.md',
|
|
369
|
+
agent: 'tester',
|
|
370
|
+
testPrompt: 'Run browser tests on pages affected by the current PR',
|
|
371
|
+
},
|
|
372
|
+
{
|
|
373
|
+
id: 55,
|
|
374
|
+
skill: 'test-xcode',
|
|
375
|
+
skillPath: '.github/skills/test-xcode/SKILL.md',
|
|
376
|
+
agent: 'tester',
|
|
377
|
+
testPrompt: 'Run Xcode tests for the iOS module',
|
|
378
|
+
},
|
|
379
|
+
{
|
|
380
|
+
id: 56,
|
|
381
|
+
skill: 'report-bug',
|
|
382
|
+
skillPath: '.github/skills/report-bug/SKILL.md',
|
|
383
|
+
agent: 'tester',
|
|
384
|
+
testPrompt: 'File a bug report for the broken pagination on the search results page',
|
|
385
|
+
},
|
|
386
|
+
{
|
|
387
|
+
id: 57,
|
|
388
|
+
skill: 'reproduce-bug',
|
|
389
|
+
skillPath: '.github/skills/reproduce-bug/SKILL.md',
|
|
390
|
+
agent: 'tester',
|
|
391
|
+
testPrompt: 'Reproduce the intermittent crash reported in issue #42',
|
|
392
|
+
},
|
|
393
|
+
{
|
|
394
|
+
id: 58,
|
|
395
|
+
skill: 'triage',
|
|
396
|
+
skillPath: '.github/skills/triage/SKILL.md',
|
|
397
|
+
agent: 'tester',
|
|
398
|
+
testPrompt: 'Triage the incoming bug reports and prioritize by severity',
|
|
399
|
+
},
|
|
400
|
+
];
|
|
401
|
+
// ─── Category 7: Orchestration & Swarm (tests 59–62) ─────────────────────
|
|
402
|
+
const ORCHESTRATION_SKILLS = [
|
|
403
|
+
{
|
|
404
|
+
id: 59,
|
|
405
|
+
skill: 'orchestrating-swarms',
|
|
406
|
+
skillPath: '.github/skills/orchestrating-swarms/SKILL.md',
|
|
407
|
+
agent: 'Beth',
|
|
408
|
+
testPrompt: 'Orchestrate a swarm of agents to parallelize the migration work',
|
|
409
|
+
},
|
|
410
|
+
{
|
|
411
|
+
id: 60,
|
|
412
|
+
skill: 'setup',
|
|
413
|
+
skillPath: '.github/skills/setup/SKILL.md',
|
|
414
|
+
agent: 'Beth',
|
|
415
|
+
testPrompt: 'Set up the project structure and initialize the development environment',
|
|
416
|
+
},
|
|
417
|
+
{
|
|
418
|
+
id: 61,
|
|
419
|
+
skill: 'heal-skill',
|
|
420
|
+
skillPath: '.github/skills/heal-skill/SKILL.md',
|
|
421
|
+
agent: 'Beth',
|
|
422
|
+
testPrompt: 'Fix this broken skill that isn\'t loading correctly',
|
|
423
|
+
},
|
|
424
|
+
{
|
|
425
|
+
id: 62,
|
|
426
|
+
skill: 'file-todos',
|
|
427
|
+
skillPath: '.github/skills/file-todos/SKILL.md',
|
|
428
|
+
agent: 'developer',
|
|
429
|
+
testPrompt: 'Scan the codebase and create tasks for all TODO/FIXME comments',
|
|
430
|
+
},
|
|
431
|
+
];
|
|
432
|
+
// ─── Category 8: CE Workflow Pipeline (tests 63–67) ──────────────────────
|
|
433
|
+
const CE_WORKFLOW_SKILLS = [
|
|
434
|
+
{
|
|
435
|
+
id: 63,
|
|
436
|
+
skill: 'ce:brainstorm',
|
|
437
|
+
skillPath: '.github/skills/ce:brainstorm/SKILL.md',
|
|
438
|
+
agent: 'ux-designer',
|
|
439
|
+
testPrompt: '/ce:brainstorm — explore requirements for the new dashboard',
|
|
440
|
+
},
|
|
441
|
+
{
|
|
442
|
+
id: 64,
|
|
443
|
+
skill: 'ce:plan',
|
|
444
|
+
skillPath: '.github/skills/ce:plan/SKILL.md',
|
|
445
|
+
agent: 'developer',
|
|
446
|
+
testPrompt: '/ce:plan — transform the feature description into a structured project plan',
|
|
447
|
+
},
|
|
448
|
+
{
|
|
449
|
+
id: 65,
|
|
450
|
+
skill: 'ce:work',
|
|
451
|
+
skillPath: '.github/skills/ce:work/SKILL.md',
|
|
452
|
+
agent: 'developer',
|
|
453
|
+
testPrompt: '/ce:work — execute the work plan and finish the feature',
|
|
454
|
+
},
|
|
455
|
+
{
|
|
456
|
+
id: 66,
|
|
457
|
+
skill: 'ce:review',
|
|
458
|
+
skillPath: '.github/skills/ce:review/SKILL.md',
|
|
459
|
+
agent: 'developer',
|
|
460
|
+
testPrompt: '/ce:review — perform exhaustive multi-agent code review',
|
|
461
|
+
},
|
|
462
|
+
{
|
|
463
|
+
id: 67,
|
|
464
|
+
skill: 'ce:compound',
|
|
465
|
+
skillPath: '.github/skills/ce:compound/SKILL.md',
|
|
466
|
+
agent: 'developer',
|
|
467
|
+
testPrompt: '/ce:compound — document what we solved to compound team knowledge',
|
|
468
|
+
},
|
|
469
|
+
];
|
|
470
|
+
// ─── Category 9: Language-Specific (tests 68–70) ─────────────────────────
|
|
471
|
+
const LANGUAGE_SKILLS = [
|
|
472
|
+
{
|
|
473
|
+
id: 68,
|
|
474
|
+
skill: 'dhh-rails-style',
|
|
475
|
+
skillPath: '.github/skills/dhh-rails-style/SKILL.md',
|
|
476
|
+
agent: 'developer',
|
|
477
|
+
testPrompt: 'Write a Rails controller for user management in DHH\'s 37signals style',
|
|
478
|
+
},
|
|
479
|
+
{
|
|
480
|
+
id: 69,
|
|
481
|
+
skill: 'andrew-kane-gem-writer',
|
|
482
|
+
skillPath: '.github/skills/andrew-kane-gem-writer/SKILL.md',
|
|
483
|
+
agent: 'developer',
|
|
484
|
+
testPrompt: 'Create a Ruby gem for CSV parsing following Andrew Kane\'s patterns',
|
|
485
|
+
},
|
|
486
|
+
{
|
|
487
|
+
id: 70,
|
|
488
|
+
skill: 'dspy-ruby',
|
|
489
|
+
skillPath: '.github/skills/dspy-ruby/SKILL.md',
|
|
490
|
+
agent: 'developer',
|
|
491
|
+
testPrompt: 'Build an LLM module using DSPy.rb signatures for intent classification',
|
|
492
|
+
},
|
|
493
|
+
];
|
|
494
|
+
// ─── Category 10: Remaining Skills (tests 71–72) ─────────────────────────
|
|
495
|
+
const REMAINING_SKILLS = [
|
|
496
|
+
{
|
|
497
|
+
id: 71,
|
|
498
|
+
skill: 'compound-docs',
|
|
499
|
+
skillPath: '.github/skills/compound-docs/SKILL.md',
|
|
500
|
+
agent: 'developer',
|
|
501
|
+
testPrompt: 'That worked! Document this solution for the team',
|
|
502
|
+
},
|
|
503
|
+
{
|
|
504
|
+
id: 72,
|
|
505
|
+
skill: 'agent-native-audit',
|
|
506
|
+
skillPath: '.github/skills/agent-native-audit/SKILL.md',
|
|
507
|
+
agent: 'security-reviewer',
|
|
508
|
+
testPrompt: 'Audit the agent-native architecture for security and reliability',
|
|
509
|
+
},
|
|
510
|
+
];
|
|
511
|
+
// ─── All skills combined for cross-cutting tests ──────────────────────────
|
|
512
|
+
const ALL_SKILLS = [
|
|
513
|
+
...AZURE_SKILLS,
|
|
514
|
+
...DESIGN_SKILLS,
|
|
515
|
+
...PRODUCT_SKILLS,
|
|
516
|
+
...DEVELOPER_WORKFLOW_SKILLS,
|
|
517
|
+
...TESTING_SKILLS,
|
|
518
|
+
...ORCHESTRATION_SKILLS,
|
|
519
|
+
...CE_WORKFLOW_SKILLS,
|
|
520
|
+
...LANGUAGE_SKILLS,
|
|
521
|
+
...REMAINING_SKILLS,
|
|
522
|
+
];
|
|
523
|
+
// ─── Tests ─────────────────────────────────────────────────────────────────
|
|
524
|
+
describe('Category 2: Azure Skills', () => {
|
|
525
|
+
describe.each(AZURE_SKILLS)('Test #$id: $skill → $agent', (test) => {
|
|
526
|
+
if (test.external) {
|
|
527
|
+
it.skipIf(!skillExists(test))('skill file exists (external)', () => {
|
|
528
|
+
expect(skillExists(test)).toBe(true);
|
|
529
|
+
});
|
|
530
|
+
it.skipIf(!skillExists(test))('skill file is non-empty', () => {
|
|
531
|
+
const content = readSkillContent(test);
|
|
532
|
+
expect(content.length).toBeGreaterThan(0);
|
|
533
|
+
});
|
|
534
|
+
}
|
|
535
|
+
else {
|
|
536
|
+
it('skill file exists on disk', () => {
|
|
537
|
+
expect(skillExists(test)).toBe(true);
|
|
538
|
+
});
|
|
539
|
+
it('skill file is non-empty', () => {
|
|
540
|
+
const content = readSkillContent(test);
|
|
541
|
+
expect(content.length).toBeGreaterThan(0);
|
|
542
|
+
});
|
|
543
|
+
}
|
|
544
|
+
it('agent is a valid Beth team member', () => {
|
|
545
|
+
expect(VALID_AGENTS).toContain(test.agent);
|
|
546
|
+
});
|
|
547
|
+
it('test prompt is non-empty', () => {
|
|
548
|
+
expect(test.testPrompt.length).toBeGreaterThan(10);
|
|
549
|
+
});
|
|
550
|
+
});
|
|
551
|
+
});
|
|
552
|
+
describe('Category 3: Design & Frontend', () => {
|
|
553
|
+
describe.each(DESIGN_SKILLS)('Test #$id: $skill → $agent', (test) => {
|
|
554
|
+
it('skill file exists on disk', () => {
|
|
555
|
+
expect(skillExists(test)).toBe(true);
|
|
556
|
+
});
|
|
557
|
+
it('skill file is non-empty', () => {
|
|
558
|
+
const content = readSkillContent(test);
|
|
559
|
+
expect(content.length).toBeGreaterThan(0);
|
|
560
|
+
});
|
|
561
|
+
it('agent is a valid Beth team member', () => {
|
|
562
|
+
expect(VALID_AGENTS).toContain(test.agent);
|
|
563
|
+
});
|
|
564
|
+
});
|
|
565
|
+
});
|
|
566
|
+
describe('Category 4: Product & Research', () => {
|
|
567
|
+
describe.each(PRODUCT_SKILLS)('Test #$id: $skill → $agent', (test) => {
|
|
568
|
+
it('skill file exists on disk', () => {
|
|
569
|
+
expect(skillExists(test)).toBe(true);
|
|
570
|
+
});
|
|
571
|
+
it('skill file is non-empty', () => {
|
|
572
|
+
const content = readSkillContent(test);
|
|
573
|
+
expect(content.length).toBeGreaterThan(0);
|
|
574
|
+
});
|
|
575
|
+
it('agent is a valid Beth team member', () => {
|
|
576
|
+
expect(VALID_AGENTS).toContain(test.agent);
|
|
577
|
+
});
|
|
578
|
+
});
|
|
579
|
+
});
|
|
580
|
+
describe('Category 5: Developer Workflow', () => {
|
|
581
|
+
describe.each(DEVELOPER_WORKFLOW_SKILLS)('Test #$id: $skill → $agent', (test) => {
|
|
582
|
+
it('skill file exists on disk', () => {
|
|
583
|
+
expect(skillExists(test)).toBe(true);
|
|
584
|
+
});
|
|
585
|
+
it('skill file is non-empty', () => {
|
|
586
|
+
const content = readSkillContent(test);
|
|
587
|
+
expect(content.length).toBeGreaterThan(0);
|
|
588
|
+
});
|
|
589
|
+
it('agent is a valid Beth team member', () => {
|
|
590
|
+
expect(VALID_AGENTS).toContain(test.agent);
|
|
591
|
+
});
|
|
592
|
+
});
|
|
593
|
+
});
|
|
594
|
+
describe('Category 6: Testing & QA', () => {
|
|
595
|
+
describe.each(TESTING_SKILLS)('Test #$id: $skill → $agent', (test) => {
|
|
596
|
+
it('skill file exists on disk', () => {
|
|
597
|
+
expect(skillExists(test)).toBe(true);
|
|
598
|
+
});
|
|
599
|
+
it('skill file is non-empty', () => {
|
|
600
|
+
const content = readSkillContent(test);
|
|
601
|
+
expect(content.length).toBeGreaterThan(0);
|
|
602
|
+
});
|
|
603
|
+
it('agent is a valid Beth team member', () => {
|
|
604
|
+
expect(VALID_AGENTS).toContain(test.agent);
|
|
605
|
+
});
|
|
606
|
+
});
|
|
607
|
+
});
|
|
608
|
+
describe('Category 7: Orchestration & Swarm', () => {
|
|
609
|
+
describe.each(ORCHESTRATION_SKILLS)('Test #$id: $skill → $agent', (test) => {
|
|
610
|
+
it('skill file exists on disk', () => {
|
|
611
|
+
expect(skillExists(test)).toBe(true);
|
|
612
|
+
});
|
|
613
|
+
it('skill file is non-empty', () => {
|
|
614
|
+
const content = readSkillContent(test);
|
|
615
|
+
expect(content.length).toBeGreaterThan(0);
|
|
616
|
+
});
|
|
617
|
+
it('agent is a valid Beth team member', () => {
|
|
618
|
+
expect(VALID_AGENTS).toContain(test.agent);
|
|
619
|
+
});
|
|
620
|
+
});
|
|
621
|
+
});
|
|
622
|
+
describe('Category 8: CE Workflow Pipeline', () => {
|
|
623
|
+
describe.each(CE_WORKFLOW_SKILLS)('Test #$id: $skill → $agent', (test) => {
|
|
624
|
+
it('skill file exists on disk', () => {
|
|
625
|
+
expect(skillExists(test)).toBe(true);
|
|
626
|
+
});
|
|
627
|
+
it('skill file is non-empty', () => {
|
|
628
|
+
const content = readSkillContent(test);
|
|
629
|
+
expect(content.length).toBeGreaterThan(0);
|
|
630
|
+
});
|
|
631
|
+
it('agent is a valid Beth team member', () => {
|
|
632
|
+
expect(VALID_AGENTS).toContain(test.agent);
|
|
633
|
+
});
|
|
634
|
+
it('test prompt starts with /ce: (slash command)', () => {
|
|
635
|
+
expect(test.testPrompt).toMatch(/^\/ce:/);
|
|
636
|
+
});
|
|
637
|
+
});
|
|
638
|
+
it('CE pipeline covers all 5 phases: brainstorm → plan → work → review → compound', () => {
|
|
639
|
+
const phases = CE_WORKFLOW_SKILLS.map((s) => s.skill);
|
|
640
|
+
expect(phases).toContain('ce:brainstorm');
|
|
641
|
+
expect(phases).toContain('ce:plan');
|
|
642
|
+
expect(phases).toContain('ce:work');
|
|
643
|
+
expect(phases).toContain('ce:review');
|
|
644
|
+
expect(phases).toContain('ce:compound');
|
|
645
|
+
});
|
|
646
|
+
});
|
|
647
|
+
describe('Category 9: Language-Specific', () => {
|
|
648
|
+
describe.each(LANGUAGE_SKILLS)('Test #$id: $skill → $agent', (test) => {
|
|
649
|
+
it('skill file exists on disk', () => {
|
|
650
|
+
expect(skillExists(test)).toBe(true);
|
|
651
|
+
});
|
|
652
|
+
it('skill file is non-empty', () => {
|
|
653
|
+
const content = readSkillContent(test);
|
|
654
|
+
expect(content.length).toBeGreaterThan(0);
|
|
655
|
+
});
|
|
656
|
+
it('all language skills route to developer', () => {
|
|
657
|
+
expect(test.agent).toBe('developer');
|
|
658
|
+
});
|
|
659
|
+
});
|
|
660
|
+
});
|
|
661
|
+
describe('Category 10: Remaining Skills', () => {
|
|
662
|
+
describe.each(REMAINING_SKILLS)('Test #$id: $skill → $agent', (test) => {
|
|
663
|
+
it('skill file exists on disk', () => {
|
|
664
|
+
expect(skillExists(test)).toBe(true);
|
|
665
|
+
});
|
|
666
|
+
it('skill file is non-empty', () => {
|
|
667
|
+
const content = readSkillContent(test);
|
|
668
|
+
expect(content.length).toBeGreaterThan(0);
|
|
669
|
+
});
|
|
670
|
+
it('agent is a valid Beth team member', () => {
|
|
671
|
+
expect(VALID_AGENTS).toContain(test.agent);
|
|
672
|
+
});
|
|
673
|
+
});
|
|
674
|
+
});
|
|
675
|
+
// ─── Cross-cutting validation ──────────────────────────────────────────────
|
|
676
|
+
describe('Cross-cutting: Test matrix integrity', () => {
|
|
677
|
+
it('all test IDs are unique', () => {
|
|
678
|
+
const ids = ALL_SKILLS.map((t) => t.id);
|
|
679
|
+
const uniqueIds = new Set(ids);
|
|
680
|
+
expect(uniqueIds.size).toBe(ids.length);
|
|
681
|
+
});
|
|
682
|
+
it('test IDs are sequential from 10 to 72 with no gaps', () => {
|
|
683
|
+
const ids = ALL_SKILLS.map((t) => t.id).sort((a, b) => a - b);
|
|
684
|
+
const expectedCount = 72 - 10 + 1;
|
|
685
|
+
expect(ids).toHaveLength(expectedCount);
|
|
686
|
+
for (let i = 0; i < expectedCount; i++) {
|
|
687
|
+
expect(ids[i]).toBe(10 + i);
|
|
688
|
+
}
|
|
689
|
+
});
|
|
690
|
+
it('all agents in the matrix are valid', () => {
|
|
691
|
+
for (const test of ALL_SKILLS) {
|
|
692
|
+
expect(VALID_AGENTS).toContain(test.agent);
|
|
693
|
+
}
|
|
694
|
+
});
|
|
695
|
+
it('no duplicate skill names in the matrix', () => {
|
|
696
|
+
const skills = ALL_SKILLS.map((t) => t.skill);
|
|
697
|
+
// prd appears in both Category 1 (hook) and Category 4 (routing) — allow it
|
|
698
|
+
// web-search also appears twice — same reason
|
|
699
|
+
// Only check within THIS matrix (Categories 2-10)
|
|
700
|
+
const duplicates = skills.filter((s, i) => skills.indexOf(s) !== i);
|
|
701
|
+
expect(duplicates).toHaveLength(0);
|
|
702
|
+
});
|
|
703
|
+
it('every non-external skill has a corresponding directory in .github/skills/', () => {
|
|
704
|
+
for (const test of ALL_SKILLS) {
|
|
705
|
+
if (test.external)
|
|
706
|
+
continue;
|
|
707
|
+
// Extract skill dir name from path
|
|
708
|
+
const match = test.skillPath.match(/\.github\/skills\/([^/]+)\//);
|
|
709
|
+
if (match) {
|
|
710
|
+
const skillDir = join(SKILLS_DIR, match[1]);
|
|
711
|
+
expect(existsSync(skillDir)).toBe(true);
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
});
|
|
715
|
+
it('every referenced agent has at least one skill in the matrix', () => {
|
|
716
|
+
const agentsInMatrix = new Set(ALL_SKILLS.map((t) => t.agent));
|
|
717
|
+
for (const agent of agentsInMatrix) {
|
|
718
|
+
const count = ALL_SKILLS.filter((t) => t.agent === agent).length;
|
|
719
|
+
expect(count).toBeGreaterThan(0);
|
|
720
|
+
}
|
|
721
|
+
});
|
|
722
|
+
});
|
|
723
|
+
//# sourceMappingURL=skill-routing.test.js.map
|