-
Notifications
You must be signed in to change notification settings - Fork 1
Description
Context
Follow-up to #533 (@nadle/kernel) and #536 (tracking issue). The @nadle/kernel package (Layer 1) provides pure resolution primitives. This issue covers Layer 2: extracting project discovery and workspace scanning from packages/nadle into a reusable @nadle/project package.
Currently, only packages/nadle (the CLI) can discover workspaces and build a project model. The language server operates in isolation per-document with zero project awareness — it can't resolve workspace-qualified references (shared:build), can't validate cross-file dependencies, and can't offer completions from other workspace config files.
What to extract from nadle core
| Logic | Current location | What it does |
|---|---|---|
| Root detection | core/options/project-resolver.ts:76-121 |
Find monorepo root via nadle.root: true in package.json, fallback to lock file detection (@manypkg/find-root) |
| Workspace discovery | core/options/project-resolver.ts:76-121 |
Read pnpm-workspace.yaml / package.json workspaces field via @manypkg/tools to enumerate all workspaces |
| Config file location | core/options/project-resolver.ts:46-74 |
For each workspace, scan for nadle.config.{js,ts,mjs,mts} (first match wins) |
| Workspace metadata | core/models/project/workspace.ts, root-workspace.ts |
Build { id, label, relativePath, absolutePath, configFilePath, packageJson } per workspace using kernel's deriveWorkspaceId() |
| Dependency resolution | core/models/project/dependency-resolver/*.ts |
Scan package.json for workspace:* deps (pnpm/yarn) or matching versions (npm) to build workspace dependency graph |
| Alias resolution | core/models/project/alias-resolver.ts |
Map workspace paths to human-readable labels via config |
| Validation | core/models/project/project.ts:88-111 |
Validate workspace labels (non-empty, no duplicates, no ID conflicts) |
Package design
packages/project/
src/
index.ts # Public API exports
project-discovery.ts # findProjectRoot(), discoverWorkspaces()
config-locator.ts # locateConfigFiles()
dependency-resolver.ts # resolveWorkspaceDependencies()
types.ts # ProjectInfo, WorkspaceInfo interfaces
package.json # deps: @nadle/kernel, @manypkg/find-root, @manypkg/tools, find-up
tsconfig.build.json
Public API
// Types
interface WorkspaceInfo {
id: string;
label: string;
relativePath: string;
absolutePath: string;
dependencies: string[];
packageName: string;
packageVersion: string | undefined;
configFilePath: string | null;
}
interface ProjectInfo {
rootDir: string;
packageManager: "pnpm" | "npm" | "yarn";
rootConfigFilePath: string | null;
workspaces: WorkspaceInfo[];
}
// Discovery
function findProjectRoot(startDir: string): Promise<string>;
function discoverWorkspaces(rootDir: string): Promise<ProjectInfo>;
function locateConfigFiles(project: ProjectInfo): Promise<ProjectInfo>;
function resolveWorkspaceDependencies(project: ProjectInfo): ProjectInfo;Dependencies
@nadle/kernel— workspace ID derivation, constants@manypkg/find-root— fallback monorepo root detection@manypkg/tools— workspace enumeration (pnpm, npm, yarn)find-up— upward directory search
Consumer changes
Language server (packages/language-server)
The biggest beneficiary. With project awareness, the LSP can:
- On initialization: discover the project root and all workspaces
- Eagerly scan all workspace
nadle.config.*files (not just open documents) - Cross-file go-to-definition: resolve
dependsOn: ["shared:build"]to the task registration inpackages/shared/nadle.config.ts - Cross-file completions: when typing in a
dependsOnstring, suggest tasks from all workspaces - Workspace-qualified reference validation: verify that
shared:buildactually exists in thesharedworkspace - Hover info enrichment: show which workspace a referenced task belongs to
nadle core (packages/nadle)
Refactor ProjectResolver and Project to delegate to @nadle/project for discovery, keeping only nadle-specific concerns (config loading via jiti, AsyncLocalStorage binding, task registration).
IntelliJ plugin (separate repo)
Can consume @nadle/project via a Kotlin/JVM port or a Node.js bridge process.
Acceptance criteria
-
@nadle/projectpackage with the API above - nadle core refactored to use
@nadle/projectfor discovery - Language server uses
@nadle/projectfor workspace-aware features - Unit tests for project discovery, workspace enumeration, dependency resolution
- Integration test: discover workspaces in
packages/sample-app
Part of #536