find_orphans
Identifies notes lacking incoming wikilinks. Optionally filter by a scope path, returns root, scope, and array of orphan relative paths.
Instructions
Finds notes with no incoming wikilinks. Optional { scope } path prefix. Returns { root, scope, orphans[] } (array of relative paths).
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||
Implementation Reference
- src/tools/link-tools.ts:148-180 (handler)makeFindOrphansTool: tool handler that parses the schema, delegates to services.links.findOrphans(), and returns { root, scope, orphans }.
function makeFindOrphansTool(container: ServiceContainer): ToolHandler { return { name: "find_orphans", description: "Finds notes with no incoming wikilinks. Optional `{ scope }` path prefix. Returns `{ root, scope, orphans[] }` (array of relative paths).", inputSchema: FindOrphansSchema, async handler(args): Promise<ToolResponse> { try { const services = requireServices(container); const { scope } = FindOrphansSchema.parse(args); log.info({ scope }, "find_orphans called"); const orphans = await services.links.findOrphans(scope); log.info({ scope, count: orphans.length }, "find_orphans complete"); return { content: [ { type: "text", text: JSON.stringify({ root: getRoot(container), scope: scope ?? null, orphans }), }, ], }; } catch (err) { log.error({ err }, "find_orphans failed"); return { content: [{ type: "text", text: JSON.stringify({ root: getRoot(container), error: err instanceof Error ? err.message : String(err), possibleSolutions: ["Check the scope path is root-relative", "Omit scope to scan the entire directory"], }) }], isError: true, }; } }, - src/tools/link-tools.ts:144-146 (schema)FindOrphansSchema: Zod schema defining the optional 'scope' string parameter for the find_orphans tool.
const FindOrphansSchema = z.object({ scope: z.string().optional(), }); - src/services/link-engine.ts:186-226 (handler)findOrphans() service method: collects files, builds in-degree map from wikilinks, returns files with zero incoming links.
async findOrphans(scope?: string): Promise<string[]> { log.info({ scope }, "findOrphans"); const files = await this.collectFiles(scope); // Build in-degree map const inDegree = new Map<string, number>(); for (const f of files) { inDegree.set(f, 0); } // Map each stem to the file paths that share it (for O(1) lookup) const stemToFiles = new Map<string, string[]>(); for (const f of files) { const stem = getStem(f); const existing = stemToFiles.get(stem); if (existing) { existing.push(f); } else { stemToFiles.set(stem, [f]); } } for (const filePath of files) { const links = await this.getLinksForFile(filePath); for (const link of links) { const stem = this.stemFromTarget(link.target); const targets = stemToFiles.get(stem); if (!targets) continue; for (const f of targets) { inDegree.set(f, (inDegree.get(f) ?? 0) + 1); } } } const orphans = files.filter((f) => (inDegree.get(f) ?? 0) === 0); log.info({ scope, orphanCount: orphans.length }, "findOrphans complete"); return orphans; } - src/tools/link-tools.ts:257-270 (registration)registerLinkTools() registers makeFindOrphansTool into the tool registry map.
export function registerLinkTools( registry: Map<string, ToolHandler>, container: ServiceContainer, ): void { const tools = [ makeGetBacklinksTool(container), makeFindUnlinkedMentionsTool(container), makeFindBrokenLinksTool(container), makeFindOrphansTool(container), makeFindBidirectionalMentionsTool(container), ]; for (const tool of tools) { registry.set(tool.name, tool); - src/tools/index.ts:38-54 (registration)LITE_TOOL_NAMES: 'find_orphans' is allowlisted in lite mode.
export const LITE_TOOL_NAMES: ReadonlySet<string> = new Set([ // Schema / lint "lint_note", "validate_folder", "validate_area", "validate_all", "list_schemas", // Link graph "find_broken_links", "find_orphans", "find_unlinked_mentions", "find_bidirectional_mentions", "get_backlinks", // Meta "switch_directory", "get_stats", ]); - src/types.ts:737-738 (helper)Interface declaration: findOrphans(scope?: string): Promise<string[]> on the LinkEngine interface.
/** Find notes with no incoming links in scope */ findOrphans(scope?: string): Promise<string[]>;