@soulcraft/brainy 3.17.0 → 3.19.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.
Files changed (50) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/README.md +58 -10
  3. package/dist/augmentations/defaultAugmentations.d.ts +0 -1
  4. package/dist/augmentations/defaultAugmentations.js +0 -5
  5. package/dist/brainy.d.ts +64 -0
  6. package/dist/brainy.js +77 -0
  7. package/dist/conversation/conversationManager.d.ts +176 -0
  8. package/dist/conversation/conversationManager.js +666 -0
  9. package/dist/conversation/index.d.ts +8 -0
  10. package/dist/conversation/index.js +8 -0
  11. package/dist/conversation/types.d.ts +231 -0
  12. package/dist/conversation/types.js +8 -0
  13. package/dist/index.d.ts +3 -0
  14. package/dist/index.js +3 -0
  15. package/dist/mcp/conversationTools.d.ts +88 -0
  16. package/dist/mcp/conversationTools.js +470 -0
  17. package/dist/neural/embeddedPatterns.d.ts +1 -1
  18. package/dist/neural/embeddedPatterns.js +1 -1
  19. package/dist/neural/naturalLanguageProcessor.js +0 -1
  20. package/dist/setup.js +0 -1
  21. package/dist/types/mcpTypes.d.ts +7 -1
  22. package/dist/unified.js +0 -1
  23. package/dist/vfs/VirtualFileSystem.d.ts +6 -4
  24. package/dist/vfs/VirtualFileSystem.js +44 -21
  25. package/dist/vfs/index.d.ts +0 -5
  26. package/dist/vfs/index.js +0 -6
  27. package/dist/vfs/semantic/ProjectionRegistry.d.ts +84 -0
  28. package/dist/vfs/semantic/ProjectionRegistry.js +118 -0
  29. package/dist/vfs/semantic/ProjectionStrategy.d.ts +69 -0
  30. package/dist/vfs/semantic/ProjectionStrategy.js +40 -0
  31. package/dist/vfs/semantic/SemanticPathParser.d.ts +73 -0
  32. package/dist/vfs/semantic/SemanticPathParser.js +285 -0
  33. package/dist/vfs/semantic/SemanticPathResolver.d.ts +99 -0
  34. package/dist/vfs/semantic/SemanticPathResolver.js +242 -0
  35. package/dist/vfs/semantic/index.d.ts +17 -0
  36. package/dist/vfs/semantic/index.js +18 -0
  37. package/dist/vfs/semantic/projections/AuthorProjection.d.ts +35 -0
  38. package/dist/vfs/semantic/projections/AuthorProjection.js +74 -0
  39. package/dist/vfs/semantic/projections/ConceptProjection.d.ts +42 -0
  40. package/dist/vfs/semantic/projections/ConceptProjection.js +87 -0
  41. package/dist/vfs/semantic/projections/RelationshipProjection.d.ts +41 -0
  42. package/dist/vfs/semantic/projections/RelationshipProjection.js +101 -0
  43. package/dist/vfs/semantic/projections/SimilarityProjection.d.ts +36 -0
  44. package/dist/vfs/semantic/projections/SimilarityProjection.js +77 -0
  45. package/dist/vfs/semantic/projections/TagProjection.d.ts +34 -0
  46. package/dist/vfs/semantic/projections/TagProjection.js +73 -0
  47. package/dist/vfs/semantic/projections/TemporalProjection.d.ts +35 -0
  48. package/dist/vfs/semantic/projections/TemporalProjection.js +89 -0
  49. package/dist/vfs/types.d.ts +1 -8
  50. package/package.json +1 -1
package/dist/vfs/index.js CHANGED
@@ -15,12 +15,6 @@ export { DirectoryImporter } from './importers/DirectoryImporter.js';
15
15
  // Streaming
16
16
  export { VFSReadStream } from './streams/VFSReadStream.js';
17
17
  export { VFSWriteStream } from './streams/VFSWriteStream.js';
18
- // Knowledge Layer Components (optional via augmentation)
19
- export { EventRecorder } from './EventRecorder.js';
20
- export { SemanticVersioning } from './SemanticVersioning.js';
21
- export { PersistentEntitySystem } from './PersistentEntitySystem.js';
22
- export { ConceptSystem } from './ConceptSystem.js';
23
- export { GitBridge } from './GitBridge.js';
24
18
  // Convenience alias
25
19
  export { VirtualFileSystem as VFS } from './VirtualFileSystem.js';
26
20
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Projection Registry
3
+ *
4
+ * Central registry for all projection strategies
5
+ * Manages strategy lookup and execution
6
+ */
7
+ import { ProjectionStrategy } from './ProjectionStrategy.js';
8
+ import { Brainy } from '../../brainy.js';
9
+ import { VirtualFileSystem } from '../VirtualFileSystem.js';
10
+ import { VFSEntity } from '../types.js';
11
+ /**
12
+ * Registry for projection strategies
13
+ * Allows dynamic registration and lookup of strategies
14
+ */
15
+ export declare class ProjectionRegistry {
16
+ private strategies;
17
+ /**
18
+ * Register a projection strategy
19
+ * @param strategy - The strategy to register
20
+ * @throws Error if strategy with same name already registered
21
+ */
22
+ register(strategy: ProjectionStrategy): void;
23
+ /**
24
+ * Get a projection strategy by name
25
+ * @param name - Strategy name
26
+ * @returns The strategy or undefined if not found
27
+ */
28
+ get(name: string): ProjectionStrategy | undefined;
29
+ /**
30
+ * Check if a strategy is registered
31
+ * @param name - Strategy name
32
+ */
33
+ has(name: string): boolean;
34
+ /**
35
+ * List all registered strategy names
36
+ */
37
+ listDimensions(): string[];
38
+ /**
39
+ * Get count of registered strategies
40
+ */
41
+ count(): number;
42
+ /**
43
+ * Resolve a dimension value to entity IDs
44
+ * Convenience method that looks up strategy and calls resolve()
45
+ *
46
+ * @param dimension - The semantic dimension
47
+ * @param value - The value to resolve
48
+ * @param brain - REAL Brainy instance
49
+ * @param vfs - REAL VirtualFileSystem instance
50
+ * @returns Array of entity IDs
51
+ * @throws Error if dimension not registered
52
+ */
53
+ resolve(dimension: string, value: any, brain: Brainy, vfs: VirtualFileSystem): Promise<string[]>;
54
+ /**
55
+ * List entities in a dimension
56
+ * Convenience method for strategies that support listing
57
+ *
58
+ * @param dimension - The semantic dimension
59
+ * @param brain - REAL Brainy instance
60
+ * @param vfs - REAL VirtualFileSystem instance
61
+ * @param limit - Max results
62
+ * @returns Array of VFSEntity
63
+ * @throws Error if dimension not registered or doesn't support listing
64
+ */
65
+ list(dimension: string, brain: Brainy, vfs: VirtualFileSystem, limit?: number): Promise<VFSEntity[]>;
66
+ /**
67
+ * Unregister a strategy
68
+ * Useful for testing or dynamic strategy management
69
+ *
70
+ * @param name - Strategy name to remove
71
+ * @returns true if removed, false if not found
72
+ */
73
+ unregister(name: string): boolean;
74
+ /**
75
+ * Clear all registered strategies
76
+ * Useful for testing
77
+ */
78
+ clear(): void;
79
+ /**
80
+ * Get all registered strategies
81
+ * Returns a copy to prevent external modification
82
+ */
83
+ getAll(): ProjectionStrategy[];
84
+ }
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Projection Registry
3
+ *
4
+ * Central registry for all projection strategies
5
+ * Manages strategy lookup and execution
6
+ */
7
+ /**
8
+ * Registry for projection strategies
9
+ * Allows dynamic registration and lookup of strategies
10
+ */
11
+ export class ProjectionRegistry {
12
+ constructor() {
13
+ this.strategies = new Map();
14
+ }
15
+ /**
16
+ * Register a projection strategy
17
+ * @param strategy - The strategy to register
18
+ * @throws Error if strategy with same name already registered
19
+ */
20
+ register(strategy) {
21
+ if (this.strategies.has(strategy.name)) {
22
+ throw new Error(`Projection strategy '${strategy.name}' is already registered`);
23
+ }
24
+ this.strategies.set(strategy.name, strategy);
25
+ }
26
+ /**
27
+ * Get a projection strategy by name
28
+ * @param name - Strategy name
29
+ * @returns The strategy or undefined if not found
30
+ */
31
+ get(name) {
32
+ return this.strategies.get(name);
33
+ }
34
+ /**
35
+ * Check if a strategy is registered
36
+ * @param name - Strategy name
37
+ */
38
+ has(name) {
39
+ return this.strategies.has(name);
40
+ }
41
+ /**
42
+ * List all registered strategy names
43
+ */
44
+ listDimensions() {
45
+ return Array.from(this.strategies.keys());
46
+ }
47
+ /**
48
+ * Get count of registered strategies
49
+ */
50
+ count() {
51
+ return this.strategies.size;
52
+ }
53
+ /**
54
+ * Resolve a dimension value to entity IDs
55
+ * Convenience method that looks up strategy and calls resolve()
56
+ *
57
+ * @param dimension - The semantic dimension
58
+ * @param value - The value to resolve
59
+ * @param brain - REAL Brainy instance
60
+ * @param vfs - REAL VirtualFileSystem instance
61
+ * @returns Array of entity IDs
62
+ * @throws Error if dimension not registered
63
+ */
64
+ async resolve(dimension, value, brain, vfs) {
65
+ const strategy = this.get(dimension);
66
+ if (!strategy) {
67
+ throw new Error(`Unknown projection dimension: ${dimension}. Registered dimensions: ${this.listDimensions().join(', ')}`);
68
+ }
69
+ // Call REAL strategy resolve method
70
+ return await strategy.resolve(brain, vfs, value);
71
+ }
72
+ /**
73
+ * List entities in a dimension
74
+ * Convenience method for strategies that support listing
75
+ *
76
+ * @param dimension - The semantic dimension
77
+ * @param brain - REAL Brainy instance
78
+ * @param vfs - REAL VirtualFileSystem instance
79
+ * @param limit - Max results
80
+ * @returns Array of VFSEntity
81
+ * @throws Error if dimension not registered or doesn't support listing
82
+ */
83
+ async list(dimension, brain, vfs, limit) {
84
+ const strategy = this.get(dimension);
85
+ if (!strategy) {
86
+ throw new Error(`Unknown projection dimension: ${dimension}`);
87
+ }
88
+ if (!strategy.list) {
89
+ throw new Error(`Projection '${dimension}' does not support listing`);
90
+ }
91
+ return await strategy.list(brain, vfs, limit);
92
+ }
93
+ /**
94
+ * Unregister a strategy
95
+ * Useful for testing or dynamic strategy management
96
+ *
97
+ * @param name - Strategy name to remove
98
+ * @returns true if removed, false if not found
99
+ */
100
+ unregister(name) {
101
+ return this.strategies.delete(name);
102
+ }
103
+ /**
104
+ * Clear all registered strategies
105
+ * Useful for testing
106
+ */
107
+ clear() {
108
+ this.strategies.clear();
109
+ }
110
+ /**
111
+ * Get all registered strategies
112
+ * Returns a copy to prevent external modification
113
+ */
114
+ getAll() {
115
+ return Array.from(this.strategies.values());
116
+ }
117
+ }
118
+ //# sourceMappingURL=ProjectionRegistry.js.map
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Projection Strategy Interface
3
+ *
4
+ * Defines how to map semantic path dimensions to Brainy queries
5
+ * Each strategy uses EXISTING Brainy indexes and methods
6
+ */
7
+ import { Brainy } from '../../brainy.js';
8
+ import { VirtualFileSystem } from '../VirtualFileSystem.js';
9
+ import { FindParams } from '../../types/brainy.types.js';
10
+ import { VFSEntity } from '../types.js';
11
+ /**
12
+ * Strategy for projecting semantic paths into entity queries
13
+ * All implementations MUST use real Brainy methods (no stubs!)
14
+ */
15
+ export interface ProjectionStrategy {
16
+ /**
17
+ * Strategy name (used for registration)
18
+ */
19
+ readonly name: string;
20
+ /**
21
+ * Convert semantic value to Brainy FindParams
22
+ * Uses EXISTING FindParams type from brainy.types.ts
23
+ */
24
+ toQuery(value: any, subpath?: string): FindParams;
25
+ /**
26
+ * Resolve semantic value to entity IDs
27
+ * Uses REAL Brainy.find() method
28
+ *
29
+ * @param brain - REAL Brainy instance
30
+ * @param vfs - REAL VirtualFileSystem instance
31
+ * @param value - The semantic value to resolve
32
+ * @returns Array of entity IDs that match
33
+ */
34
+ resolve(brain: Brainy, vfs: VirtualFileSystem, value: any): Promise<string[]>;
35
+ /**
36
+ * List all entities in this dimension
37
+ * Optional - not all strategies need to implement
38
+ *
39
+ * @param brain - REAL Brainy instance
40
+ * @param vfs - REAL VirtualFileSystem instance
41
+ * @param limit - Max results to return
42
+ */
43
+ list?(brain: Brainy, vfs: VirtualFileSystem, limit?: number): Promise<VFSEntity[]>;
44
+ }
45
+ /**
46
+ * Base class for projection strategies with common utilities
47
+ */
48
+ export declare abstract class BaseProjectionStrategy implements ProjectionStrategy {
49
+ abstract readonly name: string;
50
+ abstract toQuery(value: any, subpath?: string): FindParams;
51
+ abstract resolve(brain: Brainy, vfs: VirtualFileSystem, value: any): Promise<string[]>;
52
+ /**
53
+ * Convert Brainy Results to entity IDs
54
+ * Helper method for subclasses
55
+ */
56
+ protected extractIds(results: Array<{
57
+ id: string;
58
+ }>): string[];
59
+ /**
60
+ * Verify that an entity is a file (not directory)
61
+ * Uses REAL Brainy.get() method
62
+ */
63
+ protected isFile(brain: Brainy, entityId: string): Promise<boolean>;
64
+ /**
65
+ * Filter entity IDs to only include files
66
+ * Uses REAL Brainy.get() for each entity
67
+ */
68
+ protected filterFiles(brain: Brainy, entityIds: string[]): Promise<string[]>;
69
+ }
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Projection Strategy Interface
3
+ *
4
+ * Defines how to map semantic path dimensions to Brainy queries
5
+ * Each strategy uses EXISTING Brainy indexes and methods
6
+ */
7
+ /**
8
+ * Base class for projection strategies with common utilities
9
+ */
10
+ export class BaseProjectionStrategy {
11
+ /**
12
+ * Convert Brainy Results to entity IDs
13
+ * Helper method for subclasses
14
+ */
15
+ extractIds(results) {
16
+ return results.map(r => r.id);
17
+ }
18
+ /**
19
+ * Verify that an entity is a file (not directory)
20
+ * Uses REAL Brainy.get() method
21
+ */
22
+ async isFile(brain, entityId) {
23
+ const entity = await brain.get(entityId);
24
+ return entity?.metadata?.vfsType === 'file';
25
+ }
26
+ /**
27
+ * Filter entity IDs to only include files
28
+ * Uses REAL Brainy.get() for each entity
29
+ */
30
+ async filterFiles(brain, entityIds) {
31
+ const files = [];
32
+ for (const id of entityIds) {
33
+ if (await this.isFile(brain, id)) {
34
+ files.push(id);
35
+ }
36
+ }
37
+ return files;
38
+ }
39
+ }
40
+ //# sourceMappingURL=ProjectionStrategy.js.map
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Semantic Path Parser
3
+ *
4
+ * Parses semantic filesystem paths into structured queries
5
+ * PURE LOGIC - No external dependencies, no async operations
6
+ *
7
+ * Supported path formats:
8
+ * - Traditional: /src/auth.ts
9
+ * - By Concept: /by-concept/authentication/login.ts
10
+ * - By Author: /by-author/alice/file.ts
11
+ * - By Time: /as-of/2024-03-15/file.ts
12
+ * - By Relationship: /related-to/src/auth.ts/depth-2
13
+ * - By Similarity: /similar-to/src/auth.ts/threshold-0.8
14
+ * - By Tag: /by-tag/security/file.ts
15
+ */
16
+ export type SemanticDimension = 'traditional' | 'concept' | 'author' | 'time' | 'relationship' | 'similar' | 'tag';
17
+ export interface ParsedSemanticPath {
18
+ dimension: SemanticDimension;
19
+ value: string | Date | RelationshipValue | SimilarityValue;
20
+ subpath?: string;
21
+ filters?: Record<string, any>;
22
+ }
23
+ export interface RelationshipValue {
24
+ targetPath: string;
25
+ depth?: number;
26
+ relationshipTypes?: string[];
27
+ }
28
+ export interface SimilarityValue {
29
+ targetPath: string;
30
+ threshold?: number;
31
+ }
32
+ /**
33
+ * Semantic Path Parser
34
+ * Parses various semantic path formats into structured data
35
+ */
36
+ export declare class SemanticPathParser {
37
+ private static readonly PATTERNS;
38
+ /**
39
+ * Parse a path into semantic components
40
+ * PURE FUNCTION - no external calls, no async
41
+ */
42
+ parse(path: string): ParsedSemanticPath;
43
+ /**
44
+ * Check if a path is semantic (non-traditional)
45
+ */
46
+ isSemanticPath(path: string): boolean;
47
+ /**
48
+ * Get the dimension type from a path
49
+ */
50
+ getDimension(path: string): SemanticDimension;
51
+ /**
52
+ * Normalize a path - remove trailing slashes, collapse multiple slashes
53
+ * PURE FUNCTION
54
+ */
55
+ private normalizePath;
56
+ /**
57
+ * Parse date string (YYYY-MM-DD) into Date object
58
+ * PURE FUNCTION
59
+ */
60
+ private parseDate;
61
+ /**
62
+ * Validate parsed path structure
63
+ */
64
+ validate(parsed: ParsedSemanticPath): boolean;
65
+ /**
66
+ * Parse relationship paths: /related-to/<path>/depth-N/types-X,Y/<subpath>
67
+ */
68
+ private parseRelationshipPath;
69
+ /**
70
+ * Parse similarity paths: /similar-to/<path>/threshold-N/<subpath>
71
+ */
72
+ private parseSimilarityPath;
73
+ }
@@ -0,0 +1,285 @@
1
+ /**
2
+ * Semantic Path Parser
3
+ *
4
+ * Parses semantic filesystem paths into structured queries
5
+ * PURE LOGIC - No external dependencies, no async operations
6
+ *
7
+ * Supported path formats:
8
+ * - Traditional: /src/auth.ts
9
+ * - By Concept: /by-concept/authentication/login.ts
10
+ * - By Author: /by-author/alice/file.ts
11
+ * - By Time: /as-of/2024-03-15/file.ts
12
+ * - By Relationship: /related-to/src/auth.ts/depth-2
13
+ * - By Similarity: /similar-to/src/auth.ts/threshold-0.8
14
+ * - By Tag: /by-tag/security/file.ts
15
+ */
16
+ /**
17
+ * Semantic Path Parser
18
+ * Parses various semantic path formats into structured data
19
+ */
20
+ export class SemanticPathParser {
21
+ /**
22
+ * Parse a path into semantic components
23
+ * PURE FUNCTION - no external calls, no async
24
+ */
25
+ parse(path) {
26
+ if (!path || typeof path !== 'string') {
27
+ throw new Error('Path must be a non-empty string');
28
+ }
29
+ // Normalize path
30
+ const normalized = this.normalizePath(path);
31
+ // Try concept dimension
32
+ const conceptMatch = normalized.match(SemanticPathParser.PATTERNS.concept);
33
+ if (conceptMatch) {
34
+ return {
35
+ dimension: 'concept',
36
+ value: conceptMatch[1],
37
+ subpath: conceptMatch[2]
38
+ };
39
+ }
40
+ // Try author dimension
41
+ const authorMatch = normalized.match(SemanticPathParser.PATTERNS.author);
42
+ if (authorMatch) {
43
+ return {
44
+ dimension: 'author',
45
+ value: authorMatch[1],
46
+ subpath: authorMatch[2]
47
+ };
48
+ }
49
+ // Try time dimension
50
+ const timeMatch = normalized.match(SemanticPathParser.PATTERNS.time);
51
+ if (timeMatch) {
52
+ const dateStr = timeMatch[1];
53
+ const date = this.parseDate(dateStr);
54
+ return {
55
+ dimension: 'time',
56
+ value: date,
57
+ subpath: timeMatch[2]
58
+ };
59
+ }
60
+ // Try relationship dimension
61
+ if (normalized.startsWith('/related-to/')) {
62
+ return this.parseRelationshipPath(normalized);
63
+ }
64
+ // Try similarity dimension
65
+ if (normalized.startsWith('/similar-to/')) {
66
+ return this.parseSimilarityPath(normalized);
67
+ }
68
+ // Try tag dimension
69
+ const tagMatch = normalized.match(SemanticPathParser.PATTERNS.tag);
70
+ if (tagMatch) {
71
+ return {
72
+ dimension: 'tag',
73
+ value: tagMatch[1],
74
+ subpath: tagMatch[2]
75
+ };
76
+ }
77
+ // Default to traditional path
78
+ return {
79
+ dimension: 'traditional',
80
+ value: normalized
81
+ };
82
+ }
83
+ /**
84
+ * Check if a path is semantic (non-traditional)
85
+ */
86
+ isSemanticPath(path) {
87
+ if (!path || typeof path !== 'string') {
88
+ return false;
89
+ }
90
+ const normalized = this.normalizePath(path);
91
+ // Check if matches any semantic pattern
92
+ return (normalized.startsWith('/by-concept/') ||
93
+ normalized.startsWith('/by-author/') ||
94
+ normalized.startsWith('/as-of/') ||
95
+ normalized.startsWith('/related-to/') ||
96
+ normalized.startsWith('/similar-to/') ||
97
+ normalized.startsWith('/by-tag/'));
98
+ }
99
+ /**
100
+ * Get the dimension type from a path
101
+ */
102
+ getDimension(path) {
103
+ return this.parse(path).dimension;
104
+ }
105
+ /**
106
+ * Normalize a path - remove trailing slashes, collapse multiple slashes
107
+ * PURE FUNCTION
108
+ */
109
+ normalizePath(path) {
110
+ // Remove trailing slash (except for root)
111
+ let normalized = path.replace(/\/+$/, '');
112
+ // Collapse multiple slashes
113
+ normalized = normalized.replace(/\/+/g, '/');
114
+ // Ensure starts with /
115
+ if (!normalized.startsWith('/')) {
116
+ normalized = '/' + normalized;
117
+ }
118
+ // Special case: empty path becomes /
119
+ if (normalized === '') {
120
+ normalized = '/';
121
+ }
122
+ return normalized;
123
+ }
124
+ /**
125
+ * Parse date string (YYYY-MM-DD) into Date object
126
+ * PURE FUNCTION
127
+ */
128
+ parseDate(dateStr) {
129
+ const parts = dateStr.split('-');
130
+ if (parts.length !== 3) {
131
+ throw new Error(`Invalid date format: ${dateStr}. Expected YYYY-MM-DD`);
132
+ }
133
+ const year = parseInt(parts[0], 10);
134
+ const month = parseInt(parts[1], 10) - 1; // Months are 0-indexed in JS
135
+ const day = parseInt(parts[2], 10);
136
+ if (isNaN(year) || isNaN(month) || isNaN(day)) {
137
+ throw new Error(`Invalid date format: ${dateStr}. Expected YYYY-MM-DD`);
138
+ }
139
+ if (year < 1900 || year > 2100) {
140
+ throw new Error(`Invalid year: ${year}. Expected 1900-2100`);
141
+ }
142
+ if (month < 0 || month > 11) {
143
+ throw new Error(`Invalid month: ${month + 1}. Expected 1-12`);
144
+ }
145
+ if (day < 1 || day > 31) {
146
+ throw new Error(`Invalid day: ${day}. Expected 1-31`);
147
+ }
148
+ return new Date(year, month, day);
149
+ }
150
+ /**
151
+ * Validate parsed path structure
152
+ */
153
+ validate(parsed) {
154
+ if (!parsed || typeof parsed !== 'object') {
155
+ return false;
156
+ }
157
+ if (!parsed.dimension) {
158
+ return false;
159
+ }
160
+ if (parsed.value === undefined || parsed.value === null) {
161
+ return false;
162
+ }
163
+ // Dimension-specific validation
164
+ switch (parsed.dimension) {
165
+ case 'time':
166
+ return parsed.value instanceof Date && !isNaN(parsed.value.getTime());
167
+ case 'relationship':
168
+ const relValue = parsed.value;
169
+ return typeof relValue.targetPath === 'string' && relValue.targetPath.length > 0;
170
+ case 'similar':
171
+ const simValue = parsed.value;
172
+ return typeof simValue.targetPath === 'string' && simValue.targetPath.length > 0;
173
+ default:
174
+ return typeof parsed.value === 'string' && parsed.value.length > 0;
175
+ }
176
+ }
177
+ /**
178
+ * Parse relationship paths: /related-to/<path>/depth-N/types-X,Y/<subpath>
179
+ */
180
+ parseRelationshipPath(path) {
181
+ // Remove /related-to/ prefix
182
+ const withoutPrefix = path.substring('/related-to/'.length);
183
+ // Split into segments
184
+ const segments = withoutPrefix.split('/');
185
+ let targetPath = '';
186
+ let depth;
187
+ let types;
188
+ let subpath;
189
+ let i = 0;
190
+ // Collect path segments until we hit depth-, types-, or end
191
+ while (i < segments.length) {
192
+ const segment = segments[i];
193
+ if (segment.startsWith('depth-')) {
194
+ depth = parseInt(segment.substring('depth-'.length), 10);
195
+ i++;
196
+ continue;
197
+ }
198
+ if (segment.startsWith('types-')) {
199
+ types = segment.substring('types-'.length).split(',');
200
+ i++;
201
+ continue;
202
+ }
203
+ // If we've already collected the target path and found depth/types,
204
+ // rest is subpath
205
+ if (targetPath && (depth !== undefined || types !== undefined)) {
206
+ subpath = segments.slice(i).join('/');
207
+ break;
208
+ }
209
+ // Add to target path
210
+ if (targetPath) {
211
+ targetPath += '/' + segment;
212
+ }
213
+ else {
214
+ targetPath = segment;
215
+ }
216
+ i++;
217
+ }
218
+ const value = {
219
+ targetPath,
220
+ depth,
221
+ relationshipTypes: types
222
+ };
223
+ return {
224
+ dimension: 'relationship',
225
+ value,
226
+ subpath
227
+ };
228
+ }
229
+ /**
230
+ * Parse similarity paths: /similar-to/<path>/threshold-N/<subpath>
231
+ */
232
+ parseSimilarityPath(path) {
233
+ // Remove /similar-to/ prefix
234
+ const withoutPrefix = path.substring('/similar-to/'.length);
235
+ // Split into segments
236
+ const segments = withoutPrefix.split('/');
237
+ let targetPath = '';
238
+ let threshold;
239
+ let subpath;
240
+ let i = 0;
241
+ // Collect path segments until we hit threshold- or end
242
+ while (i < segments.length) {
243
+ const segment = segments[i];
244
+ if (segment.startsWith('threshold-')) {
245
+ threshold = parseFloat(segment.substring('threshold-'.length));
246
+ i++;
247
+ // Rest is subpath
248
+ if (i < segments.length) {
249
+ subpath = segments.slice(i).join('/');
250
+ }
251
+ break;
252
+ }
253
+ // Add to target path
254
+ if (targetPath) {
255
+ targetPath += '/' + segment;
256
+ }
257
+ else {
258
+ targetPath = segment;
259
+ }
260
+ i++;
261
+ }
262
+ const value = {
263
+ targetPath,
264
+ threshold
265
+ };
266
+ return {
267
+ dimension: 'similar',
268
+ value,
269
+ subpath
270
+ };
271
+ }
272
+ }
273
+ // Regex patterns for each dimension
274
+ SemanticPathParser.PATTERNS = {
275
+ concept: /^\/by-concept\/([^\/]+)(?:\/(.+))?$/,
276
+ author: /^\/by-author\/([^\/]+)(?:\/(.+))?$/,
277
+ time: /^\/as-of\/(\d{4}-\d{2}-\d{2})(?:\/(.+))?$/,
278
+ // Relationship: /related-to/<path>/depth-N/types-X,Y/<subpath>
279
+ // Must handle paths with slashes, so capture everything before /depth- or /types-
280
+ relationship: /^\/related-to\/(.+?)(?:\/depth-(\d+)|\/types-([^\/]+)|\/(.+))*$/,
281
+ // Similarity: /similar-to/<path>/threshold-N/<subpath>
282
+ similar: /^\/similar-to\/(.+?)(?:\/threshold-([\d.]+)|\/(.+))*$/,
283
+ tag: /^\/by-tag\/([^\/]+)(?:\/(.+))?$/
284
+ };
285
+ //# sourceMappingURL=SemanticPathParser.js.map