Skip to content

fix: harden monorepo workspace detection and workflow generation#83

Open
WolfieLeader wants to merge 7 commits intoTanStack:mainfrom
WolfieLeader:fix/monorepo-pnpm-detection
Open

fix: harden monorepo workspace detection and workflow generation#83
WolfieLeader wants to merge 7 commits intoTanStack:mainfrom
WolfieLeader:fix/monorepo-pnpm-detection

Conversation

@WolfieLeader
Copy link
Contributor

@WolfieLeader WolfieLeader commented Mar 16, 2026

🎯 Changes

Fixes #71.

This PR fixes the monorepo regressions reported against @tanstack/intent and tightens workspace handling across setup, validation, and generated CI workflows.

  • Fix setup-github-actions so monorepo roots are detected from actual workspace config, not just current skill-bearing packages.
  • Keep workflow generation anchored to the workspace root even when the command is run from a package directory.
  • Fix validate packages/<pkg>/skills so packaging warnings are evaluated against the target package instead of the workspace root.
  • Remove false !skills/_artifacts warnings for pnpm workspace packages.
  • Generate validation and watch globs from real workspace patterns instead of hardcoding packages/*.
  • Support nested workspace patterns and Deno workspace config in the workspace-resolution path.
  • Add regression coverage for monorepo root setup, package-dir setup, pnpm validation, nested workspace layouts, and monorepos with zero skill-bearing packages.

✅ Checklist

  • I have followed the steps in the Contributing guide.
  • I have tested this code locally with pnpm run test:pr.

🚀 Release Impact

  • This change affects published code, and I have generated a changeset.
  • This change is docs/CI/dev-only (no release).

Summary by CodeRabbit

Release Notes

  • Bug Fixes

    • Fixed monorepo workspace detection for validate and stale commands to work correctly from repo roots and package directories
    • Eliminated false packaging warnings in non-standard monorepo layouts
  • New Features

    • Added support for pnpm-workspace.yaml, npm/yarn/bun workspaces in package.json, and Deno workspace configurations
    • Workflows now generate with accurate skill and watch globs derived from actual workspace configuration

@changeset-bot
Copy link

changeset-bot bot commented Mar 16, 2026

🦋 Changeset detected

Latest commit: f9010aa

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@tanstack/intent Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai
Copy link

coderabbitai bot commented Mar 16, 2026

📝 Walkthrough

Walkthrough

This PR fixes monorepo workspace detection across setup-github-actions, validate, and stale commands. It introduces workspace pattern discovery from multiple manifest formats (pnpm-workspace.yaml, package.json workspaces, deno.json), converts several async functions to synchronous, and propagates workspace context through workflow generation to derive correct skill globs and paths.

Changes

Cohort / File(s) Summary
Workspace Detection & Utilities
packages/intent/src/setup.ts, packages/intent/src/utils.ts
Adds extensive monorepo/workspace handling: JSONC parsing, support for pnpm-workspace.yaml/package.json workspaces/deno configs, workspace pattern normalization, package directory resolution via glob patterns, and workspace-aware watch-path computation. Introduces new public utilities normalizeRepoUrl and readPkgJsonFile. Replaces ad-hoc monorepo detection with centralized findWorkspaceRoot approach.
Synchronous Scanning Refactor
packages/intent/src/scanner.ts, packages/intent/src/library-scanner.ts
Converts scanForIntents and scanLibrary from async to synchronous functions, returns direct values instead of Promises. Replaces internal package reading with shared readPkgJsonFile utility. Adds repository URL normalization via normalizeRepoUrl.
CLI Command Monorepo Detection
packages/intent/src/cli.ts
Refactors collectPackagingWarnings to accept isMonorepo parameter instead of internal detection logic. Updates cmdValidate to compute workspace root and propagate monorepo awareness. Adjusts async handling in scanIntentsOrFail and loop style in resolvePackageRoot.
Workflow Template Generation
packages/intent/meta/templates/workflows/validate-skills.yml
Replaces hardcoded monorepo package loop with dynamic {{WORKSPACE_SKILL_GLOBS}} placeholder. Adds globstar support, FOUND flag tracking, and fallback skip message when no skills directories discovered. Simplifies heuristic for gathering SKILL.md directories.
Test Coverage Expansion
packages/intent/tests/cli.test.ts, packages/intent/tests/setup.test.ts
Adds new pnpm monorepo integration test for validate command without false packaging warnings. Introduces test helpers and comprehensive test suites for readWorkspacePatterns, workspace package resolution, and skill detection. Expands monorepo scenario coverage for setup and workflow generation.
Type Adjustments & Cleanup
packages/intent/src/staleness.ts
Removes non-null assertion in parseSyncState when assigning sources_sha for skills (value guaranteed to exist).
Changeset Documentation
.changeset/fix-monorepo-workspace-detection.md
Documents fix for monorepo workspace detection enabling commands to work from repo roots and package directories with correct workspace-derived skill globs.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • tannerlinsley
  • LadyBluenotes

Poem

🐰 Hop through workspaces, root to leaf,
No more broken globs bringing grief,
Patterns parsed from yaml and json,
Workflows now know where skills belong,
Monorepos dance from here on! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 38.89% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The PR title accurately summarizes the primary changes: hardening monorepo workspace detection and improving workflow generation, which aligns with the main objective of fixing issues #71.
Description check ✅ Passed The PR description addresses all required sections from the template: clearly explains the changes and motivation, includes both checklist items marked complete, and specifies the release impact with a changeset generated.
Linked Issues check ✅ Passed The PR comprehensively addresses the four main objectives from issue #71: monorepo detection from workspace config, correct template variable resolution, workflow anchoring to workspace root, and packaging warning evaluation against target packages. Additional coverage includes nested patterns, Deno support, and monorepo test cases.
Out of Scope Changes check ✅ Passed All code changes are directly related to the linked issue objectives: workspace detection enhancement, workflow generation fixes, monorepo-aware validation, and related utility improvements. No unrelated changes detected.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
📝 Coding Plan
  • Generate coding plan for human review comments

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.

Tip

CodeRabbit can suggest fixes for GitHub Check annotations.

Configure the reviews.tools.github-checks setting to adjust the time to wait for GitHub Checks to complete.

@pkg-pr-new
Copy link

pkg-pr-new bot commented Mar 16, 2026

Open in StackBlitz

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

commit: f9010aa

@WolfieLeader
Copy link
Contributor Author

Let's go all green🫡

Copy link

@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.

🧹 Nitpick comments (2)
.changeset/fix-monorepo-workspace-detection.md (1)

1-5: Consider documenting the API signature changes in the changeset.

The changeset describes the monorepo detection fixes well, but doesn't mention that scanForIntents and scanLibrary changed from async to sync. If these are part of the public API, callers using await will still work (awaiting a non-Promise returns the value), but this behavioral change might be worth documenting for clarity.

If these functions are internal-only, the current changeset is sufficient.

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

In @.changeset/fix-monorepo-workspace-detection.md around lines 1 - 5, Update
the changeset to document that the functions scanForIntents and scanLibrary
changed from async to synchronous signatures; explicitly state the new return
types and note potential caller impact (e.g., awaiting a non-Promise is benign
but callers should remove unnecessary async/await), and reference the exported
symbols scanForIntents and scanLibrary so consumers can find and adapt their
usage.
packages/intent/src/utils.ts (1)

186-191: Consider edge cases in URL normalization.

The function handles common cases well, but consider these edge cases:

  1. URLs ending with .git.git would become .git after one replacement
  2. SSH URLs like git@github.com:org/repo.git are not normalized to org/repo
  3. Non-GitHub URLs (GitLab, Bitbucket) retain their full path after https:// removal

If these edge cases are acceptable for the current use case (deriving repo identifiers), the implementation is fine. Otherwise, consider more robust URL parsing.

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

In `@packages/intent/src/utils.ts` around lines 186 - 191, normalizeRepoUrl
currently only strips a single leading git+ prefix, a single trailing ".git",
and only matches "https://github.com/"; to handle the edge cases update
normalizeRepoUrl to (1) remove repeated ".git" suffixes (e.g. trim all trailing
".git" occurrences), (2) convert SSH style URLs like
"git@github.com:org/repo.git" into "org/repo" by detecting the "git@" pattern
and replacing the "user@host:" prefix with host path, and (3) optionally
generalize host stripping to remove "https?://<host>/" for non-GitHub hosts (or
keep existing behavior if only GitHub is desired); update the function
normalizeRepoUrl accordingly and add unit tests for inputs like
"git+https://github.com/org/repo.git.git", "git@github.com:org/repo.git", and a
non-GitHub https URL to validate the chosen behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In @.changeset/fix-monorepo-workspace-detection.md:
- Around line 1-5: Update the changeset to document that the functions
scanForIntents and scanLibrary changed from async to synchronous signatures;
explicitly state the new return types and note potential caller impact (e.g.,
awaiting a non-Promise is benign but callers should remove unnecessary
async/await), and reference the exported symbols scanForIntents and scanLibrary
so consumers can find and adapt their usage.

In `@packages/intent/src/utils.ts`:
- Around line 186-191: normalizeRepoUrl currently only strips a single leading
git+ prefix, a single trailing ".git", and only matches "https://github.com/";
to handle the edge cases update normalizeRepoUrl to (1) remove repeated ".git"
suffixes (e.g. trim all trailing ".git" occurrences), (2) convert SSH style URLs
like "git@github.com:org/repo.git" into "org/repo" by detecting the "git@"
pattern and replacing the "user@host:" prefix with host path, and (3) optionally
generalize host stripping to remove "https?://<host>/" for non-GitHub hosts (or
keep existing behavior if only GitHub is desired); update the function
normalizeRepoUrl accordingly and add unit tests for inputs like
"git+https://github.com/org/repo.git.git", "git@github.com:org/repo.git", and a
non-GitHub https URL to validate the chosen behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 639760bb-837c-4af4-9248-1033735b3f73

📥 Commits

Reviewing files that changed from the base of the PR and between 379efa8 and c404d2c.

📒 Files selected for processing (14)
  • .changeset/fix-monorepo-workspace-detection.md
  • packages/intent/meta/templates/workflows/validate-skills.yml
  • packages/intent/src/cli.ts
  • packages/intent/src/intent-library.ts
  • packages/intent/src/library-scanner.ts
  • packages/intent/src/scanner.ts
  • packages/intent/src/setup.ts
  • packages/intent/src/staleness.ts
  • packages/intent/src/utils.ts
  • packages/intent/tests/cli.test.ts
  • packages/intent/tests/library-scanner.test.ts
  • packages/intent/tests/scanner.test.ts
  • packages/intent/tests/setup.test.ts
  • packages/intent/tests/staleness.test.ts

Copy link

@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.

🧹 Nitpick comments (1)
packages/intent/tests/setup.test.ts (1)

255-282: Harden test teardown to avoid leaked temp dirs/mocks on assertion failures.

Several tests clean up only at the end of the test body. If an assertion throws early, teardown is skipped, which can pollute subsequent tests:

  • Lines 255–282: rmSync(monoRoot, ...) at end, unguarded
  • Lines 343–384: rmSync(monoRoot, ...) at end, unguarded
  • Lines 451–524: logSpy.mockRestore() at end, unguarded
  • Lines 526–570: logSpy.mockRestore() at end, unguarded

Wrap each test body in a try/finally block to ensure cleanup always executes:

♻️ Suggested pattern (try/finally guarded teardown)
 it('treats workspace roots without package skills as monorepos', () => {
   const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {})
+  try {
 
-  writeFileSync(
-    join(metaDir, 'templates', 'workflows', 'validate-skills.yml'),
-    'for dir in {{WORKSPACE_SKILL_GLOBS}}; do\n  echo "$dir"\ndone\n',
-  )
-  // ... test setup/assertions ...
-  logSpy.mockRestore()
+    writeFileSync(
+      join(metaDir, 'templates', 'workflows', 'validate-skills.yml'),
+      'for dir in {{WORKSPACE_SKILL_GLOBS}}; do\n  echo "$dir"\ndone\n',
+    )
+    // ... test setup/assertions ...
+  } finally {
+    logSpy.mockRestore()
+  }
 })
 it('skips !skills/_artifacts in pnpm monorepo packages (pnpm-workspace.yaml)', () => {
   const monoRoot = mkdtempSync(join(tmpdir(), 'pnpm-mono-'))
+  try {
-  const pkgDir = join(monoRoot, 'packages', 'my-lib')
-  mkdirSync(pkgDir, { recursive: true })
-  // ... test setup/assertions ...
-  rmSync(monoRoot, { recursive: true, force: true })
+    const pkgDir = join(monoRoot, 'packages', 'my-lib')
+    mkdirSync(pkgDir, { recursive: true })
+    // ... test setup/assertions ...
+  } finally {
+    rmSync(monoRoot, { recursive: true, force: true })
+  }
 })
🤖 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 255 - 282, The tests leak
temp dirs and spies when assertions throw because teardown calls (rmSync on
monoRoot and logSpy.mockRestore()) are at the end of the test bodies; wrap the
relevant test bodies that create monoRoot (where mkdtempSync is used) and those
that set logSpy in a try/finally and move rmSync(monoRoot, { recursive: true,
force: true }) and logSpy.mockRestore() into the finally block so cleanup always
runs; specifically update the test cases that reference monoRoot/mkdtempSync and
the tests that reference logSpy to use try { ... assertions ... } finally {
rmSync(...)/logSpy.mockRestore() } to guarantee teardown even on failures.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/intent/tests/setup.test.ts`:
- Around line 255-282: The tests leak temp dirs and spies when assertions throw
because teardown calls (rmSync on monoRoot and logSpy.mockRestore()) are at the
end of the test bodies; wrap the relevant test bodies that create monoRoot
(where mkdtempSync is used) and those that set logSpy in a try/finally and move
rmSync(monoRoot, { recursive: true, force: true }) and logSpy.mockRestore() into
the finally block so cleanup always runs; specifically update the test cases
that reference monoRoot/mkdtempSync and the tests that reference logSpy to use
try { ... assertions ... } finally { rmSync(...)/logSpy.mockRestore() } to
guarantee teardown even on failures.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 932e2c26-2f99-466c-8782-fae8c2e371ff

📥 Commits

Reviewing files that changed from the base of the PR and between c404d2c and f9010aa.

📒 Files selected for processing (1)
  • packages/intent/tests/setup.test.ts

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.

setup-github-actions produces broken workflows in monorepos

1 participant