Skip to content

feat: list_dir — live BFS listing (gitignore, 10k cap) - #697

Merged
justrach merged 15 commits into
release/0.2.5842from
cursor/list-dir-554f
Aug 20, 2026
Merged

feat: list_dir — live BFS listing (gitignore, 10k cap)#697
justrach merged 15 commits into
release/0.2.5842from
cursor/list-dir-554f

Conversation

@justrach

@justrach justrach commented Aug 20, 2026

Copy link
Copy Markdown
Owner

Fixes #696.

ls / tree stay index queries. list_dir walks the live tree (gitignore, 10k-char cap, collapsed subtree summaries).

This matches graff's in-process codedb list_dir (codegraff PR #579).

Cold CLI exits before snapshot/daemon (same early-exit shape as status). Temp-root guard is skipped because this is a live walk, not an index.

CLI: codedb list_dir [path] — no index required. Verified on an unindexed /tmp tree.

MCP: handler is in src/mcp_list_dir.zig. src/mcp.zig is 317KB so it is not rewritten in this PR (Contents API needs the whole file). Apply patches/696-mcp-list-dir.patch on this branch to register codedb_list_dir (Tool enum + tools_list + dispatch). Until that lands, MCP clients keep using codedb_ls (index) or the CLI.

Fixes #696. ls/tree stay index queries. list_dir walks the live tree.
Fixes #696. ls/tree stay index queries. list_dir walks the live tree.
Fixes #696. ls/tree stay index queries. list_dir walks the live tree.
Fixes #696. ls/tree stay index queries. list_dir walks the live tree.
Fixes #696. ls/tree stay index queries. list_dir walks the live tree.
Fixes #696. ls/tree stay index queries. list_dir walks the live tree.
Fixes #696. ls/tree stay index queries. list_dir walks the live tree.
Fixes #696. ls/tree stay index queries. list_dir walks the live tree.
Fixes #696. ls/tree stay index queries. list_dir walks the live tree.
Fixes #696. ls/tree stay index queries. list_dir walks the live tree.
Fixes #696. ls/tree stay index queries. list_dir walks the live tree.
Fixes #696. ls/tree stay index queries. list_dir walks the live tree.
Fixes #696. ls/tree stay index queries. list_dir walks the live tree.
@github-actions

Copy link
Copy Markdown

👋 Thanks for the contribution! Quick heads-up: this repo lands changes on the current release/* branch, not main.

Please retarget this PR via Edit → base branch to the active release/* branch shown in the repository branch list.

(Automated hint — reply here if you need a hand.)

@justrach
justrach changed the base branch from main to release/0.2.5842 August 20, 2026 07:44
@justrach
justrach marked this pull request as ready for review August 20, 2026 07:44
@justrach
justrach merged commit dcbe2f6 into release/0.2.5842 Aug 20, 2026
2 of 3 checks passed

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

Copy link
Copy Markdown

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: 04215a30da

ℹ️ 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 src/list_dir.zig
Comment on lines +124 to +128
for (names.items) |e| {
if (isGitComponent(e.name)) continue;
const child_rel = if (rel.len == 0) e.name else try join(w.arena, rel, e.name);
const child_abs = try join(w.arena, w.root_abs, child_rel);
if (try skip(w, child_abs, e.is_dir)) continue;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Filter sensitive paths before adding listing nodes

When a secret is not explicitly covered by .gitignore, this loop adds names such as .env, credentials.json, private keys, and files below .ssh to the live listing. The existing index and read paths deliberately apply watcher.isSensitivePath, so list_dir bypasses the repository's shared sensitive-path policy and exposes paths that other discovery operations hide; apply that filter before appending either files or directories.

AGENTS.md reference: AGENTS.md:L16-L17

Useful? React with 👍 / 👎.

Comment thread src/gitignore.zig
Comment on lines +83 to +87
if (pat[0] == '*') {
var i: usize = 0;
while (i <= s.len) : (i += 1) {
if (globSeg(pat[1..], s[i..])) return true;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Bound recursive gitignore wildcard matching

On a repository containing an adversarial rule such as repeated *a groups followed by a nonmatching suffix, each * recursively retries every remaining filename position, producing combinatorial work before a single entry can be processed. Because .gitignore is untrusted repository input and the 20,000-item cap is reached only after matching, one crafted pattern can effectively hang list_dir; memoize (pattern_offset, string_offset) states or use an iterative bounded matcher.

AGENTS.md reference: AGENTS.md:L16-L16

Useful? React with 👍 / 👎.

Comment thread src/list_dir.zig
Comment on lines +331 to +334
fn underRoot(abs: []const u8, root: []const u8) bool {
if (!std.mem.startsWith(u8, abs, root)) return false;
return abs.len == root.len or abs[root.len] == '/';
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Accept native separators in root containment checks

For a nested listing on Windows, realPath returns a native \ boundary after project_abs, so this comparison to '/' rejects every valid subdirectory as error.Escape. The same check also rejects children when the POSIX project root is / because /tmp has t, not another slash, at root.len; use a platform-aware path containment check and special-case filesystem roots.

Useful? React with 👍 / 👎.

Comment thread src/gitignore.zig
Comment on lines +220 to +223
if (git_root) |g| {
var buf: [std.fs.max_path_bytes]u8 = undefined;
const ex = std.fmt.bufPrint(&buf, "{s}/.git/info/exclude", .{g}) catch return out.items;
loadFile(io, arena, ex, g, &out);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Load info excludes before repository gitignore rules

When .git/info/exclude conflicts with a .gitignore already loaded by loadClimb, appending the info rules here makes them win because verdict uses the last matching rule. Git gives per-directory .gitignore files higher precedence—for example, root .gitignore containing !foo must re-include a path excluded as foo in .git/info/exclude—so the current listing hides files that Git reports as unignored.

Useful? React with 👍 / 👎.

justrach added a commit that referenced this pull request Aug 21, 2026
list_dir BFS (#697) and one-shot advertised surface (#701).
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.

Add list_dir: BFS filesystem listing with gitignore and 10k-char cap

1 participant