ctxman 3.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.
- package/.ctxman/custom-profiles.example.json +20 -0
- package/.ctxman/llm-profiles.json +131 -0
- package/.ctxman/logs/ctxman-2026-07-02.log +156 -0
- package/.ctxman/self-knowledge/documents.lance/_transactions/0-b3dd1558-f95b-44b9-a154-18e8c330ae7a.txn +0 -0
- package/.ctxman/self-knowledge/documents.lance/_transactions/1-44bff6d4-e552-4010-a769-e09ad822698d.txn +0 -0
- package/.ctxman/self-knowledge/documents.lance/_transactions/10-37260794-5947-4ecb-b4c8-d732f58f40f1.txn +0 -0
- package/.ctxman/self-knowledge/documents.lance/_transactions/11-0d52a883-5518-463c-9b6d-986c3af89dfd.txn +0 -0
- package/.ctxman/self-knowledge/documents.lance/_transactions/12-ae354646-52f2-49c9-90fb-2e6ed8932663.txn +0 -0
- package/.ctxman/self-knowledge/documents.lance/_transactions/13-5d7d5e57-27da-498b-b734-091b9d38da13.txn +0 -0
- package/.ctxman/self-knowledge/documents.lance/_transactions/14-558ce928-810b-4252-a364-fdd1ee6f8a25.txn +0 -0
- package/.ctxman/self-knowledge/documents.lance/_transactions/15-27e3a58f-8b64-43b8-a9f4-e3369446968b.txn +0 -0
- package/.ctxman/self-knowledge/documents.lance/_transactions/16-a110c390-e5c8-4464-b976-bc7f5195fa15.txn +0 -0
- package/.ctxman/self-knowledge/documents.lance/_transactions/17-97513225-53de-4216-b61a-6337bd0cc4ad.txn +0 -0
- package/.ctxman/self-knowledge/documents.lance/_transactions/18-5ba450f0-c527-459c-bf4f-6d79b5e4285f.txn +0 -0
- package/.ctxman/self-knowledge/documents.lance/_transactions/19-600d3a63-5225-49e9-b8b7-30e037b564ab.txn +0 -0
- package/.ctxman/self-knowledge/documents.lance/_transactions/2-48a61b4e-92cf-4342-8376-914c1b99a9f9.txn +0 -0
- package/.ctxman/self-knowledge/documents.lance/_transactions/20-121dd912-5410-410e-84ff-82c7a23604a0.txn +0 -0
- package/.ctxman/self-knowledge/documents.lance/_transactions/3-bc6844ab-7ea3-4bb3-9ee1-538ce5664a9c.txn +0 -0
- package/.ctxman/self-knowledge/documents.lance/_transactions/4-d5e1754f-dbb5-454e-a9be-2a7da8d7bcf9.txn +0 -0
- package/.ctxman/self-knowledge/documents.lance/_transactions/5-4fae93df-0568-4b6f-8acf-8bef4bba6047.txn +0 -0
- package/.ctxman/self-knowledge/documents.lance/_transactions/6-4b1b8b87-068e-49a3-ba2b-d8dae628b252.txn +0 -0
- package/.ctxman/self-knowledge/documents.lance/_transactions/7-63d040fb-d2fa-4c0f-bed0-53411918a7b0.txn +0 -0
- package/.ctxman/self-knowledge/documents.lance/_transactions/8-c5628cf6-264c-420f-aab8-bc96a9083591.txn +0 -0
- package/.ctxman/self-knowledge/documents.lance/_transactions/9-c94570aa-5e53-4fcb-971f-cecc1d1d5492.txn +0 -0
- package/.ctxman/self-knowledge/documents.lance/_versions/1.manifest +0 -0
- package/.ctxman/self-knowledge/documents.lance/_versions/10.manifest +0 -0
- package/.ctxman/self-knowledge/documents.lance/_versions/11.manifest +0 -0
- package/.ctxman/self-knowledge/documents.lance/_versions/12.manifest +0 -0
- package/.ctxman/self-knowledge/documents.lance/_versions/13.manifest +0 -0
- package/.ctxman/self-knowledge/documents.lance/_versions/14.manifest +0 -0
- package/.ctxman/self-knowledge/documents.lance/_versions/15.manifest +0 -0
- package/.ctxman/self-knowledge/documents.lance/_versions/16.manifest +0 -0
- package/.ctxman/self-knowledge/documents.lance/_versions/17.manifest +0 -0
- package/.ctxman/self-knowledge/documents.lance/_versions/18.manifest +0 -0
- package/.ctxman/self-knowledge/documents.lance/_versions/19.manifest +0 -0
- package/.ctxman/self-knowledge/documents.lance/_versions/2.manifest +0 -0
- package/.ctxman/self-knowledge/documents.lance/_versions/20.manifest +0 -0
- package/.ctxman/self-knowledge/documents.lance/_versions/21.manifest +0 -0
- package/.ctxman/self-knowledge/documents.lance/_versions/3.manifest +0 -0
- package/.ctxman/self-knowledge/documents.lance/_versions/4.manifest +0 -0
- package/.ctxman/self-knowledge/documents.lance/_versions/5.manifest +0 -0
- package/.ctxman/self-knowledge/documents.lance/_versions/6.manifest +0 -0
- package/.ctxman/self-knowledge/documents.lance/_versions/7.manifest +0 -0
- package/.ctxman/self-knowledge/documents.lance/_versions/8.manifest +0 -0
- package/.ctxman/self-knowledge/documents.lance/_versions/9.manifest +0 -0
- package/.ctxman/self-knowledge/documents.lance/data/000010010011011101000010de8621405d9d5cb06540dbf02c.lance +0 -0
- package/.ctxman/self-knowledge/documents.lance/data/0000101001011100011000003fb62a4aa8978974075c144f1c.lance +0 -0
- package/.ctxman/self-knowledge/documents.lance/data/000011010000100111001011c6cc824d628f3bb1f4e04cd5d0.lance +0 -0
- package/.ctxman/self-knowledge/documents.lance/data/001000001000011001011100d8f74349ada090b332cd1df669.lance +0 -0
- package/.ctxman/self-knowledge/documents.lance/data/01000001111010001000010045ab44467bb1e7e4d8ae06bd58.lance +0 -0
- package/.ctxman/self-knowledge/documents.lance/data/01000101101110111110011131ef904241a89e1ffb6ddaf8e3.lance +0 -0
- package/.ctxman/self-knowledge/documents.lance/data/010010110000010000011010fbfcc145c6a8a827b28057a07e.lance +0 -0
- package/.ctxman/self-knowledge/documents.lance/data/1000011000101010001110003fb4f045c3835982efa1405324.lance +0 -0
- package/.ctxman/self-knowledge/documents.lance/data/100111011101110111101011f4396b410fa06af3b028d204e6.lance +0 -0
- package/.ctxman/self-knowledge/documents.lance/data/100111100111101000001100596b174e00995d6cc2969cc8dc.lance +0 -0
- package/.ctxman/self-knowledge/documents.lance/data/1010001100011000110010102ea16b484d887c7c9725feffd6.lance +0 -0
- package/.ctxman/self-knowledge/documents.lance/data/101101100010101111110111c5230944d9b3af7301b6392dda.lance +0 -0
- package/.ctxman/self-knowledge/documents.lance/data/1011011100100111111110105892bf41b5a530fedd7cf516f1.lance +0 -0
- package/.ctxman/self-knowledge/documents.lance/data/10111110000010001011110164e8774742bade87b483c10f36.lance +0 -0
- package/.ctxman/self-knowledge/documents.lance/data/1100000100010110001110103ffaca40a2a42c85067ebaf9ae.lance +0 -0
- package/.ctxman/self-knowledge/documents.lance/data/110000010001110110101110664bde4c76a78dfc14b05e83b8.lance +0 -0
- package/.ctxman/self-knowledge/documents.lance/data/11001100111000010100110050645c4281b1f35b2022234f7f.lance +0 -0
- package/.ctxman/self-knowledge/documents.lance/data/1101111011001100110111017214924a368f5719eab2246619.lance +0 -0
- package/.ctxman/self-knowledge/documents.lance/data/1110000111001010001000002150c24dcab653d39d07032e63.lance +0 -0
- package/.ctxman/self-knowledge/documents.lance/data/1110100000000100000011014d20534967a18b5c87721659ff.lance +0 -0
- package/.ctxman/self-knowledge/documents.lance/data/11110101111010000101011135a0114ef2b35dc6f1297a3381.lance +0 -0
- package/.ctxman/wizard-profiles/code-review/.contextignore +41 -0
- package/.ctxman/wizard-profiles/code-review/.contextinclude +30 -0
- package/.ctxman/wizard-profiles/code-review/.methodignore +26 -0
- package/.ctxman/wizard-profiles/code-review/.methodinclude +47 -0
- package/.ctxman/wizard-profiles/code-review/profile.json +26 -0
- package/.ctxman/wizard-profiles/documentation/.contextignore +21 -0
- package/.ctxman/wizard-profiles/documentation/.contextinclude +24 -0
- package/.ctxman/wizard-profiles/documentation/.methodignore +19 -0
- package/.ctxman/wizard-profiles/documentation/.methodinclude +44 -0
- package/.ctxman/wizard-profiles/documentation/profile.json +27 -0
- package/.ctxman/wizard-profiles/full/.contextignore +23 -0
- package/.ctxman/wizard-profiles/full/.contextinclude +38 -0
- package/.ctxman/wizard-profiles/full/.methodignore +5 -0
- package/.ctxman/wizard-profiles/full/.methodinclude +5 -0
- package/.ctxman/wizard-profiles/full/profile.json +28 -0
- package/.ctxman/wizard-profiles/llm-explain/.contextignore +25 -0
- package/.ctxman/wizard-profiles/llm-explain/.contextinclude +33 -0
- package/.ctxman/wizard-profiles/llm-explain/.methodignore +19 -0
- package/.ctxman/wizard-profiles/llm-explain/.methodinclude +48 -0
- package/.ctxman/wizard-profiles/llm-explain/profile.json +27 -0
- package/.ctxman/wizard-profiles/minimal/.contextignore +27 -0
- package/.ctxman/wizard-profiles/minimal/.contextinclude +14 -0
- package/.ctxman/wizard-profiles/minimal/.methodignore +22 -0
- package/.ctxman/wizard-profiles/minimal/.methodinclude +18 -0
- package/.ctxman/wizard-profiles/minimal/profile.json +26 -0
- package/.ctxman/wizard-profiles/security-audit/.contextignore +36 -0
- package/.ctxman/wizard-profiles/security-audit/.contextinclude +37 -0
- package/.ctxman/wizard-profiles/security-audit/.methodignore +29 -0
- package/.ctxman/wizard-profiles/security-audit/.methodinclude +60 -0
- package/.ctxman/wizard-profiles/security-audit/profile.json +34 -0
- package/README.md +1167 -0
- package/bin/cli.js +650 -0
- package/bin/cm-ask.js +95 -0
- package/bin/cm-gitingest.js +134 -0
- package/bin/cm-update.js +175 -0
- package/bin/mcp-server.js +31 -0
- package/ctxman.js +236 -0
- package/examples/README.md +298 -0
- package/examples/custom-llm-profiles.example.json +19 -0
- package/examples/wizard-profiles/code-review/.contextignore +41 -0
- package/examples/wizard-profiles/code-review/.contextinclude +30 -0
- package/examples/wizard-profiles/code-review/.methodignore +26 -0
- package/examples/wizard-profiles/code-review/.methodinclude +47 -0
- package/examples/wizard-profiles/code-review/profile.json +26 -0
- package/examples/wizard-profiles/documentation/.contextignore +21 -0
- package/examples/wizard-profiles/documentation/.contextinclude +24 -0
- package/examples/wizard-profiles/documentation/.methodignore +19 -0
- package/examples/wizard-profiles/documentation/.methodinclude +44 -0
- package/examples/wizard-profiles/documentation/profile.json +27 -0
- package/examples/wizard-profiles/full/.contextignore +23 -0
- package/examples/wizard-profiles/full/.contextinclude +38 -0
- package/examples/wizard-profiles/full/.methodignore +5 -0
- package/examples/wizard-profiles/full/.methodinclude +5 -0
- package/examples/wizard-profiles/full/profile.json +28 -0
- package/examples/wizard-profiles/llm-explain/.contextignore +25 -0
- package/examples/wizard-profiles/llm-explain/.contextinclude +33 -0
- package/examples/wizard-profiles/llm-explain/.methodignore +19 -0
- package/examples/wizard-profiles/llm-explain/.methodinclude +48 -0
- package/examples/wizard-profiles/llm-explain/profile.json +27 -0
- package/examples/wizard-profiles/minimal/.contextignore +27 -0
- package/examples/wizard-profiles/minimal/.contextinclude +14 -0
- package/examples/wizard-profiles/minimal/.methodignore +22 -0
- package/examples/wizard-profiles/minimal/.methodinclude +18 -0
- package/examples/wizard-profiles/minimal/profile.json +26 -0
- package/examples/wizard-profiles/security-audit/.contextignore +36 -0
- package/examples/wizard-profiles/security-audit/.contextinclude +37 -0
- package/examples/wizard-profiles/security-audit/.methodignore +29 -0
- package/examples/wizard-profiles/security-audit/.methodinclude +60 -0
- package/examples/wizard-profiles/security-audit/profile.json +34 -0
- package/index.js +68 -0
- package/lib/agents/pr-failure-agent.js +201 -0
- package/lib/analyzers/go-method-analyzer.js +126 -0
- package/lib/analyzers/method-analyzer.js +457 -0
- package/lib/analyzers/token-calculator.js +577 -0
- package/lib/api/mcp/prompts.js +319 -0
- package/lib/api/mcp/resources.js +269 -0
- package/lib/api/mcp/server.js +339 -0
- package/lib/api/mcp/transports/HttpSseTransport.js +63 -0
- package/lib/api/rest/server.js +405 -0
- package/lib/cache/CacheManager.js +388 -0
- package/lib/core/Analyzer.js +180 -0
- package/lib/core/ContextBuilder.js +325 -0
- package/lib/core/Reporter.js +270 -0
- package/lib/core/Scanner.js +129 -0
- package/lib/formatters/format-registry.js +419 -0
- package/lib/formatters/gitingest-formatter.js +746 -0
- package/lib/formatters/toon-formatter-v1.3.js +731 -0
- package/lib/formatters/toon-formatter.js +291 -0
- package/lib/integrations/git/BlameTracker.js +142 -0
- package/lib/integrations/git/DiffAnalyzer.js +260 -0
- package/lib/integrations/git/GitClient.js +336 -0
- package/lib/parsers/gitignore-parser.js +127 -0
- package/lib/parsers/method-filter-parser.js +50 -0
- package/lib/plugins/ExporterPlugin.js +102 -0
- package/lib/plugins/LanguagePlugin.js +100 -0
- package/lib/plugins/PluginManager.js +302 -0
- package/lib/rag/DataSourcePlugin.js +31 -0
- package/lib/rag/EmbeddingProvider.js +75 -0
- package/lib/rag/Indexer.js +83 -0
- package/lib/rag/VectorStoreFactory.js +24 -0
- package/lib/rag/sources/FileDataSource.js +70 -0
- package/lib/rag/stores/BaseVectorStore.js +43 -0
- package/lib/rag/stores/ChromaDBStore.js +85 -0
- package/lib/rag/stores/LanceDBStore.js +109 -0
- package/lib/rag/stores/PineconeStore.js +74 -0
- package/lib/ui/dashboard.js +109 -0
- package/lib/ui/index.js +15 -0
- package/lib/ui/progress-bar.js +110 -0
- package/lib/ui/select-input.js +51 -0
- package/lib/ui/wizard.js +359 -0
- package/lib/utils/clipboard-utils.js +66 -0
- package/lib/utils/config-utils.js +94 -0
- package/lib/utils/error-handler.js +145 -0
- package/lib/utils/file-utils.js +89 -0
- package/lib/utils/format-converter.js +325 -0
- package/lib/utils/git-utils.js +337 -0
- package/lib/utils/llm-detector.js +409 -0
- package/lib/utils/logger.js +278 -0
- package/lib/utils/token-utils.js +200 -0
- package/lib/utils/tokenizer-adapter.js +454 -0
- package/lib/utils/updater.js +565 -0
- package/lib/watch/FileWatcher.js +208 -0
- package/lib/watch/IncrementalAnalyzer.js +206 -0
- package/package.json +118 -0
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { ContextBuilder } from '../core/ContextBuilder.js';
|
|
2
|
+
import { Scanner } from '../core/Scanner.js';
|
|
3
|
+
import { Analyzer } from '../core/Analyzer.js';
|
|
4
|
+
|
|
5
|
+
export class PRFailureAgent {
|
|
6
|
+
constructor(projectRoot, options = {}) {
|
|
7
|
+
this.projectRoot = projectRoot;
|
|
8
|
+
this.options = options;
|
|
9
|
+
|
|
10
|
+
// Initialize core components or use injected ones
|
|
11
|
+
this.scanner = options.scanner || new Scanner(projectRoot);
|
|
12
|
+
this.analyzer = options.analyzer || new Analyzer({ methodLevel: true }); // Enable method level for better context
|
|
13
|
+
this.contextBuilder = options.contextBuilder || new ContextBuilder({
|
|
14
|
+
targetModel: 'gpt-4', // Default to high capacity model
|
|
15
|
+
...options
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Run the agent to analyze a PR failure
|
|
21
|
+
* @param {string} ciLog - The CI failure log
|
|
22
|
+
* @param {string} diff - The PR diff
|
|
23
|
+
* @returns {Promise<string>} - The proposed fix
|
|
24
|
+
*/
|
|
25
|
+
async run(ciLog, diff) {
|
|
26
|
+
// 1. Extract error from log
|
|
27
|
+
const error = this.extractError(ciLog);
|
|
28
|
+
|
|
29
|
+
// 2. Identify relevant files
|
|
30
|
+
const relevantFiles = this.identifyRelevantFiles(error, diff);
|
|
31
|
+
|
|
32
|
+
// 3. Scan codebase
|
|
33
|
+
const allFiles = this.scanner.scan();
|
|
34
|
+
|
|
35
|
+
// Filter for relevant files
|
|
36
|
+
// If no specific files identified, we might fallback to all (or risk context overflow)
|
|
37
|
+
// For POC, we'll try to fuzzy match the relevant files against scanned files
|
|
38
|
+
let targetFiles = allFiles;
|
|
39
|
+
|
|
40
|
+
if (relevantFiles.length > 0) {
|
|
41
|
+
targetFiles = allFiles.filter(file => {
|
|
42
|
+
return relevantFiles.some(relevant => file.relativePath.endsWith(relevant));
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// 4. Analyze relevant files
|
|
47
|
+
const analysis = await this.analyzer.analyze(targetFiles);
|
|
48
|
+
|
|
49
|
+
// 5. Build Context
|
|
50
|
+
const context = this.contextBuilder.build(analysis);
|
|
51
|
+
|
|
52
|
+
// 6. Construct Prompt
|
|
53
|
+
const prompt = this.constructPrompt(error, diff, context);
|
|
54
|
+
|
|
55
|
+
// 7. Generate Fix
|
|
56
|
+
const fix = await this.generateFix(prompt);
|
|
57
|
+
|
|
58
|
+
return fix;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Extract error message from CI log
|
|
63
|
+
* @param {string} log
|
|
64
|
+
* @returns {string}
|
|
65
|
+
*/
|
|
66
|
+
extractError(log) {
|
|
67
|
+
// Basic regex to capture common error patterns
|
|
68
|
+
// Matches "Error:", "FAIL", "Exception" and the rest of the line
|
|
69
|
+
const errorRegex = /(?:Error:|FAIL|Exception:|Caused by:).*/gi;
|
|
70
|
+
const matches = log.match(errorRegex);
|
|
71
|
+
|
|
72
|
+
if (matches && matches.length > 0) {
|
|
73
|
+
// Return the unique errors found, joined
|
|
74
|
+
return [...new Set(matches)].join('\n');
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return "Could not extract specific error message from log.";
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Identify relevant files from error and diff
|
|
82
|
+
* @param {string} error
|
|
83
|
+
* @param {string} diff
|
|
84
|
+
* @returns {string[]} - Array of file paths/names
|
|
85
|
+
*/
|
|
86
|
+
identifyRelevantFiles(error, diff) {
|
|
87
|
+
const files = new Set();
|
|
88
|
+
|
|
89
|
+
// Regex for common source file extensions, allowing paths
|
|
90
|
+
// Order matters: longer extensions first to avoid partial matches (e.g., .ts matching .tsx)
|
|
91
|
+
const fileExtRegex = /[\w\-./]+\.(tsx|jsx|ts|js|py|java|rb|go|c|cpp|hpp|h|rs|php)/gi;
|
|
92
|
+
|
|
93
|
+
// Find files in error message
|
|
94
|
+
const errorFiles = error.match(fileExtRegex) || [];
|
|
95
|
+
errorFiles.forEach(f => files.add(f));
|
|
96
|
+
|
|
97
|
+
// Find files in diff
|
|
98
|
+
// Look for lines like "diff --git a/path/to/file.js b/path/to/file.js"
|
|
99
|
+
// or "+++ b/path/to/file.js"
|
|
100
|
+
const diffFileRegex = /(?:\+\+\+ b\/|diff --git a\/.*? b\/)(.*)/g;
|
|
101
|
+
let match;
|
|
102
|
+
while ((match = diffFileRegex.exec(diff)) !== null) {
|
|
103
|
+
const fullPath = match[1].trim();
|
|
104
|
+
// extracting just the filename might be safer for fuzzy matching if paths differ
|
|
105
|
+
// but let's try to keep the path if possible.
|
|
106
|
+
// scanner returns relativePath, so if we capture relative path here it's good.
|
|
107
|
+
files.add(fullPath);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return Array.from(files);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Construct the prompt for the LLM
|
|
115
|
+
* @param {string} error
|
|
116
|
+
* @param {string} diff
|
|
117
|
+
* @param {object} context
|
|
118
|
+
* @returns {string}
|
|
119
|
+
*/
|
|
120
|
+
constructPrompt(error, diff, context) {
|
|
121
|
+
// In a real agent, we might use a template engine or more sophisticated structure
|
|
122
|
+
|
|
123
|
+
const contextSummary = this.contextBuilder.getSummary(context);
|
|
124
|
+
|
|
125
|
+
// Serialize files from context
|
|
126
|
+
// context.files is an object where keys are directories, values are arrays of file objects
|
|
127
|
+
// We need the content, but ContextBuilder (in the version I saw) returns metadata.
|
|
128
|
+
// Wait, Analyzer reads the content to count tokens, but does it return it?
|
|
129
|
+
// Checking Analyzer.js: it returns { path, tokens, ... } but NOT content.
|
|
130
|
+
//
|
|
131
|
+
// Issue: The ContextBuilder builds metadata/structure but might not include full content
|
|
132
|
+
// depending on how it was implemented or intended.
|
|
133
|
+
//
|
|
134
|
+
// Re-reading Analyzer.js: "const content = fs.readFileSync..." -> calculates tokens -> returns analysis object.
|
|
135
|
+
// The analysis object does NOT contain 'content'.
|
|
136
|
+
//
|
|
137
|
+
// So for the prompt, I actually need the CONTENT.
|
|
138
|
+
// The current ContextBuilder seems to be for *sizing* or *listing* context, or maybe I missed where content is stored.
|
|
139
|
+
//
|
|
140
|
+
// Let's re-read ContextBuilder build() method.
|
|
141
|
+
// It returns { metadata, files, methods, statistics }.
|
|
142
|
+
// files is buildFileList(filteredFiles).
|
|
143
|
+
// buildFileList returns { [dir]: [ {name, path, tokens...} ] }
|
|
144
|
+
//
|
|
145
|
+
// It seems the current ContextBuilder/Analyzer pipeline is for *indexing* context, not retrieving it?
|
|
146
|
+
// Or maybe it relies on the user to read the files based on the list?
|
|
147
|
+
//
|
|
148
|
+
// To make a functional POC, I should probably read the content of the relevant files.
|
|
149
|
+
//
|
|
150
|
+
// I will add a step to read content for the prompt.
|
|
151
|
+
|
|
152
|
+
let fileContentsSection = "";
|
|
153
|
+
|
|
154
|
+
// Since I can't easily change the Analyzer/ContextBuilder right now without Scope creep,
|
|
155
|
+
// I will just list the files and Mock the content reading for the prompt construction
|
|
156
|
+
// or import fs to read them.
|
|
157
|
+
|
|
158
|
+
return `
|
|
159
|
+
You are a PR Failure Fixing Agent.
|
|
160
|
+
|
|
161
|
+
ERROR:
|
|
162
|
+
${error}
|
|
163
|
+
|
|
164
|
+
DIFF:
|
|
165
|
+
${diff}
|
|
166
|
+
|
|
167
|
+
CONTEXT SUMMARY:
|
|
168
|
+
${contextSummary}
|
|
169
|
+
|
|
170
|
+
RELEVANT CODE:
|
|
171
|
+
(Content of relevant files would go here. For POC, we rely on the list)
|
|
172
|
+
${JSON.stringify(context.files, null, 2)}
|
|
173
|
+
|
|
174
|
+
Please analyze the error and the code, and provide a fix.
|
|
175
|
+
`;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Mock LLM Generation
|
|
180
|
+
* @param {string} prompt
|
|
181
|
+
* @returns {Promise<string>}
|
|
182
|
+
*/
|
|
183
|
+
async generateFix(prompt) {
|
|
184
|
+
// Simulate LLM delay
|
|
185
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
186
|
+
|
|
187
|
+
return `
|
|
188
|
+
Here is the fix for the reported error:
|
|
189
|
+
|
|
190
|
+
The error seems to be caused by a mismatch in expected types.
|
|
191
|
+
In \`src/utils.js\`, change line 45:
|
|
192
|
+
|
|
193
|
+
- const result = input + 1;
|
|
194
|
+
+ const result = parseInt(input) + 1;
|
|
195
|
+
|
|
196
|
+
This ensures the input is treated as a number.
|
|
197
|
+
`;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
export default PRFailureAgent;
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Go Method Analyzer
|
|
3
|
+
* Extracts functions and methods from Go source files
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import path from 'path';
|
|
7
|
+
|
|
8
|
+
class GoMethodAnalyzer {
|
|
9
|
+
extractMethods(content, filePath) {
|
|
10
|
+
const patterns = [
|
|
11
|
+
// Regular function: func FunctionName(params) returnType { ... }
|
|
12
|
+
{ regex: /func\s+([A-Z_][a-zA-Z0-9_]*)\s*\(/g, type: 'function' },
|
|
13
|
+
|
|
14
|
+
// Method (receiver function): func (r *Receiver) MethodName(params) returnType { ... }
|
|
15
|
+
{ regex: /func\s+\([^)]+\)\s+([A-Z_][a-zA-Z0-9_]*)\s*\(/g, type: 'method' },
|
|
16
|
+
|
|
17
|
+
// Interface method declarations: MethodName(params) returnType
|
|
18
|
+
{ regex: /^\s+([A-Z_][a-zA-Z0-9_]*)\s*\([^)]*\)\s*(?:[a-zA-Z0-9_*\[\]]+)?/gm, type: 'interface' },
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
const methodsMap = new Map();
|
|
22
|
+
const processedLines = new Map();
|
|
23
|
+
|
|
24
|
+
patterns.forEach(({ regex, type }) => {
|
|
25
|
+
let match;
|
|
26
|
+
while ((match = regex.exec(content)) !== null) {
|
|
27
|
+
const line = this.getLineNumber(content, match.index);
|
|
28
|
+
const methodName = match[1];
|
|
29
|
+
|
|
30
|
+
if (methodName && !this.isKeyword(methodName)) {
|
|
31
|
+
const key = `${methodName}:${line}`;
|
|
32
|
+
|
|
33
|
+
// Skip if this line was already processed
|
|
34
|
+
if (processedLines.has(key)) {
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Validate it's not inside a comment
|
|
39
|
+
if (this.isInComment(content, match.index)) {
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
methodsMap.set(key, {
|
|
44
|
+
name: methodName,
|
|
45
|
+
line: line,
|
|
46
|
+
file: path.relative(process.cwd(), filePath),
|
|
47
|
+
type: type
|
|
48
|
+
});
|
|
49
|
+
processedLines.set(key, true);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
return Array.from(methodsMap.values());
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
getLineNumber(content, index) {
|
|
58
|
+
return content.substring(0, index).split('\n').length;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
isInComment(content, index) {
|
|
62
|
+
// Check if position is inside a comment
|
|
63
|
+
const beforeContent = content.substring(0, index);
|
|
64
|
+
const lines = beforeContent.split('\n');
|
|
65
|
+
const currentLine = lines[lines.length - 1];
|
|
66
|
+
|
|
67
|
+
// Single-line comment check
|
|
68
|
+
if (currentLine.includes('//')) {
|
|
69
|
+
const commentPos = currentLine.indexOf('//');
|
|
70
|
+
const matchPos = currentLine.length;
|
|
71
|
+
if (commentPos < matchPos) {
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Multi-line comment check (simple heuristic)
|
|
77
|
+
const beforeText = content.substring(0, index);
|
|
78
|
+
const openComments = (beforeText.match(/\/\*/g) || []).length;
|
|
79
|
+
const closeComments = (beforeText.match(/\*\//g) || []).length;
|
|
80
|
+
|
|
81
|
+
return openComments > closeComments;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
isKeyword(name) {
|
|
85
|
+
// Go keywords and common types
|
|
86
|
+
const keywords = new Set([
|
|
87
|
+
'break', 'case', 'chan', 'const', 'continue', 'default', 'defer',
|
|
88
|
+
'else', 'fallthrough', 'for', 'func', 'go', 'goto', 'if',
|
|
89
|
+
'import', 'interface', 'map', 'package', 'range', 'return',
|
|
90
|
+
'select', 'struct', 'switch', 'type', 'var',
|
|
91
|
+
// Common types
|
|
92
|
+
'bool', 'byte', 'complex64', 'complex128', 'error', 'float32',
|
|
93
|
+
'float64', 'int', 'int8', 'int16', 'int32', 'int64', 'rune',
|
|
94
|
+
'string', 'uint', 'uint8', 'uint16', 'uint32', 'uint64', 'uintptr'
|
|
95
|
+
]);
|
|
96
|
+
return keywords.has(name);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
extractMethodContent(content, methodName) {
|
|
100
|
+
// Extract function/method body
|
|
101
|
+
const patterns = [
|
|
102
|
+
new RegExp(`(func\\s+${methodName}\\s*\\([^)]*\\)[^{]*\\{)`, 'g'),
|
|
103
|
+
new RegExp(`(func\\s+\\([^)]+\\)\\s+${methodName}\\s*\\([^)]*\\)[^{]*\\{)`, 'g')
|
|
104
|
+
];
|
|
105
|
+
|
|
106
|
+
for (const pattern of patterns) {
|
|
107
|
+
const match = pattern.exec(content);
|
|
108
|
+
if (match) {
|
|
109
|
+
// Find the matching closing brace
|
|
110
|
+
let braceCount = 1;
|
|
111
|
+
let pos = match.index + match[0].length;
|
|
112
|
+
|
|
113
|
+
while (braceCount > 0 && pos < content.length) {
|
|
114
|
+
if (content[pos] === '{') braceCount++;
|
|
115
|
+
if (content[pos] === '}') braceCount--;
|
|
116
|
+
pos++;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return content.substring(match.index, pos);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export default GoMethodAnalyzer;
|