feat: index extra source roots beside the workspace, for the code you write against
The workspace index cannot answer questions about an installed framework or SDK, and in plugin development that is where most of the reading goes: 64 of 80 tool calls in one real session went to the harness checkout under /usr/local/lib/node_modules to look up the API being implemented. A root is entered whatever it is called, and its dependencies are not: a path ending in node_modules/... is the normal way to name a package tree, while a node_modules below the root is somebody else's code. A result carries the label that says which tree it came from and an absolute sourcePath, the only form a follow-up read can resolve. The tool description now also claims the move this replaces - searching before reading files to find out what a module contains.
This commit is contained in:
1 parent
bccd112ce5
commit
de4d020dcb
8 files changed
+873
-22
No files matched your search
+13
-1
@@ -142,6 +142,11 @@ export function extensionOf(path) {
|
||||
* @param {readonly string[]} [options.extensions] allowed extensions, without dots
|
||||
* @param {readonly string[]} [options.skipDirs] directory names skipped at any depth
|
||||
* @param {readonly string[]} [options.exclude] glob patterns over the relative path
|
||||
* @param {(depth: number, name: string, absolute: string) => boolean} [options.isSkipped]
|
||||
* decides directory traversal, replacing the `skipDirs` membership test. This is
|
||||
* the seam an extra index root uses: its top level is a package-manager
|
||||
* `node_modules` tree, which the built-in list exists to skip, so it must opt out
|
||||
* for the root and only the root. Depth 0 is the root's own entries.
|
||||
* @param {number} [options.maxFiles] stop after this many candidates
|
||||
* @param {number} [options.maxDepth] deepest directory level to enter
|
||||
* @param {AbortSignal} [options.signal]
|
||||
@@ -152,6 +157,7 @@ export async function listCodeFiles(root, options = {}) {
|
||||
extensions = DEFAULT_EXTENSIONS,
|
||||
skipDirs = DEFAULT_SKIP_DIRS,
|
||||
exclude = [],
|
||||
isSkipped,
|
||||
maxFiles = 20_000,
|
||||
maxDepth = 24,
|
||||
signal,
|
||||
@@ -159,6 +165,12 @@ export async function listCodeFiles(root, options = {}) {
|
||||
|
||||
const wanted = new Set(extensions.map((value) => String(value).toLowerCase()))
|
||||
const skip = new Set(skipDirs)
|
||||
// Materialised once per walk rather than tested with `isSkipped ?? default` at
|
||||
// every directory: the hot loop should not carry a branch that cannot change.
|
||||
const shouldSkip =
|
||||
isSkipped === undefined
|
||||
? (depth, name) => skip.has(name)
|
||||
: (depth, name, absolute) => isSkipped(depth, name, absolute)
|
||||
const files = []
|
||||
let truncated = false
|
||||
let skippedFiles = 0
|
||||
@@ -185,7 +197,7 @@ export async function listCodeFiles(root, options = {}) {
|
||||
const absolute = join(dir, entry.name)
|
||||
const relPath = relative(root, absolute).split(sep).join('/')
|
||||
if (entry.isDirectory()) {
|
||||
if (skip.has(entry.name)) continue
|
||||
if (shouldSkip(depth, entry.name, absolute)) continue
|
||||
if (depth >= maxDepth) continue
|
||||
if (matchesAny(relPath, exclude)) continue
|
||||
stack.push({ dir: absolute, depth: depth + 1 })
|
||||
|
||||
Reference in new issue
Block a user