Просмотр исходного кода

ignore: add file status command

Dax Raad 7 месяцев назад
Родитель
Сommit
7e5941e14b

+ 18 - 6
packages/opencode/src/cli/cmd/debug/file.ts

@@ -2,12 +2,6 @@ import { File } from "../../../file"
 import { bootstrap } from "../../bootstrap"
 import { cmd } from "../cmd"
 
-export const FileCommand = cmd({
-  command: "file",
-  builder: (yargs) => yargs.command(FileReadCommand).demandCommand(),
-  async handler() {},
-})
-
 const FileReadCommand = cmd({
   command: "read <path>",
   builder: (yargs) =>
@@ -23,3 +17,21 @@ const FileReadCommand = cmd({
     })
   },
 })
+
+const FileStatusCommand = cmd({
+  command: "status",
+  builder: (yargs) => yargs,
+  async handler() {
+    await bootstrap({ cwd: process.cwd() }, async () => {
+      const status = await File.status()
+      console.log(JSON.stringify(status, null, 2))
+    })
+  },
+})
+
+export const FileCommand = cmd({
+  command: "file",
+  builder: (yargs) =>
+    yargs.command(FileReadCommand).command(FileStatusCommand).demandCommand(),
+  async handler() {},
+})

+ 84 - 4
packages/opencode/src/file/index.ts

@@ -3,13 +3,13 @@ import { Bus } from "../bus"
 import { $ } from "bun"
 import { createPatch } from "diff"
 import path from "path"
-import { status } from "isomorphic-git"
+import * as git from "isomorphic-git"
 import { App } from "../app/app"
 import fs from "fs"
 import { Log } from "../util/log"
 
 export namespace File {
-  const log = Log.create({ service: "files" })
+  const log = Log.create({ service: "file" })
 
   export const Event = {
     Edited: Bus.event(
@@ -20,6 +20,84 @@ export namespace File {
     ),
   }
 
+  export async function status() {
+    const app = App.info()
+    if (!app.git) return []
+
+    // Get all changed files with line counts in one command
+    const diffOutput = await $`git diff --numstat HEAD`
+      .cwd(app.path.root)
+      .quiet()
+      .nothrow()
+      .text()
+
+    const changedFiles = []
+
+    if (diffOutput.trim()) {
+      const lines = diffOutput.trim().split("\n")
+      for (const line of lines) {
+        const [added, removed, filepath] = line.split("\t")
+        changedFiles.push({
+          file: filepath,
+          added: added === "-" ? 0 : parseInt(added, 10),
+          removed: removed === "-" ? 0 : parseInt(removed, 10),
+          status: "modified",
+        })
+      }
+    }
+
+    // Get untracked files
+    const untrackedOutput = await $`git ls-files --others --exclude-standard`
+      .cwd(app.path.root)
+      .quiet()
+      .nothrow()
+      .text()
+
+    if (untrackedOutput.trim()) {
+      const untrackedFiles = untrackedOutput.trim().split("\n")
+      for (const filepath of untrackedFiles) {
+        try {
+          const content = await Bun.file(
+            path.join(app.path.root, filepath),
+          ).text()
+          const lines = content.split("\n").length
+          changedFiles.push({
+            file: filepath,
+            added: lines,
+            removed: 0,
+            status: "added",
+          })
+        } catch {
+          continue
+        }
+      }
+    }
+
+    // Get deleted files
+    const deletedOutput = await $`git diff --name-only --diff-filter=D HEAD`
+      .cwd(app.path.root)
+      .quiet()
+      .nothrow()
+      .text()
+
+    if (deletedOutput.trim()) {
+      const deletedFiles = deletedOutput.trim().split("\n")
+      for (const filepath of deletedFiles) {
+        changedFiles.push({
+          file: filepath,
+          added: 0,
+          removed: 0, // Could get original line count but would require another git command
+          status: "deleted",
+        })
+      }
+    }
+
+    return changedFiles.map((x) => ({
+      ...x,
+      file: path.relative(app.path.cwd, path.join(app.path.root, x.file)),
+    }))
+  }
+
   export async function read(file: string) {
     using _ = log.time("read", { file })
     const app = App.info()
@@ -27,7 +105,7 @@ export namespace File {
     const content = await Bun.file(full).text()
     if (app.git) {
       const rel = path.relative(app.path.root, full)
-      const diff = await status({
+      const diff = await git.status({
         fs,
         dir: app.path.root,
         filepath: rel,
@@ -38,7 +116,9 @@ export namespace File {
           .quiet()
           .nothrow()
           .text()
-        const patch = createPatch(file, original, content)
+        const patch = createPatch(file, original, content, "old", "new", {
+          context: Infinity,
+        })
         return patch
       }
     }

+ 20 - 18
packages/opencode/src/file/watch.ts

@@ -22,28 +22,30 @@ export namespace FileWatcher {
       "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,
+        try {
+          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,
+            },
+          )
+          return { watcher }
+        } finally {
+          return {}
         }
       },
       async (state) => {
-        state.watcher.close()
+        state.watcher?.close()
       },
     )()
   }