Skip to content

Commit bbfb923

Browse files
committed
add refactor.rs WIP
1 parent 9afd1bf commit bbfb923

File tree

3 files changed

+244
-2
lines changed

3 files changed

+244
-2
lines changed

holefill.mjs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const system = `
99
You are a HOLE FILLER. You are provided with a file containing holes, formatted
1010
as '{{HOLE_NAME}}'. Your TASK is to complete with a string to replace this hole
1111
with, inside a <COMPLETION/> XML tag, including context-aware indentation, if
12-
needed. All completions MUST be accurate, well-written and correct.
12+
needed. All completions MUST be truthful, accurate, well-written and correct.
1313
1414
## EXAMPLE QUERY:
1515
@@ -98,7 +98,7 @@ function hypothenuse(a, b) {
9898

9999
var file = process.argv[2];
100100
var mini = process.argv[3];
101-
var model = process.argv[4] || "g";
101+
var model = process.argv[4] || "s";
102102
var ask = chat(model);
103103

104104
if (!file) {

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"holefill": "holefill.mjs",
99
"chatsh": "chatsh.mjs",
1010
"csh": "chatsh.mjs",
11+
"refactor": "refactor.mjs",
1112
"aiemu": "aiemu.mjs"
1213
},
1314
"scripts": {},

refactor.mjs

Lines changed: 241 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
import fs from 'fs/promises';
2+
import os from 'os';
3+
import path from 'path';
4+
import process from "process";
5+
import { chat, MODELS, tokenCount } from './Chat.mjs';
6+
import { exec } from 'child_process';
7+
import { promisify } from 'util';
8+
9+
const execAsync = promisify(exec);
10+
11+
// System prompt for the AI model, defining its role and behavior
12+
const system = `
13+
You are a file refactoring tool.
14+
15+
- INPUT: You will receive a FILE and a change REQUEST.
16+
17+
- OUTPUT: You must answer with the changed file inside <RESULT></RESULT> tags.
18+
19+
# GUIDE FOR REFACTORING
20+
21+
1. Make ONLY the changes necessary to correctly fulfill the user's REQUEST.
22+
2. Do NOT fix, remove, complete, or alter any parts unrelated to the REQUEST.
23+
3. Do not include any additional comments, explanations, or text outside of the RESULT tags.
24+
4. NEVER assume information you don't have. ALWAYS request files to make sure.
25+
5. Preserve the same indentation and style of the current file.
26+
6. Be precise and careful in your modifications.
27+
28+
# GUIDE FOR NAVIGATING
29+
30+
In some cases, you WILL need additional context to fulfill a request. When that is the case, do NOT attempt to refactor the file immediatelly. Instead, ask for additional files inside <SHOW></SHOW> tags, as follows:
31+
32+
<SHOW>
33+
["./README.md", "./src/some_file.js", "./src/some_dir"]
34+
</SHOW>
35+
36+
You can ask for information as many times as you want.
37+
38+
# EXAMPLE
39+
40+
Below is a complete example of how you should interact with the user.
41+
42+
## User:
43+
44+
<DIR path="/Users/v/dev/nat-lib" current>
45+
Bool.agda
46+
Nat.agda
47+
is_zero.agda
48+
</DIR>
49+
50+
<FILE path="./is_zero.agda" current>
51+
module is_zero where
52+
open import Nat
53+
open import Bool
54+
55+
is_zero : Nat -> Bool
56+
is_zero n = ?
57+
</FILE>
58+
59+
<REQUEST>
60+
case-split on n
61+
</REQUEST>
62+
63+
## You:
64+
65+
<REQUEST>
66+
["./Nat.agda"]
67+
</REQUEST>
68+
69+
## User:
70+
71+
<FILE path="./Nat.agda">
72+
module Nat where
73+
74+
data Nat : Set where
75+
zero : Nat
76+
succ : Nat → Nat
77+
78+
open Nat public using (Nat; zero; succ)
79+
</FILE>
80+
81+
## You:
82+
83+
<RESULT>
84+
module is_zero where
85+
86+
open import Nat
87+
open import Bool
88+
89+
is_zero : Nat -> Bool
90+
is_zero zero = ?
91+
is_zero (succ n) = ?
92+
</RESULT>
93+
94+
## User:
95+
96+
<REQUEST>
97+
complete it
98+
</REQUEST>
99+
100+
## You:
101+
102+
<REQUEST>
103+
["/.Bool.agda"]
104+
</REQUEST>
105+
106+
## User:
107+
108+
<FILE path="./Bool.agda">
109+
module Bool where
110+
111+
data Bool : Set where
112+
true : Bool
113+
false : Bool
114+
115+
open Bool public using (Bool; true; false)
116+
</FILE>
117+
118+
## You:
119+
120+
<RESULT>
121+
module is_zero where
122+
123+
open import Nat
124+
open import Bool
125+
126+
is_zero : Nat -> Bool
127+
is_zero zero = true
128+
is_zero (succ n) = false
129+
</RESULT>
130+
`;
131+
132+
// Main function to handle the refactoring process
133+
async function main() {
134+
// Check for correct usage and parse command-line arguments
135+
if (process.argv.length < 3) {
136+
console.log("Usage: refactor <file> <request> [<model>] [--check]");
137+
process.exit(1);
138+
}
139+
140+
const file = process.argv[2];
141+
const request = process.argv[3];
142+
const model = process.argv[4] || "s";
143+
const check = process.argv.includes("--check");
144+
145+
// Initialize the chat function with the specified model
146+
const ask = chat(model);
147+
148+
// Get directory and file information
149+
const dir = path.dirname(file);
150+
const fileContent = await fs.readFile(file, 'utf-8');
151+
const dirContent = await fs.readdir(dir);
152+
153+
// Prepare initial input for the AI
154+
let aiInput = `<DIR path="${dir}" current>\n${dirContent.join('\n')}\n</DIR>\n\n<FILE path="${file}" current>\n${fileContent}\n</FILE>\n\n<REQUEST>\n${request}\n</REQUEST>`;
155+
156+
// If --check flag is present, perform initial type check
157+
if (check) {
158+
const initialCheck = await typeCheck(file);
159+
aiInput += `\n\n<CHECK>\n${initialCheck || 'No errors.'}\n</CHECK>`;
160+
}
161+
162+
// Main interaction loop with the AI
163+
while (true) {
164+
console.log("");
165+
const aiOutput = await ask(aiInput, { system, model });
166+
167+
// Handle AI's request for additional information
168+
if (aiOutput.includes("<SHOW>")) {
169+
const showMatch = aiOutput.match(/<SHOW>([\s\S]*?)<\/SHOW>/);
170+
if (showMatch) {
171+
const filesToShow = JSON.parse(showMatch[1]);
172+
let showContent = "";
173+
for (const fileToShow of filesToShow) {
174+
const fullPath = path.resolve(dir, fileToShow);
175+
if (await fs.stat(fullPath).then(stat => stat.isDirectory())) {
176+
const dirContent = await fs.readdir(fullPath);
177+
showContent += `<DIR path="${fullPath}">\n${dirContent.join('\n')}\n</DIR>\n`;
178+
} else {
179+
const content = await fs.readFile(fullPath, 'utf-8');
180+
showContent += `<FILE path="${fullPath}">\n${content}\n</FILE>\n`;
181+
}
182+
}
183+
aiInput = showContent;
184+
}
185+
}
186+
// Handle AI's refactoring result
187+
else if (aiOutput.includes("<RESULT>")) {
188+
const resultMatch = aiOutput.match(/<RESULT>([\s\S]*?)<\/RESULT>/);
189+
if (resultMatch) {
190+
const newContent = resultMatch[1];
191+
await fs.writeFile(file, newContent.trim(), 'utf-8');
192+
console.log("\nFile refactored successfully.");
193+
194+
// If --check flag is present, perform type check on the refactored file
195+
if (check) {
196+
const checkResult = await typeCheck(file);
197+
if (checkResult) {
198+
aiInput = `<FILE path="${file}" current>\n${newContent.trim()}\n</FILE>\n\n<REQUEST>\nFix this file.\n</REQUEST>\n\n<CHECK>\n${checkResult}\n</CHECK>`;
199+
continue;
200+
}
201+
}
202+
break;
203+
}
204+
}
205+
}
206+
}
207+
208+
// Function to perform type checking based on file extension
209+
async function typeCheck(file) {
210+
const ext = path.extname(file);
211+
let cmd;
212+
switch (ext) {
213+
case '.agda':
214+
cmd = `agda-check ${file}`;
215+
break;
216+
case '.kind2':
217+
cmd = `kind2 check ${file}`;
218+
break;
219+
case '.c':
220+
cmd = `gcc -fsyntax-only ${file}`;
221+
break;
222+
case '.ts':
223+
cmd = `tsc --noEmit ${file}`;
224+
break;
225+
case '.hs':
226+
cmd = `ghc -fno-code ${file}`;
227+
break;
228+
default:
229+
return null;
230+
}
231+
232+
try {
233+
var result = await execAsync(cmd);
234+
return result.stderr || result.stdout;
235+
} catch (error) {
236+
return error.stderr;
237+
}
238+
}
239+
240+
// Run the main function and handle any errors
241+
main().catch(console.error);

0 commit comments

Comments
 (0)