Skip to content

Rdpath find#123

Merged
tobyhede merged 4 commits intomainfrom
rdpath-find
Mar 18, 2026
Merged

Rdpath find#123
tobyhede merged 4 commits intomainfrom
rdpath-find

Conversation

@tobyhede
Copy link
Copy Markdown
Owner

@tobyhede tobyhede commented Mar 18, 2026

Summary by CodeRabbit

  • New Features
    • Added a default "path" command plus a new "find" subcommand to locate files using glob patterns, with optional context scoping and deterministic sorted results.
  • Bug Fixes / Improvements
    • Better input validation, clearer error messages for invalid patterns/contexts or missing directories, and protections against unsafe traversal.
  • Documentation
    • Added rdpath usage docs with examples for path assembly and file discovery.
  • Tests
    • Added comprehensive unit and integration tests for discovery and CLI behavior.

Restructure rdpath from flat command to subcommand pattern (path as
default, find as new) for cross-platform file discovery within artifact
directories. Uses Node 24 built-in fs.glob() with isPathInside()
traversal protection. Extract validateCtx() and resolveBaseDir() helpers
from assemblePath() for reuse. Backward compatible via isDefault: true.
Replace instanceof Error with getErrorMessage() from shared/errors.js
for cross-realm ESM compatibility. Make resolveBaseDir a private
function to prevent bypassing ctx validation.
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e683eaae5d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/claude-code-plugin/src/rdpath-core.ts Outdated
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 18, 2026

Warning

Rate limit exceeded

@tobyhede has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 3 minutes and 31 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 750266e9-2ef4-45fb-a9eb-13037246034c

📥 Commits

Reviewing files that changed from the base of the PR and between 1ccc5fb and 0a457d8.

📒 Files selected for processing (2)
  • packages/claude-code-plugin/__tests__/rdpath-core.test.ts
  • packages/claude-code-plugin/src/rdpath-core.ts
📝 Walkthrough

Walkthrough

Adds a glob-based file discovery feature to rdpath via a new find subcommand, plus context validation, traversal prevention, context-scoped directory resolution, sorted matching, and CLI integration while preserving the existing path command.

Changes

Cohort / File(s) Summary
Documentation
CLAUDE.md
Added documentation for rdpath (Path Assembly Tool) including usage examples and a find subcommand description.
Core Implementation
packages/claude-code-plugin/src/rdpath-core.ts
Added findFiles (glob-based discovery), validateCtx, internal resolveBaseDir, traversal-protection pattern, RdPathFindOptions, and integrated validation/resolution into assemblePath. Exports updated to include validateCtx and findFiles.
CLI Integration
packages/claude-code-plugin/src/rdpath.ts
Converted CLI to multi-command with default path and new find command; imports findFiles/RdPathFindOptions and getErrorMessage, centralizes error formatting, and prints async find results with appropriate exit codes.
Unit Tests
packages/claude-code-plugin/__tests__/rdpath-core.test.ts
Added extensive tests for findFiles behavior (glob matching, no-match, missing dir, ctx scoping, dir-prefixes, lexicographic sorting, traversal/pattern rejection, symlink and recursive/glob scenarios); test scaffolding updated.
Integration Tests
packages/claude-code-plugin/__tests__/rdpath-find-integration.test.ts
New end-to-end CLI tests for rdpath find: verifies stdout format (one path per line), exit codes and stderr for errors, context-scoped searches, and backward-compatible --dir handling; uses spawned CLI and temp dirs.

Sequence Diagram

sequenceDiagram
    participant CLI as rdpath CLI
    participant Validator as validateCtx()
    participant Resolver as resolveBaseDir()
    participant Globber as findFiles (glob)
    participant FS as Filesystem

    CLI->>Validator: validate ctx string
    alt invalid ctx
        Validator-->>CLI: throw error
    else valid ctx
        Validator-->>CLI: return
    end

    CLI->>Resolver: resolve base dir (dir, ctx)
    Resolver->>FS: stat/check directory exists
    alt not found
        FS-->>Resolver: not found
        Resolver-->>CLI: throw "Directory not found"
    else exists
        FS-->>Resolver: ok
        Resolver-->>CLI: return scoped dir
    end

    CLI->>CLI: validate pattern (reject "..")
    alt invalid pattern
        CLI-->>CLI: exit 1 with error
    else valid pattern
        CLI->>Globber: run glob in scoped dir
        Globber->>FS: read directory tree
        FS-->>Globber: files
        Globber-->>CLI: sorted matches
        CLI-->>CLI: print matches (one per line)
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Rdpath find' directly describes the primary feature added: a new 'find' subcommand for glob-based file discovery in the rdpath tool.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch rdpath-find
📝 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.

Copy link
Copy Markdown
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

🤖 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/claude-code-plugin/__tests__/rdpath-find-integration.test.ts`:
- Around line 42-44: The current proc.on('close', (code) => resolve({ stdout,
stderr, exitCode: code ?? 0 })) masks signal-based termination by treating null
code as success; update the handler in the test to use a non-zero default (e.g.,
exitCode: code ?? 1) and/or accept the second parameter (signal) from
proc.on('close', (code, signal) => ...) and include that signal in the resolved
object so tests can distinguish normal exits from killed processes.

In `@packages/claude-code-plugin/src/rdpath.ts`:
- Around line 12-18: The import/command block (symbols assemblePath, findFiles,
RdPathFindOptions, RdPathOptions, getErrorMessage, Command, program, pathCmd) is
misformatted according to the project's formatter; run the project's formatter
(npm run format) or apply the repo's formatting rules to this section so the
import lines and Command setup follow the configured style (fix spacing,
semicolons/newlines as needed) and commit the formatted file to resolve the CI
pipeline failure.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 9c56b918-69e1-450c-881d-a78b03fc7213

📥 Commits

Reviewing files that changed from the base of the PR and between 71fe28f and e683eaa.

📒 Files selected for processing (5)
  • CLAUDE.md
  • packages/claude-code-plugin/__tests__/rdpath-core.test.ts
  • packages/claude-code-plugin/__tests__/rdpath-find-integration.test.ts
  • packages/claude-code-plugin/src/rdpath-core.ts
  • packages/claude-code-plugin/src/rdpath.ts

Comment thread packages/claude-code-plugin/src/rdpath.ts Outdated
@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages Bot commented Mar 18, 2026

Deploying rundown with  Cloudflare Pages  Cloudflare Pages

Latest commit: 0a457d8
Status: ✅  Deploy successful!
Preview URL: https://0505125f.rundown-7hl.pages.dev
Branch Preview URL: https://rdpath-find.rundown-7hl.pages.dev

View logs

Copy link
Copy Markdown
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: 1

♻️ Duplicate comments (1)
packages/claude-code-plugin/__tests__/rdpath-find-integration.test.ts (1)

42-44: ⚠️ Potential issue | 🟡 Minor

Do not map signal termination to success in runRdpath.

Line 43 uses code ?? 0, which treats signal exits as success and can hide real failures in integration tests.

🔧 Suggested fix
-      proc.on('close', (code) => {
-        resolve({ stdout, stderr, exitCode: code ?? 0 });
+      proc.on('close', (code) => {
+        resolve({ stdout, stderr, exitCode: code ?? 1 });
       });
In Node.js `child_process`, for the `'close'` event callback `(code, signal)`, can `code` be `null` when terminated by signal, and is it recommended to treat that as non-zero failure in test harnesses?
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/claude-code-plugin/__tests__/rdpath-find-integration.test.ts` around
lines 42 - 44, The test harness currently maps a null exit code to 0 in the
proc.on('close', (code) => resolve({ stdout, stderr, exitCode: code ?? 0 }))
callback, which treats signal-terminated processes as successful; change the
logic in runRdpath (the proc.on('close' handler) to treat code === null as
failure by setting exitCode to a non-zero value (e.g., 1) and include the signal
in the resolved object (resolve({ stdout, stderr, exitCode: code !== null ? code
: 1, signal })) so signal terminations are not masked as success.
🤖 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/claude-code-plugin/src/rdpath-core.ts`:
- Around line 114-140: findings: findFiles() currently allows absolute glob
patterns (which bypass cwd scoping) and includes directories in results,
violating the JSDoc that promises "matching file paths". Fix: first reject
absolute patterns (use path.isAbsolute(pattern) and throw a clear error) in
addition to the existing TRAVERSAL_PATTERN check; then when iterating glob
results from fs.glob(pattern, { cwd: absoluteDir }), ensure only files are
returned by either passing a nodir-like option to fs.glob if available or by
stat-ing each absoluteMatch (using fs.stat or fs.lstat) and skipping entries
where stat.isDirectory() is true; keep the isPathInside(absoluteDir,
absoluteMatch) validation and push path.join(resolvedDir, match) only for
verified file matches so matches[] contains only files.

---

Duplicate comments:
In `@packages/claude-code-plugin/__tests__/rdpath-find-integration.test.ts`:
- Around line 42-44: The test harness currently maps a null exit code to 0 in
the proc.on('close', (code) => resolve({ stdout, stderr, exitCode: code ?? 0 }))
callback, which treats signal-terminated processes as successful; change the
logic in runRdpath (the proc.on('close' handler) to treat code === null as
failure by setting exitCode to a non-zero value (e.g., 1) and include the signal
in the resolved object (resolve({ stdout, stderr, exitCode: code !== null ? code
: 1, signal })) so signal terminations are not masked as success.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 34726f22-1131-43c2-a0f7-391adf12adbf

📥 Commits

Reviewing files that changed from the base of the PR and between e683eaa and b00042f.

📒 Files selected for processing (4)
  • packages/claude-code-plugin/__tests__/rdpath-core.test.ts
  • packages/claude-code-plugin/__tests__/rdpath-find-integration.test.ts
  • packages/claude-code-plugin/src/rdpath-core.ts
  • packages/claude-code-plugin/src/rdpath.ts

Comment thread packages/claude-code-plugin/src/rdpath-core.ts
Address PR review feedback:
- Reject absolute glob patterns that bypass cwd scoping
- Filter glob results to files only (exclude directories)
- Treat null exit code as failure in integration test harness
Copy link
Copy Markdown
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

🤖 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/claude-code-plugin/__tests__/rdpath-core.test.ts`:
- Around line 203-233: Add a new test in rdpath-core.test.ts that creates a
dangling symlink inside testDir (symlink pointing to a non-existent target),
calls findFiles({ dir: testDir }, '*.md'), and asserts the expected behavior
(either that the dangling symlink is excluded or included according to project
convention); use the same pattern as the existing symlink tests (create files
with fs.writeFile / fs.symlink, call findFiles, and use
expect(results).toEqual(...) or expect(...).not.toContainEqual(...)) and
reference testDir and findFiles so the regression for broken links is pinned.

In `@packages/claude-code-plugin/src/rdpath-core.ts`:
- Around line 141-146: The glob loop that calls fs.realpath and fs.lstat (inside
the for-await over fs.glob with pattern/absoluteDir and using variables
absoluteMatch, realMatch, stat) needs a try-catch so a single FS error doesn't
abort findFiles; wrap the fs.realpath(realMatch) and fs.lstat(realMatch) calls
in a try block, catch errors and use the existing isNodeError(err) helper to
check err.code and continue the loop for expected recoverable codes (ENOENT,
EACCES, EPERM, ELOOP), but re-throw the error for anything else so unexpected
failures still surface.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 166631bd-8924-4f68-a86f-6da87283bd2a

📥 Commits

Reviewing files that changed from the base of the PR and between b00042f and 1be104f.

📒 Files selected for processing (3)
  • packages/claude-code-plugin/__tests__/rdpath-core.test.ts
  • packages/claude-code-plugin/__tests__/rdpath-find-integration.test.ts
  • packages/claude-code-plugin/src/rdpath-core.ts

Comment thread packages/claude-code-plugin/__tests__/rdpath-core.test.ts
Comment thread packages/claude-code-plugin/src/rdpath-core.ts Outdated
Copy link
Copy Markdown
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

🤖 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/claude-code-plugin/__tests__/rdpath-core.test.ts`:
- Around line 108-112: Add a new test in rdpath-core.test.ts that exercises the
"existing path but not a directory" branch by calling findFiles with dir set to
a path that exists as a file (e.g., path.join(testDir, 'someFile.txt')) and
asserting the promise rejects with the "Not a directory" error; locate the
existing test named 'throws for nonexistent directory' and add a sibling it(...)
that uses await expect(findFiles({ dir: path.join(testDir, '<filename>' ) },
'*.md')).rejects.toThrow('Not a directory') to pin the Not a directory branch in
the findFiles codepath.

In `@packages/claude-code-plugin/src/rdpath-core.ts`:
- Around line 104-108: The TSDoc for findFiles omits the error case where the
provided dir exists but is not a directory; update the findFiles docblock to add
a `@throws` entry describing that an Error is thrown when the path specified by
options.dir exists but is not a directory (e.g., "When dir exists but is not a
directory"). Locate the JSDoc/TSDoc immediately above the findFiles function
declaration and add the concise `@throws` clause alongside the existing throws
about invalid ctx, traversal patterns, and missing directories so the exported
API contract accurately documents all failure paths.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 361ae13e-e9c4-4a09-824d-95438b4ae7e2

📥 Commits

Reviewing files that changed from the base of the PR and between 1be104f and 1ccc5fb.

📒 Files selected for processing (2)
  • packages/claude-code-plugin/__tests__/rdpath-core.test.ts
  • packages/claude-code-plugin/src/rdpath-core.ts

Comment thread packages/claude-code-plugin/__tests__/rdpath-core.test.ts
Comment thread packages/claude-code-plugin/src/rdpath-core.ts
Symlinked matches could bypass the directory jail because isPathInside()
only checked the lexical path while fs.stat() followed the symlink.
Resolve each match with fs.realpath() before the containment check, and
resolve the base directory too so both sides compare real paths.
@tobyhede tobyhede merged commit 35cc7bb into main Mar 18, 2026
18 checks passed
@coderabbitai coderabbitai Bot mentioned this pull request Mar 18, 2026
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.

1 participant