/** * Focus resolution: which slice of the workspace an agent is confined to. * * ## Why this exists * * A workspace-wide index has to rank across every part of a repository, and in * a codebase built from many near-identical modules that is exactly where * embedding similarity fails. In the repository this was written against there * are eighteen controllers — each a state machine with the same idioms, the same * naming and the same shape — spread across 228k lines. A query about one of * them returns plausible fragments of all eighteen. * * Narrowing the index to the one being worked on removes the confusability * rather than trying to rank through it, and it does three things at once: * * 1. **precision** — there are no near-duplicates to outrank the right answer; * 2. **cold start** — ten files embed in seconds where six hundred took minutes; * 3. **context** — code the agent never sees is code that is never re-sent on * every later step, which is where the money actually is. * * ## Resolution order * * Most explicit wins, and the last fallback is the workspace root — which is the * behaviour that existed before focus did, so adopting this cannot regress a * deployment that never configures it. * * The marker step is the interesting one: a folder that contains its own * instructions *is* a scope. A controller directory holding a `CONTROLLER.md` * becomes the world the agent sees, and the document that describes the module * also defines its boundary. Nothing needed to be invented for that — the * convention already means "this folder is self-describing". */ import { existsSync, statSync } from 'node:fs' import { readdir } from 'node:fs/promises' import { dirname, isAbsolute, join, relative, resolve, sep } from 'node:path' /** * Files whose presence marks a directory as a scope root. * * Ordered by how specific they are: a `CONTROLLER.md` is a stronger claim about * a directory than the `AGENTS.md` that sits at every repository root. */ export const DEFAULT_FOCUS_MARKERS = Object.freeze(['CONTROLLER.md', 'DEBUG_UI.md', 'AGENTS.md']) /** True when `path` is `root` itself or sits underneath it. */ export function isInside(root, path) { const prefix = root.endsWith(sep) ? root : root + sep return path === root || path.startsWith(prefix) } /** True when `path` exists and is a directory. */ function statIsDirectory(path) { try { return statSync(path).isDirectory() } catch { return false } } /** Every ancestor of `from` up to and including `stop`, nearest first. */ export function ancestorsTo(from, stop) { const out = [] let current = resolve(from) const limit = resolve(stop) for (;;) { out.push(current) if (current === limit) break const parent = dirname(current) // A path that is not under `stop`, or a filesystem root, ends the walk // rather than looping. if (parent === current || !isInside(limit, parent)) break current = parent } return out } /** * Resolve the focus directory for one session. * * @param {object} input * @param {string} input.workspace absolute workspace root * @param {string} [input.cwd] directory the session is working from * @param {string} [input.explicit] a configured or caller-supplied focus * @param {(path: string) => boolean} [input.isDirectory] injection point for tests * @param {readonly string[]} [input.markers] scope-marker filenames * @param {(path: string) => boolean} [input.exists] injection point for tests * @param {{path: string, marker: string}[]} [input.scopes] scopes found by {@link discoverScopes} * @returns {{root: string, source: 'explicit'|'scope'|'marker'|'workspace', marker?: string, problem?: string}} */ export function resolveFocus(input) { const { workspace, cwd = workspace, explicit = '', markers = DEFAULT_FOCUS_MARKERS, scopes = [], exists = existsSync, isDirectory = statIsDirectory, } = input // 1. An explicit focus wins, but a bad one is reported rather than silently // ignored: a typo that quietly fell back to the whole workspace would look // like the feature doing nothing. const requested = String(explicit ?? '').trim() if (requested !== '') { const absolute = isAbsolute(requested) ? resolve(requested) : resolve(workspace, requested) if (!isInside(workspace, absolute)) { return { root: resolve(workspace), source: 'workspace', problem: `focus "${requested}" is outside the workspace`, } } if (!isDirectory(absolute)) { return { root: resolve(workspace), source: 'workspace', problem: `focus "${requested}" is not a directory`, } } return { root: absolute, source: 'explicit' } } // 2. Nothing here adopts a discovered scope automatically, and that is // deliberate. A session sitting at the repository root is not thereby // *about* any one controller, and silently confining it to whichever scope // sorted first would hide code the session legitimately needs. Discovery // exists so a caller can be shown the scopes and name one; choosing is an // explicit act, which is what `focus` is for. // 3. The nearest ancestor carrying a marker file. `cwd` is normally the // workspace root, at which point the root's own AGENTS.md matches and the // result is the workspace — the same answer the old code gave. const start = isInside(workspace, resolve(cwd)) ? resolve(cwd) : resolve(workspace) for (const directory of ancestorsTo(start, workspace)) { for (const marker of markers) { if (marker !== '' && exists(join(directory, marker))) { return { root: directory, source: 'marker', marker } } } } // 4. The workspace. return { root: resolve(workspace), source: 'workspace' } } /** A stable key for one focus directory, for index filenames. */ export function focusKey(workspace, root) { const rel = relative(resolve(workspace), resolve(root)).split(sep).join('/') return rel === '' ? '.' : rel } /** * Directories skipped while looking for scopes. * * A marker inside a dependency or a build directory describes somebody else's * project, so discovering it would offer the user a scope they do not own. */ const DISCOVERY_SKIP_DIRS = new Set([ 'node_modules', '.git', 'dist', 'build', 'out', 'coverage', 'target', '.next', '.nuxt', '.venv', 'venv', '__pycache__', 'vendor', '.cache', ]) /** * Find every directory that declares itself a scope. * * This exists because walking up from the working directory cannot find a * marker in a subdirectory, and in the repository this was written for that is * the whole point: the session sits at the workspace root while the eighteen * controllers each carry their own instructions further down. Inheritance and * discovery are different questions — "what contains me?" versus "what is * available?" — and a scope needs both. * * Results are workspace-relative and sorted, so a list shown to a user or a * model is stable between calls. * * @param {object} input * @param {string} input.workspace absolute workspace root * @param {readonly string[]} [input.markers] marker filenames * @param {number} [input.maxDepth] deepest directory level to scan * @returns {Promise<{path: string, marker: string}[]>} discovered scopes */ export async function discoverScopes(input) { const { workspace, markers = DEFAULT_FOCUS_MARKERS, maxDepth = 8 } = input const root = resolve(workspace) const found = [] const walk = async (directory, depth) => { if (depth > maxDepth) return let entries try { entries = await readdir(directory, { withFileTypes: true }) } catch { return } const names = new Set(entries.filter((entry) => entry.isFile()).map((entry) => entry.name)) for (const marker of markers) { if (names.has(marker)) { const rel = relative(root, directory).split(sep).join('/') found.push({ path: rel === '' ? '.' : rel, marker }) break } } for (const entry of entries) { if (!entry.isDirectory() || entry.isSymbolicLink()) continue if (DISCOVERY_SKIP_DIRS.has(entry.name)) continue await walk(join(directory, entry.name), depth + 1) } } await walk(root, 0) found.sort((left, right) => (left.path < right.path ? -1 : left.path > right.path ? 1 : 0)) return found }