@vibe-agent-toolkit/resources 0.1.2 → 0.1.4

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.
Files changed (92) hide show
  1. package/README.md +255 -17
  2. package/dist/collection-matcher.d.ts +63 -0
  3. package/dist/collection-matcher.d.ts.map +1 -0
  4. package/dist/collection-matcher.js +127 -0
  5. package/dist/collection-matcher.js.map +1 -0
  6. package/dist/config-parser.d.ts +63 -0
  7. package/dist/config-parser.d.ts.map +1 -0
  8. package/dist/config-parser.js +113 -0
  9. package/dist/config-parser.js.map +1 -0
  10. package/dist/frontmatter-validator.d.ts +50 -0
  11. package/dist/frontmatter-validator.d.ts.map +1 -0
  12. package/dist/frontmatter-validator.js +238 -0
  13. package/dist/frontmatter-validator.js.map +1 -0
  14. package/dist/index.d.ts +4 -3
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +3 -1
  17. package/dist/index.js.map +1 -1
  18. package/dist/link-parser.d.ts +2 -0
  19. package/dist/link-parser.d.ts.map +1 -1
  20. package/dist/link-parser.js +41 -0
  21. package/dist/link-parser.js.map +1 -1
  22. package/dist/link-validator.d.ts +25 -3
  23. package/dist/link-validator.d.ts.map +1 -1
  24. package/dist/link-validator.js +52 -40
  25. package/dist/link-validator.js.map +1 -1
  26. package/dist/multi-schema-validator.d.ts +42 -0
  27. package/dist/multi-schema-validator.d.ts.map +1 -0
  28. package/dist/multi-schema-validator.js +107 -0
  29. package/dist/multi-schema-validator.js.map +1 -0
  30. package/dist/pattern-expander.d.ts +63 -0
  31. package/dist/pattern-expander.d.ts.map +1 -0
  32. package/dist/pattern-expander.js +93 -0
  33. package/dist/pattern-expander.js.map +1 -0
  34. package/dist/resource-registry.d.ts +104 -8
  35. package/dist/resource-registry.d.ts.map +1 -1
  36. package/dist/resource-registry.js +230 -30
  37. package/dist/resource-registry.js.map +1 -1
  38. package/dist/schema-assignment.d.ts +49 -0
  39. package/dist/schema-assignment.d.ts.map +1 -0
  40. package/dist/schema-assignment.js +95 -0
  41. package/dist/schema-assignment.js.map +1 -0
  42. package/dist/schemas/project-config.d.ts +254 -0
  43. package/dist/schemas/project-config.d.ts.map +1 -0
  44. package/dist/schemas/project-config.js +57 -0
  45. package/dist/schemas/project-config.js.map +1 -0
  46. package/dist/schemas/resource-metadata.d.ts +10 -1
  47. package/dist/schemas/resource-metadata.d.ts.map +1 -1
  48. package/dist/schemas/resource-metadata.js +7 -1
  49. package/dist/schemas/resource-metadata.js.map +1 -1
  50. package/dist/schemas/validation-result.d.ts +9 -24
  51. package/dist/schemas/validation-result.d.ts.map +1 -1
  52. package/dist/schemas/validation-result.js +11 -18
  53. package/dist/schemas/validation-result.js.map +1 -1
  54. package/dist/types/resource-parser.d.ts +53 -0
  55. package/dist/types/resource-parser.d.ts.map +1 -0
  56. package/dist/types/resource-parser.js +233 -0
  57. package/dist/types/resource-parser.js.map +1 -0
  58. package/dist/types/resource-path-utils.d.ts +43 -0
  59. package/dist/types/resource-path-utils.d.ts.map +1 -0
  60. package/dist/types/resource-path-utils.js +89 -0
  61. package/dist/types/resource-path-utils.js.map +1 -0
  62. package/dist/types/resources.d.ts +140 -0
  63. package/dist/types/resources.d.ts.map +1 -0
  64. package/dist/types/resources.js +58 -0
  65. package/dist/types/resources.js.map +1 -0
  66. package/dist/types.d.ts +14 -1
  67. package/dist/types.d.ts.map +1 -1
  68. package/dist/types.js +17 -0
  69. package/dist/types.js.map +1 -1
  70. package/dist/utils.d.ts +18 -0
  71. package/dist/utils.d.ts.map +1 -1
  72. package/dist/utils.js +39 -0
  73. package/dist/utils.js.map +1 -1
  74. package/package.json +5 -2
  75. package/src/collection-matcher.ts +148 -0
  76. package/src/config-parser.ts +125 -0
  77. package/src/frontmatter-validator.ts +279 -0
  78. package/src/index.ts +10 -2
  79. package/src/link-parser.ts +50 -0
  80. package/src/link-validator.ts +70 -43
  81. package/src/multi-schema-validator.ts +128 -0
  82. package/src/pattern-expander.ts +100 -0
  83. package/src/resource-registry.ts +347 -34
  84. package/src/schema-assignment.ts +119 -0
  85. package/src/schemas/project-config.ts +71 -0
  86. package/src/schemas/resource-metadata.ts +7 -1
  87. package/src/schemas/validation-result.ts +11 -21
  88. package/src/types/resource-parser.ts +302 -0
  89. package/src/types/resource-path-utils.ts +102 -0
  90. package/src/types/resources.ts +211 -0
  91. package/src/types.ts +89 -1
  92. package/src/utils.ts +43 -0
package/README.md CHANGED
@@ -6,6 +6,7 @@ Markdown resource parsing, validation, and link integrity checking for AI agent
6
6
 
7
7
  - **Parse markdown files** - Extract links, headings, and metadata using unified/remark
8
8
  - **Validate link integrity** - Check local file links, anchor links, and detect broken references
9
+ - **Frontmatter support** - Parse YAML frontmatter, optionally validate against JSON Schemas
9
10
  - **Track resource collections** - Manage multiple markdown files with automatic ID generation
10
11
  - **Resolve cross-references** - Link resources together and track dependencies
11
12
  - **Query capabilities** - Find resources by path, ID, or glob patterns with lazy evaluation
@@ -62,9 +63,6 @@ Main class for managing collections of markdown resources.
62
63
  new ResourceRegistry(options?: ResourceRegistryOptions)
63
64
  ```
64
65
 
65
- **Options:**
66
- - `validateOnAdd?: boolean` - Validate resources immediately when added (default: `false`)
67
-
68
66
  #### Methods
69
67
 
70
68
  ##### addResource(filePath: string): Promise<ResourceMetadata>
@@ -570,6 +568,260 @@ type ValidationSeverity = 'error' | 'warning' | 'info';
570
568
  - `warning` - Non-critical issue that should be addressed (e.g., questionable link format)
571
569
  - `info` - Informational message (e.g., external URL not validated)
572
570
 
571
+ ## Frontmatter Support
572
+
573
+ The resources package parses YAML frontmatter from markdown files and stores it in `ResourceMetadata.frontmatter`. You can optionally validate frontmatter against JSON Schemas.
574
+
575
+ ### Basic Frontmatter Parsing
576
+
577
+ Frontmatter is automatically parsed when resources are added:
578
+
579
+ ```typescript
580
+ import { ResourceRegistry } from '@vibe-agent-toolkit/resources';
581
+
582
+ const registry = new ResourceRegistry();
583
+ await registry.addResource('./docs/guide.md');
584
+
585
+ const resource = registry.getResource('./docs/guide.md');
586
+ console.log('Frontmatter:', resource.frontmatter);
587
+ // { title: 'User Guide', category: 'tutorial', tags: ['api', 'getting-started'] }
588
+ ```
589
+
590
+ **Supported format**: YAML frontmatter between `---` delimiters at the start of the file:
591
+
592
+ ```markdown
593
+ ---
594
+ title: User Guide
595
+ category: tutorial
596
+ tags:
597
+ - api
598
+ - getting-started
599
+ ---
600
+
601
+ # Content starts here
602
+ ```
603
+
604
+ ### Frontmatter Validation
605
+
606
+ Validate frontmatter against JSON Schema to enforce required fields and data types:
607
+
608
+ ```typescript
609
+ import { FrontmatterValidator } from '@vibe-agent-toolkit/resources';
610
+
611
+ // Create validator with JSON Schema
612
+ const validator = new FrontmatterValidator({
613
+ type: 'object',
614
+ required: ['title', 'description'],
615
+ properties: {
616
+ title: { type: 'string', minLength: 1 },
617
+ description: { type: 'string' },
618
+ category: { enum: ['guide', 'reference', 'tutorial', 'api'] },
619
+ tags: { type: 'array', items: { type: 'string' } }
620
+ }
621
+ });
622
+
623
+ // Validate a resource
624
+ const resource = registry.getResource('./docs/guide.md');
625
+ const result = validator.validate(resource);
626
+
627
+ if (!result.valid) {
628
+ console.error('Validation errors:', result.errors);
629
+ }
630
+ ```
631
+
632
+ ### Schema Design Patterns
633
+
634
+ #### Pattern 1: Required Fields, Allow Extras
635
+
636
+ Most projects have files (README.md, etc.) without frontmatter. Use `required` for must-have fields but allow custom fields:
637
+
638
+ ```json
639
+ {
640
+ "type": "object",
641
+ "required": ["title", "description"],
642
+ "additionalProperties": true,
643
+ "properties": {
644
+ "title": { "type": "string", "minLength": 1 },
645
+ "description": { "type": "string" },
646
+ "category": { "enum": ["guide", "reference", "tutorial", "api"] }
647
+ }
648
+ }
649
+ ```
650
+
651
+ **Behavior**:
652
+ - Files without frontmatter: **Error** (missing required fields)
653
+ - Files with partial frontmatter: **Error** (missing required fields)
654
+ - Files with complete frontmatter: **Valid**
655
+ - Extra fields allowed: **Yes**
656
+
657
+ #### Pattern 2: Optional Fields Only
658
+
659
+ For projects where frontmatter is optional:
660
+
661
+ ```json
662
+ {
663
+ "type": "object",
664
+ "additionalProperties": true,
665
+ "properties": {
666
+ "title": { "type": "string" },
667
+ "description": { "type": "string" },
668
+ "category": { "enum": ["guide", "reference", "tutorial", "api"] }
669
+ }
670
+ }
671
+ ```
672
+
673
+ **Behavior**:
674
+ - Files without frontmatter: **Valid** (all fields optional)
675
+ - Files with frontmatter: **Validated** (fields must match schema types)
676
+ - Extra fields allowed: **Yes**
677
+
678
+ #### Pattern 3: Strict Schema
679
+
680
+ For knowledge bases where all metadata is required:
681
+
682
+ ```json
683
+ {
684
+ "type": "object",
685
+ "required": ["title", "description", "category", "keywords"],
686
+ "additionalProperties": false,
687
+ "properties": {
688
+ "title": { "type": "string", "minLength": 1 },
689
+ "description": { "type": "string" },
690
+ "category": { "enum": ["guide", "reference", "tutorial", "api"] },
691
+ "keywords": { "type": "array", "items": { "type": "string" } },
692
+ "source_url": { "type": "string", "format": "uri" }
693
+ }
694
+ }
695
+ ```
696
+
697
+ **Behavior**:
698
+ - Files without frontmatter: **Error** (missing required fields)
699
+ - Extra fields: **Error** (`additionalProperties: false`)
700
+ - All fields must match types: **Yes**
701
+
702
+ ### CLI Usage
703
+
704
+ The `vat resources validate` command supports frontmatter validation:
705
+
706
+ ```bash
707
+ # Parse frontmatter, report YAML errors only
708
+ vat resources validate docs/
709
+
710
+ # Validate against JSON Schema
711
+ vat resources validate docs/ --frontmatter-schema schema.json
712
+
713
+ # Example output with schema validation
714
+ vat resources validate docs/ --frontmatter-schema schema.json
715
+ # Resources validated: 42
716
+ # Links validated: 156
717
+ # Frontmatter errors:
718
+ # docs/guide.md: Missing required property 'description'
719
+ # docs/api.md: Property 'category' must be one of: guide, reference, tutorial, api
720
+ ```
721
+
722
+ ### Validation Result
723
+
724
+ Frontmatter validation results are included in `ValidationResult`:
725
+
726
+ ```typescript
727
+ interface ValidationResult {
728
+ // ... existing fields
729
+ frontmatterValidation?: {
730
+ valid: boolean;
731
+ errors: Array<{
732
+ resourcePath: string;
733
+ message: string;
734
+ field?: string;
735
+ }>;
736
+ };
737
+ }
738
+ ```
739
+
740
+ ### Example Schemas
741
+
742
+ #### Knowledge Base Schema
743
+
744
+ ```json
745
+ {
746
+ "type": "object",
747
+ "required": ["title", "description"],
748
+ "additionalProperties": true,
749
+ "properties": {
750
+ "title": { "type": "string", "minLength": 1 },
751
+ "description": { "type": "string" },
752
+ "category": { "enum": ["guide", "reference", "tutorial", "api"] },
753
+ "keywords": { "type": "array", "items": { "type": "string" } },
754
+ "source_url": { "type": "string", "format": "uri" },
755
+ "author": { "type": "string" },
756
+ "last_updated": { "type": "string", "format": "date" }
757
+ }
758
+ }
759
+ ```
760
+
761
+ #### Blog Post Schema
762
+
763
+ ```json
764
+ {
765
+ "type": "object",
766
+ "required": ["title", "date", "author"],
767
+ "additionalProperties": false,
768
+ "properties": {
769
+ "title": { "type": "string", "minLength": 1 },
770
+ "date": { "type": "string", "format": "date" },
771
+ "author": { "type": "string" },
772
+ "tags": { "type": "array", "items": { "type": "string" } },
773
+ "excerpt": { "type": "string" },
774
+ "featured": { "type": "boolean" }
775
+ }
776
+ }
777
+ ```
778
+
779
+ #### API Documentation Schema
780
+
781
+ ```json
782
+ {
783
+ "type": "object",
784
+ "required": ["title", "api_version"],
785
+ "additionalProperties": true,
786
+ "properties": {
787
+ "title": { "type": "string", "minLength": 1 },
788
+ "api_version": { "type": "string", "pattern": "^\\d+\\.\\d+\\.\\d+$" },
789
+ "endpoint": { "type": "string" },
790
+ "method": { "enum": ["GET", "POST", "PUT", "PATCH", "DELETE"] },
791
+ "deprecated": { "type": "boolean" }
792
+ }
793
+ }
794
+ ```
795
+
796
+ ### Error Handling
797
+
798
+ ```typescript
799
+ const validator = new FrontmatterValidator(schema);
800
+
801
+ for (const resource of registry.getAllResources()) {
802
+ const result = validator.validate(resource);
803
+
804
+ if (!result.valid) {
805
+ console.error(`\n${resource.filePath}:`);
806
+ for (const error of result.errors) {
807
+ console.error(` - ${error.message}`);
808
+ if (error.field) {
809
+ console.error(` Field: ${error.field}`);
810
+ }
811
+ }
812
+ }
813
+ }
814
+ ```
815
+
816
+ ### Common Validation Errors
817
+
818
+ - **Missing required property**: Field specified in `required` array is missing
819
+ - **Invalid type**: Field value doesn't match the type (e.g., number instead of string)
820
+ - **Invalid enum value**: Field value is not in the allowed enum values
821
+ - **Invalid format**: String doesn't match the format constraint (e.g., "uri", "date")
822
+ - **Additional property not allowed**: Extra field present when `additionalProperties: false`
823
+ - **YAML parsing error**: Invalid YAML syntax in frontmatter
824
+
573
825
  ## Schemas
574
826
 
575
827
  All types are backed by Zod schemas for runtime validation. You can import schemas for advanced use cases:
@@ -651,20 +903,6 @@ for (const [path, issues] of issuesByResource) {
651
903
  }
652
904
  ```
653
905
 
654
- ### Validate on Add
655
-
656
- Enable strict validation mode to fail fast on broken links:
657
-
658
- ```typescript
659
- const registry = new ResourceRegistry({ validateOnAdd: true });
660
-
661
- try {
662
- await registry.addResource('./docs/broken.md');
663
- } catch (error) {
664
- console.error('Validation failed:', error.message);
665
- }
666
- ```
667
-
668
906
  ## Examples
669
907
 
670
908
  ### Validate Project Documentation
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Collection matching utilities for determining which collections a file belongs to.
3
+ *
4
+ * Applies include/exclude pattern rules with precedence (exclude wins).
5
+ */
6
+ import type { CollectionConfig } from './schemas/project-config.js';
7
+ /**
8
+ * Check if a file path matches a collection's include/exclude rules.
9
+ *
10
+ * Rules:
11
+ * - File must match at least one include pattern
12
+ * - File must NOT match any exclude pattern
13
+ * - Exclude always wins over include
14
+ * - Pattern order does not matter
15
+ *
16
+ * Special handling for root-level patterns (*.md, *.json):
17
+ * - These match against the basename only, not the full path
18
+ * - Allows matching root-level files regardless of their absolute path
19
+ *
20
+ * Paths are normalized to forward slashes before matching for cross-platform consistency.
21
+ *
22
+ * @param filePath - Absolute file path to check
23
+ * @param collection - Collection configuration with include/exclude patterns
24
+ * @returns True if file belongs to collection
25
+ *
26
+ * @example
27
+ * ```typescript
28
+ * const collection = {
29
+ * include: ['docs'],
30
+ * exclude: ['**\/README.md']
31
+ * };
32
+ *
33
+ * matchesCollection('/project/docs/guide.md', collection) // true
34
+ * matchesCollection('/project/docs/README.md', collection) // false (excluded)
35
+ * matchesCollection('/project/src/index.ts', collection) // false (not included)
36
+ * ```
37
+ */
38
+ export declare function matchesCollection(filePath: string, collection: CollectionConfig): boolean;
39
+ /**
40
+ * Find all collections that a file belongs to.
41
+ *
42
+ * A file can belong to multiple collections if it matches their rules.
43
+ *
44
+ * @param filePath - Absolute file path to check
45
+ * @param collections - Map of collection name to collection config
46
+ * @returns Array of collection names the file belongs to
47
+ *
48
+ * @example
49
+ * ```typescript
50
+ * const collections = {
51
+ * 'rag-kb': { include: ['docs'], exclude: ['**\/README.md'] },
52
+ * 'skills': { include: ['**\/SKILL.md'] }
53
+ * };
54
+ *
55
+ * getCollectionsForFile('/project/docs/guide.md', collections)
56
+ * // ['rag-kb']
57
+ *
58
+ * getCollectionsForFile('/project/docs/SKILL.md', collections)
59
+ * // ['rag-kb', 'skills']
60
+ * ```
61
+ */
62
+ export declare function getCollectionsForFile(filePath: string, collections: Record<string, CollectionConfig>): string[];
63
+ //# sourceMappingURL=collection-matcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collection-matcher.d.ts","sourceRoot":"","sources":["../src/collection-matcher.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAQH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAWpE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,gBAAgB,GAAG,OAAO,CAuDzF;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,GAC5C,MAAM,EAAE,CAUV"}
@@ -0,0 +1,127 @@
1
+ /**
2
+ * Collection matching utilities for determining which collections a file belongs to.
3
+ *
4
+ * Applies include/exclude pattern rules with precedence (exclude wins).
5
+ */
6
+ import { basename as getBasename } from 'node:path';
7
+ import { toForwardSlash } from '@vibe-agent-toolkit/utils';
8
+ import picomatch from 'picomatch';
9
+ import { expandPatterns } from './pattern-expander.js';
10
+ /**
11
+ * Check if a pattern is a root-level pattern (e.g., *.md, *.json).
12
+ *
13
+ * Root-level patterns start with * but not **.
14
+ */
15
+ function isRootLevelPattern(pattern) {
16
+ return pattern.startsWith('*') && !pattern.startsWith('**');
17
+ }
18
+ /**
19
+ * Check if a file path matches a collection's include/exclude rules.
20
+ *
21
+ * Rules:
22
+ * - File must match at least one include pattern
23
+ * - File must NOT match any exclude pattern
24
+ * - Exclude always wins over include
25
+ * - Pattern order does not matter
26
+ *
27
+ * Special handling for root-level patterns (*.md, *.json):
28
+ * - These match against the basename only, not the full path
29
+ * - Allows matching root-level files regardless of their absolute path
30
+ *
31
+ * Paths are normalized to forward slashes before matching for cross-platform consistency.
32
+ *
33
+ * @param filePath - Absolute file path to check
34
+ * @param collection - Collection configuration with include/exclude patterns
35
+ * @returns True if file belongs to collection
36
+ *
37
+ * @example
38
+ * ```typescript
39
+ * const collection = {
40
+ * include: ['docs'],
41
+ * exclude: ['**\/README.md']
42
+ * };
43
+ *
44
+ * matchesCollection('/project/docs/guide.md', collection) // true
45
+ * matchesCollection('/project/docs/README.md', collection) // false (excluded)
46
+ * matchesCollection('/project/src/index.ts', collection) // false (not included)
47
+ * ```
48
+ */
49
+ export function matchesCollection(filePath, collection) {
50
+ // Normalize to forward slashes for cross-platform consistency
51
+ const normalizedPath = toForwardSlash(filePath);
52
+ // Extract basename for root-level pattern matching
53
+ const basename = getBasename(filePath);
54
+ // Expand patterns (paths → globs)
55
+ const includePatterns = expandPatterns(collection.include);
56
+ const excludePatterns = collection.exclude ? expandPatterns(collection.exclude) : [];
57
+ // Separate root-level patterns from other patterns
58
+ const includeRootPatterns = includePatterns.filter(isRootLevelPattern);
59
+ const includeNonRootPatterns = includePatterns.filter((p) => !isRootLevelPattern(p));
60
+ const excludeRootPatterns = excludePatterns.filter(isRootLevelPattern);
61
+ const excludeNonRootPatterns = excludePatterns.filter((p) => !isRootLevelPattern(p));
62
+ // Check excludes first (exclude wins)
63
+ // Check non-root excludes against full path
64
+ if (excludeNonRootPatterns.length > 0) {
65
+ const excludeMatcher = picomatch(excludeNonRootPatterns);
66
+ if (excludeMatcher(normalizedPath)) {
67
+ return false;
68
+ }
69
+ }
70
+ // Check root-level excludes against basename
71
+ if (excludeRootPatterns.length > 0) {
72
+ const excludeRootMatcher = picomatch(excludeRootPatterns);
73
+ if (excludeRootMatcher(basename)) {
74
+ return false;
75
+ }
76
+ }
77
+ // Check includes (need to match at least one)
78
+ let matched = false;
79
+ // Check non-root includes against full path
80
+ if (includeNonRootPatterns.length > 0) {
81
+ const includeMatcher = picomatch(includeNonRootPatterns);
82
+ if (includeMatcher(normalizedPath)) {
83
+ matched = true;
84
+ }
85
+ }
86
+ // Check root-level includes against basename
87
+ if (!matched && includeRootPatterns.length > 0) {
88
+ const includeRootMatcher = picomatch(includeRootPatterns);
89
+ if (includeRootMatcher(basename)) {
90
+ matched = true;
91
+ }
92
+ }
93
+ return matched;
94
+ }
95
+ /**
96
+ * Find all collections that a file belongs to.
97
+ *
98
+ * A file can belong to multiple collections if it matches their rules.
99
+ *
100
+ * @param filePath - Absolute file path to check
101
+ * @param collections - Map of collection name to collection config
102
+ * @returns Array of collection names the file belongs to
103
+ *
104
+ * @example
105
+ * ```typescript
106
+ * const collections = {
107
+ * 'rag-kb': { include: ['docs'], exclude: ['**\/README.md'] },
108
+ * 'skills': { include: ['**\/SKILL.md'] }
109
+ * };
110
+ *
111
+ * getCollectionsForFile('/project/docs/guide.md', collections)
112
+ * // ['rag-kb']
113
+ *
114
+ * getCollectionsForFile('/project/docs/SKILL.md', collections)
115
+ * // ['rag-kb', 'skills']
116
+ * ```
117
+ */
118
+ export function getCollectionsForFile(filePath, collections) {
119
+ const matchingCollections = [];
120
+ for (const [name, config] of Object.entries(collections)) {
121
+ if (matchesCollection(filePath, config)) {
122
+ matchingCollections.push(name);
123
+ }
124
+ }
125
+ return matchingCollections;
126
+ }
127
+ //# sourceMappingURL=collection-matcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collection-matcher.js","sourceRoot":"","sources":["../src/collection-matcher.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Configuration file parser for vibe-agent-toolkit.config.yaml
3
+ *
4
+ * Discovers and parses project configuration files with directory tree walk-up.
5
+ */
6
+ import { type ProjectConfig } from './schemas/project-config.js';
7
+ /**
8
+ * Find the config file by walking up the directory tree.
9
+ *
10
+ * Starts from the current directory and walks up until the config file is found
11
+ * or the root directory is reached.
12
+ *
13
+ * @param startDir - Directory to start searching from (default: process.cwd())
14
+ * @returns Absolute path to config file, or undefined if not found
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * const configPath = await findConfigFile();
19
+ * if (configPath) {
20
+ * console.log(`Found config: ${configPath}`);
21
+ * }
22
+ * ```
23
+ */
24
+ export declare function findConfigFile(startDir?: string): Promise<string | undefined>;
25
+ /**
26
+ * Parse a project configuration file.
27
+ *
28
+ * Reads the YAML file, parses it, and validates against the schema.
29
+ *
30
+ * @param configPath - Absolute path to config file
31
+ * @returns Parsed and validated configuration
32
+ * @throws Error if file cannot be read, YAML is invalid, or validation fails
33
+ *
34
+ * @example
35
+ * ```typescript
36
+ * const config = await parseConfigFile('/project/vibe-agent-toolkit.config.yaml');
37
+ * console.log(`Version: ${config.version}`);
38
+ * console.log(`Collections: ${Object.keys(config.resources?.collections ?? {}).join(', ')}`);
39
+ * ```
40
+ */
41
+ export declare function parseConfigFile(configPath: string): Promise<ProjectConfig>;
42
+ /**
43
+ * Load project configuration by discovering and parsing config file.
44
+ *
45
+ * Walks up the directory tree from startDir to find the config file,
46
+ * then parses and validates it.
47
+ *
48
+ * @param startDir - Directory to start searching from (default: process.cwd())
49
+ * @returns Parsed configuration, or undefined if no config file found
50
+ * @throws Error if config file is found but cannot be parsed or is invalid
51
+ *
52
+ * @example
53
+ * ```typescript
54
+ * const config = await loadConfig();
55
+ * if (config) {
56
+ * console.log('Using project config');
57
+ * } else {
58
+ * console.log('No config found, using defaults');
59
+ * }
60
+ * ```
61
+ */
62
+ export declare function loadConfig(startDir?: string): Promise<ProjectConfig | undefined>;
63
+ //# sourceMappingURL=config-parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-parser.d.ts","sourceRoot":"","sources":["../src/config-parser.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,OAAO,EAAuB,KAAK,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAItF;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,cAAc,CAAC,QAAQ,GAAE,MAAsB,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAwBlG;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAqBhF;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,UAAU,CAAC,QAAQ,GAAE,MAAsB,GAAG,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC,CAOrG"}
@@ -0,0 +1,113 @@
1
+ /**
2
+ * Configuration file parser for vibe-agent-toolkit.config.yaml
3
+ *
4
+ * Discovers and parses project configuration files with directory tree walk-up.
5
+ */
6
+ import { readFile } from 'node:fs/promises';
7
+ import path from 'node:path';
8
+ import { load as loadYaml } from 'js-yaml';
9
+ import { ProjectConfigSchema } from './schemas/project-config.js';
10
+ const CONFIG_FILENAME = 'vibe-agent-toolkit.config.yaml';
11
+ /**
12
+ * Find the config file by walking up the directory tree.
13
+ *
14
+ * Starts from the current directory and walks up until the config file is found
15
+ * or the root directory is reached.
16
+ *
17
+ * @param startDir - Directory to start searching from (default: process.cwd())
18
+ * @returns Absolute path to config file, or undefined if not found
19
+ *
20
+ * @example
21
+ * ```typescript
22
+ * const configPath = await findConfigFile();
23
+ * if (configPath) {
24
+ * console.log(`Found config: ${configPath}`);
25
+ * }
26
+ * ```
27
+ */
28
+ export async function findConfigFile(startDir = process.cwd()) {
29
+ let currentDir = path.resolve(startDir);
30
+ const { root } = path.parse(currentDir);
31
+ while (true) {
32
+ const configPath = path.join(currentDir, CONFIG_FILENAME);
33
+ try {
34
+ // Check if file exists by attempting to read metadata
35
+ // eslint-disable-next-line security/detect-non-literal-fs-filename -- constructing path during tree walk
36
+ await readFile(configPath, 'utf-8');
37
+ return configPath;
38
+ }
39
+ catch {
40
+ // File doesn't exist, continue walking up
41
+ }
42
+ // Check if we've reached the root
43
+ if (currentDir === root) {
44
+ return undefined;
45
+ }
46
+ // Move up one directory
47
+ currentDir = path.dirname(currentDir);
48
+ }
49
+ }
50
+ /**
51
+ * Parse a project configuration file.
52
+ *
53
+ * Reads the YAML file, parses it, and validates against the schema.
54
+ *
55
+ * @param configPath - Absolute path to config file
56
+ * @returns Parsed and validated configuration
57
+ * @throws Error if file cannot be read, YAML is invalid, or validation fails
58
+ *
59
+ * @example
60
+ * ```typescript
61
+ * const config = await parseConfigFile('/project/vibe-agent-toolkit.config.yaml');
62
+ * console.log(`Version: ${config.version}`);
63
+ * console.log(`Collections: ${Object.keys(config.resources?.collections ?? {}).join(', ')}`);
64
+ * ```
65
+ */
66
+ export async function parseConfigFile(configPath) {
67
+ // Read file content
68
+ // eslint-disable-next-line security/detect-non-literal-fs-filename -- configPath is from findConfigFile() walk-up
69
+ const content = await readFile(configPath, 'utf-8');
70
+ // Parse YAML
71
+ let parsed;
72
+ try {
73
+ parsed = loadYaml(content);
74
+ }
75
+ catch (error) {
76
+ throw new Error(`Invalid YAML in config file: ${error instanceof Error ? error.message : String(error)}`);
77
+ }
78
+ // Validate against schema
79
+ const result = ProjectConfigSchema.safeParse(parsed);
80
+ if (!result.success) {
81
+ const errors = result.error.errors.map((e) => `${e.path.join('.')}: ${e.message}`).join(', ');
82
+ throw new Error(`Invalid config file: ${errors}`);
83
+ }
84
+ return result.data;
85
+ }
86
+ /**
87
+ * Load project configuration by discovering and parsing config file.
88
+ *
89
+ * Walks up the directory tree from startDir to find the config file,
90
+ * then parses and validates it.
91
+ *
92
+ * @param startDir - Directory to start searching from (default: process.cwd())
93
+ * @returns Parsed configuration, or undefined if no config file found
94
+ * @throws Error if config file is found but cannot be parsed or is invalid
95
+ *
96
+ * @example
97
+ * ```typescript
98
+ * const config = await loadConfig();
99
+ * if (config) {
100
+ * console.log('Using project config');
101
+ * } else {
102
+ * console.log('No config found, using defaults');
103
+ * }
104
+ * ```
105
+ */
106
+ export async function loadConfig(startDir = process.cwd()) {
107
+ const configPath = await findConfigFile(startDir);
108
+ if (!configPath) {
109
+ return undefined;
110
+ }
111
+ return await parseConfigFile(configPath);
112
+ }
113
+ //# sourceMappingURL=config-parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-parser.js","sourceRoot":"","sources":["../src/config-parser.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,IAAI,IAAI,QAAQ,EAAE,MAAM,SAAS,CAAC;AAE3C,OAAO,EAAE,mBAAmB,EAAsB,MAAM,6BAA6B,CAAC;AAEtF,MAAM,eAAe,GAAG,gCAAgC,CAAC;AAEzD;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,WAAmB,OAAO,CAAC,GAAG,EAAE;IACnE,IAAI,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACxC,MAAM,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAExC,OAAO,IAAI,EAAE,CAAC;QACZ,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,eAAe,CAAC,CAAC;QAE1D,IAAI,CAAC;YACH,sDAAsD;YACtD,yGAAyG;YACzG,MAAM,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;YACpC,OAAO,UAAU,CAAC;QACpB,CAAC;QAAC,MAAM,CAAC;YACP,0CAA0C;QAC5C,CAAC;QAED,kCAAkC;QAClC,IAAI,UAAU,KAAK,IAAI,EAAE,CAAC;YACxB,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,wBAAwB;QACxB,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IACxC,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,UAAkB;IACtD,oBAAoB;IACpB,kHAAkH;IAClH,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IAEpD,aAAa;IACb,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC7B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,gCAAgC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAC5G,CAAC;IAED,0BAA0B;IAC1B,MAAM,MAAM,GAAG,mBAAmB,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IACrD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC9F,MAAM,IAAI,KAAK,CAAC,wBAAwB,MAAM,EAAE,CAAC,CAAC;IACpD,CAAC;IAED,OAAO,MAAM,CAAC,IAAI,CAAC;AACrB,CAAC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,WAAmB,OAAO,CAAC,GAAG,EAAE;IAC/D,MAAM,UAAU,GAAG,MAAM,cAAc,CAAC,QAAQ,CAAC,CAAC;IAClD,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,OAAO,MAAM,eAAe,CAAC,UAAU,CAAC,CAAC;AAC3C,CAAC"}