@aramassa/ai-rules 0.2.1 → 0.2.2
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/artifact/instructions/rules/test/github-actions-no-tests.md +100 -0
- package/artifact/prompts/ai-rules/for_recipe.md +379 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +8003 -233
- package/dist/recipeValidator.d.ts +18 -0
- package/dist/recipeValidator.d.ts.map +1 -0
- package/dist/recipeValidator.js +158 -0
- package/package.json +5 -1
- package/presets/prompts/prompt-creation.yaml +10 -1
- package/presets/prompts/todo-planning.yaml +3 -2
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface ValidationResult {
|
|
2
|
+
isValid: boolean;
|
|
3
|
+
warnings: string[];
|
|
4
|
+
errors: string[];
|
|
5
|
+
}
|
|
6
|
+
export declare class RecipeValidator {
|
|
7
|
+
private ajv;
|
|
8
|
+
private schema;
|
|
9
|
+
constructor();
|
|
10
|
+
initialize(): Promise<void>;
|
|
11
|
+
validateRecipe(recipeData: any): ValidationResult;
|
|
12
|
+
private formatSchemaError;
|
|
13
|
+
private getHelpfulMessageForProperty;
|
|
14
|
+
private isCommonMistake;
|
|
15
|
+
private checkCommonMistakes;
|
|
16
|
+
}
|
|
17
|
+
export declare function getRecipeValidator(): Promise<RecipeValidator>;
|
|
18
|
+
//# sourceMappingURL=recipeValidator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recipeValidator.d.ts","sourceRoot":"","sources":["../src/recipeValidator.ts"],"names":[],"mappings":"AAUA,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,GAAG,CAAM;IACjB,OAAO,CAAC,MAAM,CAAM;;IAWd,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAoBjC,cAAc,CAAC,UAAU,EAAE,GAAG,GAAG,gBAAgB;IA0CjD,OAAO,CAAC,iBAAiB;IA0BzB,OAAO,CAAC,4BAA4B;IAYpC,OAAO,CAAC,eAAe;IAUvB,OAAO,CAAC,mBAAmB;CAyC5B;AAKD,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,eAAe,CAAC,CAMnE"}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import Ajv from 'ajv';
|
|
2
|
+
import addFormats from 'ajv-formats';
|
|
3
|
+
import fs from 'fs/promises';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
6
|
+
// Get the current file's directory for schema loading
|
|
7
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
8
|
+
const __dirname = path.dirname(__filename);
|
|
9
|
+
export class RecipeValidator {
|
|
10
|
+
constructor() {
|
|
11
|
+
this.ajv = new Ajv({
|
|
12
|
+
allErrors: true,
|
|
13
|
+
verbose: true,
|
|
14
|
+
strict: false // Allow additional properties for better error messages
|
|
15
|
+
});
|
|
16
|
+
addFormats(this.ajv);
|
|
17
|
+
}
|
|
18
|
+
async initialize() {
|
|
19
|
+
try {
|
|
20
|
+
const schemaPath = path.join(__dirname, '../schemas/recipe.schema.json');
|
|
21
|
+
const schemaContent = await fs.readFile(schemaPath, 'utf-8');
|
|
22
|
+
this.schema = JSON.parse(schemaContent);
|
|
23
|
+
this.ajv.addSchema(this.schema, 'recipe');
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
console.warn('Warning: Could not load recipe schema for validation:', error);
|
|
27
|
+
// Create a minimal schema as fallback
|
|
28
|
+
this.schema = {
|
|
29
|
+
type: 'object',
|
|
30
|
+
properties: {
|
|
31
|
+
recipe: { type: 'array' }
|
|
32
|
+
},
|
|
33
|
+
required: ['recipe']
|
|
34
|
+
};
|
|
35
|
+
this.ajv.addSchema(this.schema, 'recipe');
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
validateRecipe(recipeData) {
|
|
39
|
+
const result = {
|
|
40
|
+
isValid: true,
|
|
41
|
+
warnings: [],
|
|
42
|
+
errors: []
|
|
43
|
+
};
|
|
44
|
+
// Basic structure validation
|
|
45
|
+
if (!recipeData || typeof recipeData !== 'object') {
|
|
46
|
+
result.isValid = false;
|
|
47
|
+
result.errors.push('Recipe must be a valid YAML/JSON object');
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
50
|
+
if (!Array.isArray(recipeData.recipe)) {
|
|
51
|
+
result.isValid = false;
|
|
52
|
+
result.errors.push('Recipe file must contain a "recipe" array');
|
|
53
|
+
return result;
|
|
54
|
+
}
|
|
55
|
+
// Validate against JSON schema
|
|
56
|
+
const valid = this.ajv.validate('recipe', recipeData);
|
|
57
|
+
if (!valid && this.ajv.errors) {
|
|
58
|
+
for (const error of this.ajv.errors) {
|
|
59
|
+
const errorMessage = this.formatSchemaError(error);
|
|
60
|
+
// Convert schema errors to warnings to maintain backward compatibility
|
|
61
|
+
if (this.isCommonMistake(error)) {
|
|
62
|
+
result.warnings.push(`Warning: ${errorMessage}`);
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
result.warnings.push(`Schema validation warning: ${errorMessage}`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// Check for common mistakes and provide helpful warnings
|
|
70
|
+
this.checkCommonMistakes(recipeData, result);
|
|
71
|
+
return result;
|
|
72
|
+
}
|
|
73
|
+
formatSchemaError(error) {
|
|
74
|
+
const instancePath = error.instancePath || 'root';
|
|
75
|
+
switch (error.keyword) {
|
|
76
|
+
case 'additionalProperties':
|
|
77
|
+
const extraProperty = error.params?.additionalProperty;
|
|
78
|
+
if (extraProperty) {
|
|
79
|
+
return this.getHelpfulMessageForProperty(extraProperty, instancePath);
|
|
80
|
+
}
|
|
81
|
+
return `Unknown property "${extraProperty}" at ${instancePath}`;
|
|
82
|
+
case 'required':
|
|
83
|
+
const missingProperty = error.params?.missingProperty;
|
|
84
|
+
return `Missing required property "${missingProperty}" at ${instancePath}`;
|
|
85
|
+
case 'type':
|
|
86
|
+
return `Property at ${instancePath} should be of type ${error.schema}`;
|
|
87
|
+
case 'enum':
|
|
88
|
+
return `Property at ${instancePath} should be one of: ${error.schema.join(', ')}`;
|
|
89
|
+
default:
|
|
90
|
+
return `${error.message} at ${instancePath}`;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
getHelpfulMessageForProperty(property, path) {
|
|
94
|
+
const commonMistakes = {
|
|
95
|
+
'category': 'Property "category" should be under "filters" object, not at the recipe item root level',
|
|
96
|
+
'focus': 'Property "focus" should be under "filters" object, not at the recipe item root level',
|
|
97
|
+
'description': 'Property "description" should be under "frontmatter" object, not at the recipe item root level',
|
|
98
|
+
'applyTo': 'Property "applyTo" should be under "frontmatter" object, not at the recipe item root level',
|
|
99
|
+
'target': 'Property "target" should be under "filters" object, not at the recipe item root level'
|
|
100
|
+
};
|
|
101
|
+
return commonMistakes[property] || `Unknown property "${property}" at ${path}`;
|
|
102
|
+
}
|
|
103
|
+
isCommonMistake(error) {
|
|
104
|
+
if (error.keyword !== 'additionalProperties') {
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
const property = error.params?.additionalProperty;
|
|
108
|
+
const commonMistakeProps = ['category', 'focus', 'description', 'applyTo', 'target'];
|
|
109
|
+
return commonMistakeProps.includes(property);
|
|
110
|
+
}
|
|
111
|
+
checkCommonMistakes(recipeData, result) {
|
|
112
|
+
// Check for properties that should be under filters or frontmatter
|
|
113
|
+
if (Array.isArray(recipeData.recipe)) {
|
|
114
|
+
recipeData.recipe.forEach((item, index) => {
|
|
115
|
+
if (!item || typeof item !== 'object')
|
|
116
|
+
return;
|
|
117
|
+
// Check for filter properties at root level
|
|
118
|
+
const filterProps = ['category', 'focus', 'target'];
|
|
119
|
+
filterProps.forEach(prop => {
|
|
120
|
+
if (item[prop] !== undefined) {
|
|
121
|
+
result.warnings.push(`Warning: Recipe item ${index + 1} has "${prop}" at root level. Consider moving it under "filters" object for better organization.`);
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
// Check for frontmatter properties at root level
|
|
125
|
+
const frontmatterProps = ['description', 'applyTo'];
|
|
126
|
+
frontmatterProps.forEach(prop => {
|
|
127
|
+
if (item[prop] !== undefined) {
|
|
128
|
+
result.warnings.push(`Warning: Recipe item ${index + 1} has "${prop}" at root level. Consider moving it under "frontmatter" object for better organization.`);
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
// Check for both filters and individual filter properties
|
|
132
|
+
if (item.filters && typeof item.filters === 'object') {
|
|
133
|
+
filterProps.forEach(prop => {
|
|
134
|
+
if (item[prop] !== undefined) {
|
|
135
|
+
result.warnings.push(`Warning: Recipe item ${index + 1} has both "filters.${prop}" and root-level "${prop}". The root-level property will be ignored.`);
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
// Check for root-level properties that should be under config
|
|
142
|
+
const rootLevelProps = ['baseDir'];
|
|
143
|
+
rootLevelProps.forEach(prop => {
|
|
144
|
+
if (recipeData[prop] !== undefined && !recipeData.config?.[prop]) {
|
|
145
|
+
result.warnings.push(`Warning: Root-level "${prop}" found. Consider moving it under "config" object for better organization.`);
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
// Singleton instance
|
|
151
|
+
let validatorInstance = null;
|
|
152
|
+
export async function getRecipeValidator() {
|
|
153
|
+
if (!validatorInstance) {
|
|
154
|
+
validatorInstance = new RecipeValidator();
|
|
155
|
+
await validatorInstance.initialize();
|
|
156
|
+
}
|
|
157
|
+
return validatorInstance;
|
|
158
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aramassa/ai-rules",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "This repository collects guidelines and instructions for developing AI agents. It contains documents covering communication rules, coding standards, testing strategies, and general operational practices.",
|
|
5
5
|
"workspaces": [
|
|
6
6
|
"packages/extract",
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
"dist/",
|
|
15
15
|
"artifact/",
|
|
16
16
|
"presets/",
|
|
17
|
+
"schemas/",
|
|
17
18
|
"README-npmjs.md"
|
|
18
19
|
],
|
|
19
20
|
"publishConfig": {
|
|
@@ -52,6 +53,7 @@
|
|
|
52
53
|
"@rollup/plugin-json": "^6.1.0",
|
|
53
54
|
"@rollup/plugin-node-resolve": "^16.0.1",
|
|
54
55
|
"@rollup/plugin-typescript": "^12.1.4",
|
|
56
|
+
"@types/ajv": "^0.0.5",
|
|
55
57
|
"@types/commander": "^2.12.0",
|
|
56
58
|
"@types/node": "^24.5.2",
|
|
57
59
|
"fast-glob": "^3.3.3",
|
|
@@ -64,6 +66,8 @@
|
|
|
64
66
|
"vitest": "^3.2.4"
|
|
65
67
|
},
|
|
66
68
|
"dependencies": {
|
|
69
|
+
"ajv": "^8.17.1",
|
|
70
|
+
"ajv-formats": "^3.0.1",
|
|
67
71
|
"commander": "^14.0.0",
|
|
68
72
|
"glob": "^11.0.3",
|
|
69
73
|
"yaml": "^2.8.0"
|
|
@@ -4,7 +4,16 @@ recipe:
|
|
|
4
4
|
- title: "Prompts 作成ルール"
|
|
5
5
|
out: "create_prompts.prompt.md"
|
|
6
6
|
type: "prompt"
|
|
7
|
-
|
|
7
|
+
filters:
|
|
8
|
+
category: "content-creation"
|
|
8
9
|
frontmatter:
|
|
9
10
|
description: "AI向けプロンプト作成のための包括的なルールとガイドライン。プロンプト工学のベストプラクティスを体系化。"
|
|
10
11
|
applyTo: "artifact/prompts/**/*.prompt.md"
|
|
12
|
+
- title: "Recipe ファイル作成ルール"
|
|
13
|
+
out: "create_recipe.prompt.md"
|
|
14
|
+
type: "prompt"
|
|
15
|
+
filters:
|
|
16
|
+
category: "instruction-generation"
|
|
17
|
+
frontmatter:
|
|
18
|
+
description: "AI-rulesプロジェクトにおけるレシピファイル作成のための包括的なガイドライン。複数のinstructionファイルを組み合わせた自動生成設定を支援。"
|
|
19
|
+
applyTo: "presets/**/*.yaml"
|
|
@@ -4,7 +4,8 @@ recipe:
|
|
|
4
4
|
- title: "TODO Plans 作成ルール"
|
|
5
5
|
out: "todo_plans.prompt.md"
|
|
6
6
|
type: "prompt"
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
filters:
|
|
8
|
+
category: "todo-planning"
|
|
9
|
+
focus: "workflow-management"
|
|
9
10
|
frontmatter:
|
|
10
11
|
description: "プロジェクトのTODO計画を管理するためのワークフローとガイドライン"
|