Improve Intent core loading for monorepos and agent adapters#124
Improve Intent core loading for monorepos and agent adapters#124LadyBluenotes merged 21 commits intomainfrom
Conversation
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (10)
📝 WalkthroughWalkthroughExtracts an Intent core API, adds fast-path skill resolution and exclude-pattern handling, rewrites markdown link destinations, adds ChangesIntent Core & CLI Integration
Sequence Diagram(s)sequenceDiagram
participant CLI as CLI (load)
participant Core as Intent Core
participant Parser as Use Parser
participant Excludes as Exclude Matcher
participant FastPath as Fast-Path Resolver
participant Scanner as Scanner (full-scan)
participant FileIO as File I/O / Markdown Rewriter
participant User as User Output
CLI->>Core: loadIntentSkill(use, options)
Core->>Parser: parse use
Parser-->>Core: SkillUse {packageName, skillName}
Core->>Excludes: getEffectiveExcludePatterns(...)
Excludes-->>Core: matchers
Core->>Excludes: isPackageExcluded(packageName, matchers)
Excludes-->>Core: boolean
alt package excluded
Core->>CLI: throw IntentCoreError('package-excluded')
CLI->>User: error message
else
Core->>FastPath: resolveSkillUseFastPath(parsedUse,...)
alt fast-path
FastPath-->>Core: ResolveSkillResult
else
Core->>Scanner: scanForIntents(...)
Scanner-->>Core: ScanResult
Core->>Core: resolveSkillUse via resolver
Core-->>Core: ResolveSkillResult
end
Core->>FileIO: read resolved.path
FileIO-->>Core: raw content
Core->>FileIO: rewriteLoadedSkillMarkdownDestinations(...)
FileIO-->>Core: rewritten content
Core-->>CLI: LoadedIntentSkill { content, metadata, debug }
CLI->>User: render content/path/json/debug
end
sequenceDiagram
participant CLI as CLI (list)
participant Core as Intent Core
participant Scanner as Scanner
participant Excludes as Exclude Collector
participant Formatter as Formatter
participant User as CLI Output
CLI->>Core: listIntentSkills(options)
Core->>Scanner: scanForIntents(...)
Scanner-->>Core: ScanResult {packages,warnings,conflicts}
Core->>Excludes: getEffectiveExcludePatterns(...)
Excludes-->>Core: matchers
Core->>Core: filter packages/warnings/conflicts
Core->>Formatter: format skill uses & package summaries
Formatter-->>Core: IntentSkillList
alt debug=true
Core->>Core: attach debug metadata
end
Core-->>CLI: IntentSkillList
CLI->>User: render table/json/debug
Estimated code review effort🎯 4 (Complex) | ⏱️ ~55 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Tip 💬 Introducing Slack Agent: The best way for teams to turn conversations into code.Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.
Built for teams:
One agent for your entire SDLC. Right inside Slack. 👉 Get your free trial and get 200 agent minutes per Slack user (a $50 value). 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. Review rate limit: 0/1 reviews remaining, refill in 60 minutes.Comment |
|
View your CI Pipeline Execution ↗ for commit 5153bf4
☁️ Nx Cloud last updated this comment at |
commit: |
Merging this PR will not alter performance
Performance Changes
Comparing Footnotes |
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 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/core.ts`:
- Around line 166-187: The package-boundary check is currently lexical and can
be bypassed by a symlink; before calling isPathInsidePackageRoot and existsSync,
resolve symlinks for the target file and package root (e.g., use realpathSync on
resolved.path and resolved.packageRoot) and use those real paths (e.g.,
realResolvedPath, realPackageRoot) when checking with isPathInsidePackageRoot,
when calling existsSync, and when passing skillFilePath to
rewriteLoadedSkillMarkdownDestinations (instead of the original
resolved.path/resolved.packageRoot), so the containment check and file reads
operate on the canonical filesystem locations.
- Around line 111-118: The packages list currently omits a stable package
identifier, causing collisions; update the object built in IntentSkillList (the
mapping inside core.ts that creates packages with name/version/source) to
include the packageRoot (or unique id/root) field so each package retains a
stable identity, and then update packages/intent/src/commands/list.ts
getPackageSkills(...) to index/lookup packages by that packageRoot instead of
the name+version+source tuple so monorepo duplicated installs remain distinct.
In `@packages/intent/src/core/load-resolution.ts`:
- Around line 144-181: The fast-path loader in resolveSkillUseFastPath can
return stale node_modules results in Yarn PnP repos; modify
resolveSkillUseFastPath to detect Yarn PnP (presence of .pnp.cjs or .pnp.js at
process.cwd() or the workspace root) and immediately return null when PnP is
detected so the full PnP-aware scan runs instead; implement this check at the
top of resolveSkillUseFastPath before calling
getLoadFastPathCandidateDirs/scanIntentPackageAtRoot and ensure the early
bail-out preserves the existing behavior when options.globalOnly is true.
In `@packages/intent/src/scanner.ts`:
- Around line 573-584: The retry to probe Yarn PnP is using
packageCountBeforeNodeModules captured too early (before walkWorkspacePackages),
so workspace discoveries can suppress the PnP fallback; change the baseline to
capture the count immediately before the dependency-discovery steps (i.e., just
before calling scanTarget(nodeModules.local) and the dependency scans) or
otherwise compute a baseline specifically for dependency scans, then after
scanTarget(nodeModules.local), walkKnownPackages(), and walkProjectDeps() check
that dependency-specific count hasn't increased and only then call
getPnpApi()/scanPnpPackages(); reference packageCountBeforeNodeModules,
scanTarget(nodeModules.local), walkWorkspacePackages, walkKnownPackages,
walkProjectDeps, getPnpApi, and scanPnpPackages to locate and update the logic.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 56ebcea7-25fb-43be-a39b-a3cc20d1067d
📒 Files selected for processing (20)
benchmarks/intent/load.bench.tsdocs/cli/intent-list.mddocs/cli/intent-load.mdpackages/intent/package.jsonpackages/intent/src/cli-support.tspackages/intent/src/cli.tspackages/intent/src/commands/list.tspackages/intent/src/commands/load.tspackages/intent/src/core.tspackages/intent/src/core/excludes.tspackages/intent/src/core/load-resolution.tspackages/intent/src/core/markdown.tspackages/intent/src/core/package-json.tspackages/intent/src/core/types.tspackages/intent/src/resolver.tspackages/intent/src/scanner.tspackages/intent/tests/cli.test.tspackages/intent/tests/core.test.tspackages/intent/tests/resolver.test.tspackages/intent/tests/scanner.test.ts
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (2)
packages/intent/tests/cli.test.ts (1)
1005-1025: 💤 Low valueTest creates
SKILL.mdas a directory instead of a file.Line 1014 uses
mkdirSyncto createSKILL.mdas a directory. While this tests that--pathdoesn't read the file content (since reading a directory would fail), the test assertion expects the path output to includeSKILL.mdwhich is now a directory path. This works but is confusing and could mask real issues if the resolution logic changes.Consider using a proper file that exists but verifying through other means (like mocking
readFileSync) that content isn't read.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/intent/tests/cli.test.ts` around lines 1005 - 1025, The test 'prints a skill path without reading skill content' currently creates SKILL.md as a directory via mkdirSync; change this to create an actual file (use writeFileSync or similar) at node_modules/@tanstack/query/skills/fetching/SKILL.md so the path points to a real file, and keep the assertion on main(['load', '@tanstack/query#fetching', '--path']) and logSpy intact; if you need to assert that file content is not read, add a mock/spy on fs.readFileSync (or the internal file-read helper used by main) to ensure it is not called while still creating the SKILL.md file.packages/intent/src/core/excludes.ts (1)
61-67: 💤 Low valueReDoS risk from user-supplied glob patterns is low but worth noting.
The static analysis flags potential ReDoS. In practice, the risk is mitigated because:
- Patterns come from
package.jsonconfig or CLI flags (trusted sources)- The transformation escapes most metacharacters and only allows
.*wildcardsHowever, patterns like
*****would generate.*.*.*.*.*which could cause backtracking on long package names. Consider adding a simple sanity check or documenting the expected pattern format.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/intent/src/core/excludes.ts` around lines 61 - 67, The globToRegExp function can produce catastrophic regexes from inputs like "*****"; modify globToRegExp to sanity-check and normalize the pattern before building the regex: reject or trim overly long patterns (e.g., max length 200), collapse consecutive '*' into a single '*' (or reject runs longer than, say, 3), and optionally throw a clear error for invalid patterns; implement these checks inside globToRegExp (referencing function name globToRegExp and the local variable source) so only normalized/safe patterns are converted to RegExp.
🤖 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/core/excludes.ts`:
- Around line 51-59: getEffectiveExcludePatterns currently calls
getConfigExcludePatterns(process.cwd(), context) which ignores an override
passed in options.cwd; update getEffectiveExcludePatterns to pass options.cwd
when present (e.g., use options?.cwd || process.cwd()) into
getConfigExcludePatterns so config-based excludes are read from the intended
working directory; ensure you reference the getEffectiveExcludePatterns function
and the getConfigExcludePatterns call when making the change and handle the case
where options or options.cwd is undefined.
- Around line 82-91: warningMentionsPackage currently only validates the
character after packageName which allows false positives like
"prefix@tanstack/query"; update the function (warningMentionsPackage) to also
check the character before the found match: iterate through all occurrences
using indexOf(packageName, fromIndex), for each occurrence verify the char
before is either undefined (start of string) or matches /[^a-zA-Z0-9_-]/ and the
char after is undefined or matches /[^a-zA-Z0-9_-]/; return true on the first
occurrence that satisfies both bounds, otherwise continue searching and return
false if none match.
In `@packages/intent/tests/scanner.test.ts`:
- Around line 907-916: The `@tanstack/react-start` test fixture created via
writeJson(join(reactStartDir, 'package.json'), ...) is missing the intent field;
update that writeJson call to include the same intent entry used in the other
PnP fixture (e.g., add an intent property with the pnp value/shape used
elsewhere such as intent: { type: 'pnp' }) so both Yarn PnP test fixtures are
consistent.
---
Nitpick comments:
In `@packages/intent/src/core/excludes.ts`:
- Around line 61-67: The globToRegExp function can produce catastrophic regexes
from inputs like "*****"; modify globToRegExp to sanity-check and normalize the
pattern before building the regex: reject or trim overly long patterns (e.g.,
max length 200), collapse consecutive '*' into a single '*' (or reject runs
longer than, say, 3), and optionally throw a clear error for invalid patterns;
implement these checks inside globToRegExp (referencing function name
globToRegExp and the local variable source) so only normalized/safe patterns are
converted to RegExp.
In `@packages/intent/tests/cli.test.ts`:
- Around line 1005-1025: The test 'prints a skill path without reading skill
content' currently creates SKILL.md as a directory via mkdirSync; change this to
create an actual file (use writeFileSync or similar) at
node_modules/@tanstack/query/skills/fetching/SKILL.md so the path points to a
real file, and keep the assertion on main(['load', '@tanstack/query#fetching',
'--path']) and logSpy intact; if you need to assert that file content is not
read, add a mock/spy on fs.readFileSync (or the internal file-read helper used
by main) to ensure it is not called while still creating the SKILL.md file.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: baeea595-7b7f-404d-8ef6-721292e8ac8a
📒 Files selected for processing (11)
knip.jsonpackages/intent/src/commands/list.tspackages/intent/src/commands/load.tspackages/intent/src/core.tspackages/intent/src/core/excludes.tspackages/intent/src/core/load-resolution.tspackages/intent/src/core/types.tspackages/intent/src/scanner.tspackages/intent/tests/cli.test.tspackages/intent/tests/core.test.tspackages/intent/tests/scanner.test.ts
✅ Files skipped from review due to trivial changes (1)
- knip.json
🚧 Files skipped from review as they are similar to previous changes (4)
- packages/intent/src/core/types.ts
- packages/intent/tests/core.test.ts
- packages/intent/src/scanner.ts
- packages/intent/src/commands/load.ts
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 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/core.ts`:
- Around line 42-49: The rethrow wraps resolver errors into IntentCoreError but
drops ResolveSkillUseError.suggestedSkills; modify IntentCoreError to accept and
store an optional suggestedSkills property and ensure wherever
ResolveSkillUseError is caught and rethrown (the code paths that create new
IntentCoreError) pass through err.suggestedSkills into the IntentCoreError
instance (e.g., add suggestedSkills?: SuggestedSkill[] to the IntentCoreError
constructor and assign this.suggestedSkills = suggestedSkills when constructing
from a caught ResolveSkillUseError). Ensure the exported IntentCoreError type
includes the new property so consumers can access structured skill suggestions.
- Around line 75-85: The helper withCwd currently mutates global process.cwd via
process.chdir, causing race conditions for public APIs like listIntentSkills,
resolveIntentSkill, and loadIntentSkill; instead remove use of process.chdir and
thread a cwd parameter through the scanning/resolution helpers: update withCwd
callers (listIntentSkills, resolveIntentSkill, loadIntentSkill) to accept and
pass an explicit cwd string into functions that resolve paths (e.g.,
scan/resolve helpers invoked inside those functions), add an optional cwd param
to those helper signatures and use path.resolve(baseCwd, relativePath) or join
with the provided cwd for all file lookups, and delete the process.chdir logic
so no global process state is mutated. Ensure all internal calls propagate the
cwd and default to process.cwd() only where a caller didn't supply one.
In `@packages/intent/src/core/excludes.ts`:
- Line 10: PACKAGE_NAME_BOUNDARY treats '.' as a separator which causes dotted
package names like "foo.bar" to be split; update the boundary regex constant
PACKAGE_NAME_BOUNDARY to include '.' as an allowed character (i.e., do not treat
'.' as a boundary) so warningMentionsPackage('foo.bar.baz', 'foo.bar') no longer
falsely matches; make the same change to the other identical regex occurrences
used for package tokenization (the ones referenced around the other match/block)
so all package-parsing logic consistently allows dots in package names.
In `@packages/intent/src/scanner.ts`:
- Around line 256-259: The code builds childDir by joining skillsDir with hint
parts from skillNameHints (hint, childDir, skillsDir, SKILL.md) without
validating the hint, allowing path traversal (e.g., "../"). Fix:
sanitize/validate each hint before building childDir by rejecting or normalizing
components that are empty, "." or ".." or that begin with a path separator, then
resolve the final path (using path.resolve) and assert it is contained within
skillsDir (e.g., resolvedPath.startsWith(path.resolve(skillsDir))) before
calling existsSync on the SKILL.md path; apply the same validation wherever hint
is split/joined in this file.
In `@packages/intent/tests/scanner.test.ts`:
- Line 9: Tests hardcode '/' suffixes for PnP fixture roots, which breaks
startsWith checks on Windows; update the fixtures used by the mocked
findPackageLocator in packages/intent/tests/scanner.test.ts to append the
platform separator instead of a hardcoded '/'. Replace occurrences where fixture
roots are concatenated with '/' (the roots used by the mocked
findPackageLocator) with code that uses path.sep (or path.join/Path methods) so
the locator comparisons use the OS-specific separator.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 4d4f7cee-5712-4752-9739-808540ada41b
📒 Files selected for processing (10)
packages/intent/src/cli.tspackages/intent/src/core.tspackages/intent/src/core/excludes.tspackages/intent/src/discovery/register.tspackages/intent/src/resolver.tspackages/intent/src/scanner.tspackages/intent/tests/cli.test.tspackages/intent/tests/core.test.tspackages/intent/tests/resolver.test.tspackages/intent/tests/scanner.test.ts
✅ Files skipped from review due to trivial changes (2)
- packages/intent/src/discovery/register.ts
- packages/intent/tests/core.test.ts
🚧 Files skipped from review as they are similar to previous changes (2)
- packages/intent/tests/resolver.test.ts
- packages/intent/tests/cli.test.ts
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@benchmarks/intent/load.bench.ts`:
- Around line 32-33: The benchmark is creating state.runner with
createCliRunner({ cwd: root }) which forces the runner to always use root, so
the "large-workspace" scenario never exercises workspaceRoot; update the
large-workspace case to use a runner constructed with cwd: workspaceRoot (e.g.
recreate state.runner via createCliRunner({ cwd: workspaceRoot }) before running
the large-workspace path) or make createCliRunner accept an override cwd when
invoked for that case so state.runner uses workspaceRoot for the large-workspace
benchmark.
- Around line 129-132: The console is silenced before calling createFixture()
which can throw, leaving output muted; wrap the createFixture() call so
consoleSilencer.restore() always runs on failure (use try/catch/finally or a try
around createFixture() and call consoleSilencer.restore() in the catch before
rethrowing), ensuring fixture is assigned only on success and that
consoleSilencer.silence()/consoleSilencer.restore() are paired around
createFixture() to avoid hiding errors.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 3902ef53-5c72-4369-b74e-88d87aa1ab8e
📒 Files selected for processing (1)
benchmarks/intent/load.bench.ts
Summary
node_moduleshides valid PnP packages@tanstack/intent/coreAPIs for list/load consumerslistandloadthrough the shared core behaviorloadresolution for workspace packages, root deps, pnpm isolated workspace deps, and full-scan fallback@tanstack/router-core#auth-and-guards--debugoutput forlistandloadwithout changing stdoutSummary by CodeRabbit
New Features
Documentation
Tests