From 455491f676bccc1132c172c5332c2f311fa66475 Mon Sep 17 00:00:00 2001 From: ScaleLeanChris Date: Thu, 20 Aug 2026 17:28:01 -0600 Subject: [PATCH] Include project dot paths in file listings --- .../src/command-handlers/file-list.test.ts | 36 +++++++++++++++++++ .../src/command-handlers/file-list.ts | 5 +-- packages/host-daemon-contract/src/protocol.ts | 6 +++- .../test/contract.test.ts | 2 +- 4 files changed, 45 insertions(+), 4 deletions(-) diff --git a/apps/host-daemon/src/command-handlers/file-list.test.ts b/apps/host-daemon/src/command-handlers/file-list.test.ts index 5ea132ca90..9d010d8cce 100644 --- a/apps/host-daemon/src/command-handlers/file-list.test.ts +++ b/apps/host-daemon/src/command-handlers/file-list.test.ts @@ -236,6 +236,42 @@ describe("listPathsRecursively", () => { } }); + it("includes project dot paths without traversing Git internals or dependencies", async () => { + const root = await fs.mkdtemp(path.join(os.tmpdir(), "bb-file-list-")); + try { + await fs.mkdir(path.join(root, ".github", "workflows"), { + recursive: true, + }); + await fs.writeFile(path.join(root, ".github", "workflows", "ci.yml"), ""); + await fs.writeFile(path.join(root, ".env"), ""); + await fs.mkdir(path.join(root, ".git")); + await fs.writeFile(path.join(root, ".git", "config"), ""); + await fs.mkdir(path.join(root, "node_modules", "dependency"), { + recursive: true, + }); + await fs.writeFile( + path.join(root, "node_modules", "dependency", "index.js"), + "", + ); + + const result = await listPathsRecursively({ + dir: root, + root, + includeFiles: true, + includeDirectories: true, + }); + + expect(result.map((entry) => entry.path).sort()).toEqual([ + ".env", + ".github", + ".github/workflows", + ".github/workflows/ci.yml", + ]); + } finally { + await fs.rm(root, { recursive: true, force: true }); + } + }); + it("does not return symlinked files as regular path entries", async () => { const root = await fs.mkdtemp(path.join(os.tmpdir(), "bb-file-list-")); try { diff --git a/apps/host-daemon/src/command-handlers/file-list.ts b/apps/host-daemon/src/command-handlers/file-list.ts index 1f1c96bde8..44446144a0 100644 --- a/apps/host-daemon/src/command-handlers/file-list.ts +++ b/apps/host-daemon/src/command-handlers/file-list.ts @@ -49,6 +49,8 @@ export interface ListPathsRecursivelyArgs extends PathListInclusion { root: string; } +const RECURSIVE_PATH_SKIP_NAMES = new Set([".git", "node_modules"]); + function shouldIncludePath( pathKind: HostPathEntryKind, inclusion: PathListInclusion, @@ -140,8 +142,7 @@ export async function listPathsRecursively( const entries = await fs.readdir(args.dir, { withFileTypes: true }); const results: ListedPath[] = []; for (const entry of entries) { - if (entry.name.startsWith(".")) continue; - if (entry.name === "node_modules") continue; + if (RECURSIVE_PATH_SKIP_NAMES.has(entry.name)) continue; if (entry.isSymbolicLink()) continue; const fullPath = path.join(args.dir, entry.name); diff --git a/packages/host-daemon-contract/src/protocol.ts b/packages/host-daemon-contract/src/protocol.ts index a0b3c4de9d..4bc8a5561a 100644 --- a/packages/host-daemon-contract/src/protocol.ts +++ b/packages/host-daemon-contract/src/protocol.ts @@ -1,3 +1,7 @@ +// Version 147 includes ordinary project dot paths in recursive file listings +// while continuing to exclude `.git`, `node_modules`, and symlinks. Older +// daemons silently omit paths such as `.github/workflows/ci.yml`. +// // Version 146 adds the lightweight `host.list_branch_options` RPC so branch // pickers can read cached refs while the daemon refreshes remotes in the // background. Older daemons cannot parse or serve that command. @@ -110,7 +114,7 @@ // // The version mismatch is what triggers the enrolled daemon's automatic update // instead of an `invalid-message` reconnect loop. -export const HOST_DAEMON_PROTOCOL_VERSION = 146 as const; +export const HOST_DAEMON_PROTOCOL_VERSION = 147 as const; /** * Absolute ceiling for any executable artifact delivered to a host daemon — diff --git a/packages/host-daemon-contract/test/contract.test.ts b/packages/host-daemon-contract/test/contract.test.ts index 893dcc6006..5cd4099623 100644 --- a/packages/host-daemon-contract/test/contract.test.ts +++ b/packages/host-daemon-contract/test/contract.test.ts @@ -1123,7 +1123,7 @@ describe("host-daemon command schemas", () => { // mixed version. Version 113 carried the Devin Desktop open target rename // and remains part of the protocol lineage. it("uses the current host-daemon protocol version", () => { - expect(HOST_DAEMON_PROTOCOL_VERSION).toBe(146); + expect(HOST_DAEMON_PROTOCOL_VERSION).toBe(147); expect(HOST_ARTIFACT_MAX_BYTES).toBe(256 * 1024 * 1024); });