@aramassa/ai-rules 0.1.2 → 0.1.5

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/dist/cli.js CHANGED
@@ -10424,7 +10424,7 @@ function setupProgram() {
10424
10424
  .command('extract')
10425
10425
  .description('Extract and merge markdown files')
10426
10426
  .option('--src <path>', 'Source directory')
10427
- .option('--out <path>', 'Output file', './out/instruction.md')
10427
+ .option('--out <path>', 'Output file')
10428
10428
  .option('--type <types>', 'Filter by type (comma-separated)')
10429
10429
  .option('--language <languages>', 'Filter by language (comma-separated)')
10430
10430
  .option('--attr <attributes>', 'Filter by attributes (comma-separated)')
@@ -10457,6 +10457,33 @@ function setupProgram() {
10457
10457
  });
10458
10458
  return program;
10459
10459
  }
10460
+ /**
10461
+ * Recursively scans a directory for YAML files and returns their relative paths
10462
+ */
10463
+ async function findYamlFilesRecursively(dir, baseDir = dir) {
10464
+ const yamlFiles = [];
10465
+ try {
10466
+ const items = await fs.readdir(dir, { withFileTypes: true });
10467
+ for (const item of items) {
10468
+ const fullPath = path.join(dir, item.name);
10469
+ if (item.isDirectory()) {
10470
+ // Recursively scan subdirectories
10471
+ const subFiles = await findYamlFilesRecursively(fullPath, baseDir);
10472
+ yamlFiles.push(...subFiles);
10473
+ }
10474
+ else if (item.isFile() && (item.name.endsWith('.yaml') || item.name.endsWith('.yml'))) {
10475
+ // Get relative path from base directory
10476
+ const relativePath = path.relative(baseDir, fullPath);
10477
+ yamlFiles.push(relativePath);
10478
+ }
10479
+ }
10480
+ }
10481
+ catch (error) {
10482
+ // Log errors for individual directories/files that can't be read
10483
+ console.warn(`Warning: Could not read directory "${dir}":`, error);
10484
+ }
10485
+ return yamlFiles;
10486
+ }
10460
10487
  /**
10461
10488
  * Lists available package presets
10462
10489
  */
@@ -10464,8 +10491,7 @@ async function listPresets() {
10464
10491
  const packageRoot = findPackageRoot();
10465
10492
  const presetsDir = path.join(packageRoot, 'presets');
10466
10493
  try {
10467
- const files = await fs.readdir(presetsDir);
10468
- const yamlFiles = files.filter(file => file.endsWith('.yaml') || file.endsWith('.yml'));
10494
+ const yamlFiles = await findYamlFilesRecursively(presetsDir);
10469
10495
  if (yamlFiles.length === 0) {
10470
10496
  // eslint-disable-next-line no-console
10471
10497
  console.log('No presets found in package.');
@@ -10835,7 +10861,7 @@ async function handleExtractCommand(options) {
10835
10861
  });
10836
10862
  const extractOptions = {
10837
10863
  srcDir: resolveDefaultSrcDir(options.src),
10838
- outFile: options.out,
10864
+ outFile: options.out || './out/instruction.md',
10839
10865
  types: parseCommaSeparated(options.type),
10840
10866
  languages: parseCommaSeparated(options.language),
10841
10867
  attrFilters: parseCommaSeparated(options.attr) || [],
@@ -10852,11 +10878,11 @@ async function handleExtractCommand(options) {
10852
10878
  await validateRecipeFilesExist(options.recipe);
10853
10879
  if (options.recipe.length === 1) {
10854
10880
  // Single recipe - maintain backward compatibility
10855
- await processRecipe(options.recipe[0], extractOptions, new ContentTracker(), debugLogger, options.baseDir);
10881
+ await processRecipe(options.recipe[0], extractOptions, new ContentTracker(), debugLogger, options.baseDir, options.out);
10856
10882
  }
10857
10883
  else {
10858
10884
  // Multiple recipes - process in order with auto-append
10859
- await processMultipleRecipes(options.recipe, extractOptions, debugLogger, options.baseDir);
10885
+ await processMultipleRecipes(options.recipe, extractOptions, debugLogger, options.baseDir, options.out);
10860
10886
  }
10861
10887
  }
10862
10888
  else {
@@ -10882,13 +10908,13 @@ async function handleStatsCommand(options) {
10882
10908
  /**
10883
10909
  * Processes multiple recipe files in the specified order
10884
10910
  */
10885
- async function processMultipleRecipes(recipePaths, baseOptions, debugLogger, cliBaseDir) {
10911
+ async function processMultipleRecipes(recipePaths, baseOptions, debugLogger, cliBaseDir, cliOutFile) {
10886
10912
  const contentTracker = new ContentTracker();
10887
10913
  debugLogger.log(`Processing ${recipePaths.length} recipes in order`);
10888
10914
  for (const recipePath of recipePaths) {
10889
10915
  try {
10890
10916
  debugLogger.log(`Starting processing of recipe: ${recipePath}`);
10891
- await processRecipe(recipePath, baseOptions, contentTracker, debugLogger, cliBaseDir);
10917
+ await processRecipe(recipePath, baseOptions, contentTracker, debugLogger, cliBaseDir, cliOutFile);
10892
10918
  debugLogger.log(`Completed processing of recipe: ${recipePath}`);
10893
10919
  }
10894
10920
  catch (error) {
@@ -10912,7 +10938,7 @@ async function loadTemplateFrontmatter(srcDir, types, languages, attrFilters, de
10912
10938
  }
10913
10939
  /**
10914
10940
  * Merges frontmatter values from multiple templates according to merge rules:
10915
- * - Strings: concatenate with newlines
10941
+ * - Strings: concatenate with newlines, removing duplicates while preserving order
10916
10942
  * - Arrays: combine all elements
10917
10943
  * - Objects: later values overwrite
10918
10944
  */
@@ -10928,7 +10954,19 @@ function mergeTemplateFrontmatterValues(templateFrontmatters, fieldName) {
10928
10954
  }
10929
10955
  // Check if all values are strings
10930
10956
  if (values.every(val => typeof val === 'string')) {
10931
- return values.join('\n');
10957
+ // Split each string by newlines, flatten, remove duplicates while preserving order
10958
+ const allLines = [];
10959
+ const seen = new Set();
10960
+ for (const value of values) {
10961
+ const lines = value.split('\n').map(line => line.trim()).filter(line => line.length > 0);
10962
+ for (const line of lines) {
10963
+ if (!seen.has(line)) {
10964
+ seen.add(line);
10965
+ allLines.push(line);
10966
+ }
10967
+ }
10968
+ }
10969
+ return allLines.join('\n');
10932
10970
  }
10933
10971
  // Check if all values are arrays
10934
10972
  if (values.every(val => Array.isArray(val))) {
@@ -10985,7 +11023,7 @@ async function processFrontmatterInheritance(frontmatter, srcDir, types, languag
10985
11023
  /**
10986
11024
  * Processes a recipe file with multiple extract operations
10987
11025
  */
10988
- async function processRecipe(recipePath, baseOptions, contentTracker, debugLogger, cliBaseDir) {
11026
+ async function processRecipe(recipePath, baseOptions, contentTracker, debugLogger, cliBaseDir, cliOutFile) {
10989
11027
  const resolvedPath = resolveRecipePath(recipePath);
10990
11028
  debugLogger?.log(`Processing recipe at path: ${resolvedPath}`);
10991
11029
  try {
@@ -11015,9 +11053,13 @@ async function processRecipe(recipePath, baseOptions, contentTracker, debugLogge
11015
11053
  language: item.language,
11016
11054
  mode: item.mode
11017
11055
  });
11018
- const itemOut = item.out || baseOptions.outFile;
11056
+ // Priority: CLI --out option > recipe item.out > baseOptions.outFile default
11057
+ const itemOut = cliOutFile || item.out || baseOptions.outFile;
11019
11058
  const outputFile = resolveOutputPath(itemOut, cliBaseDir, item._importBaseDir, recipeBaseDir, resolvedPath);
11020
11059
  debugLogger?.log(`Resolved output path: ${itemOut} -> ${outputFile}`, {
11060
+ cliOutFile,
11061
+ itemOut: item.out,
11062
+ fallback: baseOptions.outFile,
11021
11063
  cliBaseDir,
11022
11064
  importBaseDir: item._importBaseDir,
11023
11065
  recipeBaseDir
@@ -11142,3 +11184,5 @@ run().catch((error) => {
11142
11184
  console.error("Unhandled error:", error);
11143
11185
  process.exit(1);
11144
11186
  });
11187
+
11188
+ export { findYamlFilesRecursively };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aramassa/ai-rules",
3
- "version": "0.1.2",
3
+ "version": "0.1.5",
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",
@@ -24,8 +24,10 @@
24
24
  "start:cli": "node dist/cli.js",
25
25
  "start:dev:cli": "tsx src/cli.ts",
26
26
  "test": "vitest run --environment node test",
27
+ "test:ci": "vitest run --environment node",
27
28
  "test:all": "npm run test --workspaces",
28
- "build": "npm run --ws build && tsc -p tsconfig.build.json",
29
+ "build": "npm run --ws build && tsc -p tsconfig.build.json && chmod +x dist/cli.js",
30
+ "build:ci": "npm run --ws build && tsc -p tsconfig.build.json && chmod +x dist/cli.js",
29
31
  "build:pkg:clean": "npm run --ws clean",
30
32
  "clean": "npm run build:pkg:clean && rm -rf dist",
31
33
  "root:build": "npm run build && if [ \"$NODE_ENV\" != \"test\" ]; then rollup -c && chmod +x dist/cli.js; fi"
@@ -51,7 +53,7 @@
51
53
  "@rollup/plugin-node-resolve": "^16.0.1",
52
54
  "@rollup/plugin-typescript": "^12.1.4",
53
55
  "@types/commander": "^2.12.0",
54
- "@types/node": "^24.3.0",
56
+ "@types/node": "^24.5.2",
55
57
  "fast-glob": "^3.3.3",
56
58
  "gray-matter": "^4.0.3",
57
59
  "rollup": "^4.45.0",
package/presets/README.md CHANGED
@@ -62,6 +62,31 @@ npx @aramassa/ai-rules extract --recipe presets/infrastructure-ansible.yaml --sr
62
62
  - DevOps・SRE関連プロジェクト
63
63
  - 設定管理・自動化プロジェクト
64
64
 
65
+ ### `chrome-extension.yaml`
66
+
67
+ Chrome Extension(Manifest V3)開発プロジェクト向けの包括的なinstruction構成です。
68
+
69
+ **含まれる内容:**
70
+
71
+ - Chrome Extension Manifest V3 Development Rules - 現代的なChrome Extension開発のベストプラクティス
72
+ - Code Quality Tools - JavaScript/Chrome Extension向けのコード品質管理
73
+ - Package Management Rules - パッケージ管理とビルドプロセス
74
+ - Git Rules - バージョン管理とワークフロー
75
+ - Basic Communication Rules - 基本的なコミュニケーションルール
76
+
77
+ **使用方法:**
78
+
79
+ ```bash
80
+ npx @aramassa/ai-rules extract --recipe presets/chrome-extension.yaml --src artifact/instructions
81
+ ```
82
+
83
+ **対象プロジェクト:**
84
+
85
+ - Chrome Extension開発プロジェクト(Manifest V3)
86
+ - JavaScript/TypeScriptベースのブラウザ拡張機能
87
+ - Webブラウザの機能拡張・自動化プロジェクト
88
+ - Service Worker、Content Scripts、Popup UIを含む複合アプリケーション
89
+
65
90
  ### `chatmodes.yaml`
66
91
 
67
92
  AI対話支援機能(chatmodes)をプロジェクトに統合するための設定です。
@@ -70,6 +95,7 @@ AI対話支援機能(chatmodes)をプロジェクトに統合するための
70
95
 
71
96
  - Instruction Improve Chatmode - プロジェクト指示の改善支援
72
97
  - Planning Chatmode - todo_plans作成支援
98
+ - Bug Reproduce Chatmode - GitHub Issue バグ再現・調査・修正提案支援
73
99
 
74
100
  **使用方法:**
75
101
 
@@ -19,3 +19,11 @@ recipe:
19
19
  type: chatmode
20
20
  filters:
21
21
  chatmode: planning
22
+ - title: Bug Reproduce Chatmode
23
+ frontmatter:
24
+ "@description": true
25
+ "@tools": true
26
+ out: Bug Reproduce.chatmode.md
27
+ type: chatmode
28
+ filters:
29
+ chatmode: bug-reproduce
@@ -0,0 +1,50 @@
1
+ recipe:
2
+ - import: :basic
3
+ - title: Chrome Extension Manifest V3 - General Architecture & Security
4
+ frontmatter:
5
+ "@type": true
6
+ "@category": true
7
+ description: |
8
+ General architecture principles and security guidelines for Chrome Extension development.
9
+ Covers event-driven architecture, component separation, security best practices,
10
+ development workflow, and debugging for modern Chrome extension development.
11
+ applyTo: "**/*"
12
+ out: ./.github/instructions/chrome-extension-general.instructions.md
13
+ type: development-rules
14
+ category: chrome-extension
15
+ - title: Chrome Extension Manifest V3 - Manifest Configuration
16
+ frontmatter:
17
+ "@type": true
18
+ "@category": true
19
+ description: |
20
+ Manifest V3 configuration rules and best practices for manifest.json files.
21
+ Covers required structure, permissions design, declarativeNetRequest API setup,
22
+ and security configurations specific to manifest files.
23
+ applyTo: "**/manifest.json"
24
+ out: ./.github/instructions/chrome-extension-manifest.instructions.md
25
+ type: development-rules
26
+ category: chrome-extension
27
+ - title: Chrome Extension Manifest V3 - JavaScript/Service Worker Patterns
28
+ frontmatter:
29
+ "@type": true
30
+ "@category": true
31
+ description: |
32
+ JavaScript and Service Worker implementation patterns for Chrome extensions.
33
+ Covers event-driven design, state management, message passing, content scripts,
34
+ Offscreen API, testing strategies, and performance optimization.
35
+ applyTo: "**/*.js"
36
+ out: ./.github/instructions/chrome-extension-javascript.instructions.md
37
+ type: development-rules
38
+ category: chrome-extension
39
+ - title: Chrome Extension Manifest V3 - HTML Structure Guidelines
40
+ frontmatter:
41
+ "@type": true
42
+ "@category": true
43
+ description: |
44
+ HTML structure and UI guidelines for Chrome extension development.
45
+ Covers popup HTML, options page, offscreen documents, security best practices,
46
+ and performance optimization for HTML components.
47
+ applyTo: "**/*.html"
48
+ out: ./.github/instructions/chrome-extension-html.instructions.md
49
+ type: development-rules
50
+ category: chrome-extension
@@ -0,0 +1,11 @@
1
+ recipe:
2
+ - title: Electron Development Best Practices
3
+ frontmatter:
4
+ description: |
5
+ Comprehensive Electron development best practices emphasizing security-first and performance-by-design approaches for building secure, high-performance desktop applications.
6
+ applyTo: "**/*.{js,ts}"
7
+ framework: electron
8
+ out: ./.github/instructions/electron.instructions.md
9
+ src: artifact/instructions/rules/development/
10
+ type: development-rules
11
+ attr: "category=desktop-app,focus=electron"
@@ -0,0 +1,8 @@
1
+ recipe:
2
+ - title: "TODO Plans 作成ルール"
3
+ out: "./.github/prompts/todo_plans.prompt.md"
4
+ type: "prompt"
5
+ category: "todo-planning"
6
+ focus: "workflow-management"
7
+ frontmatter:
8
+ description: "プロジェクトのTODO計画を管理するためのワークフローとガイドライン"