The messageFilesystem
function is an asynchronous function that retrieves information about available projects and their related files by interacting with the file system and user input. It generates a prompt, filters related projects and files, and logs user responses and project information, although it has some potential performance and logging issues that should be addressed.
npm run import -- "file system access"
const path = require('path')
const fs = require('fs')
const PROFILE_PATH = process.env.HOME || process.env.HOMEPATH || process.env.USERPROFILE || '';
async function messageFilesystem(promptModel, session, prompt) {
let currentProject = path.basename(path.resolve(__dirname, '..'))
let availableProjects = fs.readdirSync(PROFILE_PATH)
.filter(dir => dir[0] != '.')
.filter(dir => fs.statSync(path.join(PROFILE_PATH, dir)).isDirectory())
.filter(dir => fs.existsSync(path.join(PROFILE_PATH, dir, '.git')))
let q1 = 'Current project: ' + currentProject
+ '\nAvailable projects:\n' + availableProjects.join('\n')
+ '\nAre any of these project related to the current prompt:\n'
+ prompt
+ '\nOnly respond with the project name or "No" if none are related.'
console.log('User: ' + q1)
let a1 = await promptModel(q1)
console.log('AI: ' + a1)
let relatedProjects = availableProjects.filter(dir => a1.match(dir))
if(relatedProjects.length == 0) {
return 'Current project: ' + currentProject
+ '\nAvailable projects:\n' + availableProjects.join('\n')
}
let projectFiles = fs.readdirSync(path.join(PROFILE_PATH, relatedProjects[0]))
.filter(dir => dir[0] != '.' && dir != 'node_modules')
.map(file => {
let currentPath = path.join(PROFILE_PATH, relatedProjects[0], file)
if(fs.statSync(currentPath).isDirectory()) {
return [file].concat(fs.readdirSync(currentPath)
.filter(dir => dir[0] != '.')
.map(dir => path.join(file, dir)))
} else {
return file
}
})
.flat(1)
let relatedFiles = []
if(currentProject == relatedProjects[0]) {
// TODO: use cell lookup instead of notebook files
let q2 = 'Current project: ' + currentProject
+ '\nRelated projects:\n' + relatedProjects.join('\n')
+ '\nProject files:\n'
let originalFilePrompt = q2
let count = 0
for(let i = 0; i < projectFiles.length; i++) {
q2 += projectFiles[i] + '\n'
count++
if(count == 25 || q2.length > 2048) {
q2 += '\nAre any of the project files relevant to the prompt:\n'
+ prompt
+ '\nOnly respond with the related file paths or file names, nothing else.'
console.log('User: ' + q2)
let a2 = await promptModel(q2)
console.log('AI: ' + a2)
relatedFiles = relatedFiles.concat(projectFiles
.filter(file => a2.match(file) || a2.match(path.basename(file))))
count = 0
q2 = originalFilePrompt
}
}
if(q2.length != originalFilePrompt.length || count > 0) {
q2 += '\nAre any of the project files relevant to the prompt:\n'
+ prompt
+ '\nOnly respond with the related file paths or file names, nothing else.'
console.log('User: ' + q2)
let a2 = await promptModel(q2)
console.log('AI: ' + a2)
relatedFiles = relatedFiles.concat(projectFiles
.filter(file => a2.match(file) || a2.match(path.basename(file))))
}
}
if(relatedFiles.length == 0) {
return 'Current project: ' + currentProject
+ '\nRelated projects:\n' + relatedProjects.join('\n')
+ '\nProject files:\n' + projectFiles.join('\n')
}
// TODO: another depth of related files
return 'Current project: ' + currentProject
+ '\nRelated projects:\n' + relatedProjects.join('\n')
+ '\nRelated files:\n' + relatedFiles.join('\n')
}
module.exports = messageFilesystem
const path = require('path');
const fs = require('fs');
const { promisify } = require('util');
const PROFILE_PATH = process.env.HOME || process.env.HOMEPATH || process.env.USERPROFILE || '';
const readdir = promisify(fs.readdir);
const readFile = promisify(fs.readFile);
const stat = promisify(fs.stat);
async function messageFilesystem(promptModel, session, prompt) {
const currentProject = path.basename(path.resolve(__dirname, '..'));
const availableProjects = await getAvailableProjects();
const relatedProjects = await getRelatedProjects(promptModel, availableProjects, prompt);
if (relatedProjects.length === 0) {
return getProjectInfo(currentProject, availableProjects);
}
const projectFiles = await getProjectFiles(relatedProjects[0]);
const relatedFiles = await getRelatedFiles(promptModel, projectFiles, prompt, currentProject);
return getProjectInfo(currentProject, availableProjects, relatedProjects, relatedFiles);
}
async function getAvailableProjects() {
return (await readdir(PROFILE_PATH))
.filter(dir => dir[0]!== '.')
.filter(dir => (await stat(path.join(PROFILE_PATH, dir))).isDirectory())
.filter(dir => (await fs.existsSync(path.join(PROFILE_PATH, dir, '.git'))));
}
async function getRelatedProjects(promptModel, availableProjects, prompt) {
const q1 = `Current project: ${path.basename(path.resolve(__dirname, '..'))}
Available projects:\n${availableProjects.join('\n')}
Are any of these project related to the current prompt:\n${prompt}
Only respond with the project name or "No" if none are related.`;
console.log('User:'+ q1);
const a1 = await promptModel(q1);
console.log('AI:'+ a1);
return availableProjects.filter(dir => a1.match(dir));
}
async function getProjectInfo(currentProject, availableProjects, relatedProjects = [], relatedFiles = []) {
return `Current project: ${currentProject}
Available projects:\n${availableProjects.join('\n')}
Related projects:\n${relatedProjects.join('\n')}
Related files:\n${relatedFiles.join('\n')}`;
}
async function getProjectFiles(projectName) {
return (await readdir(path.join(PROFILE_PATH, projectName)))
.filter(dir => dir[0]!== '.' && dir!== 'node_modules')
.map(file => {
const currentPath = path.join(PROFILE_PATH, projectName, file);
if ((await stat(currentPath)).isDirectory()) {
return [file].concat((await getProjectFiles(currentPath)));
} else {
return file;
}
})
.flat(1);
}
async function getRelatedFiles(promptModel, projectFiles, prompt, currentProject) {
const relatedFiles = [];
if (currentProject === relatedProjects[0]) {
let q2 = `Current project: ${currentProject}
Related projects:\n${relatedProjects.join('\n')}
Project files:\n`;
let originalFilePrompt = q2;
let count = 0;
for (let i = 0; i < projectFiles.length; i++) {
q2 += projectFiles[i] + '\n';
count++;
if (count === 25 || q2.length > 2048) {
q2 += `\nAre any of the project files relevant to the prompt:\n${prompt}
Only respond with the related file paths or file names, nothing else.`;
console.log('User:'+ q2);
let a2 = await promptModel(q2);
console.log('AI:'+ a2);
relatedFiles = relatedFiles.concat(projectFiles
.filter(file => a2.match(file) || a2.match(path.basename(file))));
count = 0;
q2 = originalFilePrompt;
}
}
if (q2.length!== originalFilePrompt.length || count > 0) {
q2 += `\nAre any of the project files relevant to the prompt:\n${prompt}
Only respond with the related file paths or file names, nothing else.`;
console.log('User:'+ q2);
let a2 = await promptModel(q2);
console.log('AI:'+ a2);
relatedFiles = relatedFiles.concat(projectFiles
.filter(file => a2.match(file) || a2.match(path.basename(file))));
}
}
return relatedFiles;
}
module.exports = messageFilesystem;
Function Breakdown: messageFilesystem
This is an asynchronous function that interacts with the file system to provide information about available projects and their related files. It takes in three parameters:
promptModel
: a model used to generate promptssession
: not used in this functionprompt
: a prompt to check for related projectsHere's a step-by-step breakdown of the function:
path
module to get the current working directory and its parent directory (the project root).fs
module to read the contents of the user's home directory and filter out directories that are hidden or not Git repositories.promptModel
to generate a response to the prompt and logs the user's response.Notes
fs
module to interact with the file system, which can be slow and blocking. Consider using asynchronous methods or a library like fs-promises
to improve performance.process.env.HOME
and other environment variables to determine the user's home directory. This may not work correctly on all systems or in all environments.path.basename
and path.join
to manipulate file paths, which is good practice.fs.existsSync
and fs.statSync
to check if a file or directory exists and get its stats, which is good practice.filter
and map
methods to process arrays of project files, which is good practice.console.log
to log user responses and AI-generated text, which may not be suitable for production environments where logs should be handled differently.