Compare commits

...
Sign in to create a new pull request.

1 commit

Author SHA1 Message Date
Kit Langton
e61fe8e5f8 feat: unwrap file namespaces to flat exports + barrel 2026-04-15 23:49:51 -04:00
35 changed files with 834 additions and 839 deletions

View file

@ -1,7 +1,7 @@
import { EOL } from "os"
import { AppRuntime } from "@/effect/app-runtime"
import { File } from "../../../file"
import { Ripgrep } from "@/file/ripgrep"
import { Ripgrep } from "@/file"
import { bootstrap } from "../../bootstrap"
import { cmd } from "../cmd"

View file

@ -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 { Ripgrep } from "../../../file"
import { Instance } from "../../../project/instance"
import { bootstrap } from "../../bootstrap"
import { cmd } from "../cmd"

View file

@ -8,10 +8,10 @@ import { Auth } from "@/auth"
import { Account } from "@/account"
import { Config } from "@/config"
import { Git } from "@/git"
import { Ripgrep } from "@/file/ripgrep"
import { FileTime } from "@/file/time"
import { Ripgrep } from "@/file"
import { FileTime } from "@/file"
import { File } from "@/file"
import { FileWatcher } from "@/file/watcher"
import { FileWatcher } from "@/file"
import { Storage } from "@/storage"
import { Snapshot } from "@/snapshot"
import { Plugin } from "@/plugin"

View file

@ -3,7 +3,7 @@ import { memoMap } from "./run-service"
import { Plugin } from "@/plugin"
import { LSP } from "@/lsp"
import { FileWatcher } from "@/file/watcher"
import { FileWatcher } from "@/file"
import { Format } from "@/format"
import { ShareNext } from "@/share"
import { File } from "@/file"

View file

@ -13,8 +13,8 @@ import z from "zod"
import { Global } from "../global"
import { Instance } from "../project/instance"
import { Log } from "../util"
import { Protected } from "./protected"
import { Ripgrep } from "./ripgrep"
import * as Protected from "./protected"
import * as Ripgrep from "./ripgrep"
export const Info = z
.object({

View file

@ -1,7 +1,6 @@
import { Glob } from "@opencode-ai/shared/util/glob"
export namespace FileIgnore {
const FOLDERS = new Set([
const FOLDERS = new Set([
"node_modules",
"bower_components",
".pnpm-store",
@ -30,9 +29,9 @@ export namespace FileIgnore {
"mypy_cache",
".history",
".gradle",
])
])
const FILES = [
const FILES = [
"**/*.swp",
"**/*.swo",
@ -51,17 +50,17 @@ export namespace FileIgnore {
// Coverage/test outputs
"**/coverage/**",
"**/.nyc_output/**",
]
]
export const PATTERNS = [...FILES, ...FOLDERS]
export const PATTERNS = [...FILES, ...FOLDERS]
export function match(
export function match(
filepath: string,
opts?: {
extra?: string[]
whitelist?: string[]
},
) {
) {
for (const pattern of opts?.whitelist || []) {
if (Glob.match(pattern, filepath)) return false
}
@ -77,5 +76,4 @@ export namespace FileIgnore {
}
return false
}
}

View file

@ -1 +1,6 @@
export * as File from "./file"
export * as Protected from "./protected"
export * as FileIgnore from "./ignore"
export * as FileWatcher from "./watcher"
export * as FileTime from "./time"
export * as Ripgrep from "./ripgrep"

View file

@ -37,16 +37,15 @@ const DARWIN_ROOT = ["/.DocumentRevisions-V100", "/.Spotlight-V100", "/.Trashes"
const WIN32_HOME = ["AppData", "Downloads", "Desktop", "Documents", "Pictures", "Music", "Videos", "OneDrive"]
export namespace Protected {
/** Directory basenames to skip when scanning the home directory. */
export function names(): ReadonlySet<string> {
/** Directory basenames to skip when scanning the home directory. */
export function names(): ReadonlySet<string> {
if (process.platform === "darwin") return new Set(DARWIN_HOME)
if (process.platform === "win32") return new Set(WIN32_HOME)
return new Set()
}
}
/** Absolute paths that should never be watched, stated, or scanned. */
export function paths(): string[] {
/** Absolute paths that should never be watched, stated, or scanned. */
export function paths(): string[] {
if (process.platform === "darwin")
return [
...DARWIN_HOME.map((n) => path.join(home, n)),
@ -55,5 +54,4 @@ export namespace Protected {
]
if (process.platform === "win32") return WIN32_HOME.map((n) => path.join(home, n))
return []
}
}

View file

@ -8,10 +8,9 @@ import { ripgrep } from "ripgrep"
import { Filesystem } from "@/util"
import { Log } from "@/util"
export namespace Ripgrep {
const log = Log.create({ service: "ripgrep" })
const log = Log.create({ service: "ripgrep" })
const Stats = z.object({
const Stats = z.object({
elapsed: z.object({
secs: z.number(),
nanos: z.number(),
@ -23,18 +22,18 @@ export namespace Ripgrep {
bytes_printed: z.number(),
matched_lines: z.number(),
matches: z.number(),
})
})
const Begin = z.object({
const Begin = z.object({
type: z.literal("begin"),
data: z.object({
path: z.object({
text: z.string(),
}),
}),
})
})
export const Match = z.object({
export const Match = z.object({
type: z.literal("match"),
data: z.object({
path: z.object({
@ -55,9 +54,9 @@ export namespace Ripgrep {
}),
),
}),
})
})
const End = z.object({
const End = z.object({
type: z.literal("end"),
data: z.object({
path: z.object({
@ -66,9 +65,9 @@ export namespace Ripgrep {
binary_offset: z.number().nullable(),
stats: Stats,
}),
})
})
const Summary = z.object({
const Summary = z.object({
type: z.literal("summary"),
data: z.object({
elapsed_total: z.object({
@ -78,33 +77,33 @@ export namespace Ripgrep {
}),
stats: Stats,
}),
})
})
const Result = z.union([Begin, Match, End, Summary])
const Result = z.union([Begin, Match, End, Summary])
export type Result = z.infer<typeof Result>
export type Match = z.infer<typeof Match>
export type Item = Match["data"]
export type Begin = z.infer<typeof Begin>
export type End = z.infer<typeof End>
export type Summary = z.infer<typeof Summary>
export type Row = Match["data"]
export type Result = z.infer<typeof Result>
export type Match = z.infer<typeof Match>
export type Item = Match["data"]
export type Begin = z.infer<typeof Begin>
export type End = z.infer<typeof End>
export type Summary = z.infer<typeof Summary>
export type Row = Match["data"]
export interface SearchResult {
export interface SearchResult {
items: Item[]
partial: boolean
}
}
export interface FilesInput {
export interface FilesInput {
cwd: string
glob?: string[]
hidden?: boolean
follow?: boolean
maxDepth?: number
signal?: AbortSignal
}
}
export interface SearchInput {
export interface SearchInput {
cwd: string
pattern: string
glob?: string[]
@ -112,91 +111,91 @@ export namespace Ripgrep {
follow?: boolean
file?: string[]
signal?: AbortSignal
}
}
export interface TreeInput {
export interface TreeInput {
cwd: string
limit?: number
signal?: AbortSignal
}
}
export interface Interface {
export interface Interface {
readonly files: (input: FilesInput) => Stream.Stream<string, Error>
readonly tree: (input: TreeInput) => Effect.Effect<string, Error>
readonly search: (input: SearchInput) => Effect.Effect<SearchResult, Error>
}
}
export class Service extends Context.Service<Service, Interface>()("@opencode/Ripgrep") {}
export class Service extends Context.Service<Service, Interface>()("@opencode/Ripgrep") {}
type Run = { kind: "files" | "search"; cwd: string; args: string[] }
type Run = { kind: "files" | "search"; cwd: string; args: string[] }
type WorkerResult = {
type WorkerResult = {
type: "result"
code: number
stdout: string
stderr: string
}
}
type WorkerLine = {
type WorkerLine = {
type: "line"
line: string
}
}
type WorkerDone = {
type WorkerDone = {
type: "done"
code: number
stderr: string
}
}
type WorkerError = {
type WorkerError = {
type: "error"
error: {
message: string
name?: string
stack?: string
}
}
}
function env() {
function env() {
const env = Object.fromEntries(
Object.entries(process.env).filter((item): item is [string, string] => item[1] !== undefined),
)
delete env.RIPGREP_CONFIG_PATH
return env
}
}
function text(input: unknown) {
function text(input: unknown) {
if (typeof input === "string") return input
if (input instanceof ArrayBuffer) return Buffer.from(input).toString()
if (ArrayBuffer.isView(input)) return Buffer.from(input.buffer, input.byteOffset, input.byteLength).toString()
return String(input)
}
}
function toError(input: unknown) {
function toError(input: unknown) {
if (input instanceof Error) return input
if (typeof input === "string") return new Error(input)
return new Error(String(input))
}
}
function abort(signal?: AbortSignal) {
function abort(signal?: AbortSignal) {
const err = signal?.reason
if (err instanceof Error) return err
const out = new Error("Aborted")
out.name = "AbortError"
return out
}
}
function error(stderr: string, code: number) {
function error(stderr: string, code: number) {
const err = new Error(stderr.trim() || `ripgrep failed with code ${code}`)
err.name = "RipgrepError"
return err
}
}
function clean(file: string) {
function clean(file: string) {
return path.normalize(file.replace(/^\.[\\/]/, ""))
}
}
function row(data: Row): Row {
function row(data: Row): Row {
return {
...data,
path: {
@ -204,16 +203,16 @@ export namespace Ripgrep {
text: clean(data.path.text),
},
}
}
}
function opts(cwd: string) {
function opts(cwd: string) {
return {
env: env(),
preopens: { ".": cwd },
}
}
}
function check(cwd: string) {
function check(cwd: string) {
return Effect.tryPromise({
try: () => fs.stat(cwd).catch(() => undefined),
catch: toError,
@ -230,9 +229,9 @@ export namespace Ripgrep {
),
),
)
}
}
function filesArgs(input: FilesInput) {
function filesArgs(input: FilesInput) {
const args = ["--files", "--glob=!.git/*"]
if (input.follow) args.push("--follow")
if (input.hidden !== false) args.push("--hidden")
@ -244,9 +243,9 @@ export namespace Ripgrep {
}
args.push(".")
return args
}
}
function searchArgs(input: SearchInput) {
function searchArgs(input: SearchInput) {
const args = ["--json", "--hidden", "--glob=!.git/*", "--no-messages"]
if (input.follow) args.push("--follow")
if (input.glob) {
@ -257,20 +256,20 @@ export namespace Ripgrep {
if (input.limit) args.push(`--max-count=${input.limit}`)
args.push("--", input.pattern, ...(input.file ?? ["."]))
return args
}
}
function parse(stdout: string) {
function parse(stdout: string) {
return stdout
.trim()
.split(/\r?\n/)
.filter(Boolean)
.map((line) => Result.parse(JSON.parse(line)))
.flatMap((item) => (item.type === "match" ? [row(item.data)] : []))
}
}
declare const OPENCODE_RIPGREP_WORKER_PATH: string
declare const OPENCODE_RIPGREP_WORKER_PATH: string
function target(): Effect.Effect<string | URL, Error> {
function target(): Effect.Effect<string | URL, Error> {
if (typeof OPENCODE_RIPGREP_WORKER_PATH !== "undefined") {
return Effect.succeed(OPENCODE_RIPGREP_WORKER_PATH)
}
@ -279,26 +278,26 @@ export namespace Ripgrep {
try: () => Filesystem.exists(fileURLToPath(js)),
catch: toError,
}).pipe(Effect.map((exists) => (exists ? js : new URL("./ripgrep.worker.ts", import.meta.url))))
}
}
function worker() {
function worker() {
return target().pipe(Effect.flatMap((file) => Effect.sync(() => new Worker(file, { env: env() }))))
}
}
function drain(buf: string, chunk: unknown, push: (line: string) => void) {
function drain(buf: string, chunk: unknown, push: (line: string) => void) {
const lines = (buf + text(chunk)).split(/\r?\n/)
buf = lines.pop() || ""
for (const line of lines) {
if (line) push(line)
}
return buf
}
}
function fail(queue: Queue.Queue<string, Error | Cause.Done>, err: Error) {
function fail(queue: Queue.Queue<string, Error | Cause.Done>, err: Error) {
Queue.failCauseUnsafe(queue, Cause.fail(err))
}
}
function searchDirect(input: SearchInput) {
function searchDirect(input: SearchInput) {
return Effect.tryPromise({
try: () =>
ripgrep(searchArgs(input), {
@ -318,9 +317,9 @@ export namespace Ripgrep {
}))
}),
)
}
}
function searchWorker(input: SearchInput) {
function searchWorker(input: SearchInput) {
if (input.signal?.aborted) return Effect.fail(abort(input.signal))
return Effect.acquireUseRelease(
@ -377,9 +376,9 @@ export namespace Ripgrep {
}),
(w) => Effect.sync(() => w.terminate()),
)
}
}
function filesDirect(input: FilesInput) {
function filesDirect(input: FilesInput) {
return Stream.callback<string, Error>(
Effect.fnUntraced(function* (queue: Queue.Queue<string, Error | Cause.Done>) {
let buf = ""
@ -427,9 +426,9 @@ export namespace Ripgrep {
)
}),
)
}
}
function filesWorker(input: FilesInput) {
function filesWorker(input: FilesInput) {
return Stream.callback<string, Error>(
Effect.fnUntraced(function* (queue: Queue.Queue<string, Error | Cause.Done>) {
if (input.signal?.aborted) {
@ -489,9 +488,9 @@ export namespace Ripgrep {
)
}),
)
}
}
export const layer = Layer.effect(
export const layer = Layer.effect(
Service,
Effect.gen(function* () {
const source = (input: FilesInput) => {
@ -569,7 +568,6 @@ export namespace Ripgrep {
return Service.of({ files, tree, search })
}),
)
)
export const defaultLayer = layer
}
export const defaultLayer = layer

View file

@ -5,39 +5,38 @@ import { Flag } from "@/flag/flag"
import type { SessionID } from "@/session/schema"
import { Log } from "../util"
export namespace FileTime {
const log = Log.create({ service: "file.time" })
const log = Log.create({ service: "file.time" })
export type Stamp = {
export type Stamp = {
readonly read: Date
readonly mtime: number | undefined
readonly size: number | undefined
}
}
const session = (reads: Map<SessionID, Map<string, Stamp>>, sessionID: SessionID) => {
const session = (reads: Map<SessionID, Map<string, Stamp>>, sessionID: SessionID) => {
const value = reads.get(sessionID)
if (value) return value
const next = new Map<string, Stamp>()
reads.set(sessionID, next)
return next
}
}
interface State {
interface State {
reads: Map<SessionID, Map<string, Stamp>>
locks: Map<string, Semaphore.Semaphore>
}
}
export interface Interface {
export interface Interface {
readonly read: (sessionID: SessionID, file: string) => Effect.Effect<void>
readonly get: (sessionID: SessionID, file: string) => Effect.Effect<Date | undefined>
readonly assert: (sessionID: SessionID, filepath: string) => Effect.Effect<void>
readonly withLock: <T>(filepath: string, fn: () => Effect.Effect<T>) => Effect.Effect<T>
}
}
export class Service extends Context.Service<Service, Interface>()("@opencode/FileTime") {}
export class Service extends Context.Service<Service, Interface>()("@opencode/FileTime") {}
export const layer = Layer.effect(
export const layer = Layer.effect(
Service,
Effect.gen(function* () {
const fsys = yield* AppFileSystem.Service
@ -107,7 +106,6 @@ export namespace FileTime {
return Service.of({ read, get, assert, withLock })
}),
).pipe(Layer.orDie)
).pipe(Layer.orDie)
export const defaultLayer = layer.pipe(Layer.provide(AppFileSystem.defaultLayer))
}
export const defaultLayer = layer.pipe(Layer.provide(AppFileSystem.defaultLayer))

View file

@ -13,17 +13,16 @@ import { Git } from "@/git"
import { Instance } from "@/project/instance"
import { lazy } from "@/util/lazy"
import { Config } from "../config"
import { FileIgnore } from "./ignore"
import { Protected } from "./protected"
import * as FileIgnore from "./ignore"
import * as Protected from "./protected"
import { Log } from "../util"
declare const OPENCODE_LIBC: string | undefined
export namespace FileWatcher {
const log = Log.create({ service: "file.watcher" })
const SUBSCRIBE_TIMEOUT_MS = 10_000
const log = Log.create({ service: "file.watcher" })
const SUBSCRIBE_TIMEOUT_MS = 10_000
export const Event = {
export const Event = {
Updated: BusEvent.define(
"file.watcher.updated",
z.object({
@ -31,9 +30,9 @@ export namespace FileWatcher {
event: z.union([z.literal("add"), z.literal("change"), z.literal("unlink")]),
}),
),
}
}
const watcher = lazy((): typeof import("@parcel/watcher") | undefined => {
const watcher = lazy((): typeof import("@parcel/watcher") | undefined => {
try {
const binding = require(
`@parcel/watcher-${process.platform}-${process.arch}${process.platform === "linux" ? `-${OPENCODE_LIBC || "glibc"}` : ""}`,
@ -43,30 +42,30 @@ export namespace FileWatcher {
log.error("failed to load watcher binding", { error })
return
}
})
})
function getBackend() {
function getBackend() {
if (process.platform === "win32") return "windows"
if (process.platform === "darwin") return "fs-events"
if (process.platform === "linux") return "inotify"
}
}
function protecteds(dir: string) {
function protecteds(dir: string) {
return Protected.paths().filter((item) => {
const rel = path.relative(dir, item)
return rel !== "" && !rel.startsWith("..") && !path.isAbsolute(rel)
})
}
}
export const hasNativeBinding = () => !!watcher()
export const hasNativeBinding = () => !!watcher()
export interface Interface {
export interface Interface {
readonly init: () => Effect.Effect<void>
}
}
export class Service extends Context.Service<Service, Interface>()("@opencode/FileWatcher") {}
export class Service extends Context.Service<Service, Interface>()("@opencode/FileWatcher") {}
export const layer = Layer.effect(
export const layer = Layer.effect(
Service,
Effect.gen(function* () {
const config = yield* Config.Service
@ -157,7 +156,6 @@ export namespace FileWatcher {
}),
})
}),
)
)
export const defaultLayer = layer.pipe(Layer.provide(Config.defaultLayer), Layer.provide(Git.defaultLayer))
}
export const defaultLayer = layer.pipe(Layer.provide(Config.defaultLayer), Layer.provide(Git.defaultLayer))

View file

@ -9,7 +9,7 @@ import { Bus } from "../bus"
import { Command } from "../command"
import { Instance } from "./instance"
import { Log } from "@/util"
import { FileWatcher } from "@/file/watcher"
import { FileWatcher } from "@/file"
import { ShareNext } from "@/share"
import * as Effect from "effect/Effect"

View file

@ -5,7 +5,7 @@ import { Bus } from "@/bus"
import { BusEvent } from "@/bus/bus-event"
import { InstanceState } from "@/effect"
import { AppFileSystem } from "@opencode-ai/shared/filesystem"
import { FileWatcher } from "@/file/watcher"
import { FileWatcher } from "@/file"
import { Git } from "@/git"
import { Log } from "@/util"
import { Instance } from "./instance"

View file

@ -4,7 +4,7 @@ import { Effect } from "effect"
import z from "zod"
import { AppRuntime } from "../../effect/app-runtime"
import { File } from "../../file"
import { Ripgrep } from "../../file/ripgrep"
import { Ripgrep } from "../../file"
import { LSP } from "../../lsp"
import { Instance } from "../../project/instance"
import { lazy } from "../../util/lazy"

View file

@ -22,7 +22,7 @@ import MAX_STEPS from "../session/prompt/max-steps.txt"
import { ToolRegistry } from "../tool/registry"
import { MCP } from "../mcp"
import { LSP } from "../lsp"
import { FileTime } from "../file/time"
import { FileTime } from "../file"
import { Flag } from "../flag/flag"
import { ulid } from "ulid"
import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process"

View file

@ -3,7 +3,7 @@ import * as path from "path"
import { Effect } from "effect"
import { Tool } from "./tool"
import { Bus } from "../bus"
import { FileWatcher } from "../file/watcher"
import { FileWatcher } from "../file"
import { Instance } from "../project/instance"
import { Patch } from "../patch"
import { createTwoFilesPatch, diffLines } from "diff"

View file

@ -11,10 +11,10 @@ import { LSP } from "../lsp"
import { createTwoFilesPatch, diffLines } from "diff"
import DESCRIPTION from "./edit.txt"
import { File } from "../file"
import { FileWatcher } from "../file/watcher"
import { FileWatcher } from "../file"
import { Bus } from "../bus"
import { Format } from "../format"
import { FileTime } from "../file/time"
import { FileTime } from "../file"
import { Instance } from "../project/instance"
import { Snapshot } from "@/snapshot"
import { assertExternalDirectoryEffect } from "./external-directory"

View file

@ -4,7 +4,7 @@ import { Effect, Option } from "effect"
import * as Stream from "effect/Stream"
import { InstanceState } from "@/effect"
import { AppFileSystem } from "@opencode-ai/shared/filesystem"
import { Ripgrep } from "../file/ripgrep"
import { Ripgrep } from "../file"
import { assertExternalDirectoryEffect } from "./external-directory"
import DESCRIPTION from "./glob.txt"
import { Tool } from "./tool"

View file

@ -3,7 +3,7 @@ import z from "zod"
import { Effect, Option } from "effect"
import { InstanceState } from "@/effect"
import { AppFileSystem } from "@opencode-ai/shared/filesystem"
import { Ripgrep } from "../file/ripgrep"
import { Ripgrep } from "../file"
import { assertExternalDirectoryEffect } from "./external-directory"
import DESCRIPTION from "./grep.txt"
import { Tool } from "./tool"

View file

@ -7,7 +7,7 @@ import { createInterface } from "readline"
import { Tool } from "./tool"
import { AppFileSystem } from "@opencode-ai/shared/filesystem"
import { LSP } from "../lsp"
import { FileTime } from "../file/time"
import { FileTime } from "../file"
import DESCRIPTION from "./read.txt"
import { Instance } from "../project/instance"
import { assertExternalDirectoryEffect } from "./external-directory"

View file

@ -33,13 +33,13 @@ import { Effect, Layer, Context } from "effect"
import { FetchHttpClient, HttpClient } from "effect/unstable/http"
import { ChildProcessSpawner } from "effect/unstable/process/ChildProcessSpawner"
import * as CrossSpawnSpawner from "@/effect/cross-spawn-spawner"
import { Ripgrep } from "../file/ripgrep"
import { Ripgrep } from "../file"
import { Format } from "../format"
import { InstanceState } from "@/effect"
import { Question } from "../question"
import { Todo } from "../session/todo"
import { LSP } from "../lsp"
import { FileTime } from "../file/time"
import { FileTime } from "../file"
import { Instruction } from "../session/instruction"
import { AppFileSystem } from "@opencode-ai/shared/filesystem"
import { Bus } from "../bus"

View file

@ -4,7 +4,7 @@ import z from "zod"
import { Effect } from "effect"
import * as Stream from "effect/Stream"
import { EffectLogger } from "@/effect"
import { Ripgrep } from "../file/ripgrep"
import { Ripgrep } from "../file"
import { Skill } from "../skill"
import { Tool } from "./tool"

View file

@ -7,9 +7,9 @@ import { createTwoFilesPatch } from "diff"
import DESCRIPTION from "./write.txt"
import { Bus } from "../bus"
import { File } from "../file"
import { FileWatcher } from "../file/watcher"
import { FileWatcher } from "../file"
import { Format } from "../format"
import { FileTime } from "../file/time"
import { FileTime } from "../file"
import { AppFileSystem } from "@opencode-ai/shared/filesystem"
import { Instance } from "../project/instance"
import { trimDiff } from "./edit"

View file

@ -1,5 +1,5 @@
import { test, expect } from "bun:test"
import { FileIgnore } from "../../src/file/ignore"
import { FileIgnore } from "../../src/file"
test("match nested and non-nested", () => {
expect(FileIgnore.match("node_modules/index.js")).toBe(true)

View file

@ -4,7 +4,7 @@ import * as Stream from "effect/Stream"
import fs from "fs/promises"
import path from "path"
import { tmpdir } from "../fixture/fixture"
import { Ripgrep } from "../../src/file/ripgrep"
import { Ripgrep } from "../../src/file"
const run = <A>(effect: Effect.Effect<A, unknown, Ripgrep.Service>) =>
effect.pipe(Effect.provide(Ripgrep.defaultLayer), Effect.runPromise)

View file

@ -3,7 +3,7 @@ import fs from "fs/promises"
import path from "path"
import { Cause, Deferred, Effect, Exit, Fiber, Layer } from "effect"
import * as CrossSpawnSpawner from "../../src/effect/cross-spawn-spawner"
import { FileTime } from "../../src/file/time"
import { FileTime } from "../../src/file"
import { Instance } from "../../src/project/instance"
import { SessionID } from "../../src/session/schema"
import { Filesystem } from "../../src/util"
@ -43,7 +43,7 @@ const fail = Effect.fn("FileTimeTest.fail")(function* <A, E, R>(self: Effect.Eff
throw new Error("expected file time effect to fail")
})
describe("file/time", () => {
describe("file", () => {
describe("read() and get()", () => {
it.live("stores read timestamp", () =>
provideTmpdirInstance((dir) =>

View file

@ -6,7 +6,7 @@ import { ConfigProvider, Deferred, Effect, Layer, ManagedRuntime, Option } from
import { tmpdir } from "../fixture/fixture"
import { Bus } from "../../src/bus"
import { Config } from "../../src/config"
import { FileWatcher } from "../../src/file/watcher"
import { FileWatcher } from "../../src/file"
import { Git } from "../../src/git"
import { Instance } from "../../src/project/instance"

View file

@ -5,7 +5,7 @@ import fs from "fs/promises"
import path from "path"
import { tmpdir } from "../fixture/fixture"
import { AppRuntime } from "../../src/effect/app-runtime"
import { FileWatcher } from "../../src/file/watcher"
import { FileWatcher } from "../../src/file"
import { Instance } from "../../src/project/instance"
import { GlobalBus } from "../../src/bus/global"
import { Vcs } from "../../src/project"

View file

@ -7,7 +7,7 @@ import { Agent as AgentSvc } from "../../src/agent/agent"
import { Bus } from "../../src/bus"
import { Command } from "../../src/command"
import { Config } from "../../src/config"
import { FileTime } from "../../src/file/time"
import { FileTime } from "../../src/file"
import { LSP } from "../../src/lsp"
import { MCP } from "../../src/mcp"
import { Permission } from "../../src/permission"
@ -38,7 +38,7 @@ import { ToolRegistry } from "../../src/tool/registry"
import { Truncate } from "../../src/tool/truncate"
import { Log } from "../../src/util"
import * as CrossSpawnSpawner from "../../src/effect/cross-spawn-spawner"
import { Ripgrep } from "../../src/file/ripgrep"
import { Ripgrep } from "../../src/file"
import { Format } from "../../src/format"
import { provideTmpdirInstance, provideTmpdirServer } from "../fixture/fixture"
import { testEffect } from "../lib/effect"

View file

@ -33,7 +33,7 @@ import { Agent as AgentSvc } from "../../src/agent/agent"
import { Bus } from "../../src/bus"
import { Command } from "../../src/command"
import { Config } from "../../src/config"
import { FileTime } from "../../src/file/time"
import { FileTime } from "../../src/file"
import { LSP } from "../../src/lsp"
import { MCP } from "../../src/mcp"
import { Permission } from "../../src/permission"
@ -54,7 +54,7 @@ import { ToolRegistry } from "../../src/tool/registry"
import { Truncate } from "../../src/tool/truncate"
import { AppFileSystem } from "@opencode-ai/shared/filesystem"
import * as CrossSpawnSpawner from "../../src/effect/cross-spawn-spawner"
import { Ripgrep } from "../../src/file/ripgrep"
import { Ripgrep } from "../../src/file"
import { Format } from "../../src/format"
void Log.init({ print: false })

View file

@ -5,7 +5,7 @@ import { Effect, Layer, ManagedRuntime } from "effect"
import { EditTool } from "../../src/tool/edit"
import { Instance } from "../../src/project/instance"
import { tmpdir } from "../fixture/fixture"
import { FileTime } from "../../src/file/time"
import { FileTime } from "../../src/file"
import { LSP } from "../../src/lsp"
import { AppFileSystem } from "@opencode-ai/shared/filesystem"
import { Format } from "../../src/format"
@ -138,7 +138,7 @@ describe("tool.edit", () => {
await Instance.provide({
directory: tmp.path,
fn: async () => {
const { FileWatcher } = await import("../../src/file/watcher")
const { FileWatcher } = await import("../../src/file")
const updated = await onceBus(FileWatcher.Event.Updated)
@ -371,7 +371,7 @@ describe("tool.edit", () => {
fn: async () => {
await readFileTime(ctx.sessionID, filepath)
const { FileWatcher } = await import("../../src/file/watcher")
const { FileWatcher } = await import("../../src/file")
const updated = await onceBus(FileWatcher.Event.Updated)

View file

@ -4,7 +4,7 @@ import { Cause, Effect, Exit, Layer } from "effect"
import { GlobTool } from "../../src/tool/glob"
import { SessionID, MessageID } from "../../src/session/schema"
import * as CrossSpawnSpawner from "../../src/effect/cross-spawn-spawner"
import { Ripgrep } from "../../src/file/ripgrep"
import { Ripgrep } from "../../src/file"
import { AppFileSystem } from "@opencode-ai/shared/filesystem"
import { Truncate } from "../../src/tool/truncate"
import { Agent } from "../../src/agent/agent"

View file

@ -7,7 +7,7 @@ import { SessionID, MessageID } from "../../src/session/schema"
import * as CrossSpawnSpawner from "../../src/effect/cross-spawn-spawner"
import { Truncate } from "../../src/tool/truncate"
import { Agent } from "../../src/agent/agent"
import { Ripgrep } from "../../src/file/ripgrep"
import { Ripgrep } from "../../src/file"
import { AppFileSystem } from "@opencode-ai/shared/filesystem"
import { testEffect } from "../lib/effect"

View file

@ -4,7 +4,7 @@ import path from "path"
import { Agent } from "../../src/agent/agent"
import * as CrossSpawnSpawner from "../../src/effect/cross-spawn-spawner"
import { AppFileSystem } from "@opencode-ai/shared/filesystem"
import { FileTime } from "../../src/file/time"
import { FileTime } from "../../src/file"
import { LSP } from "../../src/lsp"
import { Permission } from "../../src/permission"
import { Instance } from "../../src/project/instance"

View file

@ -6,7 +6,7 @@ import { WriteTool } from "../../src/tool/write"
import { Instance } from "../../src/project/instance"
import { LSP } from "../../src/lsp"
import { AppFileSystem } from "@opencode-ai/shared/filesystem"
import { FileTime } from "../../src/file/time"
import { FileTime } from "../../src/file"
import { Bus } from "../../src/bus"
import { Format } from "../../src/format"
import { Truncate } from "../../src/tool/truncate"