@afterxleep/doc-bot 1.0.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.
@@ -0,0 +1,207 @@
1
+ const path = require('path');
2
+
3
+ class InferenceEngine {
4
+ constructor(documentationService, manifestLoader = null) {
5
+ this.docService = documentationService;
6
+ this.manifestLoader = manifestLoader;
7
+ }
8
+
9
+ async initialize() {
10
+ // Initialize any required data
11
+ }
12
+
13
+ async getRelevantDocumentation(context) {
14
+ try {
15
+ const globalRules = await this.docService.getGlobalRules();
16
+ const contextualDocs = await this.getContextualDocs(context);
17
+ const inferredDocs = await this.getInferredDocs(context);
18
+
19
+ const confidence = this.calculateConfidence(context, contextualDocs, inferredDocs);
20
+
21
+ return {
22
+ globalRules: globalRules || [],
23
+ contextualDocs,
24
+ inferredDocs,
25
+ confidence
26
+ };
27
+ } catch (error) {
28
+ console.error('Error getting relevant documentation:', error);
29
+ return {
30
+ globalRules: [],
31
+ contextualDocs: [],
32
+ inferredDocs: [],
33
+ confidence: 0
34
+ };
35
+ }
36
+ }
37
+
38
+ async getContextualDocs(context) {
39
+ const docs = [];
40
+
41
+ // Get docs based on file path
42
+ if (context.filePath) {
43
+ const pathDocs = await this.docService.getContextualDocs(context.filePath);
44
+ docs.push(...pathDocs);
45
+ }
46
+
47
+ return this.removeDuplicates(docs);
48
+ }
49
+
50
+ async getInferredDocs(context) {
51
+ const docs = [];
52
+
53
+ // Keyword-based inference
54
+ if (context.query) {
55
+ const keywordDocs = await this.getDocsByKeywords(context.query);
56
+ docs.push(...keywordDocs);
57
+ }
58
+
59
+ // Pattern-based inference
60
+ if (context.codeSnippet) {
61
+ const patternDocs = await this.getDocsByPatterns(context.codeSnippet);
62
+ docs.push(...patternDocs);
63
+ }
64
+
65
+ // File extension inference
66
+ if (context.filePath) {
67
+ const extensionDocs = await this.getDocsByFileExtension(context.filePath);
68
+ docs.push(...extensionDocs);
69
+ }
70
+
71
+ return this.removeDuplicates(docs);
72
+ }
73
+
74
+ async getDocsByKeywords(query) {
75
+ if (!this.manifestLoader) {
76
+ return [];
77
+ }
78
+
79
+ const manifest = await this.manifestLoader.load();
80
+ const keywords = manifest.inference?.keywords || {};
81
+
82
+ const docs = [];
83
+ const queryLower = query.toLowerCase();
84
+
85
+ for (const [keyword, docPaths] of Object.entries(keywords)) {
86
+ if (queryLower.includes(keyword.toLowerCase())) {
87
+ for (const docPath of docPaths) {
88
+ const doc = this.docService.getDocument(docPath);
89
+ if (doc) {
90
+ docs.push(doc);
91
+ }
92
+ }
93
+ }
94
+ }
95
+
96
+ return docs;
97
+ }
98
+
99
+ async getDocsByPatterns(codeSnippet) {
100
+ if (!this.manifestLoader) {
101
+ return [];
102
+ }
103
+
104
+ const manifest = await this.manifestLoader.load();
105
+ const patterns = manifest.inference?.patterns || {};
106
+
107
+ const docs = [];
108
+
109
+ for (const [pattern, docPaths] of Object.entries(patterns)) {
110
+ if (codeSnippet.includes(pattern)) {
111
+ for (const docPath of docPaths) {
112
+ const doc = this.docService.getDocument(docPath);
113
+ if (doc) {
114
+ docs.push(doc);
115
+ }
116
+ }
117
+ }
118
+ }
119
+
120
+ return docs;
121
+ }
122
+
123
+ async getDocsByFileExtension(filePath) {
124
+ const ext = path.extname(filePath).toLowerCase();
125
+ const docs = [];
126
+
127
+ // Common patterns for different file types
128
+ const extensionMappings = {
129
+ '.js': ['javascript', 'js', 'node'],
130
+ '.ts': ['typescript', 'ts', 'javascript'],
131
+ '.jsx': ['react', 'jsx', 'javascript'],
132
+ '.tsx': ['react', 'tsx', 'typescript'],
133
+ '.vue': ['vue', 'javascript'],
134
+ '.py': ['python', 'py'],
135
+ '.java': ['java'],
136
+ '.cpp': ['cpp', 'c++'],
137
+ '.c': ['c', 'cpp'],
138
+ '.cs': ['csharp', 'c#'],
139
+ '.rb': ['ruby'],
140
+ '.go': ['golang', 'go'],
141
+ '.rs': ['rust'],
142
+ '.php': ['php'],
143
+ '.swift': ['swift', 'ios', 'macos'],
144
+ '.kt': ['kotlin'],
145
+ '.scala': ['scala'],
146
+ '.md': ['markdown', 'documentation'],
147
+ '.css': ['css', 'styling'],
148
+ '.scss': ['sass', 'scss', 'css'],
149
+ '.html': ['html', 'web'],
150
+ '.json': ['json', 'config'],
151
+ '.yaml': ['yaml', 'config'],
152
+ '.yml': ['yaml', 'config'],
153
+ '.xml': ['xml'],
154
+ '.sql': ['sql', 'database'],
155
+ '.sh': ['bash', 'shell', 'script'],
156
+ '.dockerfile': ['docker', 'container'],
157
+ '.tf': ['terraform', 'infrastructure']
158
+ };
159
+
160
+ const keywords = extensionMappings[ext] || [];
161
+
162
+ for (const keyword of keywords) {
163
+ const keywordDocs = await this.docService.searchDocuments(keyword);
164
+ docs.push(...keywordDocs);
165
+ }
166
+
167
+ return docs;
168
+ }
169
+
170
+ calculateConfidence(context, contextualDocs, inferredDocs) {
171
+ let confidence = 0;
172
+
173
+ // Base confidence from context richness
174
+ if (context.query) confidence += 0.3;
175
+ if (context.filePath) confidence += 0.3;
176
+ if (context.codeSnippet) confidence += 0.2;
177
+
178
+ // Boost confidence based on number of matches
179
+ if (contextualDocs.length > 0) {
180
+ confidence += Math.min(contextualDocs.length * 0.1, 0.3);
181
+ }
182
+
183
+ if (inferredDocs.length > 0) {
184
+ confidence += Math.min(inferredDocs.length * 0.05, 0.2);
185
+ }
186
+
187
+ // Reduce confidence if no matches found
188
+ if (contextualDocs.length === 0 && inferredDocs.length === 0) {
189
+ confidence *= 0.5;
190
+ }
191
+
192
+ return Math.min(confidence, 1.0);
193
+ }
194
+
195
+ removeDuplicates(docs) {
196
+ const seen = new Set();
197
+ return docs.filter(doc => {
198
+ if (seen.has(doc.fileName)) {
199
+ return false;
200
+ }
201
+ seen.add(doc.fileName);
202
+ return true;
203
+ });
204
+ }
205
+ }
206
+
207
+ module.exports = { InferenceEngine };
@@ -0,0 +1,135 @@
1
+ const fs = require('fs-extra');
2
+ const path = require('path');
3
+
4
+ class ManifestLoader {
5
+ constructor(configPath) {
6
+ this.configPath = configPath;
7
+ this.manifest = null;
8
+ this.lastModified = null;
9
+ }
10
+
11
+ async load() {
12
+ try {
13
+ const stats = await fs.stat(this.configPath);
14
+
15
+ // Only reload if file has changed
16
+ if (this.manifest && this.lastModified && stats.mtime <= this.lastModified) {
17
+ return this.manifest;
18
+ }
19
+
20
+ const content = await fs.readFile(this.configPath, 'utf8');
21
+ this.manifest = JSON.parse(content);
22
+ this.lastModified = stats.mtime;
23
+
24
+ // Validate manifest structure
25
+ this.validateManifest();
26
+
27
+ return this.manifest;
28
+ } catch (error) {
29
+ if (error.code === 'ENOENT') {
30
+ // Create default manifest if file doesn't exist
31
+ this.manifest = this.createDefaultManifest();
32
+ await this.save();
33
+ return this.manifest;
34
+ }
35
+ throw new Error(`Failed to load manifest: ${error.message}`);
36
+ }
37
+ }
38
+
39
+ async reload() {
40
+ this.manifest = null;
41
+ this.lastModified = null;
42
+ return await this.load();
43
+ }
44
+
45
+ async save() {
46
+ if (!this.manifest) {
47
+ throw new Error('No manifest to save');
48
+ }
49
+
50
+ await fs.ensureDir(path.dirname(this.configPath));
51
+ await fs.writeJSON(this.configPath, this.manifest, { spaces: 2 });
52
+ }
53
+
54
+ validateManifest() {
55
+ if (!this.manifest) {
56
+ throw new Error('Manifest is null');
57
+ }
58
+
59
+ // Required fields
60
+ if (!this.manifest.name) {
61
+ this.manifest.name = 'Project Documentation';
62
+ }
63
+
64
+ if (!this.manifest.version) {
65
+ this.manifest.version = '1.0.0';
66
+ }
67
+
68
+ // Optional fields with defaults
69
+ if (!this.manifest.globalRules) {
70
+ this.manifest.globalRules = [];
71
+ }
72
+
73
+ if (!this.manifest.contextualRules) {
74
+ this.manifest.contextualRules = {};
75
+ }
76
+
77
+ if (!this.manifest.inference) {
78
+ this.manifest.inference = {
79
+ keywords: {},
80
+ patterns: {}
81
+ };
82
+ }
83
+
84
+ // Validate globalRules is array
85
+ if (!Array.isArray(this.manifest.globalRules)) {
86
+ throw new Error('globalRules must be an array');
87
+ }
88
+
89
+ // Validate contextualRules is object
90
+ if (typeof this.manifest.contextualRules !== 'object') {
91
+ throw new Error('contextualRules must be an object');
92
+ }
93
+
94
+ // Validate inference structure
95
+ if (!this.manifest.inference.keywords) {
96
+ this.manifest.inference.keywords = {};
97
+ }
98
+
99
+ if (!this.manifest.inference.patterns) {
100
+ this.manifest.inference.patterns = {};
101
+ }
102
+ }
103
+
104
+ createDefaultManifest() {
105
+ return {
106
+ name: 'Project Documentation',
107
+ version: '1.0.0',
108
+ description: 'AI-powered documentation',
109
+ globalRules: [],
110
+ contextualRules: {},
111
+ inference: {
112
+ keywords: {},
113
+ patterns: {}
114
+ }
115
+ };
116
+ }
117
+
118
+ getManifest() {
119
+ return this.manifest;
120
+ }
121
+
122
+ getGlobalRules() {
123
+ return this.manifest?.globalRules || [];
124
+ }
125
+
126
+ getContextualRules() {
127
+ return this.manifest?.contextualRules || {};
128
+ }
129
+
130
+ getInferenceConfig() {
131
+ return this.manifest?.inference || { keywords: {}, patterns: {} };
132
+ }
133
+ }
134
+
135
+ module.exports = { ManifestLoader };