mirror of
https://github.com/wavetermdev/waveterm
synced 2026-05-23 08:48:28 +00:00
when the AI edits a file it now triggers a rebuild and the AI gets the tool output (#2546)
This commit is contained in:
parent
eb3ba64121
commit
0da0a6421e
12 changed files with 280 additions and 32 deletions
|
|
@ -254,6 +254,10 @@ const AIPanelComponentInner = memo(() => {
|
|||
return false;
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
globalStore.set(model.isAIStreaming, status == "streaming");
|
||||
}, [status]);
|
||||
|
||||
useEffect(() => {
|
||||
const keyHandler = keydownWrapper(handleKeyDown);
|
||||
document.addEventListener("keydown", keyHandler);
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ export class WaveAIModel {
|
|||
realMessage: AIMessage | null = null;
|
||||
orefContext: ORef;
|
||||
inBuilder: boolean = false;
|
||||
isAIStreaming = jotai.atom(false);
|
||||
|
||||
widgetAccessAtom!: jotai.Atom<boolean>;
|
||||
droppedFiles: jotai.PrimitiveAtom<DroppedFile[]> = jotai.atom([]);
|
||||
|
|
|
|||
|
|
@ -472,6 +472,11 @@ class RpcApiType {
|
|||
return client.wshRpcCall("resolveids", data, opts);
|
||||
}
|
||||
|
||||
// command "restartbuilderandwait" [call]
|
||||
RestartBuilderAndWaitCommand(client: WshClient, data: CommandRestartBuilderAndWaitData, opts?: RpcOpts): Promise<RestartBuilderAndWaitResult> {
|
||||
return client.wshRpcCall("restartbuilderandwait", data, opts);
|
||||
}
|
||||
|
||||
// command "routeannounce" [call]
|
||||
RouteAnnounceCommand(client: WshClient, opts?: RpcOpts): Promise<void> {
|
||||
return client.wshRpcCall("routeannounce", null, opts);
|
||||
|
|
|
|||
|
|
@ -106,7 +106,6 @@ export class BuilderAppPanelModel {
|
|||
scope: appId,
|
||||
handler: () => {
|
||||
this.loadAppFile(appId);
|
||||
this.debouncedRestart();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
// Copyright 2025, Command Line Inc.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import { WaveAIModel } from "@/app/aipanel/waveai-model";
|
||||
import { BuilderAppPanelModel } from "@/builder/store/builder-apppanel-model";
|
||||
import { BuilderBuildPanelModel } from "@/builder/store/builder-buildpanel-model";
|
||||
import { atoms } from "@/store/global";
|
||||
import { useAtomValue } from "jotai";
|
||||
import { memo, useState } from "react";
|
||||
|
|
@ -30,6 +32,29 @@ EmptyStateView.displayName = "EmptyStateView";
|
|||
|
||||
const ErrorStateView = memo(({ errorMsg }: { errorMsg: string }) => {
|
||||
const displayMsg = errorMsg && errorMsg.trim() ? errorMsg : "Unknown Error";
|
||||
const waveAIModel = WaveAIModel.getInstance();
|
||||
const buildPanelModel = BuilderBuildPanelModel.getInstance();
|
||||
const outputLines = useAtomValue(buildPanelModel.outputLines);
|
||||
const isStreaming = useAtomValue(waveAIModel.isAIStreaming);
|
||||
|
||||
const getBuildContext = () => {
|
||||
const filteredLines = outputLines.filter((line) => !line.startsWith("[debug]"));
|
||||
const buildOutput = filteredLines.join("\n").trim();
|
||||
return `Build Error:\n\`\`\`\n${displayMsg}\n\`\`\`\n\nBuild Output:\n\`\`\`\n${buildOutput}\n\`\`\``;
|
||||
};
|
||||
|
||||
const handleAddToContext = () => {
|
||||
const context = getBuildContext();
|
||||
waveAIModel.appendText(context, true);
|
||||
waveAIModel.focusInput();
|
||||
};
|
||||
|
||||
const handleAskAIToFix = async () => {
|
||||
const context = getBuildContext();
|
||||
waveAIModel.appendText("Please help me fix this build error:\n\n" + context, true);
|
||||
await waveAIModel.handleSubmit();
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="w-full h-full flex items-center justify-center bg-background">
|
||||
<div className="flex flex-col items-center gap-6 max-w-2xl text-center px-8">
|
||||
|
|
@ -38,6 +63,22 @@ const ErrorStateView = memo(({ errorMsg }: { errorMsg: string }) => {
|
|||
<div className="text-left bg-panel border border-error/30 rounded-lg p-4 max-h-96 overflow-auto">
|
||||
<pre className="text-sm text-secondary whitespace-pre-wrap font-mono">{displayMsg}</pre>
|
||||
</div>
|
||||
{!isStreaming && (
|
||||
<div className="flex gap-3 mt-2 justify-center">
|
||||
<button
|
||||
onClick={handleAddToContext}
|
||||
className="px-4 py-2 bg-panel text-primary border border-border rounded hover:bg-panel/80 transition-colors cursor-pointer"
|
||||
>
|
||||
Add Error to AI Context
|
||||
</button>
|
||||
<button
|
||||
onClick={handleAskAIToFix}
|
||||
className="px-4 py-2 bg-accent text-primary font-semibold rounded hover:bg-accent/80 transition-colors cursor-pointer"
|
||||
>
|
||||
Ask AI to Fix
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
12
frontend/types/gotypes.d.ts
vendored
12
frontend/types/gotypes.d.ts
vendored
|
|
@ -379,6 +379,11 @@ declare global {
|
|||
resolvedids: {[key: string]: ORef};
|
||||
};
|
||||
|
||||
// wshrpc.CommandRestartBuilderAndWaitData
|
||||
type CommandRestartBuilderAndWaitData = {
|
||||
builderid: string;
|
||||
};
|
||||
|
||||
// wshrpc.CommandSetMetaData
|
||||
type CommandSetMetaData = {
|
||||
oref: ORef;
|
||||
|
|
@ -909,6 +914,13 @@ declare global {
|
|||
shell: string;
|
||||
};
|
||||
|
||||
// wshrpc.RestartBuilderAndWaitResult
|
||||
type RestartBuilderAndWaitResult = {
|
||||
success: boolean;
|
||||
errormessage?: string;
|
||||
buildoutput: string;
|
||||
};
|
||||
|
||||
// wshutil.RpcMessage
|
||||
type RpcMessage = {
|
||||
command?: string;
|
||||
|
|
|
|||
|
|
@ -4,13 +4,19 @@
|
|||
package aiusechat
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/wavetermdev/waveterm/pkg/aiusechat/uctypes"
|
||||
"github.com/wavetermdev/waveterm/pkg/buildercontroller"
|
||||
"github.com/wavetermdev/waveterm/pkg/util/fileutil"
|
||||
"github.com/wavetermdev/waveterm/pkg/util/utilfn"
|
||||
"github.com/wavetermdev/waveterm/pkg/waveappstore"
|
||||
"github.com/wavetermdev/waveterm/pkg/waveobj"
|
||||
"github.com/wavetermdev/waveterm/pkg/wps"
|
||||
"github.com/wavetermdev/waveterm/pkg/wstore"
|
||||
)
|
||||
|
||||
const BuilderAppFileName = "app.go"
|
||||
|
|
@ -19,6 +25,35 @@ type builderWriteAppFileParams struct {
|
|||
Contents string `json:"contents"`
|
||||
}
|
||||
|
||||
func triggerBuildAndWait(builderId string, appId string) map[string]any {
|
||||
bc := buildercontroller.GetOrCreateController(builderId)
|
||||
rtInfo := wstore.GetRTInfo(waveobj.MakeORef(waveobj.OType_Builder, builderId))
|
||||
|
||||
var builderEnv map[string]string
|
||||
if rtInfo != nil {
|
||||
builderEnv = rtInfo.BuilderEnv
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
|
||||
defer cancel()
|
||||
|
||||
result, err := bc.RestartAndWaitForBuild(ctx, appId, builderEnv)
|
||||
if err != nil {
|
||||
log.Printf("Build failed for %s: %v", builderId, err)
|
||||
return map[string]any{
|
||||
"build_success": false,
|
||||
"build_error": err.Error(),
|
||||
"build_output": "",
|
||||
}
|
||||
}
|
||||
|
||||
return map[string]any{
|
||||
"build_success": result.Success,
|
||||
"build_error": result.ErrorMessage,
|
||||
"build_output": result.BuildOutput,
|
||||
}
|
||||
}
|
||||
|
||||
func parseBuilderWriteAppFileInput(input any) (*builderWriteAppFileParams, error) {
|
||||
result := &builderWriteAppFileParams{}
|
||||
|
||||
|
|
@ -37,7 +72,7 @@ func parseBuilderWriteAppFileInput(input any) (*builderWriteAppFileParams, error
|
|||
return result, nil
|
||||
}
|
||||
|
||||
func GetBuilderWriteAppFileToolDefinition(appId string) uctypes.ToolDefinition {
|
||||
func GetBuilderWriteAppFileToolDefinition(appId string, builderId string) uctypes.ToolDefinition {
|
||||
return uctypes.ToolDefinition{
|
||||
Name: "builder_write_app_file",
|
||||
DisplayName: "Write App File",
|
||||
|
|
@ -74,10 +109,19 @@ func GetBuilderWriteAppFileToolDefinition(appId string) uctypes.ToolDefinition {
|
|||
Scopes: []string{appId},
|
||||
})
|
||||
|
||||
return map[string]any{
|
||||
result := map[string]any{
|
||||
"success": true,
|
||||
"message": fmt.Sprintf("Successfully wrote %s", BuilderAppFileName),
|
||||
}, nil
|
||||
}
|
||||
|
||||
if builderId != "" {
|
||||
buildResult := triggerBuildAndWait(builderId, appId)
|
||||
result["build_success"] = buildResult["build_success"]
|
||||
result["build_error"] = buildResult["build_error"]
|
||||
result["build_output"] = buildResult["build_output"]
|
||||
}
|
||||
|
||||
return result, nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
@ -104,7 +148,7 @@ func parseBuilderEditAppFileInput(input any) (*builderEditAppFileParams, error)
|
|||
return result, nil
|
||||
}
|
||||
|
||||
func GetBuilderEditAppFileToolDefinition(appId string) uctypes.ToolDefinition {
|
||||
func GetBuilderEditAppFileToolDefinition(appId string, builderId string) uctypes.ToolDefinition {
|
||||
return uctypes.ToolDefinition{
|
||||
Name: "builder_edit_app_file",
|
||||
DisplayName: "Edit App File",
|
||||
|
|
@ -147,7 +191,12 @@ func GetBuilderEditAppFileToolDefinition(appId string) uctypes.ToolDefinition {
|
|||
if err != nil {
|
||||
return fmt.Sprintf("error parsing input: %v", err)
|
||||
}
|
||||
return fmt.Sprintf("editing app.go for %s (%d edits)", appId, len(params.Edits))
|
||||
numEdits := len(params.Edits)
|
||||
editStr := "edits"
|
||||
if numEdits == 1 {
|
||||
editStr = "edit"
|
||||
}
|
||||
return fmt.Sprintf("editing app.go for %s (%d %s)", appId, numEdits, editStr)
|
||||
},
|
||||
ToolAnyCallback: func(input any, toolUseData *uctypes.UIMessageDataToolUse) (any, error) {
|
||||
params, err := parseBuilderEditAppFileInput(input)
|
||||
|
|
@ -165,10 +214,19 @@ func GetBuilderEditAppFileToolDefinition(appId string) uctypes.ToolDefinition {
|
|||
Scopes: []string{appId},
|
||||
})
|
||||
|
||||
return map[string]any{
|
||||
result := map[string]any{
|
||||
"success": true,
|
||||
"message": fmt.Sprintf("Successfully edited %s with %d changes", BuilderAppFileName, len(params.Edits)),
|
||||
}, nil
|
||||
}
|
||||
|
||||
if builderId != "" {
|
||||
buildResult := triggerBuildAndWait(builderId, appId)
|
||||
result["build_success"] = buildResult["build_success"]
|
||||
result["build_error"] = buildResult["build_error"]
|
||||
result["build_output"] = buildResult["build_output"]
|
||||
}
|
||||
|
||||
return result, nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -717,8 +717,8 @@ func WaveAIPostMessageHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
if req.BuilderAppId != "" {
|
||||
chatOpts.Tools = append(chatOpts.Tools,
|
||||
GetBuilderWriteAppFileToolDefinition(req.BuilderAppId),
|
||||
GetBuilderEditAppFileToolDefinition(req.BuilderAppId),
|
||||
GetBuilderWriteAppFileToolDefinition(req.BuilderAppId, req.BuilderId),
|
||||
GetBuilderEditAppFileToolDefinition(req.BuilderAppId, req.BuilderId),
|
||||
GetBuilderListFilesToolDefinition(req.BuilderAppId),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import (
|
|||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
|
|
@ -41,6 +42,12 @@ type BuilderProcess struct {
|
|||
WaitRtn error
|
||||
}
|
||||
|
||||
type BuildResult struct {
|
||||
Success bool `json:"success"`
|
||||
ErrorMessage string `json:"errormessage,omitempty"`
|
||||
BuildOutput string `json:"buildoutput"`
|
||||
}
|
||||
|
||||
type BuilderController struct {
|
||||
lock sync.Mutex
|
||||
builderId string
|
||||
|
|
@ -182,22 +189,22 @@ func (bc *BuilderController) Start(ctx context.Context, appId string, builderEnv
|
|||
defer func() {
|
||||
panichandler.PanicHandler(fmt.Sprintf("buildercontroller[%s].buildAndRun", bc.builderId), recover())
|
||||
}()
|
||||
bc.buildAndRun(buildCtx, appId, builderEnv)
|
||||
bc.buildAndRun(buildCtx, appId, builderEnv, nil)
|
||||
}()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (bc *BuilderController) buildAndRun(ctx context.Context, appId string, builderEnv map[string]string) {
|
||||
func (bc *BuilderController) buildAndRun(ctx context.Context, appId string, builderEnv map[string]string, resultCh chan<- *BuildResult) {
|
||||
appNS, _, err := waveappstore.ParseAppId(appId)
|
||||
if err != nil {
|
||||
bc.handleBuildError(fmt.Errorf("failed to parse app id: %w", err))
|
||||
bc.handleBuildError(fmt.Errorf("failed to parse app id: %w", err), resultCh)
|
||||
return
|
||||
}
|
||||
|
||||
appPath, err := waveappstore.GetAppDir(appId)
|
||||
if err != nil {
|
||||
bc.handleBuildError(fmt.Errorf("failed to get app directory: %w", err))
|
||||
bc.handleBuildError(fmt.Errorf("failed to get app directory: %w", err), resultCh)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -205,13 +212,13 @@ func (bc *BuilderController) buildAndRun(ctx context.Context, appId string, buil
|
|||
|
||||
cachePath, err := GetBuilderAppExecutablePath(bc.builderId, appName)
|
||||
if err != nil {
|
||||
bc.handleBuildError(fmt.Errorf("failed to get builder executable path: %w", err))
|
||||
bc.handleBuildError(fmt.Errorf("failed to get builder executable path: %w", err), resultCh)
|
||||
return
|
||||
}
|
||||
|
||||
nodePath := wavebase.GetWaveAppElectronExecPath()
|
||||
if nodePath == "" {
|
||||
bc.handleBuildError(fmt.Errorf("electron executable path not set"))
|
||||
bc.handleBuildError(fmt.Errorf("electron executable path not set"), resultCh)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -248,24 +255,39 @@ func (bc *BuilderController) buildAndRun(ctx context.Context, appId string, buil
|
|||
}
|
||||
|
||||
if err != nil {
|
||||
bc.handleBuildError(fmt.Errorf("build failed: %w", err))
|
||||
bc.handleBuildError(fmt.Errorf("build failed: %w", err), resultCh)
|
||||
return
|
||||
}
|
||||
|
||||
info, err := os.Stat(cachePath)
|
||||
if err != nil {
|
||||
bc.handleBuildError(fmt.Errorf("build output not found: %w", err))
|
||||
bc.handleBuildError(fmt.Errorf("build output not found: %w", err), resultCh)
|
||||
return
|
||||
}
|
||||
|
||||
if runtime.GOOS != "windows" && info.Mode()&0111 == 0 {
|
||||
bc.handleBuildError(fmt.Errorf("build output is not executable"))
|
||||
bc.handleBuildError(fmt.Errorf("build output is not executable"), resultCh)
|
||||
return
|
||||
}
|
||||
|
||||
if resultCh != nil {
|
||||
buildOutput := ""
|
||||
if bc.outputBuffer != nil {
|
||||
lines := bc.outputBuffer.GetLines()
|
||||
buildOutput = strings.Join(lines, "\n")
|
||||
}
|
||||
select {
|
||||
case resultCh <- &BuildResult{
|
||||
Success: true,
|
||||
BuildOutput: buildOutput,
|
||||
}:
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
process, err := bc.runBuilderApp(ctx, cachePath, builderEnv)
|
||||
if err != nil {
|
||||
bc.handleBuildError(fmt.Errorf("failed to run app: %w", err))
|
||||
bc.handleBuildError(fmt.Errorf("failed to run app: %w", err), resultCh)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -371,10 +393,69 @@ func (bc *BuilderController) runBuilderApp(ctx context.Context, appBinPath strin
|
|||
}
|
||||
}
|
||||
|
||||
func (bc *BuilderController) handleBuildError(err error) {
|
||||
func (bc *BuilderController) handleBuildError(err error, resultCh chan<- *BuildResult) {
|
||||
bc.lock.Lock()
|
||||
defer bc.lock.Unlock()
|
||||
bc.setStatus_nolock(BuilderStatus_Error, 0, 1, err.Error())
|
||||
|
||||
if resultCh != nil {
|
||||
buildOutput := ""
|
||||
if bc.outputBuffer != nil {
|
||||
lines := bc.outputBuffer.GetLines()
|
||||
buildOutput = strings.Join(lines, "\n")
|
||||
}
|
||||
select {
|
||||
case resultCh <- &BuildResult{
|
||||
Success: false,
|
||||
ErrorMessage: err.Error(),
|
||||
BuildOutput: buildOutput,
|
||||
}:
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (bc *BuilderController) RestartAndWaitForBuild(ctx context.Context, appId string, builderEnv map[string]string) (*BuildResult, error) {
|
||||
if err := bc.waitForBuildDone(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resultCh := make(chan *BuildResult, 1)
|
||||
|
||||
bc.lock.Lock()
|
||||
if bc.appId != appId && bc.process != nil {
|
||||
log.Printf("BuilderController: stopping previous app %s for builder %s", bc.appId, bc.builderId)
|
||||
bc.stopProcess_nolock()
|
||||
}
|
||||
|
||||
bc.appId = appId
|
||||
bc.outputBuffer = utilds.MakeMultiReaderLineBuffer(1000)
|
||||
bc.setStatus_nolock(BuilderStatus_Building, 0, 0, "")
|
||||
|
||||
bc.publishOutputLine("", true)
|
||||
|
||||
bc.outputBuffer.SetLineCallback(func(line string) {
|
||||
bc.publishOutputLine(line, false)
|
||||
})
|
||||
bc.lock.Unlock()
|
||||
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
|
||||
buildCtx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
|
||||
go func() {
|
||||
defer cancel()
|
||||
defer func() {
|
||||
panichandler.PanicHandler(fmt.Sprintf("buildercontroller[%s].buildAndRun", bc.builderId), recover())
|
||||
}()
|
||||
bc.buildAndRun(buildCtx, appId, builderEnv, resultCh)
|
||||
}()
|
||||
|
||||
select {
|
||||
case result := <-resultCh:
|
||||
return result, nil
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
}
|
||||
}
|
||||
|
||||
func (bc *BuilderController) Stop() error {
|
||||
|
|
|
|||
|
|
@ -568,6 +568,12 @@ func ResolveIdsCommand(w *wshutil.WshRpc, data wshrpc.CommandResolveIdsData, opt
|
|||
return resp, err
|
||||
}
|
||||
|
||||
// command "restartbuilderandwait", wshserver.RestartBuilderAndWaitCommand
|
||||
func RestartBuilderAndWaitCommand(w *wshutil.WshRpc, data wshrpc.CommandRestartBuilderAndWaitData, opts *wshrpc.RpcOpts) (*wshrpc.RestartBuilderAndWaitResult, error) {
|
||||
resp, err := sendRpcRequestCallHelper[*wshrpc.RestartBuilderAndWaitResult](w, "restartbuilderandwait", data, opts)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
// command "routeannounce", wshserver.RouteAnnounceCommand
|
||||
func RouteAnnounceCommand(w *wshutil.WshRpc, opts *wshrpc.RpcOpts) error {
|
||||
_, err := sendRpcRequestCallHelper[any](w, "routeannounce", nil, opts)
|
||||
|
|
|
|||
|
|
@ -157,17 +157,18 @@ const (
|
|||
Command_TermGetScrollbackLines = "termgetscrollbacklines"
|
||||
|
||||
// builder
|
||||
Command_ListAllEditableApps = "listalleditableapps"
|
||||
Command_ListAllAppFiles = "listallappfiles"
|
||||
Command_ReadAppFile = "readappfile"
|
||||
Command_WriteAppFile = "writeappfile"
|
||||
Command_DeleteAppFile = "deleteappfile"
|
||||
Command_RenameAppFile = "renameappfile"
|
||||
Command_DeleteBuilder = "deletebuilder"
|
||||
Command_StartBuilder = "startbuilder"
|
||||
Command_GetBuilderStatus = "getbuilderstatus"
|
||||
Command_GetBuilderOutput = "getbuilderoutput"
|
||||
Command_CheckGoVersion = "checkgoversion"
|
||||
Command_ListAllEditableApps = "listalleditableapps"
|
||||
Command_ListAllAppFiles = "listallappfiles"
|
||||
Command_ReadAppFile = "readappfile"
|
||||
Command_WriteAppFile = "writeappfile"
|
||||
Command_DeleteAppFile = "deleteappfile"
|
||||
Command_RenameAppFile = "renameappfile"
|
||||
Command_DeleteBuilder = "deletebuilder"
|
||||
Command_StartBuilder = "startbuilder"
|
||||
Command_RestartBuilderAndWait = "restartbuilderandwait"
|
||||
Command_GetBuilderStatus = "getbuilderstatus"
|
||||
Command_GetBuilderOutput = "getbuilderoutput"
|
||||
Command_CheckGoVersion = "checkgoversion"
|
||||
|
||||
// electron
|
||||
Command_ElectronEncrypt = "electronencrypt"
|
||||
|
|
@ -334,6 +335,7 @@ type WshRpcInterface interface {
|
|||
RenameAppFileCommand(ctx context.Context, data CommandRenameAppFileData) error
|
||||
DeleteBuilderCommand(ctx context.Context, builderId string) error
|
||||
StartBuilderCommand(ctx context.Context, data CommandStartBuilderData) error
|
||||
RestartBuilderAndWaitCommand(ctx context.Context, data CommandRestartBuilderAndWaitData) (*RestartBuilderAndWaitResult, error)
|
||||
GetBuilderStatusCommand(ctx context.Context, builderId string) (*BuilderStatusData, error)
|
||||
GetBuilderOutputCommand(ctx context.Context, builderId string) ([]string, error)
|
||||
CheckGoVersionCommand(ctx context.Context) (*CommandCheckGoVersionRtnData, error)
|
||||
|
|
@ -1017,6 +1019,16 @@ type CommandStartBuilderData struct {
|
|||
BuilderId string `json:"builderid"`
|
||||
}
|
||||
|
||||
type CommandRestartBuilderAndWaitData struct {
|
||||
BuilderId string `json:"builderid"`
|
||||
}
|
||||
|
||||
type RestartBuilderAndWaitResult struct {
|
||||
Success bool `json:"success"`
|
||||
ErrorMessage string `json:"errormessage,omitempty"`
|
||||
BuildOutput string `json:"buildoutput"`
|
||||
}
|
||||
|
||||
type BuilderStatusData struct {
|
||||
Status string `json:"status"`
|
||||
Port int `json:"port,omitempty"`
|
||||
|
|
|
|||
|
|
@ -1051,6 +1051,35 @@ func (ws *WshServer) StartBuilderCommand(ctx context.Context, data wshrpc.Comman
|
|||
return bc.Start(ctx, appId, rtInfo.BuilderEnv)
|
||||
}
|
||||
|
||||
func (ws *WshServer) RestartBuilderAndWaitCommand(ctx context.Context, data wshrpc.CommandRestartBuilderAndWaitData) (*wshrpc.RestartBuilderAndWaitResult, error) {
|
||||
if data.BuilderId == "" {
|
||||
return nil, fmt.Errorf("must provide a builderId to RestartBuilderAndWaitCommand")
|
||||
}
|
||||
|
||||
bc := buildercontroller.GetOrCreateController(data.BuilderId)
|
||||
rtInfo := wstore.GetRTInfo(waveobj.MakeORef("builder", data.BuilderId))
|
||||
if rtInfo == nil {
|
||||
return nil, fmt.Errorf("builder rtinfo not found for builderid: %s", data.BuilderId)
|
||||
}
|
||||
|
||||
appId := rtInfo.BuilderAppId
|
||||
if appId == "" {
|
||||
return nil, fmt.Errorf("builder appid not set for builderid: %s", data.BuilderId)
|
||||
}
|
||||
|
||||
result, err := bc.RestartAndWaitForBuild(ctx, appId, rtInfo.BuilderEnv)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &wshrpc.RestartBuilderAndWaitResult{
|
||||
Success: result.Success,
|
||||
ErrorMessage: result.ErrorMessage,
|
||||
BuildOutput: result.BuildOutput,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
func (ws *WshServer) GetBuilderStatusCommand(ctx context.Context, builderId string) (*wshrpc.BuilderStatusData, error) {
|
||||
if builderId == "" {
|
||||
return nil, fmt.Errorf("must provide a builderId to GetBuilderStatusCommand")
|
||||
|
|
|
|||
Loading…
Reference in a new issue