@aramassa/ai-rules 0.3.4 → 0.4.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.
@@ -7,7 +7,6 @@ tools:
7
7
  - "searchResults"
8
8
  - "editFiles"
9
9
  - "search"
10
- - "add_issue_comment"
11
10
  - "add_sub_issue"
12
11
  - "create_issue"
13
12
  - "get_code_scanning_alert"
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAqjBA;;GAEG;AACH,wBAAsB,wBAAwB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,MAAY,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAyBpG"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAujBA;;GAEG;AACH,wBAAsB,wBAAwB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,MAAY,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAyBpG"}
package/dist/cli.js CHANGED
@@ -18241,6 +18241,7 @@ function setupProgram() {
18241
18241
  .option('--env-file <path>', 'Path to .env file for template variables')
18242
18242
  .option('--debug', 'Enable debug logging')
18243
18243
  .option('--verbose', 'Enable verbose logging (alias for --debug)')
18244
+ .option('--dry-run', 'Preview input/output files without writing')
18244
18245
  .action(async (options) => {
18245
18246
  await handleExtractCommand(options);
18246
18247
  });
@@ -18364,6 +18365,121 @@ function convertFiltersToAttrFilters(filters) {
18364
18365
  /**
18365
18366
  * Common logic for loading and filtering markdown files
18366
18367
  */
18368
+ /**
18369
+ * Displays dry-run preview for recipe processing
18370
+ */
18371
+ async function displayRecipeDryRunPreview(recipePath, recipeData, expandedRecipe, baseOptions, debugLogger, cliBaseDir, cliOutFile, cliSrc) {
18372
+ console.log('=== Recipe Dry-Run Preview ===\n');
18373
+ const presetName = recipePath.startsWith(':') ? recipePath : undefined;
18374
+ if (presetName) {
18375
+ console.log(`šŸ“¦ Recipe: ${presetName} (${expandedRecipe.length} steps)`);
18376
+ }
18377
+ else {
18378
+ console.log(`šŸ“¦ Recipe: ${recipePath} (${expandedRecipe.length} steps)`);
18379
+ }
18380
+ const recipeBaseDir = recipeData.config?.baseDir;
18381
+ let totalInputFiles = 0;
18382
+ let totalIncludedFiles = 0;
18383
+ let totalExcludedFiles = 0;
18384
+ const outputFiles = [];
18385
+ for (const [index, item] of expandedRecipe.entries()) {
18386
+ console.log(`\nStep ${index + 1}: ${item.title || `Untitled Step ${index + 1}`}`);
18387
+ // Resolve paths and options for this item
18388
+ const itemOut = cliOutFile || item.out || baseOptions.outFile;
18389
+ const outputFile = resolveOutputPath(itemOut, cliBaseDir, item._importBaseDir, recipeBaseDir, resolveRecipePath(recipePath));
18390
+ const itemTypes = item.type ? parseCommaSeparated(item.type) : baseOptions.types;
18391
+ const itemLanguages = item.language ? parseCommaSeparated(item.language) : baseOptions.languages;
18392
+ let combinedAttrFilters = [...baseOptions.attrFilters];
18393
+ if (item.filters) {
18394
+ const itemAttrFilters = convertFiltersToAttrFilters(item.filters);
18395
+ combinedAttrFilters = combinedAttrFilters.concat(itemAttrFilters);
18396
+ }
18397
+ const itemSrcDir = resolveItemSrcDir(cliSrc, item.src, item._importSrc);
18398
+ console.log(` šŸ“‚ Source: ${itemSrcDir}`);
18399
+ console.log(` šŸ” Filters: type=${itemTypes?.join(',') || '(none)'}, language=${itemLanguages?.join(',') || '(none)'}`);
18400
+ if (combinedAttrFilters.length > 0) {
18401
+ console.log(` attributes=${combinedAttrFilters.join(', ')}`);
18402
+ }
18403
+ try {
18404
+ const { allFiles, filteredFiles } = await loadAndFilterFilesWithDetails(itemSrcDir, itemTypes, itemLanguages, combinedAttrFilters, debugLogger);
18405
+ totalInputFiles += allFiles.length;
18406
+ totalIncludedFiles += filteredFiles.length;
18407
+ totalExcludedFiles += (allFiles.length - filteredFiles.length);
18408
+ console.log(`\n šŸ“„ Input Files Analysis:`);
18409
+ if (filteredFiles.length > 0) {
18410
+ console.log(` āœ“ INCLUDED (${filteredFiles.length} files):`);
18411
+ filteredFiles.forEach(file => {
18412
+ console.log(` - ${file.path}`);
18413
+ });
18414
+ }
18415
+ const excludedFiles = allFiles.filter(f => !filteredFiles.includes(f));
18416
+ // Note: Individual excluded files are not displayed to keep output concise
18417
+ // Only the count is shown in the summary below
18418
+ console.log(`\n šŸ“ Output: ${outputFile}`);
18419
+ if (!outputFiles.includes(outputFile)) {
18420
+ outputFiles.push(outputFile);
18421
+ }
18422
+ }
18423
+ catch (error) {
18424
+ console.log(` āŒ Error scanning files: ${error instanceof Error ? error.message : String(error)}`);
18425
+ }
18426
+ }
18427
+ console.log(`\nšŸ“ˆ Overall Summary:`);
18428
+ console.log(` - Total steps: ${expandedRecipe.length}`);
18429
+ console.log(` - Total input files: ${totalInputFiles} (${totalIncludedFiles} included, ${totalExcludedFiles} excluded)`);
18430
+ console.log(` - Total output files: ${outputFiles.length}`);
18431
+ console.log(`\nāš ļø Dry-run mode: No files will be written`);
18432
+ }
18433
+ /**
18434
+ * Formats file size in a human-readable format
18435
+ */
18436
+ function formatFileSize(sizeInBytes) {
18437
+ if (sizeInBytes < 1024)
18438
+ return `${sizeInBytes}B`;
18439
+ if (sizeInBytes < 1024 * 1024)
18440
+ return `${(sizeInBytes / 1024).toFixed(1)}KB`;
18441
+ return `${(sizeInBytes / (1024 * 1024)).toFixed(1)}MB`;
18442
+ }
18443
+ /**
18444
+ * Displays dry-run preview for single extraction
18445
+ */
18446
+ function displayDryRunPreview(srcDir, outFile, allFiles, filteredFiles, types, languages, attrFilters = [], verbose = false) {
18447
+ console.log('=== Extract Command Dry-Run Preview ===\n');
18448
+ console.log(`šŸ“‚ Source Directory: ${srcDir}`);
18449
+ console.log('šŸ” Filters Applied:');
18450
+ console.log(` - Type: ${types?.length ? types.join(', ') : '(none)'}`);
18451
+ console.log(` - Language: ${languages?.length ? languages.join(', ') : '(none)'}`);
18452
+ console.log(` - Attributes: ${attrFilters.length ? attrFilters.join(', ') : '(none)'}\n`);
18453
+ console.log('šŸ“„ Input Files Analysis:');
18454
+ if (filteredFiles.length > 0) {
18455
+ console.log(` āœ“ INCLUDED (${filteredFiles.length} files):`);
18456
+ filteredFiles.forEach(file => {
18457
+ const attrs = Object.entries(file.attrs)
18458
+ .filter(([key]) => key !== 'content')
18459
+ .map(([key, value]) => `${key}: ${Array.isArray(value) ? value.join(',') : value}`)
18460
+ .join(', ');
18461
+ console.log(` - ${file.path}`);
18462
+ if (verbose && attrs) {
18463
+ console.log(` → ${attrs}`);
18464
+ }
18465
+ else if (attrs) {
18466
+ console.log(` → ${attrs}`);
18467
+ }
18468
+ });
18469
+ }
18470
+ const excludedFiles = allFiles.filter(f => !filteredFiles.includes(f));
18471
+ // Note: Individual excluded files are not displayed to keep output concise
18472
+ // Only the count is shown in the summary below
18473
+ const totalSize = filteredFiles.reduce((sum, f) => sum + f.content.length, 0);
18474
+ console.log(`\nšŸ“ˆ Processing Summary:`);
18475
+ console.log(` - Total files scanned: ${allFiles.length}`);
18476
+ console.log(` - Files matching filters: ${filteredFiles.length}`);
18477
+ console.log(` - Files excluded: ${excludedFiles.length}`);
18478
+ console.log(`\nšŸ“ Output Files:`);
18479
+ console.log(` → ${outFile}`);
18480
+ console.log(` └─ Will merge ${filteredFiles.length} input files (estimated size: ~${formatFileSize(totalSize)})`);
18481
+ console.log(`\nāš ļø Dry-run mode: No files will be written`);
18482
+ }
18367
18483
  async function loadAndFilterFiles(srcDir, types, languages, attrFilters = [], debugLogger) {
18368
18484
  debugLogger?.log(`Starting file scan in directory: ${srcDir}`);
18369
18485
  debugLogger?.time('MarkdownFileScanner.parseMarkdownFiles');
@@ -18391,6 +18507,37 @@ async function loadAndFilterFiles(srcDir, types, languages, attrFilters = [], de
18391
18507
  }
18392
18508
  return filtered;
18393
18509
  }
18510
+ /**
18511
+ * Extended version of loadAndFilterFiles that returns both all files and filtered files
18512
+ * Used for dry-run mode to show exclusion details
18513
+ */
18514
+ async function loadAndFilterFilesWithDetails(srcDir, types, languages, attrFilters = [], debugLogger) {
18515
+ debugLogger?.log(`Starting file scan in directory: ${srcDir}`);
18516
+ debugLogger?.time('MarkdownFileScanner.parseMarkdownFiles');
18517
+ const files = await MarkdownFileScanner.parseMarkdownFiles(srcDir);
18518
+ debugLogger?.timeEnd('MarkdownFileScanner.parseMarkdownFiles');
18519
+ debugLogger?.log(`Total markdown files found: ${files.length}`);
18520
+ if (debugLogger?.isEnabled) {
18521
+ debugLogger.log('Files discovered:');
18522
+ files.forEach((file, index) => {
18523
+ debugLogger.log(` ${index + 1}. ${file.path}`);
18524
+ debugLogger.log(` Frontmatter attributes:`, Object.keys(file.attrs));
18525
+ });
18526
+ }
18527
+ debugLogger?.time('File filtering');
18528
+ const filtered = filterFiles(files, { types, languages, attrFilters });
18529
+ debugLogger?.timeEnd('File filtering');
18530
+ debugLogger?.log(`Files after filtering: ${filtered.length}`);
18531
+ if (debugLogger?.isEnabled && filtered.length !== files.length) {
18532
+ const excludedCount = files.length - filtered.length;
18533
+ debugLogger.log(`Excluded ${excludedCount} files due to filtering`);
18534
+ const excludedFiles = files.filter(f => !filtered.includes(f));
18535
+ excludedFiles.forEach(file => {
18536
+ debugLogger.log(` Excluded: ${file.path} (attributes: ${JSON.stringify(file.attrs)})`);
18537
+ });
18538
+ }
18539
+ return { allFiles: files, filteredFiles: filtered };
18540
+ }
18394
18541
  /**
18395
18542
  * Handles content mode processing (append/prepend/overwrite)
18396
18543
  */
@@ -18458,7 +18605,7 @@ function applyTemplateToObject(obj, templateOptions, templateEngine) {
18458
18605
  }
18459
18606
  async function processSingle(options, debugLogger) {
18460
18607
  CliOptionValidator.validateExtractOptions(options);
18461
- const { srcDir, outFile, types, languages, attrFilters, title, mode, attr, vars, envFile } = options;
18608
+ const { srcDir, outFile, types, languages, attrFilters, title, mode, attr, vars, envFile, dryRun } = options;
18462
18609
  // Resolve template variables first
18463
18610
  const templateEngine = new TemplateEngine();
18464
18611
  const variableResolver = new VariableResolver();
@@ -18483,6 +18630,17 @@ async function processSingle(options, debugLogger) {
18483
18630
  debugLogger.time('File scanning and filtering');
18484
18631
  debugLogger.log(`Scanning directory: ${srcDir}`);
18485
18632
  debugLogger.log('Applied filters:', { types, languages, attrFilters });
18633
+ // In dry-run mode, we need both all files and filtered files to show exclusion details
18634
+ if (dryRun) {
18635
+ const { allFiles, filteredFiles } = await loadAndFilterFilesWithDetails(srcDir, types, languages, attrFilters, debugLogger);
18636
+ debugLogger.timeEnd('File scanning and filtering');
18637
+ debugLogger.log(`Found ${filteredFiles.length} files after filtering`);
18638
+ // Check if verbose mode is enabled (via debug flag)
18639
+ const verbose = debugLogger.isEnabled;
18640
+ // Display dry-run preview and exit
18641
+ displayDryRunPreview(srcDir, outFile, allFiles, filteredFiles, types, languages, attrFilters, verbose);
18642
+ return;
18643
+ }
18486
18644
  const filtered = await loadAndFilterFiles(srcDir, types, languages, attrFilters, debugLogger);
18487
18645
  debugLogger.timeEnd('File scanning and filtering');
18488
18646
  debugLogger.log(`Found ${filtered.length} files after filtering`);
@@ -18675,6 +18833,7 @@ async function handleExtractCommand(options) {
18675
18833
  debug: isDebugMode,
18676
18834
  vars: options.vars,
18677
18835
  envFile: options.envFile,
18836
+ dryRun: options.dryRun,
18678
18837
  };
18679
18838
  debugLogger.log('Resolved extract options:', extractOptions);
18680
18839
  if (options.recipe && options.recipe.length > 0) {
@@ -18871,6 +19030,11 @@ async function processRecipe(recipePath, baseOptions, contentTracker, debugLogge
18871
19030
  const expandedRecipe = await expandRecipeImports(data.recipe, resolvedPath, debugLogger);
18872
19031
  debugLogger?.timeEnd('Recipe import expansion');
18873
19032
  debugLogger?.log(`After import expansion: ${expandedRecipe.length} items`);
19033
+ // If dry-run mode, display preview and exit
19034
+ if (baseOptions.dryRun) {
19035
+ await displayRecipeDryRunPreview(recipePath, data, expandedRecipe, baseOptions, debugLogger, cliBaseDir, cliOutFile, cliSrc);
19036
+ return;
19037
+ }
18874
19038
  // Initialize local tracker if not provided (for single recipe mode)
18875
19039
  const localTracker = contentTracker || new ContentTracker();
18876
19040
  for (const [index, item] of expandedRecipe.entries()) {
@@ -18983,6 +19147,7 @@ async function processRecipe(recipePath, baseOptions, contentTracker, debugLogge
18983
19147
  debug: baseOptions.debug,
18984
19148
  vars: itemVars,
18985
19149
  envFile: envFile,
19150
+ dryRun: baseOptions.dryRun,
18986
19151
  };
18987
19152
  debugLogger?.time(`Processing single extraction for item ${index + 1}`);
18988
19153
  await processSingle(options, debugLogger || new DebugLogger(false));
@@ -15,6 +15,7 @@ export interface ExtractOptions {
15
15
  debug?: boolean;
16
16
  vars?: string;
17
17
  envFile?: string;
18
+ dryRun?: boolean;
18
19
  }
19
20
  export interface StatsOptions {
20
21
  srcDir: string;
@@ -1 +1 @@
1
- {"version":3,"file":"optionValidator.d.ts","sourceRoot":"","sources":["../src/optionValidator.ts"],"names":[],"mappings":"AAAA,oBAAY,SAAS;IACnB,MAAM,WAAW;IACjB,OAAO,YAAY;IACnB,SAAS,cAAc;CACxB;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,SAAS,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAIpC;WAEY,sBAAsB,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;WAYrD,oBAAoB,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI;CAKhE"}
1
+ {"version":3,"file":"optionValidator.d.ts","sourceRoot":"","sources":["../src/optionValidator.ts"],"names":[],"mappings":"AAAA,oBAAY,SAAS;IACnB,MAAM,WAAW;IACjB,OAAO,YAAY;IACnB,SAAS,cAAc;CACxB;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,SAAS,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAIpC;WAEY,sBAAsB,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;WAYrD,oBAAoB,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI;CAKhE"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aramassa/ai-rules",
3
- "version": "0.3.4",
3
+ "version": "0.4.0",
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",