summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--packages/opencode/src/external/fzf.ts10
-rw-r--r--packages/opencode/src/external/ripgrep.ts9
-rw-r--r--packages/opencode/src/server/server.ts6
-rw-r--r--packages/opencode/src/session/system.ts51
-rw-r--r--packages/opencode/src/tool/ls.ts8
5 files changed, 75 insertions, 9 deletions
diff --git a/packages/opencode/src/external/fzf.ts b/packages/opencode/src/external/fzf.ts
index bfb1d55e8..e77975786 100644
--- a/packages/opencode/src/external/fzf.ts
+++ b/packages/opencode/src/external/fzf.ts
@@ -116,11 +116,15 @@ export namespace Fzf {
return filepath
}
- export async function search(cwd: string, query: string) {
- const results = await $`${await filepath()} --filter ${query}`
+ export async function search(input: {
+ cwd: string
+ query: string
+ limit?: number
+ }) {
+ const results = await $`${await filepath()} --filter=${input.query}`
.quiet()
.throws(false)
- .cwd(cwd)
+ .cwd(input.cwd)
.text()
const split = results
.trim()
diff --git a/packages/opencode/src/external/ripgrep.ts b/packages/opencode/src/external/ripgrep.ts
index 876078700..0c77673e3 100644
--- a/packages/opencode/src/external/ripgrep.ts
+++ b/packages/opencode/src/external/ripgrep.ts
@@ -5,6 +5,7 @@ import fs from "fs/promises"
import { z } from "zod"
import { NamedError } from "../util/error"
import { lazy } from "../util/lazy"
+import { $ } from "bun"
export namespace Ripgrep {
const PLATFORM = {
@@ -111,4 +112,12 @@ export namespace Ripgrep {
const { filepath } = await state()
return filepath
}
+
+ export async function files(cwd: string) {
+ const result =
+ await $`${await filepath()} --files --hidden --glob '!.git/*'`
+ .cwd(cwd)
+ .text()
+ return result.split("\n").filter(Boolean)
+ }
}
diff --git a/packages/opencode/src/server/server.ts b/packages/opencode/src/server/server.ts
index 9dbc96ca5..eb50f7496 100644
--- a/packages/opencode/src/server/server.ts
+++ b/packages/opencode/src/server/server.ts
@@ -457,7 +457,11 @@ export namespace Server {
async (c) => {
const body = c.req.valid("json")
const app = App.info()
- const result = await Fzf.search(app.path.cwd, body.query)
+ const result = await Fzf.search({
+ cwd: app.path.cwd,
+ query: body.query,
+ limit: 10,
+ })
return c.json(result)
},
)
diff --git a/packages/opencode/src/session/system.ts b/packages/opencode/src/session/system.ts
index 5740cce0b..9b124e41f 100644
--- a/packages/opencode/src/session/system.ts
+++ b/packages/opencode/src/session/system.ts
@@ -1,4 +1,6 @@
import { App } from "../app/app"
+import { Fzf } from "../external/fzf"
+import { Ripgrep } from "../external/ripgrep"
import { ListTool } from "../tool/ls"
import { Filesystem } from "../util/filesystem"
@@ -22,8 +24,53 @@ export namespace SystemPrompt {
return result
}
- export async function environment(sessionID: string) {
+ export async function environment() {
const app = App.info()
+
+ const tree = async () => {
+ const files = await Ripgrep.files(app.path.cwd)
+ type Node = {
+ children: Record<string, Node>
+ }
+ const root: Node = {
+ children: {},
+ }
+ for (const file of files) {
+ const parts = file.split("/")
+ let node = root
+ for (const part of parts) {
+ const existing = node.children[part]
+ if (existing) {
+ node = existing
+ continue
+ }
+ node.children[part] = {
+ children: {},
+ }
+ node = node.children[part]
+ }
+ }
+
+ function render(path: string[], node: Node): string {
+ const lines: string[] = []
+ const entries = Object.entries(node.children).sort(([a], [b]) =>
+ a.localeCompare(b),
+ )
+
+ for (const [name, child] of entries) {
+ const currentPath = [...path, name]
+ const indent = "\t".repeat(path.length)
+ const hasChildren = Object.keys(child.children).length > 0
+ lines.push(`${indent}${name}` + (hasChildren ? "/" : ""))
+
+ if (hasChildren) lines.push(render(currentPath, child))
+ }
+
+ return lines.join("\n")
+ }
+ return render([], root)
+ }
+
return [
[
`Here is some useful information about the environment you are running in:`,
@@ -34,7 +81,7 @@ export namespace SystemPrompt {
` Today's date: ${new Date().toDateString()}`,
`</env>`,
`<project>`,
- ` ${app.git ? await ListTool.execute({ path: app.path.cwd, ignore: [] }, { sessionID: sessionID, messageID: "", abort: AbortSignal.any([]) }).then((x) => x.output) : ""}`,
+ ` ${app.git ? await tree() : ""}`,
`</project>`,
].join("\n"),
]
diff --git a/packages/opencode/src/tool/ls.ts b/packages/opencode/src/tool/ls.ts
index 1995751b8..42b78d425 100644
--- a/packages/opencode/src/tool/ls.ts
+++ b/packages/opencode/src/tool/ls.ts
@@ -4,7 +4,7 @@ import { App } from "../app/app"
import * as path from "path"
import DESCRIPTION from "./ls.txt"
-const IGNORE_PATTERNS = [
+export const IGNORE_PATTERNS = [
"node_modules/",
"__pycache__/",
".git/",
@@ -18,6 +18,8 @@ const IGNORE_PATTERNS = [
".vscode/",
]
+const LIMIT = 100
+
export const ListTool = Tool.define({
id: "opencode.list",
description: DESCRIPTION,
@@ -45,7 +47,7 @@ export const ListTool = Tool.define({
if (params.ignore?.some((pattern) => new Bun.Glob(pattern).match(file)))
continue
files.push(file)
- if (files.length >= 1000) break
+ if (files.length >= LIMIT) break
}
// Build directory structure
@@ -99,7 +101,7 @@ export const ListTool = Tool.define({
return {
metadata: {
count: files.length,
- truncated: files.length >= 1000,
+ truncated: files.length >= LIMIT,
title: path.relative(app.path.root, searchPath),
},
output,