Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
97f3c74
feat: update codex plugin to support 5.5 (#23789)
rekram1-node Apr 22, 2026
69e2f3b
chore: bump Bun to 1.3.13 (#23791)
Hona Apr 22, 2026
a45d9a9
fix(app): improve icon override handling in project edit dialog (#23768)
Brendonovich Apr 22, 2026
ed3d364
chore: update nix node_modules hashes
opencode-agent[bot] Apr 22, 2026
bb69648
fix: preserve BOM in text tool round-trips (#23797)
Hona Apr 22, 2026
bfb954e
chore: generate
opencode-agent[bot] Apr 22, 2026
0595c28
test: fix cross-spawn stderr race on Windows CI (#23808)
Hona Apr 22, 2026
6aa475f
chore: generate
opencode-agent[bot] Apr 22, 2026
88c5f6b
fix: consolidate project avatar source logic (#23819)
Brendonovich Apr 22, 2026
2a480a9
fix(tui): fail fast on invalid session startup (#23837)
nexxeln Apr 22, 2026
266e965
chore: generate
opencode-agent[bot] Apr 22, 2026
85ec11d
fix(session): improve session compaction (#23870)
nexxeln Apr 22, 2026
e300209
chore: generate
opencode-agent[bot] Apr 22, 2026
a7fafe4
fix(project): use git common dir for bare repo project cache (#19054)
StevenTCramer Apr 22, 2026
d61096b
docs: add MiMo V2.5 to Go pages (#23876)
MrMushrooooom Apr 22, 2026
69b7f3b
chore: generate
opencode-agent[bot] Apr 22, 2026
732fb1b
build(search): add fff-bun runtime shims
nexxeln Apr 22, 2026
e874d2c
feat(search): add runtime-aware search service
nexxeln Apr 22, 2026
e1a908c
refactor(search): route tools and routes through search
nexxeln Apr 22, 2026
afa8c69
refactor(file): use search service for file queries
nexxeln Apr 22, 2026
e6bc596
fix(file): restore empty query fallback
nexxeln Apr 22, 2026
85e07ce
feat(search): track file reads for frecency
nexxeln Apr 22, 2026
d651f37
Merge branch 'dev' into nxl/runtime-aware-search-service
nexxeln Apr 22, 2026
690afb5
Merge remote-tracking branch 'origin/dev' into nxl/runtime-aware-sear…
nexxeln Apr 23, 2026
948c962
Merge branch 'dev' into nxl/runtime-aware-search-service
nexxeln Apr 23, 2026
f6b1ff7
bump fff-bun to stop segfaults
Hona Apr 23, 2026
442ab7f
Merge remote-tracking branch 'upstream/dev' into nxl/runtime-aware-se…
Hona Apr 30, 2026
9d5ab28
align
Hona Apr 30, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions packages/opencode/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@
"node": "./src/storage/db.node.ts",
"default": "./src/storage/db.bun.ts"
},
"#fff": {
"bun": "./src/file/fff.bun.ts",
"node": "./src/file/fff.node.ts",
"default": "./src/file/fff.bun.ts"
},
"#pty": {
"bun": "./src/pty/pty.bun.ts",
"node": "./src/pty/pty.node.ts",
Expand Down Expand Up @@ -102,6 +107,7 @@
"@clack/prompts": "1.0.0-alpha.1",
"@effect/opentelemetry": "catalog:",
"@effect/platform-node": "catalog:",
"@ff-labs/fff-bun": "0.6.4",
"@gitlab/opencode-gitlab-auth": "1.3.3",
"@hono/node-server": "1.19.11",
"@hono/node-ws": "1.3.0",
Expand Down
4 changes: 2 additions & 2 deletions packages/opencode/src/cli/cmd/debug/file.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { EOL } from "os"
import { AppRuntime } from "@/effect/app-runtime"
import { Search } from "@/file/search"
import { File } from "../../../file"
import { Ripgrep } from "@/file/ripgrep"
import { bootstrap } from "../../bootstrap"
import { cmd } from "../cmd"

Expand Down Expand Up @@ -79,7 +79,7 @@ const FileTreeCommand = cmd({
}),
async handler(args) {
await bootstrap(process.cwd(), async () => {
const tree = await AppRuntime.runPromise(Ripgrep.Service.use((svc) => svc.tree({ cwd: args.dir, limit: 200 })))
const tree = await AppRuntime.runPromise(Search.Service.use((svc) => svc.tree({ cwd: args.dir, limit: 200 })))
console.log(JSON.stringify(tree, null, 2))
})
},
Expand Down
10 changes: 5 additions & 5 deletions packages/opencode/src/cli/cmd/debug/ripgrep.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { EOL } from "os"
import { Effect, Stream } from "effect"
import { AppRuntime } from "../../../effect/app-runtime"
import { Ripgrep } from "../../../file/ripgrep"
import { Search } from "../../../file/search"
import { Instance } from "../../../project/instance"
import { bootstrap } from "../../bootstrap"
import { cmd } from "../cmd"
Expand All @@ -23,7 +23,7 @@ const TreeCommand = cmd({
async handler(args) {
await bootstrap(process.cwd(), async () => {
const tree = await AppRuntime.runPromise(
Ripgrep.Service.use((svc) => svc.tree({ cwd: Instance.directory, limit: args.limit })),
Search.Service.use((svc) => svc.tree({ cwd: Instance.directory, limit: args.limit })),
)
process.stdout.write(tree + EOL)
})
Expand Down Expand Up @@ -51,8 +51,8 @@ const FilesCommand = cmd({
await bootstrap(process.cwd(), async () => {
const files = await AppRuntime.runPromise(
Effect.gen(function* () {
const rg = yield* Ripgrep.Service
return yield* rg
const search = yield* Search.Service
return yield* search
.files({
cwd: Instance.directory,
glob: args.glob ? [args.glob] : undefined,
Expand Down Expand Up @@ -90,7 +90,7 @@ const SearchCommand = cmd({
async handler(args) {
await bootstrap(process.cwd(), async () => {
const results = await AppRuntime.runPromise(
Ripgrep.Service.use((svc) =>
Search.Service.use((svc) =>
svc.search({
cwd: Instance.directory,
pattern: args.pattern,
Expand Down
4 changes: 2 additions & 2 deletions packages/opencode/src/effect/app-runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { Auth } from "@/auth"
import { Account } from "@/account/account"
import { Config } from "@/config/config"
import { Git } from "@/git"
import { Ripgrep } from "@/file/ripgrep"
import { Search } from "@/file/search"
import { File } from "@/file"
import { FileWatcher } from "@/file/watcher"
import { Storage } from "@/storage/storage"
Expand Down Expand Up @@ -57,7 +57,7 @@ export const AppLayer = Layer.mergeAll(
Account.defaultLayer,
Config.defaultLayer,
Git.defaultLayer,
Ripgrep.defaultLayer,
Search.defaultLayer,
File.defaultLayer,
FileWatcher.defaultLayer,
Storage.defaultLayer,
Expand Down
85 changes: 85 additions & 0 deletions packages/opencode/src/file/fff.bun.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import {
FileFinder,
type FileItem,
type GrepCursor,
type GrepMatch,
type GrepResult,
type InitOptions,
type SearchResult,
} from "@ff-labs/fff-bun"

export type Result<T> = { ok: true; value: T } | { ok: false; error: string }

export type Init = InitOptions

export interface Search {
items: FileItem[]
scores: SearchResult["scores"]
totalMatched: number
totalFiles: number
}

export type File = FileItem
export type Cursor = GrepCursor | null
export type Hit = GrepMatch

export interface Grep {
items: GrepResult["items"]
totalMatched: number
totalFilesSearched: number
totalFiles: number
filteredFileCount: number
nextCursor: Cursor
regexFallbackError?: string
}

export interface Picker {
destroy(): void
waitForScan(timeout?: number): Result<boolean>
refreshGitStatus(): Result<number>
fileSearch(
query: string,
opts?: {
currentFile?: string
pageIndex?: number
pageSize?: number
},
): Result<Search>
grep(
query: string,
opts?: {
mode?: "plain" | "regex" | "fuzzy"
maxMatchesPerFile?: number
timeBudgetMs?: number
beforeContext?: number
afterContext?: number
cursor?: Cursor
},
): Result<Grep>
trackQuery(query: string, file: string): Result<boolean>
getHistoricalQuery(offset: number): Result<string | null>
}

export function available() {
return FileFinder.isAvailable()
}

export function create(opts: Init): Result<Picker> {
const made = FileFinder.create(opts)
if (!made.ok) return made
const pick = made.value
return {
ok: true,
value: {
destroy: () => pick.destroy(),
waitForScan: (timeout) => pick.waitForScan(timeout),
refreshGitStatus: () => pick.refreshGitStatus(),
fileSearch: (query, next) => pick.fileSearch(query, next),
grep: (query, next) => pick.grep(query, next),
trackQuery: (query, file) => pick.trackQuery(query, file),
getHistoricalQuery: (offset) => pick.getHistoricalQuery(offset),
},
}
}

export * as Fff from "./fff.bun"
85 changes: 85 additions & 0 deletions packages/opencode/src/file/fff.node.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
export type Result<T> = { ok: true; value: T } | { ok: false; error: string }

export interface Init {
basePath: string
frecencyDbPath?: string
historyDbPath?: string
useUnsafeNoLock?: boolean
disableMmapCache?: boolean
disableContentIndexing?: boolean
disableWatch?: boolean
aiMode?: boolean
}

export interface File {
relativePath: string
fileName: string
modified: number
}

export interface Search {
items: File[]
scores: unknown[]
totalMatched: number
totalFiles: number
}

export type Cursor = null

export interface Hit {
relativePath: string
fileName: string
lineNumber: number
byteOffset: number
lineContent: string
matchRanges: [number, number][]
contextBefore?: string[]
contextAfter?: string[]
}

export interface Grep {
items: Hit[]
totalMatched: number
totalFilesSearched: number
totalFiles: number
filteredFileCount: number
nextCursor: Cursor
regexFallbackError?: string
}

export interface Picker {
destroy(): void
waitForScan(timeout?: number): Result<boolean>
refreshGitStatus(): Result<number>
fileSearch(
query: string,
opts?: {
currentFile?: string
pageIndex?: number
pageSize?: number
},
): Result<Search>
grep(
query: string,
opts?: {
mode?: "plain" | "regex" | "fuzzy"
maxMatchesPerFile?: number
timeBudgetMs?: number
beforeContext?: number
afterContext?: number
cursor?: Cursor
},
): Result<Grep>
trackQuery(query: string, file: string): Result<boolean>
getHistoricalQuery(offset: number): Result<string | null>
}

export function available() {
return false
}

export function create(_opts: Init): Result<Picker> {
return { ok: false, error: "fff unavailable" }
}

export * as Fff from "./fff.node"
Loading
Loading