diff --git a/frontend/types/gotypes.d.ts b/frontend/types/gotypes.d.ts
index b76f911bd..f2c14723a 100644
--- a/frontend/types/gotypes.d.ts
+++ b/frontend/types/gotypes.d.ts
@@ -491,6 +491,7 @@ declare global {
"term:scrollback"?: number;
"term:vdomblockid"?: string;
"term:vdomtoolbarblockid"?: string;
+ "term:transparency"?: number;
"web:zoom"?: number;
"markdown:fontsize"?: number;
"markdown:fixedfontsize"?: number;
@@ -641,6 +642,7 @@ declare global {
"term:localshellopts"?: string[];
"term:scrollback"?: number;
"term:copyonselect"?: boolean;
+ "term:transparency"?: number;
"editor:minimapenabled"?: boolean;
"editor:stickyscrollenabled"?: boolean;
"editor:wordwrap"?: boolean;
@@ -678,6 +680,8 @@ declare global {
"window:magnifiedblocksize"?: number;
"window:magnifiedblockblurprimarypx"?: number;
"window:magnifiedblockblursecondarypx"?: number;
+ "window:confirmclose"?: boolean;
+ "window:savelastwindow"?: boolean;
"telemetry:*"?: boolean;
"telemetry:enabled"?: boolean;
"conn:*"?: boolean;
diff --git a/go.mod b/go.mod
index 772c34c62..448f0f818 100644
--- a/go.mod
+++ b/go.mod
@@ -45,9 +45,9 @@ require (
github.com/ubuntu/decorate v0.0.0-20230125165522-2d5b0a9bb117 // indirect
github.com/yusufpapurcu/wmi v1.2.4 // indirect
go.uber.org/atomic v1.7.0 // indirect
- golang.org/x/net v0.29.0 // indirect
+ golang.org/x/net v0.33.0 // indirect
)
-replace github.com/kevinburke/ssh_config => github.com/wavetermdev/ssh_config v0.0.0-20241027232332-ed124367682d
+replace github.com/kevinburke/ssh_config => github.com/wavetermdev/ssh_config v0.0.0-20241219203747-6409e4292f34
replace github.com/creack/pty => github.com/photostorm/pty v1.1.19-0.20230903182454-31354506054b
diff --git a/go.sum b/go.sum
index 8429144ec..d560a54ab 100644
--- a/go.sum
+++ b/go.sum
@@ -90,16 +90,16 @@ github.com/ubuntu/gowsl v0.0.0-20240906163211-049fd49bd93b h1:wFBKF5k5xbJQU8bYgc
github.com/ubuntu/gowsl v0.0.0-20240906163211-049fd49bd93b/go.mod h1:N1CYNinssZru+ikvYTgVbVeSi21thHUTCoJ9xMvWe+s=
github.com/wavetermdev/htmltoken v0.2.0 h1:sFVPPemlDv7/jg7n4Hx1AEF2m9MVAFjFpELWfhi/DlM=
github.com/wavetermdev/htmltoken v0.2.0/go.mod h1:5FM0XV6zNYiNza2iaTcFGj+hnMtgqumFHO31Z8euquk=
-github.com/wavetermdev/ssh_config v0.0.0-20241027232332-ed124367682d h1:ArHaUBaiQWUqBzM2G/oLlm3Be0kwUMDt9vTNOWIfOd0=
-github.com/wavetermdev/ssh_config v0.0.0-20241027232332-ed124367682d/go.mod h1:q2RIzfka+BXARoNexmF9gkxEX7DmvbW9P4hIVx2Kg4M=
+github.com/wavetermdev/ssh_config v0.0.0-20241219203747-6409e4292f34 h1:I8VZVTZEXhnzfN7jB9a7TZYpzNO48sCUWMRXHM9XWSA=
+github.com/wavetermdev/ssh_config v0.0.0-20241219203747-6409e4292f34/go.mod h1:q2RIzfka+BXARoNexmF9gkxEX7DmvbW9P4hIVx2Kg4M=
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
-golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo=
-golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0=
+golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
+golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
diff --git a/package.json b/package.json
index 6497727ea..eadcdb21d 100644
--- a/package.json
+++ b/package.json
@@ -7,7 +7,7 @@
"productName": "Wave",
"description": "Open-Source AI-Native Terminal Built for Seamless Workflows",
"license": "Apache-2.0",
- "version": "0.10.2-beta.0",
+ "version": "0.10.4",
"homepage": "https://waveterm.dev",
"build": {
"appId": "dev.commandline.waveterm"
diff --git a/pkg/filestore/blockstore_cache.go b/pkg/filestore/blockstore_cache.go
index f8608654b..ab48e7a83 100644
--- a/pkg/filestore/blockstore_cache.go
+++ b/pkg/filestore/blockstore_cache.go
@@ -227,6 +227,9 @@ func (entry *CacheEntry) readAt(ctx context.Context, offset int64, size int64, r
offset += truncateAmt
size -= truncateAmt
}
+ if size <= 0 {
+ return realDataOffset, nil, nil
+ }
}
partMap := file.computePartMap(offset, size)
dataEntryMap, err := entry.loadDataPartsForRead(ctx, getPartIdxsFromMap(partMap))
diff --git a/pkg/remote/sshclient.go b/pkg/remote/sshclient.go
index bcc4291c2..3b2b0cc90 100644
--- a/pkg/remote/sshclient.go
+++ b/pkg/remote/sshclient.go
@@ -23,6 +23,7 @@ import (
"github.com/kevinburke/ssh_config"
"github.com/skeema/knownhosts"
+ "github.com/wavetermdev/waveterm/pkg/panichandler"
"github.com/wavetermdev/waveterm/pkg/trimquotes"
"github.com/wavetermdev/waveterm/pkg/userinput"
"github.com/wavetermdev/waveterm/pkg/util/shellutil"
@@ -750,7 +751,13 @@ func combineSshKeywords(userProvidedOpts *wshrpc.ConnKeywords, configKeywords *w
// note that a `var == "yes"` will default to false
// but `var != "no"` will default to true
// when given unexpected strings
-func findSshConfigKeywords(hostPattern string) (*wshrpc.ConnKeywords, error) {
+func findSshConfigKeywords(hostPattern string) (connKeywords *wshrpc.ConnKeywords, outErr error) {
+ defer func() {
+ err := panichandler.PanicHandler("sshclient:find-ssh-config-keywords")
+ if err != nil {
+ outErr = err
+ }
+ }()
WaveSshConfigUserSettings().ReloadConfigs()
sshKeywords := &wshrpc.ConnKeywords{}
var err error
diff --git a/pkg/service/workspaceservice/workspaceservice.go b/pkg/service/workspaceservice/workspaceservice.go
index 1c86ff77b..b6c97ac8b 100644
--- a/pkg/service/workspaceservice/workspaceservice.go
+++ b/pkg/service/workspaceservice/workspaceservice.go
@@ -45,10 +45,13 @@ func (svc *WorkspaceService) UpdateWorkspace_Meta() tsgenmeta.MethodMeta {
func (svc *WorkspaceService) UpdateWorkspace(ctx context.Context, workspaceId string, name string, icon string, color string, applyDefaults bool) (waveobj.UpdatesRtnType, error) {
ctx = waveobj.ContextWithUpdates(ctx)
- _, err := wcore.UpdateWorkspace(ctx, workspaceId, name, icon, color, applyDefaults)
+ _, updated, err := wcore.UpdateWorkspace(ctx, workspaceId, name, icon, color, applyDefaults)
if err != nil {
return nil, fmt.Errorf("error updating workspace: %w", err)
}
+ if !updated {
+ return nil, nil
+ }
wps.Broker.Publish(wps.WaveEvent{
Event: wps.Event_WorkspaceUpdate})
diff --git a/pkg/shellexec/shellexec.go b/pkg/shellexec/shellexec.go
index 2c811d85c..a6fcf00e4 100644
--- a/pkg/shellexec/shellexec.go
+++ b/pkg/shellexec/shellexec.go
@@ -215,7 +215,7 @@ func StartWslShellProc(ctx context.Context, termSize waveobj.TermSize, cmdStr st
}
if isZshShell(shellPath) {
- shellOpts = append(shellOpts, fmt.Sprintf(`ZDOTDIR="%s/.waveterm/%s"`, homeDir, shellutil.ZshIntegrationDir))
+ shellOpts = append(shellOpts, fmt.Sprintf(`ZDOTDIR=%s/.waveterm/%s`, homeDir, shellutil.ZshIntegrationDir))
}
shellOpts = append(shellOpts, shellPath)
shellOpts = append(shellOpts, subShellOpts...)
diff --git a/pkg/waveobj/metaconsts.go b/pkg/waveobj/metaconsts.go
index 9071bf326..6b65249b6 100644
--- a/pkg/waveobj/metaconsts.go
+++ b/pkg/waveobj/metaconsts.go
@@ -93,6 +93,7 @@ const (
MetaKey_TermScrollback = "term:scrollback"
MetaKey_TermVDomSubBlockId = "term:vdomblockid"
MetaKey_TermVDomToolbarBlockId = "term:vdomtoolbarblockid"
+ MetaKey_TermTransparency = "term:transparency"
MetaKey_WebZoom = "web:zoom"
diff --git a/pkg/waveobj/wtypemeta.go b/pkg/waveobj/wtypemeta.go
index 41f0b7be5..bbf30cffb 100644
--- a/pkg/waveobj/wtypemeta.go
+++ b/pkg/waveobj/wtypemeta.go
@@ -94,6 +94,7 @@ type MetaTSType struct {
TermScrollback *int `json:"term:scrollback,omitempty"`
TermVDomSubBlockId string `json:"term:vdomblockid,omitempty"`
TermVDomToolbarBlockId string `json:"term:vdomtoolbarblockid,omitempty"`
+ TermTransparency *float64 `json:"term:transparency,omitempty"` // default 0.5
WebZoom float64 `json:"web:zoom,omitempty"`
diff --git a/pkg/wconfig/defaultconfig/settings.json b/pkg/wconfig/defaultconfig/settings.json
index fa8d98f88..3da7e6fd2 100644
--- a/pkg/wconfig/defaultconfig/settings.json
+++ b/pkg/wconfig/defaultconfig/settings.json
@@ -7,7 +7,7 @@
"autoupdate:installonquit": true,
"autoupdate:intervalms": 3600000,
"conn:askbeforewshinstall": true,
- "conn:wshenabled": true,
+ "conn:wshenabled": true,
"editor:minimapenabled": true,
"web:defaulturl": "https://github.com/wavetermdev/waveterm",
"web:defaultsearch": "https://www.google.com/search?q={query}",
@@ -18,6 +18,8 @@
"window:magnifiedblocksize": 0.9,
"window:magnifiedblockblurprimarypx": 10,
"window:magnifiedblockblursecondarypx": 2,
+ "window:confirmclose": true,
+ "window:savelastwindow": true,
"telemetry:enabled": true,
"term:copyonselect": true
}
diff --git a/pkg/wconfig/defaultconfig/termthemes.json b/pkg/wconfig/defaultconfig/termthemes.json
index ea8a5f1a0..d0a667f0a 100644
--- a/pkg/wconfig/defaultconfig/termthemes.json
+++ b/pkg/wconfig/defaultconfig/termthemes.json
@@ -22,12 +22,37 @@
"cmdtext": "#f0f0f0",
"foreground": "#c1c1c1",
"selectionBackground": "",
- "background": "#00000077",
+ "background": "#000000",
"cursor": ""
},
+ "onedarkpro": {
+ "display:name": "One Dark Pro",
+ "display:order": 2,
+ "background": "#21252B",
+ "foreground": "#ABB2BF",
+ "cursor": "#D7DAE0",
+ "black": "#3F4451",
+ "red": "#E06C75",
+ "green": "#98C379",
+ "yellow": "#D18F52",
+ "blue": "#61AFEF",
+ "magenta": "#C678DD",
+ "cyan": "#42B3C2",
+ "white": "#D7DAE0",
+ "brightBlack": "#4F5666",
+ "brightRed": "#FF616E",
+ "brightGreen": "#A5E075",
+ "brightYellow": "#F0A45D",
+ "brightBlue": "#4DC4FF",
+ "brightMagenta": "#DE73FF",
+ "brightCyan": "#4CD1E0",
+ "brightWhite": "#E6E6E6",
+ "gray": "#495162",
+ "cmdtext": "#ABB2BF"
+ },
"dracula": {
"display:name": "Dracula",
- "display:order": 2,
+ "display:order": 3,
"black": "#21222C",
"red": "#FF5555",
"green": "#50FA7B",
@@ -47,13 +72,12 @@
"gray": "#6272A4",
"cmdtext": "#F8F8F2",
"foreground": "#F8F8F2",
- "selectionBackground": "#44475a",
"background": "#282a36",
"cursor": "#f8f8f2"
},
"monokai": {
"display:name": "Monokai",
- "display:order": 3,
+ "display:order": 4,
"black": "#1B1D1E",
"red": "#F92672",
"green": "#A6E22E",
@@ -73,13 +97,12 @@
"gray": "#75715E",
"cmdtext": "#F8F8F2",
"foreground": "#F8F8F2",
- "selectionBackground": "#49483E",
"background": "#272822",
"cursor": "#F8F8F2"
},
"campbell": {
"display:name": "Campbell",
- "display:order": 4,
+ "display:order": 5,
"black": "#0C0C0C",
"red": "#C50F1F",
"green": "#13A10E",
@@ -99,13 +122,13 @@
"gray": "#767676",
"cmdtext": "#CCCCCC",
"foreground": "#CCCCCC",
- "selectionBackground": "#3A96DD",
+ "selectionBackground": "#3A96DD77",
"background": "#0C0C0C",
"cursor": "#CCCCCC"
},
"warmyellow": {
"display:name": "Warm Yellow",
- "display:order": 4,
+ "display:order": 6,
"black": "#3C3228",
"red": "#E67E22",
"green": "#A5D6A7",
@@ -124,33 +147,32 @@
"brightWhite": "#FFFFFF",
"background": "#2B2620",
"foreground": "#F2E6D4",
- "selectionBackground": "#B7950B",
+ "selectionBackground": "#B7950B77",
"cursor": "#F9D784"
},
- "onedarkpro": {
- "display:name": "One Dark Pro",
- "display:order": 1.5,
- "background": "#282C34",
- "foreground": "#ABB2BF",
- "cursor": "#D7DAE0",
- "selectionBackground": "#528BFF",
- "black": "#3F4451",
- "red": "#E05561",
- "green": "#8CC265",
- "yellow": "#D18F52",
- "blue": "#4AA5F0",
- "magenta": "#C162DE",
- "cyan": "#42B3C2",
- "white": "#D7DAE0",
- "brightBlack": "#4F5666",
- "brightRed": "#FF616E",
- "brightGreen": "#A5E075",
- "brightYellow": "#F0A45D",
- "brightBlue": "#4DC4FF",
- "brightMagenta": "#DE73FF",
- "brightCyan": "#4CD1E0",
- "brightWhite": "#E6E6E6",
- "gray": "#495162",
- "cmdtext": "#ABB2BF"
+ "rosepine": {
+ "display:name": "Rose Pine",
+ "display:order": 7,
+ "black": "#26233a",
+ "red": "#eb6f92",
+ "green": "#3e8fb0",
+ "yellow": "#f6c177",
+ "blue": "#9ccfd8",
+ "magenta": "#c4a7e7",
+ "cyan": "#ebbcba",
+ "white": "#e0def4",
+ "brightBlack": "#908caa",
+ "brightRed": "#ff8cab",
+ "brightGreen": "#9ccfb0",
+ "brightYellow": "#ffd196",
+ "brightBlue": "#bee6e0",
+ "brightMagenta": "#e2c4ff",
+ "brightCyan": "#ffd1d0",
+ "brightWhite": "#fffaf3",
+ "gray": "#908caa",
+ "cmdtext": "#e0def4",
+ "foreground": "#e0def4",
+ "background": "#191724",
+ "cursor": "#524f67"
}
}
diff --git a/pkg/wconfig/metaconsts.go b/pkg/wconfig/metaconsts.go
index e0c888ec6..ae01a5e81 100644
--- a/pkg/wconfig/metaconsts.go
+++ b/pkg/wconfig/metaconsts.go
@@ -33,6 +33,7 @@ const (
ConfigKey_TermLocalShellOpts = "term:localshellopts"
ConfigKey_TermScrollback = "term:scrollback"
ConfigKey_TermCopyOnSelect = "term:copyonselect"
+ ConfigKey_TermTransparency = "term:transparency"
ConfigKey_EditorMinimapEnabled = "editor:minimapenabled"
ConfigKey_EditorStickyScrollEnabled = "editor:stickyscrollenabled"
@@ -79,6 +80,8 @@ const (
ConfigKey_WindowMagnifiedBlockSize = "window:magnifiedblocksize"
ConfigKey_WindowMagnifiedBlockBlurPrimaryPx = "window:magnifiedblockblurprimarypx"
ConfigKey_WindowMagnifiedBlockBlurSecondaryPx = "window:magnifiedblockblursecondarypx"
+ ConfigKey_WindowConfirmClose = "window:confirmclose"
+ ConfigKey_WindowSaveLastWindow = "window:savelastwindow"
ConfigKey_TelemetryClear = "telemetry:*"
ConfigKey_TelemetryEnabled = "telemetry:enabled"
diff --git a/pkg/wconfig/settingsconfig.go b/pkg/wconfig/settingsconfig.go
index 437375429..685ac7f83 100644
--- a/pkg/wconfig/settingsconfig.go
+++ b/pkg/wconfig/settingsconfig.go
@@ -60,6 +60,7 @@ type SettingsType struct {
TermLocalShellOpts []string `json:"term:localshellopts,omitempty"`
TermScrollback *int64 `json:"term:scrollback,omitempty"`
TermCopyOnSelect *bool `json:"term:copyonselect,omitempty"`
+ TermTransparency *float64 `json:"term:transparency,omitempty"`
EditorMinimapEnabled bool `json:"editor:minimapenabled,omitempty"`
EditorStickyScrollEnabled bool `json:"editor:stickyscrollenabled,omitempty"`
@@ -106,6 +107,8 @@ type SettingsType struct {
WindowMagnifiedBlockSize *float64 `json:"window:magnifiedblocksize,omitempty"`
WindowMagnifiedBlockBlurPrimaryPx *int64 `json:"window:magnifiedblockblurprimarypx,omitempty"`
WindowMagnifiedBlockBlurSecondaryPx *int64 `json:"window:magnifiedblockblursecondarypx,omitempty"`
+ WindowConfirmClose bool `json:"window:confirmclose,omitempty"`
+ WindowSaveLastWindow bool `json:"window:savelastwindow,omitempty"`
TelemetryClear bool `json:"telemetry:*,omitempty"`
TelemetryEnabled bool `json:"telemetry:enabled,omitempty"`
diff --git a/pkg/wcore/wcore.go b/pkg/wcore/wcore.go
index 780344135..4b7b1558a 100644
--- a/pkg/wcore/wcore.go
+++ b/pkg/wcore/wcore.go
@@ -25,6 +25,7 @@ func EnsureInitialData() error {
ctx, cancelFn := context.WithTimeout(context.Background(), 2*time.Second)
defer cancelFn()
client, err := wstore.DBGetSingleton[*waveobj.Client](ctx)
+ firstLaunch := false
if err == wstore.ErrNotFound {
client, err = CreateClient(ctx)
if err != nil {
@@ -34,6 +35,7 @@ func EnsureInitialData() error {
if migrateErr != nil {
log.Printf("error migrating old history: %v\n", migrateErr)
}
+ firstLaunch = true
}
if client.TempOID == "" {
log.Println("client.TempOID is empty")
@@ -53,12 +55,16 @@ func EnsureInitialData() error {
log.Println("client has windows")
return nil
}
- log.Println("client has no windows, creating starter workspace")
- starterWs, err := CreateWorkspace(ctx, "Starter workspace", "custom@wave-logo-solid", "#58C142", false, true)
- if err != nil {
- return fmt.Errorf("error creating starter workspace: %w", err)
+ wsId := ""
+ if firstLaunch {
+ log.Println("client has no windows and first launch, creating starter workspace")
+ starterWs, err := CreateWorkspace(ctx, "Starter workspace", "custom@wave-logo-solid", "#58C142", false, true)
+ if err != nil {
+ return fmt.Errorf("error creating starter workspace: %w", err)
+ }
+ wsId = starterWs.OID
}
- _, err = CreateWindow(ctx, nil, starterWs.OID)
+ _, err = CreateWindow(ctx, nil, wsId)
if err != nil {
return fmt.Errorf("error creating window: %w", err)
}
diff --git a/pkg/wcore/workspace.go b/pkg/wcore/workspace.go
index b3143b2ab..1cc8ce1cf 100644
--- a/pkg/wcore/workspace.go
+++ b/pkg/wcore/workspace.go
@@ -68,26 +68,34 @@ func CreateWorkspace(ctx context.Context, name string, icon string, color string
wps.Broker.Publish(wps.WaveEvent{
Event: wps.Event_WorkspaceUpdate})
- return UpdateWorkspace(ctx, ws.OID, name, icon, color, applyDefaults)
+ ws, _, err = UpdateWorkspace(ctx, ws.OID, name, icon, color, applyDefaults)
+ return ws, err
}
-func UpdateWorkspace(ctx context.Context, workspaceId string, name string, icon string, color string, applyDefaults bool) (*waveobj.Workspace, error) {
+// Returns updated workspace, whether it was updated, error.
+func UpdateWorkspace(ctx context.Context, workspaceId string, name string, icon string, color string, applyDefaults bool) (*waveobj.Workspace, bool, error) {
ws, err := GetWorkspace(ctx, workspaceId)
+ updated := false
if err != nil {
- return nil, fmt.Errorf("workspace %s not found: %w", workspaceId, err)
+ return nil, updated, fmt.Errorf("workspace %s not found: %w", workspaceId, err)
}
if name != "" {
ws.Name = name
+ updated = true
} else if applyDefaults && ws.Name == "" {
ws.Name = fmt.Sprintf("New Workspace (%s)", ws.OID[0:5])
+ updated = true
}
if icon != "" {
ws.Icon = icon
+ updated = true
} else if applyDefaults && ws.Icon == "" {
ws.Icon = WorkspaceIcons[0]
+ updated = true
}
if color != "" {
ws.Color = color
+ updated = true
} else if applyDefaults && ws.Color == "" {
wsList, err := ListWorkspaces(ctx)
if err != nil {
@@ -95,9 +103,12 @@ func UpdateWorkspace(ctx context.Context, workspaceId string, name string, icon
wsList = waveobj.WorkspaceList{}
}
ws.Color = WorkspaceColors[len(wsList)%len(WorkspaceColors)]
+ updated = true
}
- wstore.DBUpdate(ctx, ws)
- return ws, nil
+ if updated {
+ wstore.DBUpdate(ctx, ws)
+ }
+ return ws, updated, nil
}
// If force is true, it will delete even if workspace is named.
diff --git a/pkg/wshutil/wshrpc.go b/pkg/wshutil/wshrpc.go
index 4bbbbd01e..24bb8d483 100644
--- a/pkg/wshutil/wshrpc.go
+++ b/pkg/wshutil/wshrpc.go
@@ -342,7 +342,10 @@ func (w *WshRpc) runServer() {
continue
}
if msg.IsRpcRequest() {
- go w.handleRequest(&msg)
+ go func() {
+ defer panichandler.PanicHandler("handleRequest:goroutine")
+ w.handleRequest(&msg)
+ }()
} else {
respCh := w.getResponseCh(msg.ResId)
if respCh == nil {