Skip to content

Commit 71d57fc

Browse files
committed
feat: add listDirectory tool
1 parent 70ced55 commit 71d57fc

File tree

4 files changed

+153
-61
lines changed

4 files changed

+153
-61
lines changed

package-lock.json

Lines changed: 64 additions & 60 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,8 @@
7878
"cordova-plugin-server": "file:src/plugins/server",
7979
"cordova-plugin-sftp": "file:src/plugins/sftp",
8080
"cordova-plugin-system": "file:src/plugins/system",
81-
"cordova-sqlite-storage": "^7.0.0",
8281
"cordova-plugin-websocket": "file:src/plugins/websocket",
82+
"cordova-sqlite-storage": "^7.0.0",
8383
"css-loader": "^7.1.2",
8484
"mini-css-extract-plugin": "^2.9.0",
8585
"path-browserify": "^1.0.1",
@@ -98,6 +98,7 @@
9898
"@langchain/core": "^0.3.57",
9999
"@langchain/google-genai": "^0.2.10",
100100
"@langchain/langgraph": "^0.2.74",
101+
"@langchain/langgraph-checkpoint": "^0.0.18",
101102
"@langchain/langgraph-swarm": "^0.0.3",
102103
"@ungap/custom-elements": "^1.3.0",
103104
"autosize": "^6.0.1",
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import { fetchTool } from "./fetch";
2+
import { listDirectory } from "./listDirectory";
23
import { readFile } from "./readFile";
34

45
// Export all tools as a single object
56
export const allTools = {
67
readFile,
78
fetchTool,
9+
listDirectory,
810
};
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import { StructuredTool } from "@langchain/core/tools";
2+
import fsOperation from "fileSystem";
3+
import { addedFolder } from "lib/openFolder";
4+
import { z } from "zod";
5+
6+
/**
7+
* Tool for listing files and directories in a given path
8+
*/
9+
class ListDirectoryTool extends StructuredTool {
10+
name = "listDirectory";
11+
description = "Lists files and directories in a given path";
12+
schema = z.object({
13+
path: z
14+
.string()
15+
.describe(
16+
"The relative path of the directory to list. This path must never be absolute. The first component of the path should always be the name of a root directory in the project (as shown in the sidebar). For example, if the root directories are 'directory1' and 'directory2', you can list the contents of 'directory1' by using the path 'directory1'. If the root directories are 'foo' and 'bar', and you want to list the contents of the directory 'foo/baz', you should use the path 'foo/baz'.",
17+
),
18+
});
19+
20+
async _call({ path }) {
21+
try {
22+
// Handle special cases: ".", "", "./", "*"
23+
if (path === "." || path === "" || path === "./" || path === "*") {
24+
// List all root directories (project roots)
25+
const rootDirs = addedFolder
26+
.filter((folder) => folder && folder.title)
27+
.map((folder) => folder.title)
28+
.join("\n");
29+
return rootDirs;
30+
}
31+
32+
// Split the path to get project name and subpath
33+
const pathParts = path.split("/");
34+
const projectName = pathParts[0];
35+
const subPath = pathParts.slice(1).join("/");
36+
37+
// Find the project in addedFolder array
38+
const project = addedFolder.find(
39+
(folder) => folder.title === projectName,
40+
);
41+
if (!project) {
42+
return `Error: Path '${path}' not found in opened projects`;
43+
}
44+
45+
// Construct the full URL
46+
const dirUrl = subPath ? project.url + "/" + subPath : project.url;
47+
48+
// List directory entries
49+
const entries = await fsOperation(dirUrl).lsDir();
50+
if (!Array.isArray(entries)) {
51+
return `Error: Path not found: ${path}`;
52+
}
53+
54+
// Separate folders and files
55+
const folders = [];
56+
const files = [];
57+
for (const entry of entries) {
58+
// Skip "." and ".."
59+
if (entry.name === "." || entry.name === "..") continue;
60+
const entryRelPath = subPath ? subPath + "/" + entry.name : entry.name;
61+
if (entry.isDirectory) {
62+
folders.push(`${projectName}/${entryRelPath}`);
63+
} else if (entry.isFile) {
64+
files.push(`${projectName}/${entryRelPath}`);
65+
}
66+
}
67+
68+
let output = "";
69+
if (folders.length > 0) {
70+
output += `# Folders:\n${folders.join("\n")}\n`;
71+
}
72+
if (files.length > 0) {
73+
output += `\n# Files:\n${files.join("\n")}\n`;
74+
}
75+
if (output.trim() === "") {
76+
output = `${path} is empty.`;
77+
}
78+
return output.trim();
79+
} catch (error) {
80+
return `Error reading directory: ${error.message}`;
81+
}
82+
}
83+
}
84+
85+
export const listDirectory = new ListDirectoryTool();

0 commit comments

Comments
 (0)