Bladeren bron

add basic session list command

Aiden Cline 2 maanden geleden
bovenliggende
commit
a8ad74aef3
2 gewijzigde bestanden met toevoegingen van 108 en 0 verwijderingen
  1. 106 0
      packages/opencode/src/cli/cmd/session.ts
  2. 2 0
      packages/opencode/src/index.ts

+ 106 - 0
packages/opencode/src/cli/cmd/session.ts

@@ -0,0 +1,106 @@
+import type { Argv } from "yargs"
+import { cmd } from "./cmd"
+import { Session } from "../../session"
+import { bootstrap } from "../bootstrap"
+import { UI } from "../ui"
+import { Locale } from "../../util/locale"
+import { EOL } from "os"
+
+export const SessionCommand = cmd({
+  command: "session",
+  describe: "manage sessions",
+  builder: (yargs: Argv) => yargs.command(SessionListCommand).demandCommand(),
+  async handler() {},
+})
+
+export const SessionListCommand = cmd({
+  command: "list",
+  describe: "list sessions",
+  builder: (yargs: Argv) => {
+    return yargs
+      .option("max-count", {
+        alias: "n",
+        describe: "limit to N most recent sessions",
+        type: "number",
+      })
+      .option("format", {
+        describe: "output format",
+        type: "string",
+        choices: ["table", "json"],
+        default: "table",
+      })
+  },
+  handler: async (args) => {
+    await bootstrap(process.cwd(), async () => {
+      const sessions = []
+      for await (const session of Session.list()) {
+        if (!session.parentID) {
+          sessions.push(session)
+        }
+      }
+
+      sessions.sort((a, b) => b.time.updated - a.time.updated)
+
+      const limitedSessions = args.maxCount ? sessions.slice(0, args.maxCount) : sessions
+
+      if (limitedSessions.length === 0) {
+        return
+      }
+
+      let output: string
+      if (args.format === "json") {
+        output = formatSessionJSON(limitedSessions)
+      } else {
+        output = formatSessionTable(limitedSessions)
+      }
+
+      const shouldPaginate = process.stdout.isTTY && !args.maxCount && args.format === "table"
+
+      if (shouldPaginate) {
+        const proc = Bun.spawn({
+          cmd: ["less", "-R", "-S"],
+          stdin: "pipe",
+          stdout: "inherit",
+          stderr: "inherit",
+        })
+
+        proc.stdin.write(output)
+        proc.stdin.end()
+        await proc.exited
+      } else {
+        console.log(output)
+      }
+    })
+  },
+})
+
+function formatSessionTable(sessions: Session.Info[]): string {
+  const lines: string[] = []
+
+  const maxIdWidth = Math.max(20, ...sessions.map((s) => s.id.length))
+  const maxTitleWidth = Math.max(25, ...sessions.map((s) => s.title.length))
+
+  const header = `Session ID${" ".repeat(maxIdWidth - 10)}  Title${" ".repeat(maxTitleWidth - 5)}  Updated`
+  lines.push(header)
+  lines.push("─".repeat(header.length))
+  for (const session of sessions) {
+    const truncatedTitle = Locale.truncate(session.title, maxTitleWidth)
+    const timeStr = Locale.todayTimeOrDateTime(session.time.updated)
+    const line = `${session.id.padEnd(maxIdWidth)}  ${truncatedTitle.padEnd(maxTitleWidth)}  ${timeStr}`
+    lines.push(line)
+  }
+
+  return lines.join(EOL)
+}
+
+function formatSessionJSON(sessions: Session.Info[]): string {
+  const jsonData = sessions.map((session) => ({
+    id: session.id,
+    title: session.title,
+    updated: session.time.updated,
+    created: session.time.created,
+    projectId: session.projectID,
+    directory: session.directory,
+  }))
+  return JSON.stringify(jsonData, null, 2)
+}

+ 2 - 0
packages/opencode/src/index.ts

@@ -25,6 +25,7 @@ import { AcpCommand } from "./cli/cmd/acp"
 import { EOL } from "os"
 import { WebCommand } from "./cli/cmd/web"
 import { PrCommand } from "./cli/cmd/pr"
+import { SessionCommand } from "./cli/cmd/session"
 
 process.on("unhandledRejection", (e) => {
   Log.Default.error("rejection", {
@@ -93,6 +94,7 @@ const cli = yargs(hideBin(process.argv))
   .command(ImportCommand)
   .command(GithubCommand)
   .command(PrCommand)
+  .command(SessionCommand)
   .fail((msg) => {
     if (
       msg.startsWith("Unknown argument") ||