Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
8cf0716
Initial plan
Copilot Feb 9, 2026
4ae8ca5
Add workspace parent detection using resolve-workspace-root
Copilot Feb 9, 2026
d7ea7f0
Add documentation for nested workspace support
Copilot Feb 9, 2026
636eaca
Improve workspace parent detection to support nested workspaces
Copilot Feb 9, 2026
21dd54f
Address code review feedback: improve workspace detection logic and f…
Copilot Feb 9, 2026
572af97
Refactor: move findUltimateWorkspaceRoot to lib/utils.js
Copilot Feb 9, 2026
2a740a4
Simplify: use resolveWorkspaceRootAsync directly instead of findUltim…
Copilot Feb 9, 2026
24cf5cc
Add --no-parent-workspace flag and improve parent workspace detection…
Copilot Feb 9, 2026
6f4a3dc
Add debug logging for parent workspace detection
Copilot Feb 9, 2026
d8a63a6
Refactor import for resolveWorkspaceRootAsync
voxpelli Feb 9, 2026
b32653b
Change debug messages to use console.error instead of console.log
Copilot Feb 9, 2026
3ceffca
Add type annotation for reasons array to achieve 100% type coverage
Copilot Feb 9, 2026
f4f891c
Set includeWorkspaceRoot to false when using parent workspace detection
Copilot Feb 9, 2026
c9c2483
Support parent workspace detection with custom paths and add debug he…
Copilot Feb 9, 2026
8b88590
Add examples and integration tests for monorepo workspace support
Copilot Feb 9, 2026
8ad8f14
Improve examples and tests with unified/remark parsing
Copilot Feb 9, 2026
fa70920
Refactor integration tests for better reusability and add monorepo ex…
Copilot Feb 9, 2026
679e98a
Fix critical bug: always set cwd in lookupOptions + split monorepo RE…
Copilot Feb 9, 2026
062725e
Fix critical bug: always set cwd in lookupOptions + split monorepo RE…
Copilot Feb 9, 2026
e478577
Refactor integration tests and enhance examples
Copilot Feb 9, 2026
52202d5
Fix glob pattern in package.json scripts
Copilot Feb 9, 2026
4c7f990
Fix test-ci script to avoid recursive call
Copilot Feb 9, 2026
33ce039
Address code review feedback: improve assertion style
Copilot Feb 9, 2026
05366d7
Add distinct errors to all three examples
Copilot Feb 9, 2026
53758c4
Add test/helpers.js to tsconfig and revert test script to explicit form
Copilot Feb 9, 2026
9028ce9
Fix CI failures: normalize line endings and fix helper function signa…
Copilot Feb 9, 2026
463880e
Fix CI failures: normalize line endings and fix helper function signa…
Copilot Feb 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,22 @@ Use [installed-check-core](https://github.com/voxpelli/node-installed-check-core
* `--no-include-workspace-root` – excludes the workspace root package. Negated equivalent of npm's [`--include-workspace-root`](https://docs.npmjs.com/cli/v10/commands/npm-run-script#include-workspace-root)
* `--no-workspaces` – excludes workspace packages. Negated equivalent of npm's [`--workspaces`](https://docs.npmjs.com/cli/v10/commands/npm-run-script#workspaces)
* `--workspace=ARG` / `-w ARG` – excludes all workspace packages not matching these names / paths. Equivalent to npm's [`--workspace` / `-w`](https://docs.npmjs.com/cli/v10/commands/npm-run-script#workspace)
* `--workspace-ignore=ARG` – xcludes the specified paths from workspace lookup. (Supports globs)
* `--workspace-ignore=ARG` – excludes the specified paths from workspace lookup. (Supports globs)

### Nested workspace support

When running `installed-check` within a workspace that is part of a larger monorepo (e.g., when using `git subtree` or working in a nested monorepo structure), the tool will automatically detect the parent workspace root and include modules from the parent's `node_modules` directory. This ensures that dependencies hosted at the monorepo root level are properly detected and checked.

For example, if you have a structure like:
```
/parent-monorepo
/node_modules (shared dependencies)
/packages
/my-workspace
/package.json
```

Running `installed-check` in `/parent-monorepo/packages/my-workspace` will automatically detect the parent monorepo and check dependencies from both the workspace and the parent's `node_modules`.

### Additional command line options

Expand Down
65 changes: 63 additions & 2 deletions cli.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
/* eslint-disable no-console, unicorn/no-process-exit */

import pathModule from 'node:path';
import chalk from 'chalk';
import meow from 'meow';
import { messageWithCauses, stackWithCauses } from 'pony-cause';
import { installedCheck, ROOT } from 'installed-check-core';
import resolveWorkspaceRootPkg from 'resolve-workspace-root';

const { resolveWorkspaceRootAsync } = resolveWorkspaceRootPkg;

const EXIT_CODE_ERROR_RESULT = 1;
const EXIT_CODE_INVALID_INPUT = 2;
Expand Down Expand Up @@ -106,13 +110,70 @@ let checks = [
...versionCheck ? /** @type {const} */ (['version']) : [],
];

// Detect if we're in a workspace within a larger monorepo
// If so, use the ultimate parent workspace root to enable access to parent's node_modules
const requestedCwd = cli.input[0] || process.cwd();

/**
* Find the ultimate parent workspace root by walking up the directory tree
*
* @param {string} dir
* @returns {Promise<string|undefined>}
*/
async function findUltimateWorkspaceRoot (dir) {
const currentRoot = await resolveWorkspaceRootAsync(dir);
if (!currentRoot) return;

// Keep looking for parent workspace roots by checking parent directories
let checkDir = pathModule.dirname(currentRoot);
let ultimateRoot = currentRoot;

while (checkDir && checkDir !== ultimateRoot) {
const parentRoot = await resolveWorkspaceRootAsync(checkDir);

// If we found a parent workspace root that contains our current root
if (parentRoot && ultimateRoot.startsWith(parentRoot + pathModule.sep)) {
ultimateRoot = parentRoot;
checkDir = pathModule.dirname(parentRoot);
} else {
// Move up one directory and continue searching
const newCheckDir = pathModule.dirname(checkDir);
if (newCheckDir === checkDir) {
// Reached filesystem root
break;
}
checkDir = newCheckDir;
}
}

return ultimateRoot;
}

const parentWorkspaceRoot = await findUltimateWorkspaceRoot(requestedCwd);

let resolvedCwd = requestedCwd;
let workspaceFilter = workspace;

// If we found a parent workspace root different from our requested cwd,
// we're in a nested workspace situation
if (parentWorkspaceRoot && parentWorkspaceRoot !== requestedCwd) {
// Use the parent workspace root as cwd to get access to its node_modules
resolvedCwd = parentWorkspaceRoot;

// If no explicit workspace filter was provided, filter to just the current workspace
// to avoid checking all workspaces in the parent monorepo
if (!workspace || workspace.length === 0) {
workspaceFilter = [requestedCwd];
}
}

/** @type {import('installed-check-core').LookupOptions} */
const lookupOptions = {
cwd: cli.input[0],
cwd: resolvedCwd !== requestedCwd ? resolvedCwd : undefined,
ignorePaths: workspaceIgnore,
includeWorkspaceRoot,
skipWorkspaces: !workspaces,
workspace,
workspace: workspaceFilter,
};

/** @type {import('installed-check-core').InstalledCheckOptions} */
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
"installed-check-core": "^8.3.0",
"meow": "^13.0.0",
"pony-cause": "^2.1.10",
"resolve-workspace-root": "^2.0.1",
"version-guard": "^1.1.1"
},
"devDependencies": {
Expand Down
Loading