refactor: migrate from Bun.Glob to npm glob package

Replace Bun.Glob usage with a new Glob utility wrapper around the npm 'glob' package.
This moves us off Bun-specific APIs toward standard Node.js compatible solutions.

Changes:
- Add new src/util/glob.ts utility module with scan(), scanSync(), and match()
- Default include option is 'file' (only returns files, not directories)
- Add symlink option (default: false) to control symlink following
- Migrate all 12 files using Bun.Glob to use the new Glob utility
- Add comprehensive tests for the glob utility

Breaking changes:
- Removed support for include: 'dir' option (use include: 'all' and filter manually)
- symlink now defaults to false (was true in most Bun.Glob usages)

Files migrated:
- src/util/log.ts
- src/util/filesystem.ts
- src/tool/truncation.ts
- src/session/instruction.ts
- src/storage/json-migration.ts
- src/storage/storage.ts
- src/project/project.ts
- src/cli/cmd/tui/context/theme.tsx
- src/config/config.ts
- src/tool/registry.ts
- src/skill/skill.ts
- src/file/ignore.ts
This commit is contained in:
Dax Raad
2026-02-19 12:33:56 -05:00
parent 56dda4c98c
commit 3c21735b35
17 changed files with 231 additions and 127 deletions

View File

@@ -28,6 +28,7 @@ import { constants, existsSync } from "fs"
import { Bus } from "@/bus"
import { GlobalBus } from "@/bus/global"
import { Event } from "../server/event"
import { Glob } from "../util/glob"
import { PackageRegistry } from "@/bun/registry"
import { proxied } from "@/util/proxied"
import { iife } from "@/util/iife"
@@ -351,14 +352,12 @@ export namespace Config {
return ext.length ? file.slice(0, -ext.length) : file
}
const COMMAND_GLOB = new Bun.Glob("{command,commands}/**/*.md")
async function loadCommand(dir: string) {
const result: Record<string, Command> = {}
for await (const item of COMMAND_GLOB.scan({
absolute: true,
followSymlinks: true,
dot: true,
for (const item of await Glob.scan("{command,commands}/**/*.md", {
cwd: dir,
absolute: true,
dot: true,
})) {
const md = await ConfigMarkdown.parse(item).catch(async (err) => {
const message = ConfigMarkdown.FrontmatterError.isInstance(err)
@@ -390,15 +389,13 @@ export namespace Config {
return result
}
const AGENT_GLOB = new Bun.Glob("{agent,agents}/**/*.md")
async function loadAgent(dir: string) {
const result: Record<string, Agent> = {}
for await (const item of AGENT_GLOB.scan({
absolute: true,
followSymlinks: true,
dot: true,
for (const item of await Glob.scan("{agent,agents}/**/*.md", {
cwd: dir,
absolute: true,
dot: true,
})) {
const md = await ConfigMarkdown.parse(item).catch(async (err) => {
const message = ConfigMarkdown.FrontmatterError.isInstance(err)
@@ -430,14 +427,12 @@ export namespace Config {
return result
}
const MODE_GLOB = new Bun.Glob("{mode,modes}/*.md")
async function loadMode(dir: string) {
const result: Record<string, Agent> = {}
for await (const item of MODE_GLOB.scan({
absolute: true,
followSymlinks: true,
dot: true,
for (const item of await Glob.scan("{mode,modes}/*.md", {
cwd: dir,
absolute: true,
dot: true,
})) {
const md = await ConfigMarkdown.parse(item).catch(async (err) => {
const message = ConfigMarkdown.FrontmatterError.isInstance(err)
@@ -467,15 +462,13 @@ export namespace Config {
return result
}
const PLUGIN_GLOB = new Bun.Glob("{plugin,plugins}/*.{ts,js}")
async function loadPlugin(dir: string) {
const plugins: string[] = []
for await (const item of PLUGIN_GLOB.scan({
absolute: true,
followSymlinks: true,
dot: true,
for (const item of await Glob.scan("{plugin,plugins}/*.{ts,js}", {
cwd: dir,
absolute: true,
dot: true,
})) {
plugins.push(pathToFileURL(item).href)
}