mirror of
https://github.com/aljazceru/opencode.git
synced 2025-12-22 18:24:21 +01:00
add file watcher
This commit is contained in:
@@ -36,12 +36,15 @@ export namespace App {
|
|||||||
services: Map<any, { state: any; shutdown?: (input: any) => Promise<void> }>
|
services: Map<any, { state: any; shutdown?: (input: any) => Promise<void> }>
|
||||||
}>("app")
|
}>("app")
|
||||||
|
|
||||||
|
export const use = ctx.use
|
||||||
|
|
||||||
const APP_JSON = "app.json"
|
const APP_JSON = "app.json"
|
||||||
|
|
||||||
export type Input = {
|
export type Input = {
|
||||||
cwd: string
|
cwd: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const provideExisting = ctx.provide
|
||||||
export async function provide<T>(
|
export async function provide<T>(
|
||||||
input: Input,
|
input: Input,
|
||||||
cb: (app: App.Info) => Promise<T>,
|
cb: (app: App.Info) => Promise<T>,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { App } from "../app/app"
|
import { App } from "../app/app"
|
||||||
import { ConfigHooks } from "../config/hooks"
|
import { ConfigHooks } from "../config/hooks"
|
||||||
|
import { FileWatcher } from "../file/watch"
|
||||||
import { Format } from "../format"
|
import { Format } from "../format"
|
||||||
import { LSP } from "../lsp"
|
import { LSP } from "../lsp"
|
||||||
import { Share } from "../share/share"
|
import { Share } from "../share/share"
|
||||||
@@ -13,6 +14,7 @@ export async function bootstrap<T>(
|
|||||||
Format.init()
|
Format.init()
|
||||||
ConfigHooks.init()
|
ConfigHooks.init()
|
||||||
LSP.init()
|
LSP.init()
|
||||||
|
FileWatcher.init()
|
||||||
|
|
||||||
return cb(app)
|
return cb(app)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { bootstrap } from "../../bootstrap"
|
||||||
import { cmd } from "../cmd"
|
import { cmd } from "../cmd"
|
||||||
import { FileCommand } from "./file"
|
import { FileCommand } from "./file"
|
||||||
import { LSPCommand } from "./lsp"
|
import { LSPCommand } from "./lsp"
|
||||||
@@ -12,6 +13,16 @@ export const DebugCommand = cmd({
|
|||||||
.command(RipgrepCommand)
|
.command(RipgrepCommand)
|
||||||
.command(FileCommand)
|
.command(FileCommand)
|
||||||
.command(SnapshotCommand)
|
.command(SnapshotCommand)
|
||||||
|
.command({
|
||||||
|
command: "wait",
|
||||||
|
async handler() {
|
||||||
|
await bootstrap({ cwd: process.cwd() }, async () => {
|
||||||
|
await new Promise((resolve) =>
|
||||||
|
setTimeout(resolve, 1_000 * 60 * 60 * 24),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
||||||
.demandCommand(),
|
.demandCommand(),
|
||||||
async handler() {},
|
async handler() {},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { App } from "../../app/app"
|
|
||||||
import { Provider } from "../../provider/provider"
|
import { Provider } from "../../provider/provider"
|
||||||
import { Server } from "../../server/server"
|
import { Server } from "../../server/server"
|
||||||
import { Share } from "../../share/share"
|
import { Share } from "../../share/share"
|
||||||
|
import { bootstrap } from "../bootstrap"
|
||||||
import { cmd } from "./cmd"
|
import { cmd } from "./cmd"
|
||||||
|
|
||||||
export const ServeCommand = cmd({
|
export const ServeCommand = cmd({
|
||||||
@@ -23,7 +23,7 @@ export const ServeCommand = cmd({
|
|||||||
describe: "starts a headless opencode server",
|
describe: "starts a headless opencode server",
|
||||||
handler: async (args) => {
|
handler: async (args) => {
|
||||||
const cwd = process.cwd()
|
const cwd = process.cwd()
|
||||||
await App.provide({ cwd }, async () => {
|
await bootstrap({ cwd }, async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
if (Object.keys(providers).length === 0) {
|
if (Object.keys(providers).length === 0) {
|
||||||
return "needs_provider"
|
return "needs_provider"
|
||||||
|
|||||||
50
packages/opencode/src/file/watch.ts
Normal file
50
packages/opencode/src/file/watch.ts
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
import { z } from "zod"
|
||||||
|
import { Bus } from "../bus"
|
||||||
|
import fs from "fs"
|
||||||
|
import { App } from "../app/app"
|
||||||
|
import { Log } from "../util/log"
|
||||||
|
|
||||||
|
export namespace FileWatcher {
|
||||||
|
const log = Log.create({ service: "file.watcher" })
|
||||||
|
|
||||||
|
export const Event = {
|
||||||
|
Updated: Bus.event(
|
||||||
|
"file.watcher.updated",
|
||||||
|
z.object({
|
||||||
|
file: z.string(),
|
||||||
|
event: z.union([z.literal("rename"), z.literal("change")]),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
export function init() {
|
||||||
|
App.state(
|
||||||
|
"file.watcher",
|
||||||
|
() => {
|
||||||
|
const app = App.use()
|
||||||
|
const watcher = fs.watch(
|
||||||
|
app.info.path.cwd,
|
||||||
|
{ recursive: true },
|
||||||
|
(event, file) => {
|
||||||
|
log.info("change", { file, event })
|
||||||
|
if (!file) return
|
||||||
|
// for some reason async local storage is lost here
|
||||||
|
// https://github.com/oven-sh/bun/issues/20754
|
||||||
|
App.provideExisting(app, async () => {
|
||||||
|
Bus.publish(Event.Updated, {
|
||||||
|
file,
|
||||||
|
event,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
)
|
||||||
|
return {
|
||||||
|
watcher,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async (state) => {
|
||||||
|
state.watcher.close()
|
||||||
|
},
|
||||||
|
)()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -188,6 +188,11 @@ export namespace Message {
|
|||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
.optional(),
|
.optional(),
|
||||||
|
user: z
|
||||||
|
.object({
|
||||||
|
snapshot: z.string().optional(),
|
||||||
|
})
|
||||||
|
.optional(),
|
||||||
})
|
})
|
||||||
.openapi({ ref: "MessageMetadata" }),
|
.openapi({ ref: "MessageMetadata" }),
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user