Skip to content

refactor(intent): add shared project context resolver for validate and edit-package-json#93

Merged
LadyBluenotes merged 11 commits intomainfrom
refactor
Mar 25, 2026
Merged

refactor(intent): add shared project context resolver for validate and edit-package-json#93
LadyBluenotes merged 11 commits intomainfrom
refactor

Conversation

@LadyBluenotes
Copy link
Member

@LadyBluenotes LadyBluenotes commented Mar 23, 2026

Summary

  • add a shared resolveProjectContext() helper to centralize workspace root, package root, monorepo, workspace pattern, and target path resolution
  • route validate and edit-package-json through the shared resolver instead of using command-specific monorepo detection
  • fix pnpm workspace regressions where pnpm-workspace.yaml was ignored, leading to false !skills/_artifacts warnings and incorrect package targeting
  • fixes bug: pnpm-workspace.yaml not detected by validate and edit-package-json commands #86
  • replace the workspace suffix-stripping logic with segment-by-segment resolution for literal segments, *, and **
  • normalize workspace patterns before resolution and return deduped, stably sorted package roots
  • support exclusion patterns from workspace config by subtracting !-prefixed matches from resolved package roots
  • extract the shared workspace discovery helpers into a dedicated module and update internal consumers to use it directly
  • fixes bug: resolveWorkspacePackages fails for nested workspace patterns #88

Notes

  • resolveProjectContext() now provides one consistent answer for:
    • current working directory
    • workspace root
    • owning package root
    • monorepo status
    • workspace patterns
    • target package.json path
    • target skills directory
  • validate now makes packaging decisions from the resolved target package rather than process.cwd() alone
  • runEditPackageJson() now updates the owning package for a target path, including workspace package skills directories
  • added focused coverage for:
    • workspace root cwd
    • workspace package cwd
    • explicit packages/foo/skills targeting
    • pnpm workspaces defined only in pnpm-workspace.yaml

Summary by CodeRabbit

Release Notes

  • Bug Fixes

    • Fixed workspace package discovery for patterns using nested glob expressions (* and ** wildcards).
    • Improved support for pnpm workspace configuration detection.
    • Resolved monorepo targeting issues in validation workflows.
  • Tests

    • Added test coverage for workspace pattern resolution and monorepo validation scenarios.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 23, 2026

📝 Walkthrough

Walkthrough

The PR refactors monorepo and workspace detection by extracting shared logic into dedicated modules. A new workspace-patterns.ts module handles workspace pattern reading and package resolution with support for pnpm layouts. A new project-context.ts module computes project metadata (workspace root, package root, skills directories). The validate.ts and setup.ts commands now use resolveProjectContext to properly detect workspaces including pnpm formats, fixing false packaging warnings.

Changes

Cohort / File(s) Summary
Changeset Documentation
.changeset/busy-peas-fail.md, .changeset/red-regions-shine.md
Mark @tanstack/intent for patch release; document workspace pattern normalization fix and shared project context resolver refactor for pnpm workspace support.
Workspace Pattern Module
packages/intent/src/workspace-patterns.ts
New module implementing workspace pattern discovery and resolution with support for pnpm-workspace.yaml, package.json workspaces, glob patterns (*, **), exclusions (!), and skill file detection across workspace packages.
Project Context Module
packages/intent/src/core/project-context.ts
New module exporting resolveProjectContext() function that computes workspace root, package root, workspace patterns, skills directory, and monorepo status for a given CWD and target path.
Command Refactoring
packages/intent/src/commands/validate.ts, packages/intent/src/setup.ts
Updated to use resolveProjectContext instead of inline monorepo detection; validate.ts refactors collectPackagingWarnings to accept ProjectContext; setup.ts refactors runEditPackageJson to compute files entries from context; both now properly detect pnpm workspaces.
Import Path Updates
packages/intent/src/cli-support.ts, packages/intent/src/scanner.ts
Changed dynamic imports and module references from ./setup.js to ./workspace-patterns.js for workspace-related helpers.
Test Coverage
packages/intent/tests/project-context.test.ts, packages/intent/tests/workspace-patterns.test.ts, packages/intent/tests/cli.test.ts, packages/intent/tests/setup.test.ts
Added comprehensive test suites for new modules and updated commands, covering pnpm workspace detection, context resolution, pattern normalization, and monorepo packaging behavior.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • tannerlinsley
  • LadyBluenotes

Poem

🐰 Workspace patterns hop and play,
pnpm workspaces saved the day!
No more false warnings in our monorepo,
Context resolved—our code's a hero!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Description check ❓ Inconclusive The PR description comprehensively covers changes, motivation, and issue fixes, but the author-provided description does not follow the repository's template structure. Verify that the author completed the checklist items (Contributing guide, testing, changeset) as specified in the template, even though they're not explicitly acknowledged in the summary.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main refactoring: adding a shared project context resolver used by both validate and edit-package-json commands.
Linked Issues check ✅ Passed The PR successfully addresses all coding requirements from issue #86: detects pnpm-workspace.yaml via resolveProjectContext(), fixes validate and edit-package-json monorepo detection, and eliminates false !skills/_artifacts warnings.
Out of Scope Changes check ✅ Passed All changes are directly related to centralizing project context resolution and fixing pnpm workspace detection; no out-of-scope modifications detected.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@pkg-pr-new
Copy link

pkg-pr-new bot commented Mar 23, 2026

Open in StackBlitz

npm i https://pkg.pr.new/@tanstack/intent@93

commit: 667e06f

- Add process.exitCode = 1 on JSON parse failure in setup.ts (was silently returning success)
- Skip _artifacts validation for monorepo packages in validate.ts (artifacts live at workspace root)
- Add JSDoc to resolveProjectContext explaining dual-fallback resolution strategy
- Add comment to resolveWorkspacePatternSegments describing glob matching behavior
- Add standalone (non-monorepo) project test for resolveProjectContext

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Collaborator

@KyleAMathews KyleAMathews left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ran a comprehensive review (code quality, error handling, test coverage, type design, comments). Changes look solid — the refactoring successfully consolidates three separate monorepo-detection implementations into a clean shared ProjectContext.

Applied a few fixes in 094609e:

  • setup.ts: Added missing process.exitCode = 1 on JSON parse failure (was silently returning success, breaking CI detection)
  • validate.ts: Skip _artifacts validation for monorepo packages (artifacts live at workspace root, not under each package)
  • project-context.ts: Added JSDoc explaining the dual-fallback workspace root resolution strategy
  • workspace-patterns.ts: Added comment on the recursive glob segment matcher
  • project-context.test.ts: Added test for standalone (non-monorepo) project path — was previously untested at the unit level

All 226 tests pass.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (3)
packages/intent/src/commands/validate.ts (1)

5-8: Split the mixed type/value import.

ESLint is already erroring on this form (import/consistent-type-specifier-style), so CI will keep failing until ProjectContext moves to a separate import type.

Suggested fix
-import {
-  type ProjectContext,
-  resolveProjectContext,
-} from '../core/project-context.js'
+import { resolveProjectContext } from '../core/project-context.js'
+import type { ProjectContext } from '../core/project-context.js'
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/intent/src/commands/validate.ts` around lines 5 - 8, The current
import mixes a type and a value which triggers ESLint's
import/consistent-type-specifier-style; split the import into a type-only import
for ProjectContext and a separate value import for resolveProjectContext by
replacing the single mixed import with an "import type { ProjectContext } from
'../core/project-context.js'" and a normal "import { resolveProjectContext }
from '../core/project-context.js'"; ensure you only change the import statements
and keep the module path and identifiers (ProjectContext, resolveProjectContext)
intact.
packages/intent/tests/setup.test.ts (1)

188-220: Add the workspace-root package case too.

These tests lock in the workspace-package paths, but not the case where the workspace root itself owns skills/. If the new context signal is reused there, runEditPackageJson(monoRoot) can incorrectly omit !skills/_artifacts for the root package as well, so I'd add that regression before this lands.

Based on learnings: !skills/_artifacts should be omitted only for sub-packages inside a monorepo, not for the workspace root package itself.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/intent/tests/setup.test.ts` around lines 188 - 220, Add a new test
case that runs runEditPackageJson against the monorepo root (created by
createMonorepo) to verify that the workspace-root package keeps the
'!skills/_artifacts' exclusion; call runEditPackageJson(monoRoot), assert
result.added includes 'files: "skills"', then read the root package.json and
assert pkg.files contains both 'skills' and '!skills/_artifacts' (opposite of
the sub-package assertions), and finally clean up with rmSync(monoRoot, {
recursive: true, force: true }).
packages/intent/tests/workspace-patterns.test.ts (1)

34-37: Restore every saved cwd in afterEach.

withCwd() is stack-based, but this cleanup only unwinds one frame. A future nested helper call would leak process.cwd() into the next test.

♻️ Suggested tweak
 afterEach(() => {
-  if (cwdStack.length > 0) {
-    process.chdir(cwdStack.pop()!)
-  }
+  while (cwdStack.length > 0) {
+    process.chdir(cwdStack.pop()!)
+  }

   for (const root of roots.splice(0)) {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/intent/tests/workspace-patterns.test.ts` around lines 34 - 37, The
afterEach cleanup only pops a single cwd from cwdStack, which can leak nested
withCwd() changes; modify the afterEach hook that references cwdStack and
process.chdir so it fully unwinds the stack (e.g., while (cwdStack.length > 0)
pop and chdir each saved cwd) to restore every saved cwd and ensure no
process.cwd() state is leaked between tests.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/intent/src/commands/validate.ts`:
- Around line 69-74: The check for `_artifacts` uses context.isMonorepo which is
too broad; change the gate to detect whether the target package is a workspace
sub-package (i.e., not the workspace root). Replace occurrences that read
`!context.isMonorepo` (used with `files.includes('!skills/_artifacts')` and the
duplicate block at 171-173) with a condition that checks the package is inside a
workspace but not the workspace root, e.g. verify `context.workspaceRoot &&
context.workspaceRoot !== context.packageRoot` (or use an explicit
`context.isWorkspaceSubpackage` boolean if available) so only sub-packages
skip/require the `!skills/_artifacts` validation and warning.

In `@packages/intent/src/core/project-context.ts`:
- Around line 35-47: The isMonorepo flag incorrectly uses workspaceRoot !==
null; change it so it only becomes true when a workspace exists AND the current
package is inside it (i.e. packageRoot is not the workspace root). Update the
returned isMonorepo expression in project-context.ts to check both workspaceRoot
!== null and packageRoot !== workspaceRoot (or equivalent null-safe comparison)
so the root package is not treated as a sub-package by callers like validate and
runEditPackageJson.

---

Nitpick comments:
In `@packages/intent/src/commands/validate.ts`:
- Around line 5-8: The current import mixes a type and a value which triggers
ESLint's import/consistent-type-specifier-style; split the import into a
type-only import for ProjectContext and a separate value import for
resolveProjectContext by replacing the single mixed import with an "import type
{ ProjectContext } from '../core/project-context.js'" and a normal "import {
resolveProjectContext } from '../core/project-context.js'"; ensure you only
change the import statements and keep the module path and identifiers
(ProjectContext, resolveProjectContext) intact.

In `@packages/intent/tests/setup.test.ts`:
- Around line 188-220: Add a new test case that runs runEditPackageJson against
the monorepo root (created by createMonorepo) to verify that the workspace-root
package keeps the '!skills/_artifacts' exclusion; call
runEditPackageJson(monoRoot), assert result.added includes 'files: "skills"',
then read the root package.json and assert pkg.files contains both 'skills' and
'!skills/_artifacts' (opposite of the sub-package assertions), and finally clean
up with rmSync(monoRoot, { recursive: true, force: true }).

In `@packages/intent/tests/workspace-patterns.test.ts`:
- Around line 34-37: The afterEach cleanup only pops a single cwd from cwdStack,
which can leak nested withCwd() changes; modify the afterEach hook that
references cwdStack and process.chdir so it fully unwinds the stack (e.g., while
(cwdStack.length > 0) pop and chdir each saved cwd) to restore every saved cwd
and ensure no process.cwd() state is leaked between tests.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d0f8dd4d-b037-4053-8824-43a6019bcb54

📥 Commits

Reviewing files that changed from the base of the PR and between a1ecb68 and 667e06f.

📒 Files selected for processing (12)
  • .changeset/busy-peas-fail.md
  • .changeset/red-regions-shine.md
  • packages/intent/src/cli-support.ts
  • packages/intent/src/commands/validate.ts
  • packages/intent/src/core/project-context.ts
  • packages/intent/src/scanner.ts
  • packages/intent/src/setup.ts
  • packages/intent/src/workspace-patterns.ts
  • packages/intent/tests/cli.test.ts
  • packages/intent/tests/project-context.test.ts
  • packages/intent/tests/setup.test.ts
  • packages/intent/tests/workspace-patterns.test.ts

Comment on lines 69 to 74
// In monorepos, _artifacts lives at repo root, not under packages —
// the negation pattern is a no-op and shouldn't be added.
const isMonorepoPkg = isInsideMonorepo(root)

if (!isMonorepoPkg && !files.includes('!skills/_artifacts')) {
if (!context.isMonorepo && !files.includes('!skills/_artifacts')) {
warnings.push(
'"!skills/_artifacts" is not in the "files" array — artifacts will be published unnecessarily',
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

context.isMonorepo is too broad for the _artifacts gate.

resolveProjectContext marks the workspace root package as monorepo too, so these branches now skip the local skills/_artifacts validation and !skills/_artifacts warning for a root package that still needs them. Gate this on “target package is a workspace sub-package” instead of “a workspace root exists”.

Suggested direction
+const isWorkspaceSubpackage =
+  context.packageRoot !== null &&
+  context.workspaceRoot !== null &&
+  context.packageRoot !== context.workspaceRoot
+
 // In monorepos, _artifacts lives at repo root, not under packages —
 // the negation pattern is a no-op and shouldn't be added.
-    if (!context.isMonorepo && !files.includes('!skills/_artifacts')) {
+    if (!isWorkspaceSubpackage && !files.includes('!skills/_artifacts')) {
       warnings.push(
         '"!skills/_artifacts" is not in the "files" array — artifacts will be published unnecessarily',
       )
     }
@@
 const artifactsDir = join(skillsDir, '_artifacts')
-if (!context.isMonorepo && existsSync(artifactsDir)) {
+if (!isWorkspaceSubpackage && existsSync(artifactsDir)) {
Based on learnings: `_artifacts` handling should answer whether the target package is a sub-package inside a monorepo, not merely whether the package belongs to any workspace.

Also applies to: 171-173

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/intent/src/commands/validate.ts` around lines 69 - 74, The check for
`_artifacts` uses context.isMonorepo which is too broad; change the gate to
detect whether the target package is a workspace sub-package (i.e., not the
workspace root). Replace occurrences that read `!context.isMonorepo` (used with
`files.includes('!skills/_artifacts')` and the duplicate block at 171-173) with
a condition that checks the package is inside a workspace but not the workspace
root, e.g. verify `context.workspaceRoot && context.workspaceRoot !==
context.packageRoot` (or use an explicit `context.isWorkspaceSubpackage` boolean
if available) so only sub-packages skip/require the `!skills/_artifacts`
validation and warning.

Comment on lines +35 to +47
const workspaceRoot =
findWorkspaceRoot(packageRoot ?? resolvedTargetPath) ??
findWorkspaceRoot(resolvedCwd)
const workspacePatterns = workspaceRoot
? (readWorkspacePatterns(workspaceRoot) ?? [])
: []

return {
cwd: resolvedCwd,
workspaceRoot,
packageRoot,
isMonorepo: workspaceRoot !== null,
workspacePatterns,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Don’t mark the workspace root package as isMonorepo.

workspaceRoot !== null conflates “a workspace exists” with “this package is inside the workspace”. When packageRoot === workspaceRoot, callers like validate and runEditPackageJson will treat the root package like a sub-package and skip the !skills/_artifacts handling that still needs to happen there.

[suggested fix]

🐛 Suggested fix
   const workspaceRoot =
     findWorkspaceRoot(packageRoot ?? resolvedTargetPath) ??
     findWorkspaceRoot(resolvedCwd)
+  const isMonorepo =
+    packageRoot !== null &&
+    workspaceRoot !== null &&
+    workspaceRoot !== packageRoot
   const workspacePatterns = workspaceRoot
     ? (readWorkspacePatterns(workspaceRoot) ?? [])
     : []

   return {
     cwd: resolvedCwd,
     workspaceRoot,
     packageRoot,
-    isMonorepo: workspaceRoot !== null,
+    isMonorepo,

Based on learnings: packaging-related monorepo checks should answer whether the package is inside the workspace, not whether the package root itself is the workspace root.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const workspaceRoot =
findWorkspaceRoot(packageRoot ?? resolvedTargetPath) ??
findWorkspaceRoot(resolvedCwd)
const workspacePatterns = workspaceRoot
? (readWorkspacePatterns(workspaceRoot) ?? [])
: []
return {
cwd: resolvedCwd,
workspaceRoot,
packageRoot,
isMonorepo: workspaceRoot !== null,
workspacePatterns,
const workspaceRoot =
findWorkspaceRoot(packageRoot ?? resolvedTargetPath) ??
findWorkspaceRoot(resolvedCwd)
const isMonorepo =
packageRoot !== null &&
workspaceRoot !== null &&
workspaceRoot !== packageRoot
const workspacePatterns = workspaceRoot
? (readWorkspacePatterns(workspaceRoot) ?? [])
: []
return {
cwd: resolvedCwd,
workspaceRoot,
packageRoot,
isMonorepo,
workspacePatterns,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/intent/src/core/project-context.ts` around lines 35 - 47, The
isMonorepo flag incorrectly uses workspaceRoot !== null; change it so it only
becomes true when a workspace exists AND the current package is inside it (i.e.
packageRoot is not the workspace root). Update the returned isMonorepo
expression in project-context.ts to check both workspaceRoot !== null and
packageRoot !== workspaceRoot (or equivalent null-safe comparison) so the root
package is not treated as a sub-package by callers like validate and
runEditPackageJson.

@LadyBluenotes LadyBluenotes merged commit 09fea20 into main Mar 25, 2026
5 checks passed
@LadyBluenotes LadyBluenotes deleted the refactor branch March 25, 2026 00:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: resolveWorkspacePackages fails for nested workspace patterns bug: pnpm-workspace.yaml not detected by validate and edit-package-json commands

2 participants