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

feat: more scriptable tui (api)

adamdotdevin 6 месяцев назад
Родитель
Сommit
872b1e068f

+ 114 - 0
packages/opencode/src/server/server.ts

@@ -905,6 +905,120 @@ export namespace Server {
         }),
         async (c) => c.json(await callTui(c)),
       )
+      .post(
+        "/tui/open-sessions",
+        describeRoute({
+          description: "Open the session dialog",
+          operationId: "tui.openSessions",
+          responses: {
+            200: {
+              description: "Session dialog opened successfully",
+              content: {
+                "application/json": {
+                  schema: resolver(z.boolean()),
+                },
+              },
+            },
+          },
+        }),
+        async (c) => c.json(await callTui(c)),
+      )
+      .post(
+        "/tui/open-themes",
+        describeRoute({
+          description: "Open the theme dialog",
+          operationId: "tui.openThemes",
+          responses: {
+            200: {
+              description: "Theme dialog opened successfully",
+              content: {
+                "application/json": {
+                  schema: resolver(z.boolean()),
+                },
+              },
+            },
+          },
+        }),
+        async (c) => c.json(await callTui(c)),
+      )
+      .post(
+        "/tui/open-models",
+        describeRoute({
+          description: "Open the model dialog",
+          operationId: "tui.openModels",
+          responses: {
+            200: {
+              description: "Model dialog opened successfully",
+              content: {
+                "application/json": {
+                  schema: resolver(z.boolean()),
+                },
+              },
+            },
+          },
+        }),
+        async (c) => c.json(await callTui(c)),
+      )
+      .post(
+        "/tui/submit-prompt",
+        describeRoute({
+          description: "Submit the prompt",
+          operationId: "tui.submitPrompt",
+          responses: {
+            200: {
+              description: "Prompt submitted successfully",
+              content: {
+                "application/json": {
+                  schema: resolver(z.boolean()),
+                },
+              },
+            },
+          },
+        }),
+        async (c) => c.json(await callTui(c)),
+      )
+      .post(
+        "/tui/clear-prompt",
+        describeRoute({
+          description: "Clear the prompt",
+          operationId: "tui.clearPrompt",
+          responses: {
+            200: {
+              description: "Prompt cleared successfully",
+              content: {
+                "application/json": {
+                  schema: resolver(z.boolean()),
+                },
+              },
+            },
+          },
+        }),
+        async (c) => c.json(await callTui(c)),
+      )
+      .post(
+        "/tui/execute-command",
+        describeRoute({
+          description: "Execute a TUI command (e.g. switch_mode)",
+          operationId: "tui.executeCommand",
+          responses: {
+            200: {
+              description: "Command executed successfully",
+              content: {
+                "application/json": {
+                  schema: resolver(z.boolean()),
+                },
+              },
+            },
+          },
+        }),
+        zValidator(
+          "json",
+          z.object({
+            command: z.string(),
+          }),
+        ),
+        async (c) => c.json(await callTui(c)),
+      )
       .route("/tui/control", TuiRoute)
 
     return result

+ 6 - 0
packages/sdk/stainless/stainless.yml

@@ -134,7 +134,13 @@ resources:
   tui:
     methods:
       appendPrompt: post /tui/append-prompt
+      submitPrompt: post /tui/submit-prompt
+      clearPrompt: post /tui/clear-prompt
       openHelp: post /tui/open-help
+      openSessions: post /tui/open-sessions
+      openThemes: post /tui/open-themes
+      openModels: post /tui/open-models
+      executeCommand: post /tui/execute-command
 
 settings:
   disable_mock_tests: true

+ 1 - 1
packages/tui/cmd/opencode/main.go

@@ -86,7 +86,7 @@ func main() {
 	logger := slog.New(apiHandler)
 	slog.SetDefault(logger)
 
-	slog.Debug("TUI launched", "app", appInfoStr, "modes", modesStr)
+	slog.Debug("TUI launched", "app", appInfoStr, "modes", modesStr, "url", url)
 
 	go func() {
 		err = clipboard.Init()

+ 37 - 0
packages/tui/internal/tui/tui.go

@@ -609,6 +609,15 @@ func (a Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 		case "/tui/open-help":
 			helpDialog := dialog.NewHelpDialog(a.app)
 			a.modal = helpDialog
+		case "/tui/open-sessions":
+			sessionDialog := dialog.NewSessionDialog(a.app)
+			a.modal = sessionDialog
+		case "/tui/open-themes":
+			themeDialog := dialog.NewThemeDialog()
+			a.modal = themeDialog
+		case "/tui/open-models":
+			modelDialog := dialog.NewModelDialog(a.app)
+			a.modal = modelDialog
 		case "/tui/append-prompt":
 			var body struct {
 				Text string `json:"text"`
@@ -620,6 +629,34 @@ func (a Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 				text = " " + text
 			}
 			a.editor.SetValueWithAttachments(existing + text + " ")
+		case "/tui/submit-prompt":
+			updated, cmd := a.editor.Submit()
+			a.editor = updated.(chat.EditorComponent)
+			cmds = append(cmds, cmd)
+		case "/tui/clear-prompt":
+			updated, cmd := a.editor.Clear()
+			a.editor = updated.(chat.EditorComponent)
+			cmds = append(cmds, cmd)
+		case "/tui/execute-command":
+			var body struct {
+				Command string `json:"command"`
+			}
+			json.Unmarshal((msg.Body), &body)
+			command := commands.Command{}
+			for _, cmd := range a.app.Commands {
+				if string(cmd.Name) == body.Command {
+					command = cmd
+					break
+				}
+			}
+			if command.Name == "" {
+				slog.Error("Invalid command passed to /tui/execute-command", "command", body.Command)
+				return a, nil
+			}
+			updated, cmd := a.executeCommand(commands.Command(command))
+			a = updated.(Model)
+			cmds = append(cmds, cmd)
+
 		default:
 			break
 		}