Skip to main content
Glama

GenAIScript

Official
by microsoft
MIT License
43
2,820
  • Linux
  • Apple
watch.ts4.22 kB
import { FSWatcher, watch } from "chokidar" import { basename, resolve } from "node:path" import { CHANGE, CLOSE, GENAI_ANY_REGEX, OPEN } from "../../core/src/constants" import { createGitIgnorer } from "../../core/src/gitignore" import { Project } from "../../core/src/server/messages" import { buildProject } from "./build" import { filterScripts, ScriptFilterOptions } from "../../core/src/ast" import { CancellationOptions, toSignal } from "../../core/src/cancellation" import { logError } from "../../core/src/util" import { genaiscriptDebug } from "../../core/src/debug" const dbg = genaiscriptDebug("watch") interface ProjectWatcherOptions extends ScriptFilterOptions { paths: ElementOrArray<string> cwd: string } export class ProjectWatcher extends EventTarget { private _watcher: FSWatcher private _project: Project private _scripts: PromptScript[] constructor(readonly options: ProjectWatcherOptions & CancellationOptions) { super() const signal = toSignal(this.options.cancellationToken) signal?.addEventListener("abort", this.close.bind(this)) } get cwd() { return this.options.cwd } async open() { if (this._watcher) return dbg(`starting`) await this.refresh() const { paths, cwd } = this.options const gitIgnorer = await createGitIgnorer() // Initialize watcher. this._watcher = watch(paths, { ignored: (path, stats) => { if (!stats) return false if (stats.isDirectory()) { const b = basename(path) if (/^\./.test(b)) return true } else if (stats.isFile() && !GENAI_ANY_REGEX.test(path)) { return true } const filtered = gitIgnorer([path]) if (filtered.length === 0) return true return false }, persistent: false, ignoreInitial: true, awaitWriteFinish: { stabilityThreshold: 2000, pollInterval: 1000, }, atomic: true, interval: 1000, binaryInterval: 5000, depth: 30, cwd, }) const changed = () => { dbg(`changed`) this.dispatchEvent(new Event(CHANGE)) } this._watcher .on("error", (error) => logError(`watch: ${error}`)) .on("add", changed) .on("change", changed) .on("unlink", changed) this.addEventListener(CHANGE, this.refresh.bind(this)) this.dispatchEvent(new Event(OPEN)) } private async refresh() { this._project = undefined } async project() { if (!this._project) { dbg(`building project`) this._project = await buildProject() } return this._project } async scripts() { if (!this._scripts) { const project = await this.project() this._scripts = filterScripts(project.scripts, this.options) } return this._scripts?.slice(0) } async close() { dbg(`closing`) await this._watcher?.close() this._watcher = undefined this.dispatchEvent(new Event(CLOSE)) } } /** * Starts a file watcher for a project, monitoring specified paths and reacting to changes. * * @param options - Optional configuration object: * - paths: One or more paths to watch. Defaults to the current directory. * - cwd: The current working directory for the watcher. Defaults to the resolved current directory. * - cancellationToken: A token to signal cancellation of the watcher. * - rest: Additional options including script filtering options. * @returns An initialized ProjectWatcher instance. */ export async function startProjectWatcher( options?: ScriptFilterOptions & { paths?: ElementOrArray<string> cwd?: string } & CancellationOptions ) { const { paths = ".", cwd = resolve("."), ...rest } = options || {} const watcher = new ProjectWatcher({ paths, cwd, ...rest }) await watcher.open() return watcher }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/microsoft/genaiscript'

If you have feedback or need assistance with the MCP directory API, please join our Discord server